一、容器技术

1、容器简介

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

像 RPM 等打包系统可协助管理员管理应用依赖项。比如安装 httpd 软件包时,RPM系统会确保同时安装该软件包的正确库和其他依赖项。

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

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

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

2、RHEL 容器管理工具

Red Hat Enterprise Linux 9 提供了一组容器工具,可用于在单一服务器上运行多个容器:

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

这些工具与开放容器项目(OCI)兼容。这说明你同样可以管理由兼容 OCI 的容器引擎,如Docker(你甚至可以把 Docker 命令全部换成 podman......),创建的任何 Linux 容器。(但用的最多的还是 Docker 吧😅,熟悉 Docker 的话学整个还是很快的,我看以后也没有时间写一篇关于 Docker 的简易教程)这里附上红帽官方对 Docker 和 podman 的比较:什么是 Podman?

3、容器与虚拟机的区别

虚拟机虚拟化的是硬件,每个虚拟机包含完整的操作系统和应用程序,运行在虚拟硬件上。显然这样的开销非常大,如果我仅仅是想运行两个互不兼容的软件却模拟了整个操作系统,会造成非常大的性能浪费。

而容器会共享主机操作系统内核,这样就不用再模拟出整个操作系统,仅仅隔离不同的运行环境。显然这样占用的资源会比虚拟整个操作系统少得多🥰。

lVLh2v17-1.png

4、容器镜像和注册表

要运行容器,必须使用容器镜像。容器镜像是包含编码步骤的静态文件,它充当创建容器的模板。容器镜像打包应用及其所有依赖项。

容器注册表是用于存储和检索容器镜像的存储库(类似于之前学习的 dnf/yum 库)。您可以从注册表中将这些容器镜像拉取到本地系统,以用于运行容器。

容器默认的注册表配置文件位于 etc/containers/registries,默认提供 3 个注册表(有些注册表需要登陆红帽开发者账号):

  • registry.redhat.io (需要身份验证)
  • registry.connect.redhat.com (需要身份验证)
  • docker.io(不需要身份验证)

由于我的是练习环境,注册表、注册地址和开发者账号都是测试用的,实际注册地址和注册表配置参考构建、运行和管理容器 | Red Hat Product Documentation,开发者账号要自行在红帽官网注册然后订阅成为开发者(免费)。

podman login [registry.lab.example.com] :登陆 [registry.lab.example.com] 注册表

lVLh2v17-2.png

二、部署容器

podman 是来自 container-tools 元数据包的全功能容器引擎,用于管理开放容器计划(OCI)容器和镜像。podman 实用程序的运作不使用守护进程,因此开发人员无需系统上的特权用户帐户来启动或停止容器。

lVLh2v17-3.png

1、安装容器工具

dnf install container-tools :安装包含与容器和容器镜像交互所需程序(podman、buildah、skopeo)的软件包

lVLh2v17-4.png

2、在注册表中下载镜像文件

podman search [registry.lab.example.com]/ :在注册表 [registry.lab.example.com] 中搜索镜像

lVLh2v17-5.png

podman pull [registry.lab.example.com/rhel8/httpd-24]:[latest] :拉取 [registry.lab.example.com/rhel8/httpd-24] 镜像,将标签标记为 [latest](不填默认也是 latest)

lVLh2v17-6.png

podman images :显示本地镜像

lVLh2v17-17.png

3、通过镜像运行容器

podman run -d --name [httpd] [registry.lab.example.com/rhel8/httpd-24:latest] :从镜像 [registry.lab.example.com/rhel8/httpd-24:latest] 创建并允许一个名为 [httpd] 的容器并在后台运行

  • -d :以分离模式(detached mode)运行容器,容器在后台运行

lVLh2v17-8.png

podman ps :查看正在运行的容器

lVLh2v17-9.png

4、容器中的环境隔离

podman exec [httpd] [ps -ax] :在 [httpd] 容器内执行 [ps -ax] 命令来查看进程(podman exec 能在运行中的容器内执行命令)

lVLh2v17-10.png

podman exec -it [httpd] [/bin/bash] :使用 [/bin/bash] 终端打开容器 [httpd](容器必须在运行)

  • -i :保持标准输入(stdin)打开,即使没有附加到终端
  • -t :分配一个伪终端(pseudo-TTY),通常与 -i 一起使用以支持交互式操作

lVLh2v17-11.png

5、删除容器

podman stop [httpd] :停止容器 [httpd]

lVLh2v17-12.png

podman start [httpd] :启动容器 [httpd]

lVLh2v17-13.png

podman rm [httpd] :删除容器 [httpd](容器必须在运行)

lVLh2v17-14.png

6、容器持久存储

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

若要持久保留数据,可以使用 --volume(-v)选项挂载主机目录到容器内部。

但是如果直接使用 podman run -d --name [httpd] -v [/app-artifacts]:[/var/www/html] [registry.lab.example.com/rhel8/httpd-24:latest] 命令创建容器会导致容器没有权限访问内部 [/var/www/html] 目录(可使用 podma exec -it httpd /bin/bash 命令进入容器后再使用 cd /var/www/html 验证,会提示 /var/www/html:Permission denied),这是由于主机上 [/app-artifacts] 目录中设置的 SELinux 上下文不正确。

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

因此,当您将 [/app-artifacts] 目录挂载为 [/var/www/html] 目录的持久存储时,您可以使用 podman run -v [/app-artifacts]:[/var/www/html]:Z 命令设置该目录的 SELinux 上下文。

podman run -d --name [httpd] -v [/app-artifacts]:[/var/www/html]:Z [registry.lab.example.com/rhel8/httpd-24:latest] :从镜像 [registry.lab.example.com/rhel8/httpd-24:latest] 创建并允许一个名为 [httpd] 的容器在后台运行,并将 [/app-artifacts] 目录挂载为 [/var/www/html] 目录的持久存储,同时使用 -Z 选项为 [/app-artifacts] 目录设置 container_file_t SELinux 上下文

lVLh2v17-15.png

7、分配端口映射到容器

podman run -d --name [httpd] -p [8080]:[18080] [registry.lab.example.com/rhel8/httpd-24:latest] :从镜像 [registry.lab.example.com/rhel8/httpd-24:latest] 创建并允许一个名为 [httpd] 的容器在后台运行,将容器内部的 [8080] 端口映射为主机的 [18080] 端口(记得打开防火墙😘)

lVLh2v17-16.png

podman port -a :查看容器的端口转发

lVLh2v17-17.png

三、将容器配置为系统服务

1、使用 systemd 管理用户服务

用户可以运行容器来完成系统任务。当希望一直运行某个容器,如 Web 服务器或数据库。在传统环境中,特权用户通常将这些服务配置为在系统启动时运行,并使用 systemctl 命令进行管理。

作为普通用户,您可以创建 systemd 单元来配置您的 rootless 容器(在 Docker 中是不行的,因为 Docker 需要 root 权限)。利用此配置,您可以通过,systemctl 命令将容器作为常规系统服务进行管理。

下面博主将通过一个例子解释如何实现:将 http24 容器镜像的 webserver1 容器配置为在系统启动时启动,并且将 Web 服务器内容挂载在 /app-artifacts 目录,并将 8080 端口从本地计算机映射到容器。将容器配置为通过 systemctl 命令来启动和停止。

2、使用 SSH 登陆其他用户

podman 是一款无状态实用程序(我也不知道什么意思,反正官网是这么写的,感兴趣可以自己查🤔),必须在 SSH 会话中使用,不能在 sudo 或 su shell 中使用。

ssh [wallah]@localhost :使用 ssh 登陆 [wallah] 用户

lVLh2v17-18.png

3、创建容器

podman run -d --name [webserver] -p [8080]:[8080] -v /app-artifacts:/var/www/html:Z [registry.lab.example.com/rhel8/httpd-24:latest] :从镜像 [registry.lab.example.com/rhel8/httpd-24:latest] 创建并允许一个名为[webserver] 的容器在后台运行,并将 [/app-artifacts] 目录挂载为 [/var/www/html] 目录的持久存储,同时使用 -Z 选项为 [/app-artifacts] 目录设置 container_file_t SELinux 上下文,且容器内部的 [8080] 端口映射为主机的 [8080] 端口

lVLh2v17-19.png

4、为容器创建 systemd 用户文件

mkdir -p ~/.config/systemd/user :创建 systemd 配置目录

lVLh2v17-20.png

podman generate systemd --name [webserver] --new --files :在当前目录生成容器 [webserver] 的 systemd 配置文件

  • --new :在服务开始时生成一个新的容器,服务结束时删除该容器(不加则是开始和停止容器)
  • --files :在当前目录自动生成 [webserver] 的 systemd 配置文件(systemd 靠配置文件来识别服务,如果没有配置文件将找不到服务。如果不加则只会将配置文件内容输出到控制台上)

lVLh2v17-21.png

5、启动 systemd 用户服务

systemctl --user daemon-reload :重新加载用户级 systemd 服务配置

lVLh2v17-22.png

systemctl --user enable --now [container-webserver] :启动用户级服务 [container-webserver] 并设置为用户登陆时自动启动

lVLh2v17-23.png

systemctl --user status [container-webserver] :查看用户级服务 [container-webserver] 状态

lVLh2v17-24.png

6、配置 systemd 用户服务开机自启

loginctl enable-linger :强制已启用的服务在系统启动时启动,关闭时停止

lVLh2v17-25.png