Modules
A module, typically, defines a stage in a dockerfile. It represents a particular way of filling in a Jinja2 template which can be sorted, depended on, and prioritized in a final dockerfile. Ultimately, the dockerfile is generated by stringing together a tree of modules.
Modules must be stored in docker-printer/modules/*.yml
A module is defined like the following:
name: base
priority: 100
template:
file: stage.Dockerfile.jinja2
variables:
base: python:${PYTHON_VERSION}-${BASE_OS}
env:
APP_DIR: /rearc-data-platform
instructions:
- RUN mkdir -p ${APP_DIR}
- WORKDIR ${APP_DIR}
image_args:
PYTHON_VERSION: 3.9
BASE_OS: slim-buster
The name must be unique. Filenames of modules are ignored.
Modules can be linked using depends_on, which is a list of names of other modules that must be included in any docker image this module is used in:
name: common-deps
priority: 70
depends_on:
- base
template:
file: pip-install.Dockerfile.jinja2
variables:
requirement_files:
- source: ./requirements/jobs_common.txt
destination: ./requirements.txt
A higher priority value means that a module must come earlier in the build chain. So if two modules are used in a target, and A is priority 100 and B is priority 50, then the B stage will be based on the A stage. Note that you must define at least one module or template that explicitly depends on an ultimate base image, such as an image from Docker Hub or a private base image.
Warning
priority takes precedence over depends_on. Module ordering is exclusively determined by priority; depends_on only ensures that both modules will be included somewhere in the dockerfile. In particular, depends_on makes no guarantee that the dependency module will be the immediate base image of the module declaring that dependency. Where order of modules matters, make sure to define priority values appropriately.
The Template
The template key in a module refers to, and fills in, a jinja2 template. Jinja2 is configured to look in docker-printer/templates/, so naming schemes follow normal Jinja standards from there.
The Jinja template is filled with the values passed by templates.variables. That data is passed directly to the template. This makes it possible not merely to fill in the base template, but to define custom arguments in your personal templates which can be passed from your modules. Besides being parsed as valid YAML, these variables are not validated in any way outside of Jinja.
<module>.yml schema
{
"title": "Module",
"type": "object",
"properties": {
"name": {
"title": "Name",
"type": "string"
},
"depends_on": {
"title": "Depends On",
"default": [],
"type": "array",
"items": {
"type": "string"
}
},
"priority": {
"title": "Priority",
"default": 0,
"type": "integer"
},
"setup": {
"$ref": "#/definitions/FilledTemplate"
},
"template": {
"$ref": "#/definitions/FilledTemplate"
},
"image_args": {
"title": "Image Args",
"default": {},
"type": "object"
}
},
"required": [
"name",
"template"
],
"definitions": {
"FilledTemplate": {
"title": "FilledTemplate",
"type": "object",
"properties": {
"file": {
"title": "File",
"default": "stage.Dockerfile.jinja2",
"type": "string"
},
"variables": {
"title": "Variables",
"default": {},
"type": "object"
}
}
}
}
}