Image Layout¶
Ixian modules use a Dockerfile layout designed to support modular
multi stage builds. The layout is structured minimize COPY
commands and simplify task checks when working with multiple stages.
Base Image¶
Image builds must specify a base image. This may be a stock image such as Phusion/base-image
or
your own base image.
A customized base image is a good place to put lengthy installs or configuration that doesn’t change very often. Note that all other images extend the base image. Changes here trigger a rebuild of all other images.
Examples of files that belong in the base: * Package updates and installs (e.g. apt, yum) * Certificates * Any other common tooling
Note
Ixian tries to be platform agnostic but when needed it’s build stages will be designed for Phusion/base-image, a docker optimized Ubuntu variant.
Modules¶
Modules build a heirarchy of stages on top of the base image.
Modules files are stored in DOCKER.WORK_DIR
. Files are arranged by the stages they are added
in.
/opt/project
+- bin // All module executables may go in this directory.
| exe_1 // These do not trigger rebuilds.
| exe_2
|
\- etc
+- module_1 // Module config belongs in etc. Each module uses it's own
| file_a // directory
| file_b
\- module_2
file_c
Executables share a directory. Changes to executables don’t trigger rebuilds so they share a directory.
/opt/project
+- bin
exe_1
exe_2
Config files are split up into separate directories to simplify completeness checks and building images. Built-in modules each only use their own directory. Only this directory needs to be checked by completeness checks.
class MyImageBuildTask(Task)
check = [
# Checking the entire directory without enumerating specific files
FileHash("/opt/project/etc/my_module")
]
When the image is built only these two directories need to be copied in.
# In the modules Dockerfile, copy in the related files.
COPY root/project/bin/ /opt/project/bin
COPY root/project/etc/my_module /opt/project/etc/
Runtime Image¶
The runtime image is used to combine files from the intermediate images. It also adds runtime config files that weren’t needed by build stages. This is the final step to building an image.
Examples of runtime files:
Test runner and lint configs
Web server configs
.env
files
\- etc
+- runtime // The runtime has a config directory like everything other module
| file_a
| file_b
If they can be, built-in tools are configured to expect the config file in the modules etc
.
Some build tools require symlinks to the config file to be added to the DOCKER.WORKING_DIR
.
Built-ins that require this will indicate so in their setup instructions. These symlinks can be
created in either base image or runtime image.
# for example, package.json must be in the working directory ``NPM install`` is called from
RUN ln -s /opt/project/etc/npm/package.json
Development Environment¶
Development enviroment uses docker-compose to buid a runtime rather than the runtime itself. Within docker-compose volumes may be used for live-code editing. This avoids rebuilding the runtime image whenever it’s dependencies change. If your build-stage stages are designed well, the runtime image only has operations to merge intermediate images making it simple to replicate with docker-compose volumes.
bin
and etc
only require a single volume each. Modules don’t need to do anything special
as they store their files under this directory.
docker-compose run \ -v root/project/bin/:/opt/project/bin \ -v root/project/etc/:/opt/project/etc app