Ubuntu Podman 容器镜像构建

Podman 容器镜像构建全流程指南

目标:从零构建 myhome:1.0 镜像(基于 Ubuntu 20.04,集成 Python 2、编译工具链、repo、sudo),并运行验证。


阶段一:环境准备

第 1 步:确认 Podman 已安装

bash 复制代码
podman --version

预期 :podman version 4.x.x

作用:确认容器引擎可用。


第 2 步:确认环境已清空

bash 复制代码
podman ps -a
podman images

预期:两条命令都只剩表头,没有任何容器和镜像。

作用:保证从干净状态开始,避免旧镜像干扰。


第 3 步:配置镜像源(用户级,不用 sudo)

bash 复制代码
mkdir -p ~/.config/containers

cat > ~/.config/containers/registries.conf << 'EOF'
unqualified-search-registries = ["docker.io"]

[[registry]]
prefix = "docker.io"
location = "docker.m.daocloud.io"
EOF

作用 :告诉 Podman------拉 docker.io 的镜像时,走 daocloud 这个国内镜像站。

验证:

bash 复制代码
cat ~/.config/containers/registries.conf

应该看到刚写入的三行内容。

为什么用 daocloud? 这台机器 Docker Hub 官方源连不上(registry-1.docker.io 超时),daocloud 经测试可用。中科大 docker.mirrors.ustc.edu.cn 和网易 hub-mirror.c.163.com 在本机 DNS 解析失败。


阶段二:准备基础镜像

第 4 步:拉取 ubuntu:20.04

bash 复制代码
podman pull ubuntu:20.04

预期:

复制代码
Resolving "ubuntu" using unqualified-search registries (~/.config/containers/registries.conf)
Trying to pull docker.io/library/ubuntu:20.04...
Getting image source signatures
Copying blob ... done
Copying config b7bab04fd9aa done
Writing manifest to image destination
Storing signatures
b7bab04fd9aa...

作用:把基础镜像下载到本地,作为后面构建的地基。

验证:

bash 复制代码
podman images

应该看到:

复制代码
REPOSITORY               TAG      IMAGE ID      SIZE
docker.io/library/ubuntu 20.04    b7bab04fd9aa  75.2 MB

阶段三:写 Containerfile

第 5 步:建构建目录并写 Containerfile

bash 复制代码
mkdir -p ~/container-build
cd ~/container-build

写入 Containerfile:

bash 复制代码
cat > Containerfile << 'EOF'
FROM ubuntu:20.04

# 第 1 步:换清华源(用 http,因为此时容器里还没有 ca-certificates)
RUN sed -i 's|http://archive.ubuntu.com|http://mirrors.tuna.tsinghua.edu.cn|g' \
        /etc/apt/sources.list \
 && sed -i 's|http://security.ubuntu.com|http://mirrors.tuna.tsinghua.edu.cn|g' \
        /etc/apt/sources.list

# 第 2 步:先装 ca-certificates 和 curl/wget(http 不需要证书)
RUN apt update && apt install -y --no-install-recommends \
        ca-certificates curl wget \
 && rm -rf /var/lib/apt/lists/*

# 第 3 步:根证书已就绪,把源切换成 https
RUN sed -i 's|http://mirrors.tuna.tsinghua.edu.cn|https://mirrors.tuna.tsinghua.edu.cn|g' \
        /etc/apt/sources.list

# 第 4 步:装编译工具链 + python2 + sudo(此时 https 可用)
RUN apt update && apt install -y --no-install-recommends \
        git \
        build-essential cpio unzip rsync bc xz-utils \
        sudo vim \
        python2 python2-dev \
 && ln -sf /usr/bin/python2 /usr/bin/python \
 && rm -rf /var/lib/apt/lists/*

# 第 5 步:装 repo(py2 兼容版)
RUN curl -sSL https://storage.googleapis.com/git-repo-downloads/repo-1 \
        -o /usr/local/bin/repo \
 || curl -sSL https://storage.googleapis.com/git-repo-downloads/repo \
        -o /usr/local/bin/repo \
 && chmod +x /usr/local/bin/repo

# 第 6 步:建用户 + 配免密 sudo
RUN useradd -m -s /bin/bash -G sudo user_name \
 && echo 'user_name ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/user_name \
 && chmod 0440 /etc/sudoers.d/user_name

USER user_name
WORKDIR /home/user_name
CMD ["bash"]
EOF

关键设计点:

步骤 为什么这样写
换源用 http:// 容器里还没有 ca-certificates,https 会握手失败(踩过坑)
先装 ca-certificates 拿到根证书,后面 https 才可用
再切回 https:// 走加密通道
ln -sf python2 python v821 SDK 脚本默认调 python,指向 py2
NOPASSWD:ALL 容器内免密 sudo,避免编译脚本卡住要输密码
最后才 USER chenkang 装软件需要 root,装完再切普通用户

验证:

bash 复制代码
cat Containerfile
ls -la

阶段四:构建镜像

第 6 步:构建

bash 复制代码
podman build -t myhome:1.0 . 2>&1 | tee build.log

参数说明:

参数 作用
-t myhome:1.0 给镜像起名 myhome,版本 1.0
. 当前目录,作为构建上下文(找 Containerfile、传文件进去)
`2>&1 tee build.log`

预期结尾:

复制代码
Successfully tagged localhost/myhome:1.0

验证:

bash 复制代码
podman images

应该看到两个镜像:

复制代码
REPOSITORY               TAG      IMAGE ID      SIZE
localhost/myhome         1.0      xxxxxxxxxxxx  482 MB
docker.io/library/ubuntu 20.04    b7bab04fd9aa  75.2 MB

第 7 步:查看镜像分层

bash 复制代码
podman history myhome:1.0

作用:看清镜像是怎么一层层叠出来的,对应 Containerfile 的每一步。

预期结构(从上到下 = 从新到旧):

复制代码
ID            CREATED BY                                     SIZE
ecf4fc53ee06  CMD ["bash"]                                    0 B
<missing>     WORKDIR /home/chenkang                          0 B
<missing>     USER chenkang                                   0 B
<missing>     useradd -m ...chenkang                         366 kB
e5accc04...   curl repo                                      44 kB
8cfcae73...   apt install python2 build-essential ...        389 MB
1affcb17...   sed ... 换 https                                13.8 kB
960ca9f3...   apt install ca-certificates                    16.9 MB
9f3ee0f6...   sed ... 换 http             ← FROM ubuntu:20.04
b7bab04fd9aa  CMD ["/bin/bash"]                               0 B
<missing>     ADD file:...                                   75.2 MB   ← ubuntu 根文件系统
...

最底下带 FROM docker.io/library/ubuntu:20.04 注释的那层,就是整个镜像的基础层。


阶段五:运行容器

第 8 步:启动容器(先验证环境)

bash 复制代码
podman run -it --rm myhome:1.0 bash

参数说明:

参数 作用
-it 交互式 + 分配伪终端(能进 bash 敲命令)
--rm 退出后自动删除容器(不留垃圾)
myhome:1.0 用哪个镜像
bash 容器启动后执行的命令(进 shell)

执行后命令行提示符会变成容器内的,类似:

复制代码
chenkang@xxxxxxxxxxx:~$

第 9 步:在容器内验证

bash 复制代码
whoami
python --version
python2 --version
python -c "import zlib; print('zlib OK')"
repo --version
sudo -n true && echo "sudo OK"

预期:

复制代码
chenkang
Python 2.7.18
Python 2.7.18
zlib OK
<repo 版本号>
sudo OK

退出容器:

bash 复制代码
exit

第 10 步:挂载代码目录运行(实际使用场景)

bash 复制代码
podman run -it --rm \
  -v /home/chenkang/project:/home/chenkang/project:Z \
  myhome:1.0 bash

参数说明:

参数 作用
-v 宿主机路径:容器路径:Z 把宿主机目录挂进容器,两边共享文件
:Z 让 SELinux 给挂载点打正确标签(不开 SELinux 的机器可省略)

进容器后:

bash 复制代码
cd /home/chenkang/project    # 这里就是宿主机的代码
ls                           # 能看到宿主机 project 目录里的文件

阶段六:日常运维命令

场景 命令
查看运行中的容器 podman ps
查看所有容器(含已停止) podman ps -a
查看镜像 podman images
进一个正在运行的容器 podman exec -it <容器名> bash
停止容器 podman stop <容器名>
删除容器 podman rm <容器名>
删除镜像 podman rmi myhome:1.0
清理悬空镜像/缓存 podman image prune
彻底清空所有 podman system reset --force
查看镜像分层 podman history myhome:1.0
查看容器详细信息 podman inspect <容器名>

附录:核心概念速查

镜像、容器、Containerfile 的关系

复制代码
Containerfile  (文本)          ← 菜谱:描述环境该怎么配
     │  podman build
     ▼
镜像 myhome:1.0  (静态文件)    ← 蛋糕:一次构建,永久留存,只读
     │  podman run
     ▼
容器  (运行中的进程)           ← 吃蛋糕的过程:可启动多个,用完即删

镜像分层

  • 每一层是只读的,构建后不可变
  • 层是共享的:两个镜像共用同一基础层,磁盘只占一份
  • 容器在顶层加一个可写层:运行时产生的文件都在这一层,容器删除即消失

为什么 myhome 的 482 MB 里包含 ubuntu 的 75.2 MB

不是复制,是引用 。myhome 最底层的 ID 就是 b7bab04fd9aa(ubuntu 的 ID),两者共享那 75.2 MB。

podman build vs podman run

命令 作用 输入 输出
podman build 造镜像 Containerfile 一个镜像
podman run 跑容器 一个镜像 一个运行中的容器
  • build 只在改了 Containerfile 后重跑
  • run 可以跑很多次,每次基于同一镜像起新容器
    -
相关推荐
探索云原生3 小时前
Ascend vNPU 实战:从原生 Docker 到 Ascend Docker Runtime
linux·ai·云原生·kubernetes·gpu
无足鸟ICT3 小时前
【RHCA+】_etc_yum.conf
linux·运维
nazisami3 小时前
操作系统基础IO
linux·缓冲区·系统文件io·一切皆文件
zbyyd3 小时前
Linux驱动:UART串口通信、GT9147触摸屏与IIO-ADC驱动开发
linux·驱动开发·arm
zbyyd4 小时前
Linux驱动:SPI子系统与ADXL345三轴加速度传感器驱动开发
linux·驱动开发·arm
coward914 小时前
全志和瑞芯微平台反编译设备树
linux·嵌入式硬件
zbyyd4 小时前
Linux驱动开发:Misc混杂设备与设备树实战
linux·驱动开发
业余程序员plus5 小时前
RDMA-Verbs-软件架构(二)
linux·rdma·rocev2·mlx5·verbs·uverbs·libibverbs
坤坤子吖5 小时前
Linux 线程同步与互斥——条件变量与线程同步
linux·开发语言·c++·笔记·学习