31

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.

Rahul
  • 2,515
  • 3
  • 25
  • 29
  • "uname -a" gives me this: Linux 95e5ae04dbbc 4.2.0-27-generic #32-Ubuntu SMP Fri Jan 22 04:49:08 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux. I can't say if its ubuntu14.04 or fedora or ubuntu15.10. – Rahul Feb 28 '16 at 23:11
  • Even for using sys, I need to know which version of python to use. The question itself is how I can determine which version to use. :) – Rahul Feb 28 '16 at 23:24
  • I kept reading your question the wrong way. That is why I deleted my comments. Apologies. :) – idjaw Feb 28 '16 at 23:35

6 Answers6

42

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
Community
  • 1
  • 1
morxa
  • 3,221
  • 3
  • 27
  • 43
  • 1
    This looks good. It works on the latest distributions. However, when I tried to see centos:6 image, it doesn't have this file in it. centos:latest has it. – Rahul Feb 29 '16 at 06:26
  • RHEL6 (and thus CentOS 6) is so old, back then `/etc/os-release` didn't exist yet. You might want to glob for `/etc/*-release` instead. I think RHEL6 had a `/etc/redhat-release`, I guess CentOS has something similar. – morxa Feb 29 '16 at 06:38
  • Thanks @morxa. I used a combination of both python and os-release for getting version info. Till now, it is covering almost all the cases (redhat, ubuntu, debian, centos, opensuse, cirros...) https://github.com/BU-NU-CLOUD-SP16/Container-Code-Classification/blob/master/scripts/platform.sh – Rahul Mar 01 '16 at 07:17
11

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)
pie
  • 365
  • 2
  • 9
  • Fails for centos. ` sh-4.2# cat /etc/issue -----> gives ----> Kernel \r on an \m` – Rahul Feb 28 '16 at 23:55
  • for every distribution, the command will change. For ex, it changed from Ubuntu to Redhat. Similarly, it might change for opensuse. This solution doesn't seem to scale. – Rahul Feb 29 '16 at 00:37
6

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"
> ...
Qinsi
  • 780
  • 9
  • 15
3

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"
nonopolarity
  • 146,324
  • 131
  • 460
  • 740
1

You should use following cmd to detect Ubuntu release name:

export UBUNTU_RELEASE=$(lsb_release  -sc || cat /etc/*-release|grep -oP  'CODENAME=\K\w+$'|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=\K\w+$'|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" 
Valeriy Solovyov
  • 5,384
  • 3
  • 27
  • 45
  • Agreed, but this only works for ubuntu. The question is how to determine for most of the operating systems. The selected answer and comments on that has good points of covering most of the important distros. And its easier as well. – Rahul May 03 '16 at 19:20
  • The python is not a part of a distribution of some Docker Base Images. So I suggest embed specific detections based on your distro type. PS: I added Debian and I will update on next distros – Valeriy Solovyov May 03 '16 at 21:04
  • Yup, thats why I used /etc/os-release first, and if its not present, then rely on python. You can check the comment in the answer which points to github link doing the same. Yeah, it fails for images which don't have both /etc/os-release and python, but otherwise, it works for many known distros. – Rahul May 03 '16 at 21:44
0

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

daniel
  • 25
  • 7