Exercise 1.2 - Working with Container Images

Return to Workshop

Exercise 1.2 - Working with Container Images

Exercise Description

In this exercise, you’ll learn the fundamentals of container images, including how to run them and how to see what is inside of a container. Container storage volumes will be discussed, showing how to mount external file systems, with useful functions and data. We will also discuss container metadata and explain what types of information you can get from them.

Section 1: Container Images

What you can do with container images, using 'podman run'

When you execute the podman run command, a new container is created, from a container image. That container consists of the image contents, plus any features based on additional selected options.

The command you pass on the podman run command line considers the inside of the container its running environment. So, by default, very little of the host system is visible. For example, by default, the running application sees:

  • The file system provided by the container image.

  • A new process table from inside the container (no processes from the host are visible).

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

Additionally you can also…​

  • Make a directory from the host available to the container, from the podman run command line:

  • 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.

Step 1. 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 /]#

Step 2. Try these commands

ls
whoami
uname -a

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

exit

Section 2: Container Storage Volumes

In this section, we will mount a system volume to a container and use commands that are not present in the container.

Note: 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, using the following command.

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

Step 1. 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

Step 2. 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

Step 3. Run the following URL command to show there are no files via the webserver.

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>

Step 4. 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

Step 5. 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

Step 6. 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>

Section 3: Container metadata

Container images have metadata associated with them that can describe 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, as shown in the following example.

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

Note: Output has been truncated slightly for readability

You can see the use of cgroups when attached to the container tty.

podman run --rm -it rhel7 bash

Listing the contents of /proc/1/cgroup will show the cgroup labels.

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
Workshop
Student ID

Return to Workshop