容器持久存储与网络配置全面详解
目录
1. 培训目标与容器管理基础
培训目标概述
通过从容器主机共享存储为容器数据提供持久化存储,并配置容器网络环境。这对于运行数据库等需要数据持久化的服务至关重要。
容器资源管理策略
容器可以运行简单的临时进程,也可以配置为持续运行服务(如数据库服务器)。对于长期运行的服务,需要额外配置:
-
持久存储:确保数据在容器重启或删除后不丢失
-
网络访问:允许外部客户端访问容器服务
2. 环境变量配置:容器自定义的关键
问题发现与诊断
首次尝试运行MariaDB容器失败:
podman run -d registry.lab.example.com/rhe18/mariadb-105 --name db01
使用 podman container logs db01 检查日志,发现容器需要特定的环境变量才能正常启动:
日志分析结果:
You must either specify the following environment variables:
MYSQL_USER (regex: '^[a-zA-Z0-9_]+$')
MYSQL_PASSWORD (regex: '^[a-zA-Z0-9_\-!@#$%^&*()\-=<>,.?;:]+$')
MYSQL_DATABASE (regex: '^[a-zA-Z0-9_]+$')
Or the following environment variable:
MYSQL_ROOT_PASSWORD (regex: '^[a-zA-Z0-9_\-!@#$%^&*()\-=<>,.?;:]+$')
Or both.
问题根源:MariaDB容器需要数据库配置信息,但未提供必需的环境变量。
镜像信息获取与解析
使用 skopeo inspect 命令查看镜像元数据:
skopeo inspect docker://registry.lab.example.com/rhel8/mariadb-105
关键发现:
-
usage字段提供了运行示例 -
镜像文档显示了可用的环境变量
MariaDB环境变量详解
| 变量名 | 描述 | 正则验证规则 |
|---|---|---|
| MYSQL_USER | 要创建的MySQL帐户用户名 | ^[a-zA-Z0-9_]+$ |
| MYSQL_PASSWORD | 用户帐户密码 | ^[a-zA-Z0-9_\-!@#$%^&*()\-=<>,.?;:]+$ |
| MYSQL_DATABASE | 数据库名称 | ^[a-zA-Z0-9_]+$ |
| MYSQL_ROOT_PASSWORD | root用户密码(可选) | ^[a-zA-Z0-9_\-!@#$%^&*()\-=<>,.?;:]+$ |
正确配置环境变量
使用 -e 选项传递环境变量:
podman run -d --name db01 \
-e MYSQL_USER=student \
-e MYSQL_PASSWORD=student \
-e MYSQL_DATABASE=dev_data \
-e MYSQL_ROOT_PASSWORD=redhat \
registry.lab.example.com/rhe18/mariadb-105
验证容器状态:
podman ps
输出结果解析:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4b8f01be7fd6 registry.lab.example.com/rhe18/mariadb-105:latest run-mysqld 6 seconds ago Up 6 seconds ago db01
-
STATUS: Up 6 seconds:容器正常运行
-
相比之前的 Exited (1) 状态,说明环境变量配置成功
3. 容器持久存储配置
存储需求背景
默认情况下,容器使用基于镜像的存储层,所有新数据在容器删除后都会丢失。对于数据库等需要数据持久化的应用,必须配置持久存储。
文件系统权限配置
MariaDB容器中,mysql用户必须拥有/var/lib/mysql目录的权限。
查看容器内mysql用户信息:
podman exec -it db01 grep mysql /etc/passwd
输出:mysql:x:27:27:MySQL Server:/var/lib/mysql:/sbin/nologin
关键信息:mysql用户的UID和GID都是27
Rootless容器的UID/GID映射
在Rootless容器中,用户命名空间内的UID/GID与主机上的UID/GID存在映射关系:
podman unshare cat /proc/self/uid_map
输出分析:
text
0 1000 1 1 100000 65536
-
容器内UID 0 → 主机UID 1000
-
容器内UID 1 → 主机UID 100000
-
容器内UID 27 → 主机UID 100026
创建持久存储目录
mkdir /home/user/db_data
podman unshare chown 27:27 /home/user/db_data
验证目录所有权:
ls -l /home/user/
输出:drwxrwxr-x. 3 100026 100026 18 May 5 14:37 db_data
结果说明:目录所有者为UID 100026,对应容器内的UID 27
挂载持久存储
使用-v选项挂载目录:
podman run -d --name db01 \
-e MYSQL_USER=student \
-e MYSQL_PASSWORD=student \
-e MYSQL_DATABASE=dev_data \
-e MYSQL_ROOT_PASSWORD=redhat \
-v /home/user/db_data:/var/lib/mysql \
registry.lab.example.com/rhel8/mariadb-105
4. SELinux上下文配置
权限错误分析
容器日志显示权限错误:
podman container logs db01
错误信息:
mkdir: cannot create directory '/var/lib/mysql/db_data': Permission denied
Fatal error Can't create database directory '/var/lib/mysql/db_data'
问题根源:SELinux安全上下文不正确,阻止容器访问主机目录。
SELinux解决方案
容器存储需要container_file_t SELinux上下文类型。使用Z选项自动设置正确上下文:
podman run -d --name db01 \
-e MYSQL_USER=student \
-e MYSQL_PASSWORD=student \
-e MYSQL_DATABASE=dev_data \
-e MYSQL_ROOT_PASSWORD=redhat \
-v /home/user/db_data:/var/lib/mysql:Z \
registry.lab.example.com/rhel8/mariadb-105
验证SELinux上下文:
ls -z /home/user/
输出:system_u:object_r:container_file_t:s0:c81,c1009 db_data
结果说明:目录已正确标记为container_file_t类型,容器可以正常访问。
5. 容器端口映射配置
端口映射原理
将容器主机上的网络端口映射到容器内部端口,实现外部客户端访问容器服务。
配置端口映射:
podman run -d --name db01 \
-e MYSQL_USER=student \
-e MYSQL_PASSWORD=student \
-e MYSQL_DATABASE=dev_data \
-e MYSQL_ROOT_PASSWORD=redhat \
-v /home/user/db_data:/var/lib/mysql:Z \
-p 13306:3306 \
registry.lab.example.com/rhe18/mariadb-105
映射说明:
-
主机端口:13306
-
容器端口:3306
-
发送到主机13306端口的流量将被转发到容器的3306端口
验证端口映射
podman port -a
输出:1c22fd905120 3306/tcp -> 0.0.0.0:13306
podman port db01
输出:3306/tcp -> 0.0.0.0:13306
结果分析:成功建立从主机13306端口到容器3306端口的映射。
防火墙配置
允许外部访问13306端口:
firewall-cmd --add-port=13306/tcp --permanent
firewall-cmd --reload
Rootless容器端口限制
重要限制:
-
Rootless容器无法绑定1024以下的特权端口
-
可以使用
podman run -p 8080:80将高端口映射到容器特权端口 -
需要特权端口时,必须以root用户运行Podman
6. 容器DNS配置与网络连接
网络后端检测
Podman支持多种网络后端:
podman info --format {{.Host.NetworkBackend}}
输出:netavark
网络后端类型:
-
Netavark:RHEL 9+默认后端
-
CNI:传统后端
创建支持DNS的网络
默认Podman网络不支持DNS解析,需要创建自定义网络:
podman network create --gateway 10.87.0.1 --subnet 10.87.0.0/16 db_net
网络配置说明:
-
网络名称:db_net
-
网关:10.87.0.1
-
子网:10.87.0.0/16
验证网络配置
podman network inspect db_net
输出分析:显示网络详细信息,确认网关、子网和DNS设置正确。
容器连接到自定义网络
创建连接到db_net网络的容器:
数据库容器:
podman run -d --name db01 \
-e MYSQL_USER=student \
-e MYSQL_PASSWORD=student \
-e MYSQL_DATABASE=dev_data \
-e MYSQL_ROOT_PASSWORD=redhat \
-v /home/user/db_data:/var/lib/mysql:Z \
-p 13306:3306 \
--network db_net \
registry.lab.example.com/rhe18/mariadb-105
客户端容器:
podman run -d --name client01 \
--network db_net \
registry.lab.example.com/ubi8/ubi:latest \
sleep infinity
安装网络测试工具
容器镜像通常只包含最小软件包,需要安装网络工具:
podman exec -it db01 dnf install -y iputils iproute
podman exec -it client01 dnf install -y iputils iproute
DNS解析测试
测试容器间通过主机名通信:
podman exec -it db01 ping -c3 client01
输出分析:
PING client01.dns.podman (10.87.0.4) 56(84) bytes of data.
64 bytes from 10.87.0.4 (10.87.0.4): icmp_seq=1 ttl=64 time=0.049 ms
-- client01.dns.podman ping statistics --
3 packets transmitted, 3 received, 0% packet loss, time 2007ms
podman exec -it client01 ping -c3 db01
输出分析:
PING db01.dns.podman (10.87.0.3) 56(84) bytes of data.
64 bytes from 10.87.0.3 (10.87.0.3): icmp_seq=1 ttl=64 time=0.021 ms
-- db01.dns.podman ping statistics --
3 packets transmitted, 3 received, 0% packet loss, time 2047ms
测试结果:
-
成功通过容器名进行DNS解析
-
网络延迟正常,无丢包
-
容器间通信正常
IP地址验证
podman exec -it db01 ip a | grep 10.8
输出:inet 10.87.0.3/16 brd 10.87.255.255 scope global eth0
podman exec -it client01 ip a | grep 10.8
输出:inet 10.87.0.4/16 brd 10.87.255.255 scope global eth0
IP分配确认:
-
db01: 10.87.0.3
-
client01: 10.87.0.4
7. 多网络连接配置
创建第二个网络
podman network create backend
查看所有网络
podman network ls
输出:
NETWORK ID NAME DRIVER
a7fea510a6d1 backend bridge
fe680efc5276 db_net bridge
2f259bab93aa podman bridge
动态连接额外网络
运行时将backend网络连接到现有容器:
podman network connect backend db01
podman network connect backend client01
验证多网络配置
podman inspect db01
网络配置输出:
"backend": {
"EndpointID": "",
"Gateway": "10.89.1.1",
"IPAddress": "10.89.1.4",
},
"db_net": {
"EndpointID": "",
"Gateway": "10.87.0.1",
"IPAddress": "10.87.0.3",
}
podman inspect client01
网络配置输出:
"backend": {
"EndpointID": "",
"Gateway": "10.89.1.1",
"IPAddress": "10.89.1.5",
},
"db_net": {
"EndpointID": "",
"Gateway": "10.87.0.1",
"IPAddress": "10.87.0.4",
}
多网络IP分配:
-
db01: db_net(10.87.0.3), backend(10.89.1.4)
-
client01: db_net(10.87.0.4), backend(10.89.1.5)
多网络连通性测试
podman exec -it client01 ping -c3 10.89.1.4 | grep 'packet loss'
输出:3 packets transmitted, 3 received, 0% packet loss, time 2052ms
podman exec -it client01 ping -c3 10.87.0.3 | grep 'packet loss'
输出:3 packets transmitted, 3 received, 0% packet loss, time 2054ms
测试结论:client01容器可以通过两个网络与db01容器通信。
总结
通过完整的配置过程,我们成功实现了:
-
环境变量配置:正确传递数据库配置参数
-
持久存储:配置主机目录映射,确保数据持久化
-
SELinux安全:正确设置安全上下文,确保容器访问权限
-
网络端口映射:实现外部客户端访问容器服务
-
DNS解析:创建自定义网络,支持容器间通过主机名通信
-
多网络连接:实现网络流量分离和管理
更多推荐


所有评论(0)