Podman的进阶 | Word Count: 3.1k | Reading Time: 13mins | Post Views:
在容器化领域,Podman 作为 Docker 的无守护进程替代方案越来越受欢迎,尤其是对于优先考虑安全性和灵活性的开发人员而言。经过前面的学习,我们已经初步入门如何使用Podman命令行来管理容器。我们今天来尝试使用YAML脚本来管理多容器的单机编排,它允许用户使用熟悉的语法管理多容器应用程序而无需根守护进程。
2025.02 深圳·东莞·松山湖·三丫坡·华为员工培训中心·图书馆
Podman Compose 主要功能 Podman Compose 是一个命令行工具,使用podman-py编写的,功能类似于 Docker Compose。Podman-compose是通过使用RESTful API来启动容器。它允许您使用 YAML 配置文件定义、管理和运行多容器应用程序。与 Docker Compose 一样,Podman Compose 从文件中读取配置docker-compose.yml
并将其转换为 Podman 命令。Podman 与 Docker 的不同之处在于,它默认以非 root 用户身份运行容器,从而提高了安全性和灵活性,尤其是在多用户环境中。Podman Compose 扩展了此功能,使您能够在更安全的环境中编排容器服务。
使用Compose的3个核心步骤
定义应用环境,配置dockerfile文件以便可以在任何地方复制它
定义组成应用的服务,配置docker-compose.yml文件
启动并运行整个应用程序
Podman的主要优势
无根操作 :无需root权限即可管理容器
Docker Compose 兼容性 :它支持大多数docker-compose.yml
配置
安全性 :不需要守护进程,因此与 Docker 相比,它不太容易受到攻击
可交换的后端 :如果需要,Podman 可以与其他容器后端一起工作。
基本用法 安装Podman-compose 1 2 3 4 5 $ sudo dnf install -y podman-compose$ podman-compose -v podman-compose version 1.3.0 podman version 5.3.1 $ mkdir compose && cd compose && touch podman-compose.yml
创建podman-compose.yml 该podman-compose.yml
文件定义了应用程序所需的服务、网络和卷。这是一个包含两个服务的简单示例:一个Web 服务和一个数据库 服务。
1 2 3 4 5 6 7 8 9 10 11 12 version: '3' services: web: image: httpd:latest ports: - "8080:80" db: image: mysql:latest environment: MYSQL_ROOT_PASSWORD: P@ssw0rd ports: - "3306:3306"
运行容器 要启动podman-compose.yml
文件中定义的容器,请使用以下命令:
1 2 3 4 5 6 7 8 9 10 11 12 # 后台拉起服务 $ podman-compose up -d 8dd89b3c422552e30a39c425226d0ab986f91857b3a8fd32ab9605e72fd1e4af 746a5811deb206bd2cfd53a9e5f77d1d58f46eb31c6a72930601aa346877b18e compose_web_1 fe8a4165055d5248dba7828e2951edd482d89cc90fbcac166c044f04d782ef0b compose_db_1 # 校验 $ podman ps CONTAINER ID IMAGE COMMAND PORTS NAMES 746a5811deb2 docker.io/library/wordpress:latest apache2-foregroun... 0.0.0.0:8080->80/tcp compose_web_1 fe8a4165055d docker.io/library/mysql:latest mysqld 0.0.0.0:3306->3306/tcp, 33060/tcp compose_db_1
此命令将启动web
和db
容器。然后我们可以校验一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # 检验web服务 $ curl 127.0.0.1:8080 <html><body><h1>It works!</h1></body></html> # 检验数据库服务 $ sudo dnf -y install mysql$ mysql -uroot -p -h127.0.0.1 Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 10 Server version: 9.2.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;
停止容器 要停止正在运行的容器,您可以使用:
1 2 3 4 5 6 7 8 # 这将停止并删除与配置相关的所有容器。 $ podman-compose down compose_web_1 compose_db_1 compose_db_1 compose_web_1 8dd89b3c422552e30a39c425226d0ab986f91857b3a8fd32ab9605e72fd1e4af compose_default
进阶用法 Podman Compose 可以处理更复杂的配置。以下是一些管理多容器应用程序的高级示例。
添加网络 您可以在文件中定义自定义网络docker-compose.yml
。这允许容器在隔离网络中进行通信。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 version: '3' services: webApp: container_name: webApp image: httpd:latest restart: always networks: - frontend - backend ports: - "8080:80" mySql: container_name: mySql image: mysql:latest restart: always networks: - backend environment: MYSQL_ROOT_PASSWORD: P@ssw0rd networks: frontend: driver: bridge name: frontend backend: driver: bridge internal: true name: backend
在此示例中,Web
服务与frontend
和backend
网络都进行通信,但mysql数据库连接到backend
。
使用持久卷 为了在容器重启时保持数据持久,您可以在docker-compose.yml
文件中定义卷,这确保即使容器停止或删除,数据仍保持完整。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 version: '3' services: webApp: container_name: webApp image: wordpress:latest restart: always networks: - frontend - backend ports: - "8080:80" environment: WORDPRESS_DB_HOST: mySql WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: se(urepa55 volumes: - $HOME/webApp/web_data:/var/www/html depends_on: - mySql mySql: container_name: mySql image: mysql:latest restart: always networks: - backend environment: MYSQL_ROOT_PASSWORD: P@ssword MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: se(urepa55 security_opt: - no -new-privileges:true volumes: - $HOME/webApp/mysql_data:/var/lib/mysql volumes: wordpress_data: driver: local mysql_data: driver: local networks: frontend: driver: bridge name: frontend backend: driver: bridge internal: true name: backend
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # 执行podman-compose命令 [sujx@docker compose]$ podman-compose up -d mySql webApp webApp mySql 0d53d6ab2b5bf9ce8b0d62ee889dc857567d882effd060cc2e193d026f19803b backend frontend f2477194e504c96fe34d0e79a1ce0313590c985063436d4ad7604dd678213d03 4f693cd301c3f34eb31739e7e6f555ae3395310c638fe9b8b378e10e5943c77c mySql 4d5f8e9e9b25c7ca6cd1b1ab1909926f2a5db2d7f4af7ecf0ebc5248beff5948 webApp # 测试数据库连接 [sujx@docker compose]$ podman exec -it mySql mysql -uwpuser -p # 确认数据持久化 [sujx@docker compose]$ podman volume inspect wordpress_data
然后我们访问相关站点
无根模式 Podman 的主要优势之一是其无 root 操作,这增强了安全性。Podman Compose 继承了此功能,允许您以非 root 用户身份运行容器。
1 podman-compose --rootless up
此命令确保您的容器以无根模式运行,从而在多用户环境中提供更好的安全性和隔离性。
常见问题 尽管 Podman Compose 的设计非常方便用户使用,但您在设置和执行过程中仍可能会遇到一些问题。以下是一些常见问题及其解决方案。
1.不支持的命令
由于 Podman 不是 Docker,因此某些docker-compose.yml
功能可能无法立即使用。请务必参考Podman 文档 以确保兼容性。
2.网络连接问题
在某些情况下,由于网络配置原因,容器可能无法正确通信。请确保在配置文件中使用正确的网络。
3.卷安装错误
由于路径或权限不正确,可能会发生与卷安装相关的错误。请确保设置了正确的目录权限,尤其是在无根模式下。
4.Podman Compose 是 Docker Compose 的替代品吗?
是的,Podman Compose 的工作原理与 Docker Compose 类似,通常可以作为使用文件管理容器的替代品docker-compose.yml
。
5.如何确保我的 Podman 容器在无根模式下运行?
只需以普通用户身份安装 Podman Compose,然后无需 即可运行命令sudo
。Podman 会自动检测无根环境。
6.我可以将 Docker Compose 与 Podman 一起使用吗?
虽然 Podman Compose 是首选工具,但您可以通过设置环境变量来重定向命令,将 Docker Compose 与 Podman 结合使用。不过,Podman Compose 专门针对 Podman 进行了优化,可提供更无缝的体验。
7.Podman Compose 是否支持 Docker Swarm?
Podman Compose 不支持开箱即用的 Docker Swarm 或 Kubernetes。对于超出简单容器管理的编排,请考虑将 Podman 与Kubernetes 或OpenShift 结合使用。
8.Podman Compose 比 Docker Compose 慢吗?
不是,Podman Compose 针对性能进行了优化,并且在某些情况下,由于其无守护进程架构,它可以比 Docker Compose 更快。
Kubernets YAML文件 将命令行选项转换为结构化语言,对于从单节点容器转移到运行规模化容器的开发人员来说是一个障碍。这涉及到如何指定卷、镜像、安全约束、网络端口等。Podman的产品经理Scott McCarty提出一个一个想法:“我真正想做的是帮助用户从Podman转移到使用Kubernets管理其容器。”这就促使开发人员创建了一个新的Podman命令: podman generate kube
用Podman生成K8S YAML文件 单个容器生成yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 # 创建一个httpd的容器,并将web服务端口映射到8081 [sujx@docker ~]$ podman run -d --name http -p 8081:80 httpd b312c82803bc1ef5ba5496eef84aa5a0ffdce3fe620e8b5cf540714bf02b1baf # 检查容器运行情况 [sujx@docker ~]$ curl 127.0.0.1:8081 <html><body><h1>It works!</h1></body></html> # 将容器属性导出为kubernets YAML文件 [sujx@docker ~]$ podman generate kube http >> http.yaml # 查看YAML文件 [sujx@docker ~]$ cat http.yaml # Save the output of this file and use kubectl create -f to import # it into Kubernetes. # apiVersion: v1 kind: Pod metadata: creationTimestamp: "2025-02-26T13:36:36Z" labels: app: http-pod name: http-pod spec: containers: - image: docker.io/library/httpd:latest name: http ports: - containerPort: 80 hostPort: 8081
然后,我们就可以依据这个文件添加replicas这样的运行参数,从而加快Kubernets应用的部署
compose生成yaml 创建compose文件 将前文中所用到的podman-compose文件添加pod的标签 “io.podman.compose.pod: wordpress”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 version: '3' services: webApp: container_name: webApp image: wordpress:latest restart: always networks: - frontend - backend ports: - "8080:80" environment: WORDPRESS_DB_HOST: mySql WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: se(urepa55 volumes: - $HOME/webApp/web_data:/var/www/html depends_on: - mySql labels: io.podman.compose.pod: wordpress mySql: container_name: mySql image: mysql:latest restart: always networks: - backend environment: MYSQL_ROOT_PASSWORD: P@ssword MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: se(urepa55 volumes: - $HOME/webApp/mysql_data:/var/lib/mysql labels: io.podman.compose.pod: wordpress volumes: wordpress_data: driver: local mysql_data: driver: local networks: frontend: driver: bridge name: frontend backend: driver: bridge internal: true name: backend
运行pod 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # 执行compose [sujx@docker compose]$ podman-compose up -d e16655a97b1f7be0b7c2cd47dfe8ac7b28cd4441ba2f07084ec21d8f10494dbc dc8017d1e0fa6516aa8c793628169822ffbc10fbeae2a33da9314eaeff901ade mySql 9a01c257347596ea98cbeec7cf8accf9b7b8ce965aedabe213859c5da8c11599 webApp # 查看容器 [sujx@docker compose]$ docker ps CONTAINER ID IMAGE COMMAND PORTS NAMES b312c82803bc docker.io/library/httpd:latest httpd-foreground 0.0.0.0:8081->80/tcp http dc8017d1e0fa docker.io/library/mysql:latest mysqld 3306/tcp, 33060/tcp mySql # 查看pod [sujx@docker compose]$ podman pod list POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS e16655a97b1f pod_compose Running 14 seconds ago 2 # 导出yaml文件 [sujx@docker compose]$ podman generate kube pod_compose > wordpress.yaml
生成YAML文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 --- apiVersion: v1 kind: Pod metadata: annotations: io.kubernetes.cri-o.SandboxID/mySql: 9a134961881c0d6d3ae7309c6a8f99cd07f5eb2e46fe2174a073a1cf7b7446b3 io.kubernetes.cri-o.SandboxID/webApp: 9a134961881c0d6d3ae7309c6a8f99cd07f5eb2e46fe2174a073a1cf7b7446b3 creationTimestamp: "2025-02-26T13:31:10Z" labels: app: podcompose name: podcompose spec: containers: - args: - mysqld env: - name: MYSQL_ROOT_PASSWORD value: P@ssword - name: MYSQL_USER value: wordpress - name: MYSQL_PASSWORD value: se(urepa55 - name: MYSQL_DATABASE value: wordpress image: docker.io/library/mysql:latest name: mySql volumeMounts: - mountPath: /var/lib/mysql name: home-sujx-webApp-mysql_data-host-0 - args: - apache2-foreground env: - name: WORDPRESS_DB_HOST value: mySql - name: WORDPRESS_DB_PASSWORD value: se(urepa55 - name: WORDPRESS_DB_USER value: wordpress image: docker.io/library/wordpress:latest name: webApp ports: - containerPort: 80 hostPort: 8080 volumeMounts: - mountPath: /var/www/html name: home-sujx-webApp-web_data-host-0 volumes: - hostPath: path: /home/sujx/webApp/mysql_data type: Directory name: home-sujx-webApp-mysql_data-host-0 - hostPath: path: /home/sujx/webApp/web_data type: Directory name: home-sujx-webApp-web_data-host-0
使用边车容器生成 应用的部署 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 # 创建pod $ podman pod create --name wordpress-pod -p 8080:80 0fe838363193acf301f7ccd0e64d7a7d3939a2d01a95133caa3667ba18da9f86 # 创建持久化卷 # 创建 WordPress 数据卷 $ podman volume create wordpress-data # 创建 MySQL 数据卷 $ podman volume create mysql-data # 创建 MySQL 容器 $ podman run -d \ --pod wordpress-pod \ --name mySql \ -v mysql-data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD="P@ssword" \ -e MYSQL_DATABASE=wordpress \ -e MYSQL_USER=wordpress \ -e MYSQL_PASSWORD="se(urepa55" \ docker.io/library/mysql:latest # 创建 wordpress 容器 $ podman run -d \ --pod wordpress-pod \ --name wordpress \ -v wordpress-data:/var/www/html \ -e WORDPRESS_DB_HOST=mySql \ -e WORDPRESS_DB_USER=wordpress \ -e WORDPRESS_DB_PASSWORD="se(urepa55" \ -e WORDPRESS_DB_NAME=wordpress \ docker.io/library/wordpress:latest # 查看pod状态 $ podman pod ps POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS 0fe838363193 wordpress Running 30 minutes ago 40f050d3a766 3 # 查看容器状态 $ podman ps --pod IMAGE PORTS PODNAME localhost/podman-pause:5.3.1-1732147200 0.0.0.0:8080->80/tcp wordpress docker.io/library/mysql:latest 0.0.0.0:8080->80/tcp, 3306/tcp, 33060/tcp mySql wwordpress docker.io/library/wordpress:latest 0.0.0.0:8080->80/tcp wordpress wwordpress # 导出YAML文件 $ podman generate kube wordpress-pod >> wordpress-pod.yaml
查看YAML文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 apiVersion: v1 kind: Pod metadata: annotations: io.kubernetes.cri-o.SandboxID/mySql: 9b9005a230e398b1f82844fdef9072f1a27c2a7cd3a54089d33e540c1198e287 io.kubernetes.cri-o.SandboxID/wordpress: 9b9005a230e398b1f82844fdef9072f1a27c2a7cd3a54089d33e540c1198e287 creationTimestamp: "2025-02-26T14:42:19Z" labels: app: wordpress-pod name: wordpress-pod spec: containers: - args: - mysqld env: - name: MYSQL_ROOT_PASSWORD value: P@ssword - name: MYSQL_PASSWORD value: se(urepa55 - name: MYSQL_DATABASE value: wordpress - name: MYSQL_USER value: wordpress image: docker.io/library/mysql:latest name: mySql ports: - containerPort: 80 hostPort: 8080 volumeMounts: - mountPath: /var/lib/mysql name: mysql-data-pvc - args: - apache2-foreground env: - name: WORDPRESS_DB_NAME value: wordpress - name: WORDPRESS_DB_USER value: wordpress - name: WORDPRESS_DB_PASSWORD value: se(urepa55 - name: WORDPRESS_DB_HOST value: mySql image: docker.io/library/wordpress:latest name: wordpress volumeMounts: - mountPath: /var/www/html name: wordpress-data-pvc volumes: - name: mysql-data-pvc persistentVolumeClaim: claimName: mysql-data - name: wordpress-data-pvc persistentVolumeClaim: claimName: wordpress-data
Kubernets YAML部署到podman上 获取目标文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 apiVersion: v1 kind: Pod metadata: creationTimestamp: null labels: run: pod1 name: pod1 spec: containers: - image: traefik/whoami imagePullPolicy: IfNotPresent name: pod1 resources: {} dnsPolicy: ClusterFirst restartPolicy: Always status: {}
执行目标文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 # 拉取镜像并创建pod [sujx@docker podman]$ podman play kube pod1-build.yml ✔ docker.io/traefik/whoami:latest Trying to pull docker.io/traefik/whoami:latest... Getting image source signatures Copying blob acd87f41b56b done | Copying blob 1d1ddb624e47 done | Copying blob 8f64377bf2e7 done | Copying config 9943fa5dfa done | Writing manifest to image destination Pod: 0bbcb963f9fdb678ee1e27c2601e3dbefaeecca9e5bc66b1acf4bdf498054e20 Container: 121f65a16979e99a2f16a28325d6f29ffb27006f369654e0faea2fc7ac8fe1f6 # 校验pod [sujx@docker podman]$ podman pod ps POD ID NAME STATUS INFRA ID # OF CONTAINERS 0bbcb963f9fd pod1 Running 30a2774ac83e 2 # 检查容器 [sujx@docker podman]$ podman ps --pod IMAGE PORTS NAMES POD ID PODNAME localhost/podman-pause:5.3.1-1732147200 0bbcb963f9fd-infra 0bbcb963f9fd pod1 docker.io/traefik/whoami:latest 80/tcp pod1-pod1 0bbcb963f9fd pod1 # 关闭pod和容器 [sujx@docker podman]$ podman play kube pod1-build.yml --down Pods stopped: 0bbcb963f9fdb678ee1e27c2601e3dbefaeecca9e5bc66b1acf4bdf498054e20 Pods removed: 0bbcb963f9fdb678ee1e27c2601e3dbefaeecca9e5bc66b1acf4bdf498054e20 Secrets removed: Volumes removed: