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 可以跑很多次,每次基于同一镜像起新容器
    -
相关推荐
2601_967987372 小时前
安装 Redis 或 Redis Stack
linux·windows·redis·macos·安装
feng_you_ying_li2 小时前
linux之数据链路层
linux·网络·智能路由器
GeW3 小时前
高端化走到深处,是数据库和Linux的事
linux
程序员初一4 小时前
Linux 远程桌面有四种做法
linux·ssh
程序开发阿元5 小时前
1C1G 能跑什么:把留常驻服务和不留摆进一张内存表
linux·ssh
xbzb7 小时前
自定义 yum 软件源:Linux 上 createrepo,Windows 上纯 Python 也能造
linux·运维·windows·python·yum·createrepo
Android系统攻城狮7 小时前
Linux FFmpeg深度解析之avio_open调用流程与实战(三十八)
linux·运维·服务器·ffmpeg·音视频进阶·ffmpeg音视频
独隅7 小时前
WebStorm Linux 版安装实战与核心效能展示
linux·ide·webstorm
雪落漂泊9 小时前
Linux进程(五):进程地址空间篇
linux·运维·服务器
AR-26710-10 小时前
Linux Day32——网络,ROCE-IB与以太网
linux·运维