-
Notifications
You must be signed in to change notification settings - Fork 51
6. Docker Workflows
Docker is very versatile so you can come up with several different workflows.
Note: Consider the below to be "Work in progress". It very much represents our understanding of Docker workflows. But as Docker tools constantly evolve, things may change pretty fast. And what was considered to be good practice today may be outdated tomorrow. You're advised to read the below with care and come up with your own ideas.
- No docker registry required
- Slower deployment due to extra build step
This is a very simple workflow: In each environment the runtime image is built
from the Dockerfile
. Developers need to be informed whenever the Dockerfile
changes
so that they rebuild their local image.
No images are shared between developers, so the initial and also each consecutive build step
could take quite some time, depending on
how much
the Dockerfile
has changed since the last build in this environment.
- Requires a docker registry (either self-hosted or from 3rd party)
- Quick and simple deployment
Here we can take two approaches: With or without a base image. In both cases
the Dockerfile
should be organized in a way, that the rather static or less changing parts
should be on top of the Dockerfile
and the dynamic or frequently changing
parts (e.g. COPY . /var/www/html
) at the bottom of the file.
We use a single Dockerfile
and each time we want to make a deployment, we create
a new tagged image and push it to the registry. This image can then be pulled to
production.
One drawback here is, that each deployment image contains a full copy of your source code, even if you only changed a couple of lines since the last deployed image.
It's also important that the developers alway pull the last deployed image to their machine, as otherwhise docker couldn't reuse cached layers the next time it builds a new image.
Here we use two Dockerfiles:
- One for the base image, e.g.
Dockerfile.base
and - one for the final image(s), which extends from the base image
The base image stays the same for some time and is used as basis for many deployment images. This has the advantage that (hopefully) many files from the base image can be reused, whenever a new deployment image is built. So the actual release image layer will have a very small footprint and, in effect, once a base image is shared among developers and on production, there's not much data to be moved around with each release.
To start we'd first move the current Dockerfile
and create a base image:
mv Dockerfile Dockerfile.base
docker build -f Dockerfile.base -t myregistry.com:5000/myapp:base-1.0.0
docker push myregistry.com:5000/myapp:base-1.0.0
Now we have a base image as version base-1.0.0
. For ongoing development we take
it from there and use a minimal second Dockerfile
that is based on this image:
FROM myregistry.com:5000/myapp:base-1.0.0
COPY composer.json /var/www/html/
COPY composer.lock /var/www/html/
RUN composer self-update && \
composer install --no-progress
COPY . /var/www/html
RUN mkdir runtime web/assets \
&& chown www-data:www-data runtime web/assets
So other developers will now use this simplified Dockerfile
for their daily work.
They don't have to rebuild all the layers from the base image and will only stack
their local changes on top.
We'll also use this file for the final deployment images:
docker build -t myregistry.com:5000/myapp:1.0.0
docker build -t myregistry.com:5000/myapp:1.0.1
docker build -t myregistry.com:5000/myapp:1.0.2
...
Note: Version numbers here are only used to make the example clearer. You'd probably use a different versioning scheme, especially if you do continous deployments.
After some releases your latest code will differ more and more from the base image. So more and more files will have changed since it was created and this will make your deployment images bigger and bigger with each release. To avoid this you can create an updated base image from your latest code:
docker build -f Dockerfile.base -t myregistry.com:5000/myapp:base-1.1.0
docker push myregistry.com:5000/myapp:base-1.1.0
Note: You may want to modify
Dockerfile.base
to extend from your old base image first. This will save extra space, but add more file layers to your docker images over time, which is limited to 127.
Now we have an updated base image and can use that for ongoing development.
We therefore have to update the FROM
line in the Dockerfile
:
FROM myregistry.com:5000/myapp:base-1.1.0