Exercise 1.2 - Working with Container Images

Return to Workshop

Run Container Images

When you execute the podman run command, you essentially spin up and create a new container from a container image. That container consists of the contents of the image, plus features based on any additional options you specify.

The command you pass on the podman run command line sees the inside the container as its running environment so, by default, very little can be seen of the host system. For example, by default, the running applications sees:

  • The file system provided by the container image.

  • A new process table from inside the container (no processes from the host can be seen).

  • New network interfaces (by default, a separate container network interface provides a private IP address to each container via DHCP).

If you want to make a directory from the host available to the container, map network ports from the container to the host, limit the amount of memory the container can use, or expand the CPU shares available to the container, you can do those things from the podman run command line.

Launch a container and explore inside interactively:

podman run --rm -it registry.access.redhat.com/rhel7 /bin/bash
Trying to pull registry.access.redhat.com/rhel7...Getting image source signatures
Copying blob sha256:e0f71f706c2a1ff9efee4025e27d4dfd4f328190f31d16e11ef3283bc16d6842
 71.45 MB / ? [--------------------=---------------------------------------] 7s
Copying blob sha256:121ab4741000471a7e2ddc687dedb440060bf9845ca415a45e99e361706f1098
 1.22 KB / ? [----------------------------------------------------=--------] 0s
Copying config sha256:7a840db7f020be49bb60fb1cc4f1669e83221d61c1af23ff2cac2f870f9deee8
 6.21 KB / 6.21 KB [========================================================] 0s
Writing manifest to image destination
Storing signatures

NOTE: When you see a prompt like the following, you are in the container:

[root@7e5a67870995 /]#

Commands to try:

ls
whoami
uname -a

When you are finished looking around the internals of the container, type exit to exit.

exit

Container Storage Volumes

To show that container storage volumes can be used to mount external file systems with useful functions and data, we will mount a system volume to a container and use commands that are not present in the container. The following command will fail as the "ip" command is not present in the base rhel7 container image.

Volume Mounts

Container images are very minimal installs of their referenced operating system, so commonly-used commands may not be present.

nonexistent command "ip"
podman run --rm -it rhel7 /usr/sbin/ip a
container create failed: container_linux.go:348: starting container process caused "exec: \"/usr/sbin/ip\": stat /usr/sbin/ip: no such file or directory"
: internal libpod error

However, if we use -v <source>:<destination>, the <source> file or directory is mapped from the container host to the inside of the container. Running the same command with the -v volume switch will run the ip command successfully:

podman run -v /usr/sbin:/usr/sbin --rm -it rhel7 /usr/sbin/ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
3: eth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 22:06:a3:f0:c6:a0 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.88.0.4/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::2006:a3ff:fef0:c6a0/64 scope link tentative
       valid_lft forever preferred_lft forever

Volume Mounts (continued)

Volume mounts can be used for logging to the container host for event retention

mounting logs via volumes
podman run -v /dev/log:/dev/log --rm rhel7 logger Testing logging to the host

Search for the container event on the container host log

search the container host
journalctl | grep "Testing logging"
May 26 03:28:42 ip-10-0-2-6.ec2.internal root[25499]: Testing logging to the host

Persistent container data

The -w switch specifies the working directory where binaries are executed. If unspecified, the root directory (/) is used.

Run Python simple server
mkdir /opt/rhel_data
podman run -d -p 8080:8000 --name="python_web" \
       -w /opt \
       -v /opt/rhel_data:/opt rhel7 \
       /bin/python -m SimpleHTTPServer 8000

Verify the container is running using the podman ps switch

podman ps
CONTAINER ID   IMAGE                                     COMMAND                  CREATED AT                      STATUS              PORTS                                            NAMES
fcd06aee9533   registry.access.redhat.com/rhel7:latest   /bin/python -m Simp...   2018-05-23 17:21:40 +0000 UTC   Up 45 seconds ago   0.0.0.0:8080->8000/udp, 0.0.0.0:8080->8000/tcp   python_web

Run the following URL command to show there are no files present in the container’s /opt directory.

Check to see no files in opt
ll /opt/rhel_data/
total 0
Check to see no files via the web server
curl localhost:8080
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html>
<title>Directory listing for /</title>
<body>
<h2>Directory listing for /</h2>
<hr>
<ul>
</ul>
<hr>
</body>
</html>

Now create several files with a script in the host /opt/rhel_data directory.

for i in {1..10}; do touch /opt/rhel_data/file${i}; done

View the newly created files in /opt/rhel_data

ll /opt/rhel_data/
total 0
-rw-r--r--. 1 root root 0 Feb 14 22:38 file1
-rw-r--r--. 1 root root 0 Feb 14 22:38 file10
-rw-r--r--. 1 root root 0 Feb 14 22:38 file2
-rw-r--r--. 1 root root 0 Feb 14 22:38 file3
-rw-r--r--. 1 root root 0 Feb 14 22:38 file4
-rw-r--r--. 1 root root 0 Feb 14 22:38 file5
-rw-r--r--. 1 root root 0 Feb 14 22:38 file6
-rw-r--r--. 1 root root 0 Feb 14 22:38 file7
-rw-r--r--. 1 root root 0 Feb 14 22:38 file8
-rw-r--r--. 1 root root 0 Feb 14 22:38 file9

Then use curl to view the files from the python webserver that is serving files from the mounted /opt/rhel_data volume:

curl localhost:8080
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html>
<title>Directory listing for /</title>
<body>
<h2>Directory listing for /</h2>
<hr>
<ul>
<li><a href="file1">file1</a>
<li><a href="file10">file10</a>
<li><a href="file2">file2</a>
<li><a href="file3">file3</a>
<li><a href="file4">file4</a>
<li><a href="file5">file5</a>
<li><a href="file6">file6</a>
<li><a href="file7">file7</a>
<li><a href="file8">file8</a>
<li><a href="file9">file9</a>
</ul>
<hr>
</body>
</html>

Container metadata

Container images have metadata associated with them that can tell you a lot about processes and network settings. The following command returns a little over 300 lines of JSON data. The output below is truncated for brevity. Feel free to read over the metadata.

podman inspect python_web
[{
    "ID": "fcd06aee95338748ab86faddd696c2cda212e7797b1e44428434da4a0d0b2b45",
    "Created": "2018-05-23T17:21:40.315773016Z",
    "Path": "/bin/python",
    "Args": [
      "-m",
      "SimpleHTTPServer",
      "8000"
    ],
...
    "Name": "python_web",
    "RestartCount": 0,
    "Driver": "overlay",
    "MountLabel": "system_u:object_r:svirt_sandbox_file_t:s0:c744,c884",
    "ProcessLabel": "system_u:system_r:svirt_lxc_net_t:s0:c744,c884",
...

Scripting Pro Tips

You can use a dot notation to parse the metadata returned by podman inspect and use it in your scripting to quickly access properties you need.

podman inspect -f {{.NetworkSettings.IPAddress}} python_web
10.88.0.6

Note: output truncated slightly for readability

You can see the use of cgroups when attached to the container tty. Listing the contents of /proc/1/cgroup will show the cgroup labels.

podman run --rm -it rhel7 bash
cat /proc/1/cgroup
11:blkio:/libpod_parent/libpod-conmon-592226ddcc0625dce98127b4fc0e2e3ee98cb44fdadc579301d8f8647825964c/
10:hugetlb:/libpod_parent/libpod-conmon-592226ddcc0625dce98127b4fc0e2e3ee98cb44fdadc579301d8f8647825964c/
9:pids:/libpod_parent/libpod-conmon-592226ddcc0625dce98127b4fc0e2e3ee98cb44fdadc579301d8f8647825964c/
8:cpuacct,cpu:/libpod_parent/libpod-conmon-592226ddcc0625dce98127b4fc0e2e3ee98cb44fdadc579301d8f8647825964c/
7:freezer:/libpod_parent/libpod-conmon-592226ddcc0625dce98127b4fc0e2e3ee98cb44fdadc579301d8f8647825964c/
6:cpuset:/libpod_parent/libpod-conmon-592226ddcc0625dce98127b4fc0e2e3ee98cb44fdadc579301d8f8647825964c/
5:net_prio,net_cls:/libpod_parent/libpod-conmon-592226ddcc0625dce98127b4fc0e2e3ee98cb44fdadc579301d8f8647825964c/
4:perf_event:/libpod_parent/libpod-conmon-592226ddcc0625dce98127b4fc0e2e3ee98cb44fdadc579301d8f8647825964c/
3:devices:/libpod_parent/libpod-conmon-592226ddcc0625dce98127b4fc0e2e3ee98cb44fdadc579301d8f8647825964c/
2:memory:/libpod_parent/libpod-conmon-592226ddcc0625dce98127b4fc0e2e3ee98cb44fdadc579301d8f8647825964c/
1:name=systemd:/libpod_parent/libpod-conmon-592226ddcc0625dce98127b4fc0e2e3ee98cb44fdadc579301d8f8647825964c/

Type exit to exit the container. Running the same command from your student system, outside of the container context, will list the same top level groups without labels.

cat /proc/1/cgroup
11:devices:/
10:cpuset:/
9:freezer:/
8:hugetlb:/
7:pids:/
6:net_prio,net_cls:/
5:perf_event:/
4:blkio:/
3:memory:/
2:cpuacct,cpu:/
1:name=systemd:/

Workshop Details

Domain Red Hat Logo
Workshop
Student ID

Return to Workshop