How to install the same version of a docker image? - docker

On machine A I have docker image FOO/BAR installed. How do I query the version of that image, and how do I install the same version to machine B?
Please note that on machine B I don't need the newest available version of FOO/BAR, but the same version as machine A. I don't want to keep local modifications to the image made on machine A.

Docker uses a tag or digest to distinguish between different versions of an image. When specifying neither a tag or a digest, all Docker commands assume that you want to use the default tag latest. But you can always be more specific.
Assuming the image comes from a registry FOO and is called BAR, there are two ways how you can pull the same version of the image: either by tag or by digest. You can only use the tag if you know that it is unique and not reused. This is often the case when using build numbers or Git hashes as tags, but if you want to be absolutely sure, use the digest.
On machine A, run docker images --digests. Look for FOO/BAR and its digest (starting with sha:).
On machine B, run the following command and replace {digest} with the digest from machine A:
docker pull FOO/BAR#{digest}
This is an example how it could look:
docker pull FOO/BAR#sha256:e4957dfd892f656ae672dfa03eb7a73f1c47bd24fc95f2231fc5ac91a76092a0
This will download the same version that is available on machine A to machine B. Since it comes from the registry, it's a fresh copy without any modifications.

Use a tag!
docker image supports tag, which is usually used as a version number. When building an image, you can specify a tag:
docker build -t myimage:v0.1 .
Then use the same image is easy:
docker run -d myimage:v0.1 entrypoint.sh
If you do not specify a tag, and everything works fine. Because docker uses default tag latest, which can be annoying when updating and keeping them sync.
latest image can change all the time(usually with CI/CD auto-build), so easy container can use different images. If there is not what you expected, use a tag always!

Related

How to find availability of newer versions of docker images in docker-compose

How to find availability of newer versions of docker images in a docker-compose file containing multiple services, if you don't happen to use the latest version of a docker image (similar to npm outdated, gradlew dependencyUpdates gem outdated)
Docker images don't have a concept of versions like a package manager does. Docker images have tags. Those tags can be anything that the image author chooses them to be. Some image authors may publish tags that indicate the version of the software that is in the image, and other image authors may simply push newer images over top of the same tag over time.
For example, if you use the nginx:mainline tag when specifying the image, it will grab whatever the current nginx mainline version is at the time you pull the image. This is due to the policy that the nginx official image publishers have in the way they tag images. They also have specific version tags such as nginx:1.21.1 which happens to point to the same blobs as nginx:mainline at the time this answer is written.
Given this particular image tagging policy, you can set docker-compose.yml to point to nginx:mainline and regularly run docker-compose up --pull -d. This will cause compose to try to pull the nginx:mainline image again, and then cycle any containers that need to be cycled. In the case of a newer nginx:mainline image being present on the registry, compose would pull that new image and then recreate the container using the new image.
docker-compose itself does not have the ability to compare what is on a registry to what is present on a local docker engine.
You can query the registry via the API to see the sha256 digest that a given tag returns, or use the reg CLI tool to interact with a registry: https://github.com/genuinetools/reg
Continuing with the nginx:mainline example, say I deployed my compose file with nginx:mainline when the corresponding version was 1.20.0, but 1.21.1 is out now. I would do the following to make a comparison:
docker inspect nginx:mainline --format '{{.Id}}'
This would return the long sha256 image id for nginx:mainline
I can then query the repository with the following:
reg manifest nginx:mainline
This returns a json document describing the image and its layers. In the config key, there is a digest key. If this key matches, you know it is the same image. If it is different, you know that the remote copy is different.
You can use jq in conjunction with this command to get the correct value:
reg manifest nginx:mainline | jq -r .config.digest
This means that if I rerun docker-compose up --pull -d, the remote image will be pulled and my container recreated to use it.
--
If you use the specific version tag instead of the mainline tag, then you could script out available tags and try to programmatically determine if there's a new version that way.
In the case of the nginx repository, the version specific tags (excluding variants like -alpine) always only contain numbers and dots. Because that's this image's specific strategy for versioning in its tags, I can get a list of those like this and sort them by version:
reg tags nginx | grep '^[0-9,\.]*$' | sort -V
I'd have to determine some way to compare that list of versions with the current version, and that's covered in this stack overflow question: How to compare two strings in dot separated version format in Bash?
Of course, this is only an example based on the image tagging strategy of a docker official image that specifically tags versions of the software in this particular pattern. Other image authors may have their own pattern that you would need to implement logic for.

how to keep docker images if pulling newer image

I'm using some docker images, which I have pulled from a registry:
docker pull registry.example.com/project/backend:latest
docker pull registry.example.com/project/frontend:latest
Now there is a new version on the server registry. If I do a new pull, I will overwrite the current images. But I need to keep the current working images in case I do get some problems with the newest latest images.
So, how do I create a kind of backup of my running backend:latest and frontend:latest? After that I can pull the latest latest image and in case I need to, I can use the old working images...
To keep the current image on your local environment you can use docker tag
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
For example:
docker tag registry.example.com/project/backend:latest registry.example.com/project/backend:backup
Then when you pull the latest, the registry.example.com/project/backend:backup still existing
Pulling an image never deletes an existing image. However, if you have an image with the same name, the old image will become unnamed, and you'll have to refer to it by its image ID.
You've now seen the downside to using :latest tags. This is why it is better to reference an image by a specific version tag that the maintainer won't re-push.
First, you shouldn't be using latest in production environments. Rather define a tag you confirmed working.
And instead of executing stuff in an image to set it up, you should write a Dockerfile and make the installation repeatable and create your local image. That's actually one of the main reasons why docker is used.

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

do I need to manually tag "latest" when pushing to docker public repository?

Suppose I have an image me/mystuff:v0.0.1
I find if I push it to the repository:
docker push me/mystuff:v0.0.1
latest is not created, and on a pull from another machine it will complain, e.g.
ssh me#faraway
(faraway) $ docker run -it me/mystuff /bin/bash
will result in a not found error for me/mystuff:latest
I can add the latest tag and push explicitly to the public repository:
docker login me
docker tag me/mystuff:v0.0.1 me/mystuff:latest
docker push me/mystuff:latest
and then from another machine:
docker pull me/mystuff
will work because latest exists.
I am also finding that once latest exists, it does not auto update when a new numbered version is pushed.
Can I somehow eliminate this step of manually tagging latest and have latest automatically point to the latest numbered version?
Or is it there for a reason, like allowing the separation of development versions (tagged with a vN.N.N only) from the production version (tagged latest)?
The latest is just the default value of the tag if none is specified. If you push a tagged image it does not replace the current image tagged with latest.

Docker: How to prevent the use of latest image from docker registry?

I was using centos image from https://registry.hub.docker.com/u/blalor/centos/
For some reason Blalor decided to remove passwd from the list of packages installed on the base image and my dockers stopped working on new deployments. Why does not docker know the build which was used for my dockers? I have had to change my base images now and change every server's docker image.
I could not use the tag feature because there is the tagging for the blalor's images? Do I have to use the source code and host the centos image myself so that it does not change again?
You do not need to use sources. If you have a working image, you can do docker history <your image> to see the image ID that was used and tag the proper one into shortfellow/centos. If you do not have a working image, on the link you provided, there is a build detail section with the history of build. You can see that on January 13th, 2014, it has been built and the image then was a531daec9f98. You can do FROM a531daec9f98 on your dockerfile to make sure it will never change or you can docker tag a531daec9f98 shortfellow/centos (you will need to docker pull a531daec9f98 before).
It is very similar to git in a sense that if you are using someone's repository, and if that someone does not use tags or branches, when he updates his reposiroty and you re pull, you will have the latest version with the new changes. In order to get back to the version you liked, you need to find the commit id. The solution would be to fork the repository. Which you can do on Docker by tagging the image under you username and pushing to a registry (docker push username/image)

Resources