Understanding Containers
A container is a complete package to run an application, which contains all application dependencies
Containers make it easy to run different versions of application dependencies side-by-side. Since containers are isolated environments, their functions has no effect on other containers
Containers run on top of a container engine that is offered by the host operating system
The operating system kernel is not included in the container, but offered by the host
Containers use container images to initiate
Containers as Processes
The purpose of a container is to run an isolated process
To do this, container images are configured to run a standard application
Once the application is complete, the container is closed
Application containers are used to run common applications, such as scripts that has dependencies to run
System Containers are used as the foundation to build custom images, and don’t come with a standard application
Container Requirements
Containers are Linux and rely heavily on features provided by the Linux kernel:
- Namespaces for isolation between processes. An example is
chroot
jail, in which a file directory is provided to the application container and the container is locked to that directory - Control Group for resource management
- SELinux to ensure security
One container per application
Multiple applications can be connected in Microservices
To manage containers at an enterprise level, orchestration is needed. RedHat offers OpenShift as its Kuburnetes distribution, which is used for orchestration
Containers on RHEL8
Available solutions are highly compatible and interchangeable because of the Open Containers initiative
RHEL8 does not offer Docker support
Available solutions:
- podman: Manages containers and container images
- buildah: Creates new container images
- skopeo: Inspects, deletes, copies, and signs images
Understanding Rootless Containers
If containers need to run a process on a privileged port, they need to run with root privileges
Rootless containers will run as a non-root user
Running containers as root is not safe
Running a Container
Ensure the container management tools are installed:
yum module install container-tools
Once installed, containers fro the Docker Registry can be ran:
podman run -d nginx
RedHat registries can be found at registry.redhat.io, and third-party products are available via registry.connect.redhat.com
RedHat registry access requires authentication using podman login
, where RedHat account name and password are provided
Registries are processed in order within /etc/containers/registries.conf
To acquire a specific container, a complete name reference can be used:
podman pull registry.access.redhat.com/ubi8/ubi:latest
How to Run a Container
Use podman pull
to pre-pull the image from the registry to the local system
Use podman run
to pull the container and run it
By default, the container in the foreground. To avoid this, pass the -d
option to run the container in detached mode
The -it
option will run the container in an interactive tty mode
The --rm
container will remove the container after its use
Detach from a container while in tty mode by using CTRL+p
, CTRL+q
exit
will exit from the primary container application using exit
podman ps
will print all currently running containers
--all
will print all containers still available on the system
If a system container is ran without interactive mode, it will close immeidately once /bin/bash
is loaded
To attach to a running container:
podman attach [CONTAINER_NAME]
Use podman ps
to acquire the container name
Managing Images
Understanding Images
The image is the read-only runnable instance of the container
Images are obtained from registries, which are specified in /etc/containers/registries.conf
Additiontal registries can be added in the [registries.search]
section
Insecure registries are not protected with TLS encryption and must be listed in [registries.insecure]
Searching for Images
podman search
searches all registries
podman search --no-trunc [registry.redhat.io/rhel8](<http://registry.redhat.io/rhel8>)
searches specific registry on the RHEL8 string
Filters can be used on search results:
--limit 5
: Shows a maximum of 5 images per registry--filter stars=5
: Shows images with 5 stores or more--filter is-official=true
: Shows official images only
Web search is available through https://access.redhat.com/containers or https://hub.docker.io
Inspecting Images
skopeo
inspects images before pulling them:
skopeo inspect docker://registry.redhat.io/ubi8/ubi
podman
can be used to inspect images that are locally available:
podman images
podman inspect registry.redhat.io/ubi8/ubi
Removing Images
When new versions of images become available, the old version will be kept on the system as well
podman images
will list all available images
podman rmi [PACKAGE_NAME]
will remove the specified image
Advanced Image Management
buildah
provides advance image management and can be used to create custom images
buildah bud
will build an image based on a Dockerfile
Managing Containers
Managing Container Ports
Map a host to the container application port to make it reachable from the outside
To map host port 8000 to container port 80:
podman run -d -p 8000:80 nginx
podman port -a
will show all current container port mappings
Ensure to also open any ports in the host firewall:
firewall-cmd --add-port 8000/tcp
firewall-cmd --add-pot 8000/tcp --permenant
Containers running without root privileges can only bind to a non-privileged host port
Managing Environment Variables
Some containers require environment variables to run them
If a container fails due to this requirement, use podman logs [CONTAINER_NAME]
, which will show the application log
Alternatively, the podman inspect
command can be used and information can be found within the usage
section
Use -e [VAR]=[VALUE]
when starting a container to pass variable values:
podman run -d --name mydb -e MYSQL_ROOT_PASSWORD=password -e MYSQL_USER=bob -e MYSQL_PASSWORD=password -e MYSQL_DATABASE=books -p 3306:3306 mariadb
Managing Container State
podman stop [CONTAINER_NAME]
stops a container gracefully by sending the SIGTERM signal
If the container isn’t stopped within 10 seconds, the container then receives the SIGKILL signal
podman kill [CONTAINER_NAME]
immediately sends the SIGKILL signal to the container
podman restart [CONTAINER_NAME]
restarts a container that was previously stopped
Running Commands in a Container
podman exec [CONTAINER_NAME] uname -r
runs an additional process inside a running container
podman exec -it [CONTAINER_NAME] /bin/bash
accesses an interactive shell
podman exec -l cat /etc/redhat-release
runs the command on the last container that used in any command
Understanding Root Containers
By default, podman runs non-root containers
Non-root containers cannot bind to a privileged port and do not have an IP Address
sudo podman run -d nginx
will start a root container
Root containers can only be listed by using sudo podman ps
After starting a root container, a bridge device is created on the host operating system that works like NAT to make sure the root container can access the external network
Attaching Storage to Containers
Container storage is ephemeral
Modifications are written to the container writable layer and pertain only for the container’s lifetime
Persistent storage keeps files externally
Use bind mounts to connect a directory inside the container to a directory on the host
Preparing Host Storage
Ensure that the user account used in the container has access to the host directory and set the SELinux context type to container_file_t
If the container user is owner of the host directory, the :Z
option can be used:
podman run -d -v /webfiles:/webfiles:Z nginx
Mount Storage Inside the Container
First create the mount point on the host:
sudo mkdir /dbfiles
Then, apply the correct file permissions:
sudo chmod o+w /dbfiles
Ensure the the directory has the correct user ownership:
sudo chown user:user /dbfiles
Apply the required SELinux context:
sudo semanage fcontext -a -t container_file_t "/dbfiles(/.*)?"
Managing Containers as Services
Autostarting Containers
To automatically start containers in a stand-alone situation, systemd user unit files can be created for rootless containers and managed with systemctl
If Kubernetes or OpenShift is used, containers will be automatically started by default
Running Systemd Services as a User
Systemd user services start when a user session is opened, and closed when the user session is stopped
Use loginctl enable-linger
to change that behavior and start user services for a specific user:
loginctl enable-linger user
loginctl show-user user
Managing Containers Using systemd Services
Create a regular user account to manage all containers
Use podman
to generate a user systemd file for an existing container. The file will be generated in the current working directory:
podman generate systemd --name [CONTAINER_NAME] --files
To have systemd create the container when the service starts, and delete it again when the service stops, add --new
:
podman generate systemd --name [CONTAINER_NAME] --files --new
To generate a service file for a root container, do it from /etc/systemd/system
as the current directory
Create User Unit Files
Create user specific files in ~/.config/systemd/user
Manage them using systemctl --user
command:
systemctl --user daemon-reload
systemctl --user enable app.service
systemctl --user start app.service
systectl --user
commands only work when logging in on console or SSH and do not work in sudo and su sessions