Creating & Managing Basic Containers In Linux (Understanding Containers)

In this lesson, you will learn the basics of containers in Linux, how to start, stop & delete a container and how to manage containers.

UNDERSTANDING THE SUBJECT MATTER

What Is a Container / Linux Container?

Containers are set of one or more running instances isolated from the system. The container technology is quite similar to virtualization except that container is isolated.

Container uses namespaces(process, user, network, mount, etc) and control groups (cgroups) for isolation.

Compared to virtualization, containers are portable, reusable, and can be used for quick deployment.

From the diagram above, for virtualization, you can see that the applications are not isolated because they use the binaries and libraries of the guest OS, and modifications made on the guest OS libraries may likely affect the applications.

Unlike containerization, if modifications are made to the guest OS libraries, it will not most times affect the containerized application because they are isolated from the guest OS libraries.

What Is a Container Image

Before you can create a container, you need an image, and images can be gotten from registries, just as you will need to get packages from repositories.

There are a lot of Image registries out there, the paid and the unpaid ones. Be sure to know and trust the registries before using them.

Red Hat distributes container images from two locations. One is (registry.redhat.io) and the other is (registry.access.redhat). The former requires authentication before you can use it while the latter does not require authentication.

If you are an existing customer of Red Hat with subscription(s), you can use your existing credentials to authenticate, otherwise, you will need to signup for the Red Hat Developer Program or 30-day trial subscriptions.

You can also get more information about these registries and their content here.

A container image is usually in this type of format [registry.redhat.io/rhel8/httpd-24:1-122]

where,

“registry.redhat.io” is the image registry

“rhel8” is the image username(s).

“httpd-24” is the image name and

“1-22” is the image tag.

If a tag is not specified, the latest tag of the image will be used by default.

So for example, if I build a container image and I decide to call the image name “webapp” and the image username “victor” because I built the image. If I also decide to put the image in a registry called “registry.tekneed.me”, the image can be referenced as [registry.tekneed.me/victor/webapp].

Then from my image, I and other users can begin to create a container.

What are The Tools Used To Create & Manage Containers In Linux

The utility used to create a container is podman. If you wish to build a container image, you can also do that with a utility called buildah while the skopeo utility can be used to inspect and do other container management activities.

The podman utility can be used to do a lot of container management processes. As we go on in this lesson, you will see how far we can use the podman utility

How Does A Basic Linux Container Work

Container leverage on the kernel and the key components of the operating system such as SELinux, namespace, cgroup, seccomp, etc. Hence, with just an operating system and some of its core component, one can run a container.

However, a container will run in an isolated environment or a different namespace from the operating system.

Namespaces make the isolation of resources/containers possible. It isolates the containers from each other and from the container hosts.

cgroups (control groups) on the other hand manages the system resources and regulates containers from using up the resources on the hosts.

While SELinux is used to protect container processes from each other and from the host machine.

containers in Linux

From the diagram above, you can see that the operating system is running on its namespace and with its libraries while the container image is running on a namespace and its libraries different from the operating system.

Hence, the running services or processes on the operating system will be different from that of the container.

One of the ways to verify this is by using the “ps -ef” command on the container and on the host which we will verify as we go on.

A container image, of course, may need a storage device, depending on how the image was built and the functions it will be used for. As regards storage, a storage device can be attached to the container from the container host. We will see how to do this in the “ACTION TIME” section below

More so, a port on the container host can also be forwarded to a container so that users will be able to connect to the services running on the container. We will also see how to do this in the “ACTION TIME” section below.

In summary, creating containers requires logging into the registry, downloading the container image, and running the container.

More so, before we can create a container, we need to install the module that contains the container utilities.

Let’ see how we can do all of these.

How To Install container tools module in Linux

To install container tools module, use the command,

[root@DRDEV1 ~]# yum module install container-tools -y

Updating Subscription Management repositories.
Last metadata expiration check: 0:00:30 ago on Mon 30 Nov 2020 05:15:34 PM GMT.
Dependencies resolved.

How To Login To an Image Registry In Linux

To login to an image registry in Linux, use the command,

[root@DRDEV1 ~]# podman login registry.redhat.io

Username: my_username
Password:
Login Succeeded!

How To Download a Container Image In Linux

To download a container image in Linux, use the command

# podman pull <registry-name>/<registry-username>/<image-name>:<tag>

For example,

# podman pull registry.redhat.io/rhel8/httpd-24:1-122

N:B: The latest tag will be used if you don’t specify a tag.

verify the downloaded image

# podman images <registry-username>/<image-name>:<tag>
# podman images registry.redhat.io/rhel8/httpd-24:1-122

How To Run/Start a Container In Linux

*To run or start a container in Linux with an interactive shell, use the command,

podman run --name <container-name> -it <registry-username>/<image-name>:<tag> /bin/bash

For example,

podman run --name site1 registry.redhat.io/rhel8/httpd-24:1-122 /bin/bash

NB 1: the option (it) means you are calling for an interactive shell.

NB 2: /bin/bash will start the container with an interactive bash shell

NB 3: If you don’t specify a name when running or starting a container, a random name will be given to the container.

NB 4: you can also run or start a container this way without downloading the images first. However, the image will be downloaded before it can be started thereby taking time before the container is started.

NB 4: if you exit out of the interactive bash shell, the container will stop because you started the container with an interactive shell. You can prevent this by starting the container in the background.

*To start or run a container without an interactive shell in Linux, use the command,

podman run -d --name site1 registry.redhat.io/rhel8/httpd-24:1-122

NB: The (-d) option means detach the image, that is, the container should run in the background.

To use the interactive shell if the container is running in the background, use the command,

podman exec -it <container-name-OR-id> bash

For example,

podman exec -it site1 bash

NB: If you exit of the container, the container will not stop because you didn’t start the container with an interactive shell.


How To View Container Logs In Linux

To view logs, use the command,

podman logs <container-name-OR-ID>

How To Start, Stop and Restart a Container In Linux

*To start a container, use the command,

# podman start <container-name-OR-ID>

*To stop a container, use the command,

# podman stop <container-name-OR-ID>

*To restart a container, use the command,

# podman restart <container-name-OR-ID>

How To Search For a Container Image In Linux

To search for the httpd images in the “registry.redhat.io” registry for example, use the command,

[student@DRDEV1 ~]$ podman search registry.redhat.io/httpd

INDEX       NAME                                                                  DESCRIPTION                                       STARS   OFFICIAL   AUTOMATED
redhat.io   registry.redhat.io/rhscl/httpd-24-rhel7                               Apache HTTP 2.4 Server                            0          
redhat.io   registry.redhat.io/cloudforms46-beta/cfme-openshift-httpd             CloudForms is a management and automation pl...   0          
redhat.io   registry.redhat.io/cloudforms46/cfme-openshift-httpd                  Web Server image for a multi-pod Red Hat® C...    0
..............    

How To Search For Image tags In Linux

To search for image tags in Linux, use the command,

[student@DRDEV1 ~]$ skopeo inspect docker://registry.redhat.io/rhel8/httpd-24 |more

{
    "Name": "registry.redhat.io/rhel8/httpd-24",
    "Digest": "sha256:43b6a13d3e6674ec684ba2cdf433633cabe4963a24e00b59f32532b31bbf1ce5",
    "RepoTags": [
        "1-112",
        "1-118",
        "1-118-source",
        "1-70",
............

How To View Locally Stored Images In Linux

[student@DRDEV1 ~]$ podman images

REPOSITORY                         TAG               IMAGE ID      CREATED       SIZE
registry.redhat.io/rhel8/httpd-24  1-112.1599745027  737cae068fa5  2 months ago  432 MB
registry.redhat.io/rhel8/httpd-24  1-112             e00cffb90b64  3 months ago  430 MB
registry.redhat.io/rhel8/httpd-24  1-105             7e93f25a9468  4 months ago  430 MB
registry.redhat.io/rhel8/httpd-24  1-89              e57f2e65a71b  8 months ago  401 MB

*To remove or delete a locally stored image, use the command,

 podman rmi registry.redhat.io/rhel8/httpd-24

How To Verify a Running Container & Delete a Container In Linux

* To verify a running container, use the command,

# podman ps

*To verify an archived container, use the command,

# podman ps -a

*To delete a running container, use the command,

# podman rm container-id-OR-name

How To Attach Storage To a Container In Linux With podman

By nature, containers are ephemeral, and when they crash or are restarted, all the data in them vanishes as well. Hence, the need to attach an external storage outside of a container so that data can be persistent. By doing this, even if your container crashes, the data still remains, and when the container is recreated, the storage or volume can be attached to the container again.

One can also use the storage host of where the container resides for a very small environment by creating a path/directory for the container storage.

For example, if you want to use a directory on the container host or any external storage that will be mapped to a container host, one can take the following steps.

1. Create a directory.

sudo mkdir /var/pv

2. The user that is running the processes in the container must be able to write files to the directory/volume. We can do this by defining the numeric user ID from the container. For example, if the numeric user ID of the container application is 45, we can change the ownership of the directory by using the command below.

sudo chown -R 45:45 /var/pv

3. We need to apply the “container_file_t” type context to the volume (directory and all sub-directories). We can do this by using the command below

semanage fcontext -a -t container_file_t '/var/pv(/.*)?'

4. use the restorecon command by writing the appropriate context in the filesystem

restorecon -Rv /var/pv

5. Mount the volume to the container by using the -v flag as shown below.

podman run -v /var/pv:/var/lib/mysql mysql

*where (/var/lib/mysql) is where the volume will be attached to on the container, and

*(mysql) is the container name

NOTE: if the volume, /var/lib/mysql already exists inside the container, the volume, /var/pv mount overlays but will not delete the contents in the container. The original content will be accessible again if the mount is removed.

**Another direct method***

To attach storage to a container, use the volume option (-v) and use the Z option to set the directory type context to the right SELinux type context (container-file-t).

For example, to attach the path, (/tekneed/mnt/web_file) on the host to a container as /var/www/html, use the option,

-v /tekneed:/var/www/html:Z

We will see how to use this in the “ACTION TIME” section below.


How To Forward a Port To a Container In Linux With podman

By default, internal IPs are given to every container when it is created, and containers can only talk to each other when they are on the same hosts. Containers in a host are isolated from containers in other hosts, even if the hosts are on the same network.

For example, if you have container 1 and container 2 on host A, and you also have container 3 and container 4 on host B, container 1 and container 2 can only talk to each other by default, while container 2 and container 3 can only talk to each other by default.

Container 1 and container 2 on host A cannot communicate with container 3 and container 4 on host B.

To allow containers to communicate outside of their hosts, we must use port forwarding, which means that any request that comes into the host at the port you specified for the host will be forwarded to the container application port. If you do not specify a port for the host, a random port will be assigned to the host for the container.

The -p flag is used to specify port forwarding.

For examples,

*To forward port 8081 on the container host with the IP of 192.168.0.33 to a container application on port 80, use the command below.

sudo podman run -d --name httpd -p 192.168.0.33:8081:80 registry.redhat.io/rhel8/httpd-24:latest

*If you do not want to specify a port on the host and want podman to use a random port, use the command below.

sudo podman run -d --name httpd -p 192.168.0.33::80 registry.redhat.io/rhel8/httpd-24:latest

*To see the random port podman assigns to the host, use the command,

[victor@DRDEV1 ~]$ sudo podman port httpd

80/tcp -> 127.0.0.1:34237

[victor@DRDEV1 ~]$ curl 127.0.0.1:34237

<html><body><h1>It works!</h1></body></html>

Where

*httpd is the container name

In summary, and in conclusion,

For example, to forward port 8080 on the container host to port 8821 on the container, use the option,

-p 8080:8821

We will see how to use this in the “ACTION TIME” section below.


How To add Environment Variable To a Container In Linux

To add an environment variable to a container, use the -e option. For example, to add the environment variable, WEB_NAME and the value apache, use the option,

-e WEB_NAME=apache

How To Make a Container Persistent In Linux

To make a container persistent, configure the container as a systemd service by taking the following steps.

*create a systemd directory where a user’s unit files will be defined and generate the file

# mkdir -p ~/.config/systemd/user
# cd ~/.config/systemd/user
# podman generate --name <container-name> --files --new

with the (–files) option, the files will be generated inside the current directory

with the (–new) option, the container will be created whenever the service starts and be deleted whenever the service stops.

* enable the linger feature to make the systemd service persistent

# loginctl enable-linger

*start and enable the container as a service

# systemctl --user daemon-reload
systemctl --user enable --now container-<container-name>

ACTION TIME

Having understood what a container is, let’s see the step by step guide of how to create a container in Linux.

Step By Step Guide Of How To Create a Basic Container In Linux

create an apache webserver container with the latest tag from registry.redhat.io/rhel8/httpd-24 named tekhour and should be accessible on port 8080.

The service running on the container should be persistent. On the host, create a file (/tekneed/html/index.html) and attach it to the container as /var/www

1. Install the module that contains the container utilities

[victor@DRDEV1 ~]# sudo yum module install container-tools

Updating Subscription Management repositories.
Red Hat Enterprise Linux 8 for x86_64 - AppStream (RPMs)                                                       2.6 kB/s | 4.5 kB     00:01
Red Hat CodeReady Linux Builder for RHEL 8 x86_64 (RPMs)                                                       7.5 kB/s | 4.5 kB     00:00
Red Hat Enterprise Linux 8 for x86_64 - BaseOS (RPMs)                                                          6.6 kB/s | 4.1 kB     00:00
............

2. login to the registry

[victor@DRDEV1 ~]# podman login registry.redhat.io

Username: tekneed
Password:
Login Succeeded!

3. inspect the httpd-24 image

[victor@DRDEV1 ~]# skopeo inspect docker://registry.redhat.io/rhel8/httpd-24 |more
{
    "Name": "registry.redhat.io/rhel8/httpd-24",
    "Digest": "sha256:43b6a13d3e6674ec684ba2cdf433633cabe4963a24e00b59f32532b31bbf1ce5",
..........

4. download the image

[victor@DRDEV1 ~]# podman pull registry.redhat.io/rhel8/httpd-24:latest

Trying to pull registry.redhat.io/rhel8/httpd-24:latest...
Getting image source signatures
Copying blob c375cdde5b27 skipped: already exists
Copying blob 1b8dabac56ed skipped: already exists
Copying blob 6500ac87b29f skipped: already exists
Copying blob 0c7bc3c1e1a3 [--------------------------------------] 0.0b / 0.0b
Copying config 9efdfdd093 done
Writing manifest to image destination
Storing signatures
9efdfdd093de32e1a6035e885342fd03e09bf3aec68057996f191181755dd04c

4. create the file, /tekneed/html/index.html

[victor@DRDEV1 ~]# mkdir -p ~/tekneed/html
[victor@DRDEV1 ~]# echo "This is a test" > ~/tekneed/html/index.html

5. Make sure others have read permission on the file.

[victor@DRDEV1 ~]$ ls -ld ~/tekneed/

drwxrwxr-x. 3 victor victor 18 Dec  9 18:03 /home/victor/tekneed/
[victor@DRDEV1 ~]$ ls -l ~/tekneed/html/index.html

-rw-rw-r--. 1 victor victor 15 Dec  9 18:04 /home/victor/tekneed/html/index.html

6. create the container

[victor@DRDEV1 ~]$  podman run -d --name tekhour -p 8080:8080 -v ~/tekneed:/var/www:Z registry.redhat.io/rhel8/httpd-24:latest

f4e4606f78b0751fb23d8af186a578fa6bc515129a5db58912bbacd4c5c573c7

7. verify that the container has been created.

[victor@DRDEV1 ~]$ podman ps

CONTAINER ID  IMAGE                                     COMMAND               CREATED        STATUS            PORTS                   NAMES
f4e4606f78b0  registry.redhat.io/rhel8/httpd-24:latest  /usr/bin/run-http...  7 seconds ago  Up 7 seconds ago  0.0.0.0:8080->8080/tcp  tekhour

8. verify that you can access the storage attached to the container over port 8080

[victor@DRDEV1 ~]# curl http://localhost:8080

This is a test

If you reboot your system, the container will not start across reboot. We need to follow the steps below to make it persistent.

9. create the systemd directory where the user’s unit files will be defined.

[victor@DRDEV1 ~]$ mkdir -p ~/.config/systemd/user

10. Generate the user’s unit file in the created directory

[victor@DRDEV1 ~]$ cd ~/.config/systemd/user
[victor@DRDEV1 user]$ podman generate systemd --name tekhour --files --new

/home/victor/.config/systemd/user/container-tekhour.service
[victor@DRDEV1 user]$ ls

container-tekhour.service

11. enable linger and verify it’s been enabled.

[victor@DRDEV1 user]$ loginctl enable-linger
[victor@DRDEV1 user]$ loginctl show-user victor

UID=1005
GID=1005
Name=victor
Timestamp=Mon 2020-12-07 09:19:31 GMT

........

12. stop and remove the container.

[victor@DRDEV1 user]$ podman stop tekhour

f4e4606f78b0751fb23d8af186a578fa6bc515129a5db58912bbacd4c5c573c7
[victor@DRDEV1 user]$ podman rm tekhour

f4e4606f78b0751fb23d8af186a578fa6bc515129a5db58912bbacd4c5c573c7

13. start and enable the container as a service.

[victor@DRDEV1 ~]$ systemctl --user daemon-reload
[victor@DRDEV1 ~]$ systemctl --user enable --now container-site1

Created symlink /home/victor/.config/systemd/user/multi-user.target.wants/container-site1.service → 

14. verify if the container is up and can access the storage.

[victor@DRDEV1 ~]$ podman ps
[victor@DRDEV1 ~]$ curl http://localhost:8080

This is a test

Tutorial Video On Managing Basic Containers In Linux

RHCSA 8 Exam Practice Question On Understanding & Managing Basic Containers In Linux

Your feedback is welcomed. If you love others, you will share with others

20 Comments

  1. Hi Victor,
    Can you answer this question for me please?
    1. Create a container logserver from an image rsyslog in note 1 from registry.lab.example.com
    configure the container with systemd services by an exiting user wallah service name should be container-logserver and configure it automatic configure
    2) Configure your host journal to store all journal across reboot
    copy all jornal form /var/log/journal and all subdirectories to /home/wallah/container-logserver
    configure automount /var/log/journal from logserver container to /home/wallah/container_server when container start

  2. hi, when i use this command
    $ systemctl –user daemon-reload
    i have and error message which is [Failed to connect to bus: no such file or directory]
    can you help me?

  3. Hello Tekneed,

    Can you please allow me to have a look on configuration Rsyslog log-server Container?

    Please Pleasee.

  4. Hi Viktor, with regards to question 20: When you run “logger “hello”” in the container do you actually see any logging in the mounted directory in /home/wallah?
    I followed the exercise but I see no logging happening.

  5. hi victor,
    i am able to make persistent storage.but not able to figure out how and where all the log messages are stored. How and where we able to see logger’s messages on those storage. can you show a example. exam rhel8 is asking to log a message to store on both container and persistent storage .

Leave a Reply

Your email address will not be published.


*