determine OS distribution of a docker image
Question:
I need to determine the OS distribution name for any docker image. I can tag ubuntu:latest as image1:latest, but I should be able to get the distribution information of image1:latest when it is launched.
For achieving this, I used the below mentioned command to determine the OS version:
$ docker tag ubuntu image1
$
$ docker run -it image1 /bin/sh -c "echo import platform > test.py; echo print(platform.dist()) >> test.py; python3 test.py"
('Ubuntu', '14.04', 'trusty')
$
However, this has a dependency on whether the image has python2 or python3 in it. It fails for ubuntu:12.04 and I need to use python2 there.
$ docker run -it ubuntu /bin/sh -c "echo import platform > test.py; echo print(platform.dist()) >> test.py; python3 test.py"
('Ubuntu', '14.04', 'trusty')
$
$ docker run -it ubuntu:12.04 /bin/sh -c "echo import platform > test.py; echo print(platform.dist()) >> test.py; python3 test.py"
/bin/sh: 1: python3: not found
$
$ docker run -it ubuntu:12.04 /bin/sh -c "echo import platform > test.py; echo print(platform.dist()) >> test.py; python2 test.py"
('Ubuntu', '12.04', 'precise')
$
Q1. Is there a way I can achieve the same without knowing which version of python is there in a particular image?
NOTE: The goal is to determine which was the base image used to build this image. I don’t have access to the Dockerfile used to build this image.
Q2. There is another approach of using entrypoint. I can build a separate image from the current image using Dockerfile. Or, I can specify entrypoint in cmdline when creating container but I need the script to be accessible within the container. I am guessing that I might need shared storage when using cmdline, is there a better way to achieve this? Any pointers would be really helpful.
Thanks.
Answers:
You could use /etc/issue file for Debian/Ubuntu:
root@ubuntu_container:/# cat /etc/issue
Ubuntu 14.04.3 LTS n l
or /etc/redhat-release for CentOS/Red Hat/Fedora:
[root@fedora_container /]# cat /etc/redhat-release
Fedora release 23 (Twenty Three)
[root@centos_container /]# cat /etc/redhat-release
CentOS Linux release 7.2.1511 (Core)
The Filesystem Hierarchy Standard has a standard definition for /etc/os-release
, which should be available on most distributions:
The /etc/os-release and /usr/lib/os-release files contain operating system identification data.
The basic file format of os-release is a newline-separated list of environment-like shell-compatible variable assignments. It is possible to source the configuration from shell scripts.
This means you can just source /etc/os-release
and use $NAME
or $ID
to identify the distribution. As an example, on Fedora it looks like this:
% source /etc/os-release
% echo $NAME
Fedora
% echo $ID
fedora
On Debian:
% source /etc/os-release
% echo $NAME
Debian GNU/Linux
% echo $ID
debian
You should use following cmd to detect Ubuntu release name:
export UBUNTU_RELEASE=$(lsb_release -sc || cat /etc/*-release|grep -oP 'CODENAME=Kw+$'|head -1)
For Ubuntu docker images I am using following cmds when I need to add multiverse to apt.source.lists and haven’t duplicate lines:
RUN export UBUNTU_RELEASE=$(lsb_release -sc || cat /etc/*-release|grep -oP 'CODENAME=Kw+$'|head -1) &&
echo "deb http://archive.ubuntu.com/ubuntu/ ${UBUNTU_RELEASE}-security multiverse" >> /etc/apt/sources.list &&
echo "deb-src http://archive.ubuntu.com/ubuntu/ ${UBUNTU_RELEASE}-security multiverse" >> /etc/apt/sources.list &&
echo "deb http://archive.ubuntu.com/ubuntu/ ${UBUNTU_RELEASE} multiverse" >> /etc/apt/sources.list &&
echo "deb-src http://archive.ubuntu.com/ubuntu/ ${UBUNTU_RELEASE} multiverse" >> /etc/apt/sources.list &&
echo "removing duplicated strings from /etc/apt/sources.list" &&
awk '!x[$0]++' /etc/apt/sources.list > /tmp/sources.list &&
cat /tmp/sources.list > /etc/apt/sources.list &&
You should use following cmd to detect Debian release name ( I am using it for my docker images):
export DEBIAN_RELEASE=$(awk -F'[" ]' '/VERSION=/{print $3}' /etc/os-release | tr -cd '[[:alnum:]]._-' ) &&
[[ "x${DEBIAN_RELEASE}" = "x" ]] && export DEBIAN_RELEASE="unstable"
Expanding on @morxa’s answer and comment, some sh
doesn’t have source
defined. In such case we can use
grep NAME /etc/*-release
to be able to see what the OS is. Usually the PRETTY_NAME
can tell the whole name:
PRETTY_NAME="Ubuntu 20.04 LTS"
Most answers give us OS release, but the question is also concern docker.
I’m lazy, especially when I have more than 20 images, so:
docker image ls | perl -lane 'print "docker run --rm $F[0]:$F[1] cat /etc/os-release" unless /REPOSITORY/' | sh | grep PRETTY
And most images have results:
> PRETTY_NAME="Ubuntu 16.04.1 LTS"
> PRETTY_NAME="Ubuntu 14.04.3 LTS"
> PRETTY_NAME="Ubuntu 18.04.1 LTS"
> PRETTY_NAME="Debian GNU/Linux 9 (stretch)"
> PRETTY_NAME="Debian GNU/Linux 9 (stretch)"
> PRETTY_NAME="Debian GNU/Linux bullseye/sid"
> PRETTY_NAME="Ubuntu 18.04.3 LTS"
> PRETTY_NAME="Ubuntu 16.04.1 LTS"
> ...
If you don’t want to do any action on the image you mat try to figure out winch os it base on the firsts layers .
for finding the layers just type
docker inspect <image name>
then see the layer section.
then you can make a list of each layer belong to which base image
I need to determine the OS distribution name for any docker image. I can tag ubuntu:latest as image1:latest, but I should be able to get the distribution information of image1:latest when it is launched.
For achieving this, I used the below mentioned command to determine the OS version:
$ docker tag ubuntu image1
$
$ docker run -it image1 /bin/sh -c "echo import platform > test.py; echo print(platform.dist()) >> test.py; python3 test.py"
('Ubuntu', '14.04', 'trusty')
$
However, this has a dependency on whether the image has python2 or python3 in it. It fails for ubuntu:12.04 and I need to use python2 there.
$ docker run -it ubuntu /bin/sh -c "echo import platform > test.py; echo print(platform.dist()) >> test.py; python3 test.py"
('Ubuntu', '14.04', 'trusty')
$
$ docker run -it ubuntu:12.04 /bin/sh -c "echo import platform > test.py; echo print(platform.dist()) >> test.py; python3 test.py"
/bin/sh: 1: python3: not found
$
$ docker run -it ubuntu:12.04 /bin/sh -c "echo import platform > test.py; echo print(platform.dist()) >> test.py; python2 test.py"
('Ubuntu', '12.04', 'precise')
$
Q1. Is there a way I can achieve the same without knowing which version of python is there in a particular image?
NOTE: The goal is to determine which was the base image used to build this image. I don’t have access to the Dockerfile used to build this image.
Q2. There is another approach of using entrypoint. I can build a separate image from the current image using Dockerfile. Or, I can specify entrypoint in cmdline when creating container but I need the script to be accessible within the container. I am guessing that I might need shared storage when using cmdline, is there a better way to achieve this? Any pointers would be really helpful.
Thanks.
You could use /etc/issue file for Debian/Ubuntu:
root@ubuntu_container:/# cat /etc/issue
Ubuntu 14.04.3 LTS n l
or /etc/redhat-release for CentOS/Red Hat/Fedora:
[root@fedora_container /]# cat /etc/redhat-release
Fedora release 23 (Twenty Three)
[root@centos_container /]# cat /etc/redhat-release
CentOS Linux release 7.2.1511 (Core)
The Filesystem Hierarchy Standard has a standard definition for /etc/os-release
, which should be available on most distributions:
The /etc/os-release and /usr/lib/os-release files contain operating system identification data.
The basic file format of os-release is a newline-separated list of environment-like shell-compatible variable assignments. It is possible to source the configuration from shell scripts.
This means you can just source /etc/os-release
and use $NAME
or $ID
to identify the distribution. As an example, on Fedora it looks like this:
% source /etc/os-release
% echo $NAME
Fedora
% echo $ID
fedora
On Debian:
% source /etc/os-release
% echo $NAME
Debian GNU/Linux
% echo $ID
debian
You should use following cmd to detect Ubuntu release name:
export UBUNTU_RELEASE=$(lsb_release -sc || cat /etc/*-release|grep -oP 'CODENAME=Kw+$'|head -1)
For Ubuntu docker images I am using following cmds when I need to add multiverse to apt.source.lists and haven’t duplicate lines:
RUN export UBUNTU_RELEASE=$(lsb_release -sc || cat /etc/*-release|grep -oP 'CODENAME=Kw+$'|head -1) &&
echo "deb http://archive.ubuntu.com/ubuntu/ ${UBUNTU_RELEASE}-security multiverse" >> /etc/apt/sources.list &&
echo "deb-src http://archive.ubuntu.com/ubuntu/ ${UBUNTU_RELEASE}-security multiverse" >> /etc/apt/sources.list &&
echo "deb http://archive.ubuntu.com/ubuntu/ ${UBUNTU_RELEASE} multiverse" >> /etc/apt/sources.list &&
echo "deb-src http://archive.ubuntu.com/ubuntu/ ${UBUNTU_RELEASE} multiverse" >> /etc/apt/sources.list &&
echo "removing duplicated strings from /etc/apt/sources.list" &&
awk '!x[$0]++' /etc/apt/sources.list > /tmp/sources.list &&
cat /tmp/sources.list > /etc/apt/sources.list &&
You should use following cmd to detect Debian release name ( I am using it for my docker images):
export DEBIAN_RELEASE=$(awk -F'[" ]' '/VERSION=/{print $3}' /etc/os-release | tr -cd '[[:alnum:]]._-' ) &&
[[ "x${DEBIAN_RELEASE}" = "x" ]] && export DEBIAN_RELEASE="unstable"
Expanding on @morxa’s answer and comment, some sh
doesn’t have source
defined. In such case we can use
grep NAME /etc/*-release
to be able to see what the OS is. Usually the PRETTY_NAME
can tell the whole name:
PRETTY_NAME="Ubuntu 20.04 LTS"
Most answers give us OS release, but the question is also concern docker.
I’m lazy, especially when I have more than 20 images, so:
docker image ls | perl -lane 'print "docker run --rm $F[0]:$F[1] cat /etc/os-release" unless /REPOSITORY/' | sh | grep PRETTY
And most images have results:
> PRETTY_NAME="Ubuntu 16.04.1 LTS"
> PRETTY_NAME="Ubuntu 14.04.3 LTS"
> PRETTY_NAME="Ubuntu 18.04.1 LTS"
> PRETTY_NAME="Debian GNU/Linux 9 (stretch)"
> PRETTY_NAME="Debian GNU/Linux 9 (stretch)"
> PRETTY_NAME="Debian GNU/Linux bullseye/sid"
> PRETTY_NAME="Ubuntu 18.04.3 LTS"
> PRETTY_NAME="Ubuntu 16.04.1 LTS"
> ...
If you don’t want to do any action on the image you mat try to figure out winch os it base on the firsts layers .
for finding the layers just type
docker inspect <image name>
then see the layer section.
then you can make a list of each layer belong to which base image