I am new to docker and this is just a fascinating tool. However, I can’t understand one thing about it. Simple Dockerfile usually begins with OS name and version, like:
FROM ubuntu:xenial
....
But which Linux OS will be used for Dockerfile like
FROM perl
....
or
FROM python:3.6
....
Of course I can find this out by running a container from this image and printing out the OS info, like:
docker run -it --rm perl bash
# cat /etc/*-release
or
docker run -it --rm python:3.6 bash
# cat /etc/*-release
BTW, In both cases the OS is "Debian GNU/Linux 10 (buster)".
So, my questions are:
-
How do I find out which OS will be run for a specific docker image without actually creating a docker container from it (the
docker inspect
command does not provide this info:docker inspect perl | grep -i Debian
) -
How do I change the OS type for existing docker image. For example, I have an image that uses Ubuntu 14.04, and I want to change it to Ubuntu 18.04..
Thank you for your help:)
3
Answers
The only way to determine what os is being used is as you have described: spawn a container and print the os information. There is no metadata that says "this image was build using
<x>
".In many (but not all) situations, this information may not be especially important.
If you have access to the
Dockerfile
used to build the image, you can of course change the base image (the image named in theFROM
line) and build a new one, but you may find that this requires a number of other changes due to different software versions in your updated image.A docker image doesn’t need an OS. There’s a possibility of extending the scratch image which is purposely empty and the container may only contain one binary or some volume.
Having an entire OS is possible but also misleading: The host shares its kernel with the container. (This is not a virtual machine.)
That means that no matter what "OS" you are running, the same kernel in the container is found:
Both:
will report the same kernel of your host machine.
So you have to look into different ways:
or
or for Cent OS:
In stead of scratch, a lot of images are also alpine-based to avoid the size overhead. An ubuntu base image can easily have 500MB fingerprint whereas alpine uses around 5MB; so I rather check for that as well.
Also avoid the trap of manually installing everything onto one Ubuntu image inside one big Dockerfile. Docker works best if each service is its own container that you link together. (For that check out
docker-compose
.)In the end, you as an user shouldn’t care about the OS of an image, but rather its size. Only as a developer of the Dockerfile is it relevant to know the OS and that you’ll find out either by looking into the Dockerfile the image was built (if it’s on docker hub you can read it there).
You basically have to look what was used to create your image an use the appropriate tools for the job. (Debian-based images use
apt-get
, alpine usesapk
, and Fedora usesyum
.)You can use "
docker cp
" to extract the "/etc/os-release
" file without starting the container:Note: I had to use "
docker cp -L
" because/etc/os-release
is a symlink onubuntu:latest
.Honestly, I find this to be a lot of trouble just to avoid starting the container, and it requires the "/etc/os-release" file to be present. If you’re willing to (very) briefly run the container, I find this more convenient, and a little more robust. Note: it’s very important to specify
--entrypoint=""
, otherwise the container will start invoking its normal startup routine!Here’s the same command against "alpine:latest":
Note: I add "/etc/hostname" to the list of files to "head" to make sure it finds 2 or more files, to ensure "head" to uses its "==> file <==" output style. Whereas if it only runs against a single file it doesn’t print the filename.