Should I Set docker image version in docker-compose? - docker

Imagine I have docker-compose.yml for adding mongo as a container, is it a good thing to set verion in front of image name or let it to be the latest by default?
version: '3.8'
services:
mongo:
image: mongo:4.0
ports:
- "27017:27017"
Actually what is the pros and cons for application in development and production realeses?
image: mongo:4.0 VS image: mongo

Including a version number as you've done is good practice. I'd generally use a major-only image tag (mongo:4) or a major+minor tag (mongo:4.4) but not a super-specific version (mongo:4.4.10) unless you have automation to update it routinely.
Generally the Docker Hub images get rebuilt fairly routinely; but, within a given patch line, only the most-recent versions get patches. Say the debian:focal base image gets a security update. As of this writing, the mongo image has 4, 4.4, and 4.4.10 tags, so all of those get rebuilt, but e.g. 4.4.9 won't. So using a too-specific version could mean you don't get important updates.
Conversely, using latest means you just don't care what version you have. Your question mentions mongo:4.0 but mongo:latest is currently version 5.0.5; are there compatibility issues with that major-version upgrade?
The key rules here are:
If you already have some image:tag locally, launching a container will not pull it again, even if it's updated in the repository.
Minor-version tags like mongo:4.4 will continue to get updates as long as they are supported, but you may need to docker-compose pull to get updates.
Patch-version tags like mongo:4.4.9 will stop getting updates as soon as there's a newer patch version, even if you docker pull mongo:4.4.9.
Using a floating tag like ...:latest or a minor-version tag could mean different systems get different builds of the image, depending on what they have locally. (Your coworker could have a different mongo:latest than you; this is a bigger problem in cluster environments like Kubernetes.)

I think it's a good thing to put version in front of the image name, you can manage them more easily, but you have to be careful to pass the update regularly to avoid loopholes.

Related

Is it bad practice to use mysql:latest as docker image?

Docker was built to make sure that code can run on any device without any issues of missing libraries, wrong versions, etc.
However if you use the "latest" tag instead of a fixed version number, then you actually don't know on beforehand with which version of the image you'll end up. Perhaps your code is at the time of writing compatible with the "latest" version but not in the future. Is it then a bad practice to use this tag? Is it a better practice to use a fixed version number?
Usually, probably, for the reasons you state, you likely want to avoid ...:latest tags here.
For databases in particular, there can be differences in the binary interfaces, and there definitely are differences in the on-disk storage. If you were expecting MySQL 5.7 but actually got MySQL 8.0 you might get some surprising behavior. If a MySQL 9.0 comes out and you get an automatic upgrade then your local installation might break.
A generic reason to avoid ...:latest is that Docker will use a local copy of an image with the right tag, without checking Docker Hub or another repository. So again in the hypothetical case where MySQL 9.0 comes out, but system A has an old mysql:latest that's actually 8.0, docker run mysql on an otherwise clean system B will get a different image, and that inconsistency can be problematic.
You will probably find Docker image tags for every specific patch release of the database, but in general only the most recent build gets security updates. I'd suggest that pinning to a minor version mysql:8.0 is a good generic approach; you may want the more specific version mysql:8.0.29 in your production environment if you need to be extremely conscious of the upgrades.
Some other software is less picky this way. I'd point at the Redis in-memory data store and the Nginx HTTP server as two things where their network interfaces and configuration have remained very stable. Probably nothing will go wrong if you use nginx:latest or redis:latest, even if different systems do wind up with different versions of the image.

Docker image versioning with docker stack

I've setup a staging and a production server. The flow is as follows. I develop and push my new image to the staging registry. There the code is tested and if everything fits I want to push the image to the production server. I also want to use versioning. I thought about incrementing the image tag.( Not just ass latest) I deploy my application with docker stack and a compose file.
Now I want to ask about a best practice.
Example:
current image: xyz:0.1
new image: xyz:0.2
In my compose file I referance the image xyz:auto_lastest_version_here
I want to be able to see the version string and not just the latest Tag.
Is there already a mechanism or a way to reduce an update to docker pull - > pull the latest version available
stack deploy ... to update the specific container.
EDIT: I guess I can write a script where I extract the latest Tag from the images and refer the this by using an env var in my compose file. I just thought there might be an easier way or standard way provided by docker.
Image repository names and tags are just strings attached to a blob which is the actual image data. Docker and the docker registry don't really have a concept of the most recent version of a blob -- the ":latest" tag doesn't even have internal significance - it's just a string which is used by default when building, and there's nothing preventing you from tagging an older image as :latest.
Fortunately, you can tag an image with multiple tags, and that provides a reasonable solution. For me, I tag with a string identifying the version I want on my production server, like ":live" or ":production", in addition to tagging with the actual version number. Thus, lets say you have images myimage:1.0.0, myimage:1.0.1, and myimage:1.1.0, you could run:
docker tag "myimage:1.1.0" "myimage:production"
...to add a production tag to it. The stack file you deploy on the production server would always then refer to myimage:production.
The real advantage to that is that if users start complaining about problems when you switch to 1.1.0, you can simply tag myimage:1.0.1 as myimage:production and redeploy, and it would switch back to the older version.
Not sure if this is the "best" practice, but it's the one I use.

How can I retrieve an older image for Docker instead of latest?

What command(s) do I have to run to retrieve an older image of a software offered in Docker?
I have problems with the latest image of localstack so I though I could try older versions to see what happens. However, I saw a comment in an issue mentioning editing the YAML file this way:
image: localstack/localstack:0.9
but no other info... (it was not the point of the issue, so it's understandable).
I've been looking around and saw many posts about getting the latest image (i.e. docker update ...), but nothing that would allow me to go back in time except for images that I would happen to already have.
Just the change above had absolutely no effect. I'm wondering how can I get Docker to download an older image so I can run that older one instead of the latest? I'm also wondering about how to find a list of available tags for a given docker to make sure I use a version that actually exists.
You should look for existing tags at desired repo's hub.
If you are using docker-compose the correct way to do it is:
image: <image>:<tag>
If no tag was found then it is not available or does not exist.
Here are tags available at localstack hub

Versioning a docker composition

I usually use simple production images composition to manage my production deployments hence exclusively relying on docker-compose.
I'm not using Kubernetes or other tools since I want to keep it simple for my simple apps (I don't deploy on multiple hosts, manage load balancing or do CD/CI)
Here is how my production composition could look like:
version: '3'
services:
php:
image: ${CONTAINER_REGISTRY_BASE}/php:${VERSION}
depends_on:
- db
env_file:
- ./api.env
api:
image: ${CONTAINER_REGISTRY_BASE}/api:${VERSION}
depends_on:
- php
- db
db:
image: mariadb:10.2
client:
image: ${CONTAINER_REGISTRY_BASE}/client-prod:${VERSION}
env_file:
- ./client.env
admin:
image: ${CONTAINER_REGISTRY_BASE}/admin-prod:${VERSION}
env_file:
- ./admin.env
Keeping one global version for the application stack in a .env file, when I update this version I simply have to do this:
docker-compose build
docker-compose push
And in the production server (after having updated the version)
docker-compose up -d
As you can imagine, the issue is that I'm shipping the whole stack even if there is a very small modification in one of the services.
I thought about having a different version for each service but it seems quite complicated to maintain as we can't really be sure what is the last version for each.
Am I seeing it wrong ? Shouldn't I use docker-compose in production ? In which case what should I use ?
Can someone suggest me a simple deployment way based on a docker registry ?
Short Answer:
You should actually have separate services for each, and I'd recommend moving away from just the normal Docker server for your production to Swarm.
Long Answer:
If you move to Docker Swarm, you can use the same compose file with a few changes to make it into a stack file. What this does is creates a series of services, individually maintained by the Swarm.
During your build process, I would recommend assigning each new build a specific version number, and then tagging it specifically as latest or dev. Push the latest or dev version to the repository.
The reason for this is two fold:
When you update your stack file, you'll want to specify a discrete version of the image to use. IE 1.2.3 or whatever your newest is for the service you had just changed. This is because if you try to use "latest" there's a good change the Swarm won't even try to pull the image because on deployment. I've always found it's better to avoid ambiguity in the production sense
For developers, whenever they start working, or whenever they're doing work on their local environment, they can always target the dev or latest image via composer overrides (basically calling two compose files in sequence, the first having core definitions, the second having changes or additions etc)
Whenever you do a docker stack deploy, it's only going to look at differences in the services to make changes. I'd play around with it, but I think it would fit your work flow a lot better.
Side note:
I've never really found a good use case for databases existing in Docker shy of (1) lack of resources or (2) integration testing.

How stable are version-tagged docker baseimages? Should I make my own copy?

I am creating docker images based on base-images from docker.io (for example ubuntu:14.04).
I want my docker-builds to be 100% reproducible. One requirement for this is, that the baseimage does not change (or if it changes, it is a decision by me to use the changed baseimage).
Can I be sure that a version tagged base image (like ubuntu:14.04) will always be exactly the same?
Or should I make my own copy in my own private repository?
Version tags like ubuntu:14.04 can be expected to change with bug fixes. If you want to be sure you get the exact same image (still containing the fixed bugs) you can use the hash of the image:
FROM ubuntu#sha256:4a725d3b3b1c
But you can not be sure this exact version will be hosted forever by docker hub.
Safest way is to create your own docker repository server. Push the images you are using to that repository. Use the hash notation to pull the images from your local repos.
FROM dockerrepos.yourcompany.com/ubuntu#sha256:4a725d3b3b1c

Resources