Bootstrap

Linux容器(初学了解)

目录

一、容器

1.1、容器技术

1.2、容器和虚拟机之间的差异

1.3、Rootless 和 Rootful 容器

1.4、设计基于容器的架构

1.5、容器管理工具

1.6、容器镜像和注册表

1.7、配置容器注册表

1.8、使用容器文件构建容器镜像

二、部署容器

2.1、Podman 实用程序

2.2、安装容器使用工具

2.3、从注册表下载容器镜像文件

2.4、从容器文件创建容器镜像

2.5、运行容器

2.6、删除容器和镜像

三、管理容器存储和网络资源

3.1、管理容器资源

3.2、容器的环境变量

3.3、容器持久存储

3.4、容器存储的 SELinux 上下文

3.5、分配端口映射到容器

四、作为系统服务来管理容器

4.1、使用 systemd 单元管理小型容器环境

4.2、systemd 用户服务要求


一、容器


1.1、容器技术

软件应用通常依赖于运行时环境提供的系统库、配置文件或服务。传统上,软件应用的运行时环境安装在物理主机或虚拟机上运行的操作系统中。然后,管理员在操作系统上安装应用依赖项。

在RHEL中,诸如 RPM 等打包系统可协助管理员管理相关依赖项。安装 httpd 软件包时,RPM 系统会确保同时安装该软件包的正确库和其他依赖项。

以传统方式部署的软件应用的主要弊端时这些依赖项会受到运行时环境的束缚。应用需要的支持软件的版本可能比操作系统提供的软件更旧或更新。同样,同一系统上的两个应用可能需要同一软件互不兼容的不同版本。

解决这些冲突的方式之一是将应用打包并作为容器进行部署。容器是由一个或多个与系统其余部分隔离的进程组成的集合。软件容器是打包应用以简化其部署和管理的一种方式。

以实体集装箱为例,集装箱是打包和装运货物的标准方式。它作为一个箱子进行标记、装载、卸载,以及从一个位置运输到另一个位置。集装箱中的内容与其他集装箱的内容隔离,因此互不影响。这些基本原则也适用于软件容器。

RHEL 通过运用以下核心技术来支持容器:

  • 用于资源管理的控制组(cgroup)
  • 用于进程隔离的命名空间(namespace)
  • 加强安全边界的SELinux 和 Secomp(安全计算模式)

1.2、容器和虚拟机之间的差异

容器提供许多与虚拟机相同的益处,如安全、存储和网络隔离等

这两种技术都将其应用库和运行时资源与主机操作系统或虚拟机监控程序隔离开,反之亦然。

容器和虚拟机以不同的方式与硬件和底层操作系统交互。

虚拟机具有以下特征:

  • 使多个操作系统能够同时在一个硬件平台上运行。
  • 使用虚拟机监控程序将硬件分为多个硬件虚拟环境。
  • 需要一个完整的操作系统环境来支持该应用。

容器具有以下特征:

  • 直接在操作系统上运行,从而跨系统上的所有容器共享资源。
  • 共享主机的内核,但它将应用进程与系统其余部分隔离开来。
  • 与虚拟机相比,它需要的硬件资源要少得多,因此容器的启动速度也更快。
  • 包括所有依赖项,如系统和编程依赖项,以及配置设置。

1.3、Rootless 和 Rootful 容器

在容器主机上,你可以 root 用户或普通非特权用户身份运行容器。由特权用户运行的容器称为 Rootful容器。由非特权用户运行的容器称为 Rootless 容器。

Rootless 容器不允许使用通常为特权用户保留的系统资源,例如访问受限目录,或在受限端口(1024以下的端口)上发布网络服务。此功能可防止潜在攻击者获取容器主机上的 root 权限。

1.4、设计基于容器的架构

容器是重复利用托管应用并使其可以移植的有效方式。容器可以轻松地从一个环境迁移到另一个环境,如从开发环境迁移到生产环境。你可以保存一个容器的多个版本,并根据需要快速访问每个版本。

容器通常是临时的。你可以将运行中容器所生成的数据永久保存到持久存储中,但容器本身通常会在需要时运行,然后停止并被删除。下次需要该特定容器时,将启动新的容器进程。

你可以在单个容器中安装含有多个服务的复杂软件应用。例如,Web 服务器可能需要使用数据库和消息传递系统。不过,将一个容器用于多个服务会难以管理。

更好的设计是在单独的容器中运行每个组件、Web服务器、数据库和消息传递系统。这样,更新和维护单个应用组件不会影响其他组件或应用堆栈。

1.5、容器管理工具

RHEL 提供了一组容器工具,可用于在单一服务器上运行多个容器。

  • podman 管理容器和容器镜像
  • skopeo 检查、复制、删除和签署镜像
  • buildah 创建容器镜像

这些工具与开放容器项目(OCI)兼容。借助这些工具,你可以管理由兼容 OCI 的容器引擎(如
Podman 或 Docker)创建的任何 Linux 容器。这些工具专门设计用于在单节点容器主机上的 RHEL 下运行容器。

1.6、容器镜像和注册表

要运行容器,你必须使用容器镜像。容器镜像是包含编码步骤的静态文件,它充当创建容器的蓝图。容器镜像打包应用及其所有依赖项,如系统库、编程语言运行时和库,以及其他配置设置。

容器镜像根据规范构建,如开放容器项目(OCI)镜像格式规范。这些规范定义容器镜像的格式,以及镜像支持的容器主机操作系统和硬件架构的元数据。

容器注册表是用于存储和检索容器镜像的存储库。开发人员将容器镜像推送或上传到容器注册表中,你可以从注册表中将这些容器镜像拉取或下载到本地系统,以用于运行容器。

可使用包含第三方镜像的公共注册表,也可使用自己组织控制的私有注册表。容器镜像来源很重要。和任何其他软件包一样,你必须知道是否可以信任容器镜像中的代码。对于是否及如何提供、评估和测试提交给它们的容器镜像,不同的注册表有不同的策略。

红帽通过两个主容器注册表分发认证容器镜像,你可以使用红帽登录凭据来使用这两个注册表。

  • registry.redhat.io                         适用基于官方红帽产品的容器
  • registry.connect.redhat.com       适用基于第三方产品的容器

红帽提供通用基础镜像(UBI)镜像作为构建容器的初始层。UBI 镜像是最小化的容器镜像,可以作为应用构建的第一层。

1.7、配置容器注册表

容器注册表的默认配置文件是 /etc/containers/registeries.conf 文件

[root@kittod ~]# cat /etc/containers/registries.conf
...
unqualified-search-registries = ["registry.access.redhat.com",
"registry.redhat.io", "docker.io"]
...

建议使用非特权用户来管理容器,因此你可以在 $HOME/.config/containers 目录中为容器注册表创建registries.conf 文件。此目录中的配置文件会覆盖 /etc/containers/registries.conf 文件中的设置,Podman rootless 模式运行时使用。

如果在使用 podman 命令时不指定容器镜像的完全限定名称,则此文件的注册表列表用于搜索容器镜像。

如果从命令行指定容器镜像的完全限定名称,则容器实用程序不会在此部分中搜索。参数可以留空,以确保你使用容器镜像的完全限定名称。

在文件的 [[registry]] 部分中,配置容器注册表的设置。使用单独的配置来配置每个容器注册表的设置。

[[registry]]
location = "registry.lab.example.com"
insecure = true
blocked = false

1.8、使用容器文件构建容器镜像

容器文件是一种文本文件,内含用于构建容器镜像的指令。容器文件通常具有定义其文件和目录所在路径或 URL 的上下文。生成的容器镜像由只读层组成,每一层代表容器文件中的一条指令。

以下输出是一个容器文件的示例,它使用 registry.access.redhat.com 注册表中的 UBI 镜像,安装
python3 软件包,并将 hello 字符串打印到控制台。

[root@kittod ~]# cat Containerfile
FROM registry.access.redhat.com/ubi9/ubi:latest
RUN dnf install -y python39
CMD ["/bin/bash","-c","echo hello"]

二、部署容器


2.1、Podman 实用程序

  • Podman 是来自 container-tools 元数据包的全功能容器引擎,用于管理开放容器计划容器和镜像。
  • podman 实用程序的运作不使用守护进程,因此开发人员无需系统上的特权用户账户来启动和停止容器。Podman 提供多个子命令来与容器和镜像交互。以下列表显示了一些使用的子命令。
命令描述
podman build使用容器文件构建容器镜像
podman run在新容器中运行命令
podman images列出本地存储中的镜像
podman ps打印有关容器的信息
podman inspect显示容器、镜像、卷、网络或容器集的配置
podman pull从注册表下载镜像
podman cp在容器和本地文件系统之间复制文件或目录
podman exec在运行的容器内运行命令
podman rm删除一个或多个容器
podman rmi删除一个或多个本地存储的镜像
podman search在注册表中搜索镜像

2.2、安装容器使用工具

[root@kittod ~]# dnf install container-tools -y
[root@kittod ~]# dnf info container-tools
...
Source       : container-tools-1-12.el9.src.rpm
Repository   : @System
From repo   : baseos2
Summary     : A meta-package witch container tools such as podman, buildah,
skopeo, etc.
License     : MIT
Description : Latest versions of podman, buildah, skopeo, runc, conmon, CRIU,
Udica, etc as
            : well as dependencies such as container-selinux built and tested
together, and
            : updated.

2.3、从注册表下载容器镜像文件

首先,确保 podman 实用程序已配置为从 registry.redhat.io 注册表搜索和下载容器。podman info 命令显示 podman 实用程序的配置信息,包括其配置的注册表。

[root@kittod ~]# podman info
...
registries:
search:
 - registry.access.redhat.com
 - registry.redhat.io
 - docker.io
...

搜索镜像

[root@kittod ~]# podman search python
NAME                                       DESCRIPTION
docker.io/library/python                   Python is an interpreted,
interactive, objec...
docker.io/library/pypy                     PyPy is a fast, compliant alternative
implem...
docker.io/library/hylang                   Hy is a Lisp dialect that translates
express...
docker.io/bitnami/python                   Bitnami Python Docker Image
docker.io/cimg/python                      
...

下载镜像

[root@kittod ~]# podman pull docker.io/library/python
Trying to pull docker.io/library/python:latest...
Getting image source signatures
Copying blob e1aa7eb23da8 done  
Copying blob 2b9b41aaa3c5 done  
Copying blob 7bb465c29149 done  
Copying blob 11402150a57e done  
Copying blob 49b40be4436e done  
Copying blob c558fac597f8 done  
Copying blob 297428e82567 done  
Copying blob 28e810024ad5 done  
Copying config a3aef63c6c done  
Writing manifest to image destination
a3aef63c6c1029222ff635a72a0fcaddba1fd7a26abdf2491ace8eb3c654471e

查看镜像

[root@kittod ~]# podman images
REPOSITORY                       TAG         IMAGE ID     CREATED     SIZE
docker.io/library/python         latest     a3aef63c6c10  3 weeks ago  1.04 GB
registry.access.redhat.com/ubi9  9.3-1552   4d6addf62a90  6 weeks ago  219 MB

2.4、从容器文件创建容器镜像

[root@kittod ~]# cat Containerfile
FROM registry.access.redhat.com/ubi9/ubi:latest
RUN dnf install -y python39
CMD ["/bin/bash","-c","sleep infinity"]

以上就是一个容器文件,可以使用 podman build 命令来构建镜像。podman build 命令的语法如下所示:

[root@kittod ~]# podman build -t NAME:TAG DIR

NAME: 新镜像的名称
TAG:        新镜像的标签。如果未指定标签,则镜像自动标记为 latest。
DIR:        工作目录路径。容器文件必须位于工作目录中,如果工作目录是当前目录,则你可以用点(.)来指定,使用 -f 标志指定与当前目录不同的目录。

以下案例中,使用 podman build 命令 -t 选项为新镜像提供 python39 名称和 1.0 标签。容器文件位于当前目录中。

[root@kittod ~]# podman build -t python39:1.0 .
STEP 1/3: FROM registry.access.redhat.com/ubi9/ubi:latest
STEP 2/3: RUN dnf install -y python39
Updating Subscription Management repositories.
Unable to read consumer identity
This system is not registered with an entitlement server. You can use
subscription-manager to register.
Red Hat Universal Base Image 9 (RPMs) - BaseOS  1.0 MB/s | 515 kB     00:00    
Red Hat Universal Base Image 9 (RPMs) - AppStre 3.2 MB/s | 1.8 MB     00:00    
Red Hat Universal Base Image 9 (RPMs) - CodeRea 376 kB/s | 192 kB     00:00    
Package python3-3.9.18-1.el9_3.1.x86_64 is already installed.
Dependencies resolved.
Nothing to do.
Complete!
--> 812de9c20183
STEP 3/3: CMD ["/bin/bash","-c","sleep infinity"]
COMMIT python39:1.0
--> 51798a38a896
Successfully tagged localhost/python39:1.0
51798a38a89623dd04a0c28f8dd10fa834f362c43fc2d22747456d34f05681e4

查看镜像

[root@kittod ~]# podman images
REPOSITORY                           TAG         IMAGE ID     CREATED        
SIZE
localhost/python39                   1.0         51798a38a896  13 seconds ago
 225 MB
docker.io/library/python             latest     a3aef63c6c10  3 weeks ago    
1.04 GB
registry.access.redhat.com/ubi9/ubi latest     4d6addf62a90  6 weeks ago    
219 MB
registry.access.redhat.com/ubi9      9.3-1552   4d6addf62a90  6 weeks ago    
219 MB
[root@kittod ~]# podman inspect localhost/python39:1.0
...
              "Cmd": [
                   "/bin/bash",
                   "-c",
                   "sleep infinity"
              ],
...

2.5、运行容器

现在,你已拥有所需的容器镜像,可以使用它们来运行容器。容器可以处于以下状态之一:

  • Created 已创建好但尚未启用
  • 运行中 与其进程一起运行的容器
  • 已停止 其进程已停止的容器
  • Paused 其进程已暂停的容器。不支持 Rootless 容器。
  • Deleted 其进程处于已死状态的容器

podman ps 命令列出系统上正在运行的容器。使用 podman ps -a 来命令查看计算机中的所有容器(已创建、已停止、已暂停和正在运行)

可使用 podman create 命令来创建容器,以便稍后运行。若要创建容器,请使用 localhost/python39容器镜像 ID。也可以使用 --name 选项设置名称来标识容器。此命令的输出是容器的长 ID。

[root@kittod ~]# podman create --name python39 localhost/python39:1.0
59db5289c2d3ff04bee8427bb48c8f373e450a170f2d12af5bfdb180cf82d703
[root@kittod ~]# podman ps
CONTAINER ID IMAGE       COMMAND     CREATED     STATUS     PORTS       NAMES
[root@kittod ~]# podman ps -a
CONTAINER ID IMAGE                   COMMAND               CREATED        
STATUS     PORTS       NAMES
59db5289c2d3 localhost/python39:1.0 /bin/bash -c slee...  25 seconds ago
Created                 python39

启动容器

[root@kittod ~]# podman start python39
python39
[root@kittod ~]# podman ps
CONTAINER ID IMAGE                   COMMAND               CREATED            
STATUS       PORTS       NAMES
59db5289c2d3 localhost/python39:1.0 /bin/bash -c slee... About a minute ago
Up 4 seconds             python39

当然也可以直接使用 podman run 指令来完成下载镜像、启动镜像操作。

2.6、删除容器和镜像

你可以分别使用 podman rm 和 podman rmi 命令来删除容器和镜像。在删除容器镜像之前,必须先从该镜像移除任何现有的运行中的容器。

你决定删除 python39 容器及其相关镜像。如果你在 python39 容器存在时尝试删除:则会出现错误。

[root@kittod ~]# podman rmi localhost/python39:1.0
Error: image used by
59db5289c2d3ff04bee8427bb48c8f373e450a170f2d12af5bfdb180cf82d703: image is in use
by a container: consider listing external containers and force-removing image

你必须先停止容器,然后才能删除它,若要停止容器,请使用 podman stop 命令

[root@kittod ~]# podman stop python39
WARN[0010] StopSignal SIGTERM failed to stop container python39 in 10 seconds,
resorting to SIGKILL
python39
[root@kittod ~]# podman ps
CONTAINER ID IMAGE       COMMAND     CREATED     STATUS     PORTS       NAMES
[root@kittod ~]# podman ps -a
CONTAINER ID IMAGE                   COMMAND               CREATED        
STATUS                       PORTS       NAMES
59db5289c2d3 localhost/python39:1.0 /bin/bash -c slee...  13 minutes ago
Exited (137) 14 seconds ago             python39
[root@kittod ~]# podman rmi localhost/python39:1.0
Error: image used by
59db5289c2d3ff04bee8427bb48c8f373e450a170f2d12af5bfdb180cf82d703: image is in use
by a container: consider listing external containers and force-removing image
[root@kittod ~]# podman rm python39
python39
[root@kittod ~]# podman rmi localhost/python39:1.0
Untagged: localhost/python39:1.0
Deleted: 51798a38a89623dd04a0c28f8dd10fa834f362c43fc2d22747456d34f05681e4
Deleted: 812de9c201838bfaef7c532a02c5ed4d6be46d5f17b3de2b3460988b4d1fa722

三、管理容器存储和网络资源

3.1、管理容器资源

你可以使用容器来运行简单的进程,然后退出。

还可以配置容器以连续运行某一个服务,如数据库服务器。如果要持续运行服务,你最终可能需要向容器添加更多资源,如持久存储或对其他网络的访问权限。

你可以使用不同的策略为容器配置持久存储:

  • 对于红帽 OpenShift 等企业容器平台上的大型部署,你可以使用复杂的存储解决方案为容器提供存储,而无需了解底层基础架构。
  • 对于单个容器主机上且无需扩展的小型部署,你可以通过在运行中的容器上创建要挂载的目录,从容器主机创建持久存储。

当 Web 服务器或数据库服务器等容器为容器主机外部的客户端提供内容时,你必须为这些客户端设置通信通道,以访问容器的内容。你可以配置端口映射,以启用与容器的通信。通过端口映射,目的地为容器主机上端口的请求将被转发到容器内的端口。

设想你要操作以下案例:

  • 基于 MySQL,创建名为 db01 的容器化数据库。
  • 配置容器端口映射和主机防火墙,以允许端口 3306/tcp 上的流量。
  • 配置 db01 容器,以使用具有适当 SELinux 上下文的持久存储。
  • 添加适当的网络配置,以便 client01 容器可以使用 DNS 与 db01 容器通信。

3.2、容器的环境变量

一些容器镜像允许在创建时传递环境变量以自定义容器。你可以使用环境变量为容器设置参数,以根据你的环境进行定制,无需创建自己的自定义镜像。通常,你不会修改容器镜像,因为这会向镜像添加层,或许更加难以维护。

你使用以下命令运行容器化数据库,但发现容器无法启动。

[root@kittod ~]# podman run -d mysql --name db01
Resolved "mysql" as an alias (/var/cache/containers/short-name-aliases.conf)
Trying to pull docker.io/library/mysql:latest...
Getting image source signatures
Copying blob 42b720363d36 done  
Copying blob 81badc5f380f done  
Copying blob 1e72891ace67 done  
Copying blob 87aeb61f1478 done  
Copying blob 1cacbea6ceda done  
Copying blob c490e5dd1a9d done  
Copying blob 6b3b50f9990a done  
Copying blob 3811d52cfa61 done  
Copying blob 05bc7a0277d8 done  
Copying blob cc0abd25a274 done  
Copying config a88c3e85e8 done  
Writing manifest to image destination
d0ec6624a156a81615ab0e8526141a7a4c1b4cc876fe99b5fe68a70c1d91dd10
[root@kittod ~]# podman ps
CONTAINER ID IMAGE       COMMAND     CREATED     STATUS     PORTS       NAMES
[root@kittod ~]# podman ps -a
CONTAINER ID IMAGE                           COMMAND     CREATED       STATUS  
                PORTS       NAMES
2115ce7f06e9 docker.io/library/mysql:latest mysqld      6 seconds ago Exited
(1) 6 seconds ago             db01

可以使用以下命令调查容器状态的原因

[root@kittod ~]# podman logs db01
2024-03-07 04:38:22+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server
8.3.0-1.el8 started.
2024-03-07 04:38:22+00:00 [Note] [Entrypoint]: Switching to dedicated user
'mysql'
2024-03-07 04:38:22+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server
8.3.0-1.el8 started.
2024-03-07 04:38:22+00:00 [ERROR] [Entrypoint]: Database is uninitialized and
password option is not specified
  You need to specify one of the following as an environment variable:
   - MYSQL_ROOT_PASSWORD
   - MYSQL_ALLOW_EMPTY_PASSWORD
   - MYSQL_RANDOM_ROOT_PASSWORD

从前面的输出中可以看到,需要以下变量之一用于配置数据库:

- MYSQL_ROOT_PASSWORD
- MYSQL_ALLOW_EMPTY_PASSWORD
- MYSQL_RANDOM_ROOT_PASSWORD

重新启动容器

[root@kittod ~]# podman run -d --name db02 -e MYSQL_ROOT_PASSWORD=redhat mysql
3ad477e4a0ef60cecf0835c8501a0c2fe31311f6639418d932dc5778af74874f
[root@kittod ~]# podman ps
CONTAINER ID IMAGE                           COMMAND     CREATED       STATUS  
    PORTS       NAMES
3ad477e4a0ef docker.io/library/mysql:latest mysqld      2 seconds ago Up 3
seconds             db02
[root@kittod ~]# podman exec -it db02 /bin/bash
bash-4.4# mysql -uroot -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.3.0 MySQL Community Server - GPL
Copyright (c) 2000, 2024, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql             |
| performance_schema |
| sys               |
+--------------------+
4 rows in set (0.00 sec)
mysql>

3.3、容器持久存储

默认情况下,在运行容器时,其所有内容都使用基于容器的镜像。鉴于容器镜像的寿命短,用户或应用写入的所有新数据在移除容器后都会丢失。

若要持久保留数据,你可以将容器中的主机文件系统内容与 --volume(-v) 选项搭配使用。在容器中使用此卷类型时,你必须考虑文件系统级别的权限。

在 mysql 容器镜像中,mysql 用户必须拥有 /var/lib/mysql 目录,就如同 MySQL 在主机运行一样。你打算挂载到容器中的目录必须具有 mysql 作为用户和组所有者。如果以 root 用户身份运行容器,则主机上的 UID 和 GID 与容器内 UID 和 GID 匹配。

UID 和 GID 匹配配置在 Rootless 容器中的出现方式不同。在 Rootless 容器中,用户具有容器内的 root访问权限,因为 Podman 在用户命名空间内启动容器。

你可以使用 podman unshare 命令在用户命名空间内运行命令。要获取用户命名空间的 UID 映射,请使用 podman unshare cat 命令。

[root@kittod ~]# su - redhat
[redhat@kittod ~]$ podman unshare cat /proc/self/uid_map  
        0       1000          1
        1     100000      65536
[redhat@kittod ~]$ podman unshare cat /proc/self/gid_map
        0       1000          1
        1     100000      65536

创建 Rootless 容器 db03,并将 /home/redhat/db_data 目录挂载到 db03 容器中,以在容器的
/var/lib/mysql 目录中提供持久存储。然后创建该目录,并使用命令将 999 用户命名空间设置为该目录的所有者和所属组。

[root@kittod ~]# ssh redhat@localhost
redhat@localhost's password:
Register this system with Red Hat Insights: insights-client --register
Create an account or view all your systems at https://red.ht/insights-dashboard
Last login: Thu Mar  7 12:57:11 2024
[redhat@kittod ~]$ mkdir db_data
[redhat@kittod ~]$ ll db_data/ -d
drwxr-xr-x. 2 redhat redhat 6 Mar  7 13:08 db_data/
[redhat@kittod ~]$ id
uid=1000(redhat) gid=1000(redhat) groups=1000(redhat)
context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[redhat@kittod ~]$ podman run -d --name db03 -e MYSQL_ROOT_PASSWORD=redhat mysql
✔ docker.io/library/mysql:latest
Trying to pull docker.io/library/mysql:latest...
Getting image source signatures
Copying blob 42b720363d36 done  
Copying blob 81badc5f380f done  
Copying blob 87aeb61f1478 done  
Copying blob c490e5dd1a9d done  
Copying blob 1cacbea6ceda done  
Copying blob 1e72891ace67 done  
Copying blob 6b3b50f9990a done  
Copying blob 3811d52cfa61 done  
Copying blob 05bc7a0277d8 done  
Copying blob cc0abd25a274 done  
Copying config a88c3e85e8 done  
Writing manifest to image destination
53d73653f4aec14930570d44320806880f65e511bda59260a10442135b3712d7
[redhat@kittod ~]$ podman ps
CONTAINER ID IMAGE                           COMMAND     CREATED       STATUS  
    PORTS       NAMES
53d73653f4ae docker.io/library/mysql:latest mysqld      6 seconds ago Up 7
seconds             db03
[redhat@kittod ~]$ podman exec -it db03 /bin/bash
bash-4.4# grep mysql /etc/passwd
mysql:x:999:999::/var/lib/mysql:/bin/bash
bash-4.4# exit
exit
[redhat@kittod ~]$ podman unshare chown 999:999 db_data/
[redhat@kittod ~]$ ll
total 0
drwxr-xr-x. 2 100998 100998 6 Mar  7 13:08 db_data

创建 Rootless 容器 db04,挂载对应目录。

[redhat@kittod ~]$ podman run -d --name db04 \
> -e MYSQL_ROOT_PASSWORD=redhat \
> -v /home/redhat/db_data:/var/lib/mysql \
> mysql
4dd6fa8f0510071c9d1c9c2d12491b72829f6c6df75da1147f339c76435b3ecf
[redhat@kittod ~]$ podman ps
CONTAINER ID IMAGE                           COMMAND     CREATED         STATUS
        PORTS       NAMES
53d73653f4ae docker.io/library/mysql:latest mysqld      16 minutes ago Up 16
minutes             db03
[redhat@kittod ~]$ podman ps -a
CONTAINER ID IMAGE                           COMMAND     CREATED         STATUS
                    PORTS       NAMES
53d73653f4ae docker.io/library/mysql:latest mysqld      16 minutes ago Up 16
minutes                         db03
4dd6fa8f0510 docker.io/library/mysql:latest mysqld      16 seconds ago Exited
(1) 16 seconds ago             db04
[redhat@kittod ~]$ podman logs db04
2024-03-07 05:27:09+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server
8.3.0-1.el8 started.
find: '/var/lib/mysql/': Permission denied
find: '/var/lib/mysql': Permission denied

根据提示发现,对应的目录依然没有权限,原因是没有正确设置 SELinux 上下文。

3.4、容器存储的 SELinux 上下文

你必须先设置 container_file_t SELinux 上下文类型,然后才能将该目录作为持久存储挂载到容器。如果目录没有 container_file_t SELinux 上下文,则容器无法访问该目录。你可以将 Z 选项附加到 podmanrun 命令 -v 选项的参数,以自动设置目录的 SELinux 上下文。

因此,可以使用以下命令来设置该目录的 SELinux 上下文。

-v /home/user/db_data:/var/lib/mysql:Z

然后可以使用命令验证目录中设置的 SELinux 是否正确。

ls -Z /home/user

案例:

[redhat@kittod ~]$ podman run -d --name db05 -e MYSQL_ROOT_PASSWORD=redhat -v
/home/redhat/db_data/:/var/lib/mysql:Z mysql
b58244ec254b1b846595f7596b66f677155d83d5ea7bc19bcd8c4b36facdad8a
[redhat@kittod ~]$ podman ps
CONTAINER ID IMAGE                           COMMAND     CREATED       STATUS  
    PORTS       NAMES
53d73653f4ae docker.io/library/mysql:latest mysqld      3 hours ago   Up 3
hours               db03
b58244ec254b docker.io/library/mysql:latest mysqld      3 seconds ago Up 3
seconds             db05
[redhat@kittod ~]$ ll -Z
total 4
drwxr-xr-x. 7 100998 100998 system_u:object_r:container_file_t:s0:c777,c949 4096
Mar  7 16:21 db_data

3.5、分配端口映射到容器

要提供对容器的网络访问权限,客户端必须连接到容器主机上的端口,这些端口将网络流量传递到容器中的端口。将容器主机上的网络端口映射到容器中的端口时,容器将接收发送到主机网络端口的网络流量。

例如,你可以将容器主机上的 13306 端口映射到容器上的 3306 端口,以便与 mysql 容器通信。因此,发送到容器主机端口 13306 的流量将由容器中运行的 mysql 接收。

你可以使用 podman run 命令 -p 选项设置从容器主机上 3306 端口到 db06 容器上 13306 端口的端口映射。

[redhat@kittod ~]$ podman run -d --name db06 -e MYSQL_ROOT_PASSWORD=redhat -v
/home/redhat/db_data/:/var/lib/mysql:Z -p 13306:3306 mysql
c874977ab31ca97ec8efeb76129a7d5ab670521566e8a11c9dd000c566f921e3
[redhat@kittod ~]$ podman ps
CONTAINER ID IMAGE                           COMMAND     CREATED       STATUS  
    PORTS                   NAMES
53d73653f4ae docker.io/library/mysql:latest mysqld      3 hours ago   Up 3
hours                             db03
b58244ec254b docker.io/library/mysql:latest mysqld      7 minutes ago Up 7
minutes                           db05
c874977ab31c docker.io/library/mysql:latest mysqld      4 seconds ago Up 4
seconds  0.0.0.0:13306->3306/tcp db06

使用 podman port 命令 -a 选项可显示正在使用的所有容器端口映射。

[redhat@kittod ~]$ podman port -a
c874977ab31c
3306/tcp -> 0.0.0.0:13306

你可以使用 firewall-cmd 命令允许端口 13306 流量传入容器主机,以便可以重定向到容器。注意:要使用 root 用户。

[root@kittod ~]# firewall-cmd --permanent --add-port=13306/tcp
success
[root@kittod ~]# firewall-cmd --reload
success

四、作为系统服务来管理容器

4.1、使用 systemd 单元管理小型容器环境

你可以运行容器来完成系统任务,或获取一系列命令的输出。你可能还希望运行无限期运行服务的容器,如 Web 服务器或数据库。在传统环境中,特权用户通常将这些服务配置为在系统启动时运行,并使用 systemctl 命令进行管理。

作为普通用户,你可以创建 systemctl 单元来配置你的 Rootless 容器。利用此配置,你可以通过
systemctl 命令将容器作为常规系统服务进行管理。

基于 systemd 单元管理容器主要用于不需要扩展的基本和小型部署。对于许多基于容器的应用和服务的更复杂扩展和编排,可以使用基于 Kubernetes 的企业编排平台,如 OpenShift 平台等。

假设有如下案例:

作为系统管理员,你被安排了一项任务,将基于 http24 容器镜像的 webserver1 容器配置为在系统启动时启动。你还必须为 Web 服务器内容挂载 /app-artifacts 目录,并将 8080 端口从本地计算机映射到容器。将容器配置为通过 systemctl 命令来启动和停止。

4.2、systemd 用户服务要求

作为普通用户,你可以使用 systemctl 命令启用服务。该服务在你打开会话时启动,并在关闭最后一个会话时停止。此行为与系统服务有所不同,系统服务时在系统启动时启动并在系统关机时停止。

默认情况下,当你使用 useradd 命令创建用户账户时,系统将使用普通用户 ID 范围中的下一个可用 ID。系统还在 /etc/subuild 文件中为用户的容器保留一系列 ID 。如果你使用 useradd 命令 --system 选项创建用户账户,则系统不会为用户容器保留范围。因此,无法使用系统账户启动 Rootless 容器。

[root@kittod ~]# passwd appdev-adm
Changing password for user appdev-adm.
New password:
BAD PASSWORD: The password is shorter than 8 characters
Retype new password:
passwd: all authentication tokens updated successfully.

使用该用户进行登录

[root@kittod ~]# ssh appdev-adm@localhost
appdev-adm@localhost's password:
Register this system with Red Hat Insights: insights-client --register
Create an account or view all your systems at https://red.ht/insights-dashboard
Last login: Thu Mar  7 17:18:52 2024
[appdev-adm@kittod ~]$ podman info
host:
arch: amd64
buildahVersion: 1.31.3
cgroupControllers:
 - memory
 - pids
...

然后,配置容器注册表并运行容器

[appdev-adm@kittod ~]$ mkdir app-artifacts
[appdev-adm@kittod ~]$ ll -Z app-artifacts/
total 0
[appdev-adm@kittod ~]$ ll -Z app-artifacts/ -d
drwxr-xr-x. 2 appdev-adm appdev-adm unconfined_u:object_r:user_home_t:s0 6 Mar  7
17:22 app-artifacts/
[appdev-adm@kittod ~]$ podman run -d --name webserver1 -p 8080:8080 -v ~/app-
artifacts/:/var/www/html:Z httpd
✔ docker.io/library/httpd:latest
Trying to pull docker.io/library/httpd:latest...
Getting image source signatures
Copying blob e1caac4eb9d2 done  
Copying blob b60d4b66b268 done  
Copying blob 4f4fb700ef54 done  
Copying blob 87b0fe460fd9 done  
Copying blob 9cebd3e3b523 done  
Copying blob e9304da947c5 done  
Copying config 2776f4da9d done  
Writing manifest to image destination
6e6424033fc98af13e9b794f62d684548cfc38879e049ff2a781e2cd387a0909
[appdev-adm@kittod ~]$ podman ps
CONTAINER ID IMAGE                           COMMAND           CREATED      
STATUS       PORTS                   NAMES
6e6424033fc9 docker.io/library/httpd:latest httpd-foreground  4 seconds ago Up
5 seconds  0.0.0.0:8080->8080/tcp webserver1
[appdev-adm@kittod ~]$ ll app-artifacts/ -Z
total 0
[appdev-adm@kittod ~]$ ll app-artifacts/ -Zd
drwxr-xr-x. 2 appdev-adm appdev-adm
system_u:object_r:container_file_t:s0:c187,c569 6 Mar  7 17:22 app-artifacts/
[appdev-adm@kittod ~]$ echo welcome > app-artifacts/haha.html
[appdev-adm@kittod ~]$ podman exec -it webserver1 /bin/bash
root@6e6424033fc9:/usr/local/apache2# ls /var/www/html/
haha.html

;