Podman 教程

Podman 通过 Containerfile 或 Dockerfile 构建镜像

在 Podman 中,可通过 podman build 命令根据 Containerfile 或 Dockerfile 构建容器镜像,功能与 docker build 类似,支持基于指令分步构建镜像,且完全兼容 Docker 的构建语法。

podman build 命令将读取指定路径下的 Containerfile(默认文件名),按照文件中的指令(如 FROM、RUN、COPY 等)逐步构建镜像层,最终生成可运行的容器镜像。

基本语法

下面是 podman build 命令的基本语法:

podman build [选项] 构建上下文路径

构建上下文(Context):构建时指定的路径(目录),该目录下的所有文件会被发送到 Podman 守护进程,供 COPY、ADD 等指令使用。

常用选项说明:

  • -t, --tag    为构建的镜像指定标签(格式:名称:标签),可多次使用指定多个标签。示例:-t myapp:v1 -t myapp:latest

  • -f, --file    指定自定义构建文件(非默认 Containerfile 时使用)。示例:-f ./build/Dockerfile.prod

  • --build-arg    传递构建时变量(对应 Dockerfile  中的 ARG 指令)。示例:--build-arg VERSION=1.0

  • --no-cache    不使用缓存,强制重新执行所有构建步骤(避免缓存导致的旧内容残留)。

  • --rm    构建完成后自动删除中间容器(默认启用,--rm=false 可保留中间容器用于调试)。

  • --platform    指定构建镜像的目标平台(如 linux/amd64、linux/arm64),需配合多架构构建支持。

  • -q, --quiet    静默模式,仅输出最终镜像 ID,不显示构建过程日志。

  • --pull 字符串[="always"]     拉取镜像策略("always"|"missing"|"never"|"newer")(默认 "missing")

更多选项参考 podman build 命令参考手册。

  

常用示例

为了后续顺利进行,这里特意提供了一个简单的 nginx 镜像 Containerfile 文件,内容如下:

# 基础镜像:使用官方 Nginx 稳定版(Alpine 版本,体积更小)
FROM nginx:stable-alpine

# 维护者信息(可选)
LABEL maintainer="hxstrive@outlook.com"
LABEL description="Custom Nginx image with custom config and static files"

# 更换 Alpine 镜像源为国内源(加速依赖安装,可选)
#RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories

# 安装必要工具(如 curl 用于健康检查,可选)
RUN apk update && \
    apk add --no-cache curl && \
    rm -rf /var/cache/apk/*  # 清理缓存,减小镜像体积

# 复制自定义 Nginx 配置文件(覆盖默认配置)
# 假设当前目录有 nginx.conf(主配置)和 conf.d/ 目录(虚拟主机配置)
COPY nginx.conf /etc/nginx/nginx.conf
COPY conf.d/ /etc/nginx/conf.d/

# 复制自定义静态网页到 Nginx 默认站点目录
# 假设当前目录有 html/ 目录,包含 index.html 等文件
COPY html/ /usr/share/nginx/html/

# 调整文件权限(避免容器内权限问题,尤其是 rootless 模式下)
RUN chown -R nginx:nginx /usr/share/nginx/html /var/log/nginx && \
    chmod -R 755 /usr/share/nginx/html

# 配置 Nginx 日志输出到标准输出(便于容器日志收集,如 podman logs)
RUN ln -sf /dev/stdout /var/log/nginx/access.log && \
    ln -sf /dev/stderr /var/log/nginx/error.log

# 暴露 Nginx 默认端口(80 或 443,根据配置文件调整)
EXPOSE 80
# EXPOSE 443  # 若启用 HTTPS,取消注释

# 健康检查:定期检查 Nginx 服务是否正常(可选)
# HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
#   CMD curl -f http://localhost/ || exit 1

# 启动命令(使用官方默认,无需修改,Nginx 以非 daemon 模式运行)
CMD ["nginx", "-g", "daemon off;"]

完整信息参考:Containerfile 实战:自己的 Nginx 镜像

 

基础构建(默认 Containerfile)

在当前目录下寻找 Containerfile,构建镜像并标记为 myapp:v1:

podman build -t myapp:v1 .

注意:“.”表示构建上下文为当前目录(所有文件会被纳入构建范围)。

D:\Podman\nginx-custom> podman build -t myapp:v1 .
STEP 1/11: FROM nginx:stable-alpine
Resolving "nginx" using unqualified-search registries (/home/user/.config/containers/registries.conf)
Trying to pull docker.io/library/nginx:stable-alpine...
Getting image source signatures
Copying blob sha256:c4fca37af7b3b885e76d1a14e76d630444c2868b27ff67848e077142d9771faa
Copying blob sha256:8e049f0fd1511eaabb03da73d0582501fd3a012ddb00620ff653b1a13b646310
Copying blob sha256:71a39d0d04b2893246ec57f9cf1b074a63fd0f094098a8b1741d0e625f4009c1
Copying blob sha256:e6918dcfd20da0647335265f4647268123ce772646f9dea11cae650f26be0276
Copying blob sha256:f637881d1138581d892d9eb942c56e0ccc7758fe3bdc0f1e6cd66059fdfd8185
Copying blob sha256:b8554c5f1ad0265d1dc3a5f23b3b52e93fa1cdeda0c6b54618d3f9168e6ed01b
Copying blob sha256:bc1d7488b05ed88bc5975378fd4ef0f1ea4b6114d13fa5cbeec6a572588e0c00
Copying blob sha256:3e300a7cb18c79c3ddadf170ae2c540c8feafdf7fcdc6cd5d5a3cd229fb0cada
Copying config sha256:c318e336065b17ff460aeac6d14bce5d0b13e35f25d5cb1843b635359fc00c9a
Writing manifest to image destination
STEP 2/11: LABEL maintainer="hxstrive@outlook.com"
--> 9bdaee115371
STEP 3/11: LABEL description="Custom Nginx image with custom config and static files"
--> 25e42c577947
STEP 4/11: RUN apk update &&     apk add --no-cache curl &&     rm -rf /var/cache/apk/*  # 清理缓存,减小镜像体积
fetch https://dl-cdn.alpinelinux.org/alpine/v3.21/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.21/community/x86_64/APKINDEX.tar.gz
v3.21.5-75-g1ace668154e [https://dl-cdn.alpinelinux.org/alpine/v3.21/main]
v3.21.5-74-g3749f9c5659 [https://dl-cdn.alpinelinux.org/alpine/v3.21/community]
OK: 25403 distinct packages available
fetch https://dl-cdn.alpinelinux.org/alpine/v3.21/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.21/community/x86_64/APKINDEX.tar.gz
OK: 45 MiB in 68 packages
--> 2cd6ec07db11
STEP 5/11: COPY nginx.conf /etc/nginx/nginx.conf
--> 66f18af4c329
STEP 6/11: COPY conf.d/ /etc/nginx/conf.d/
--> 312172934889
STEP 7/11: COPY html/ /usr/share/nginx/html/
--> eadeb4df71d7
STEP 8/11: RUN chown -R nginx:nginx /usr/share/nginx/html /var/log/nginx &&     chmod -R 755 /usr/share/nginx/html
--> 3a10a23e62ab
STEP 9/11: RUN ln -sf /dev/stdout /var/log/nginx/access.log &&     ln -sf /dev/stderr /var/log/nginx/error.log
--> dcbb61f0482b
STEP 10/11: EXPOSE 80
--> 01bc606a1c22
STEP 11/11: CMD ["nginx", "-g", "daemon off;"]
COMMIT myapp:v1
--> fd16466b1336
Successfully tagged localhost/myapp:v1
fd16466b13362d56c8af4c985767ef3707171614f76780745c5c885a120b5e0e

D:\Podman\nginx-custom> podman images
REPOSITORY               TAG            IMAGE ID      CREATED        SIZE
localhost/myapp          v1             fd16466b1336  7 seconds ago  49.9 MB

  

使用自定义构建文件

指定路径为 ./nginx-custom下的 Containerfile 作为构建文件,./nginx-custom 为构建上下文,构建镜像:

podman build -f ./nginx-custom/Containerfile -t myapp:1.0 ./nginx-custom

注意:-f 指定构建文件路径,./nginx-custom 为构建上下文(仅 ./nginx-custom 目录下的文件可被 COPY 等指令访问)。

D:\Podman> podman build -f ./nginx-custom/Containerfile -t myapp:1.0 ./nginx-custom
STEP 1/11: FROM nginx:stable-alpine
Resolving "nginx" using unqualified-search registries (/home/user/.config/containers/registries.conf)
Trying to pull docker.io/library/nginx:stable-alpine...
Getting image source signatures
Copying blob sha256:c4fca37af7b3b885e76d1a14e76d630444c2868b27ff67848e077142d9771faa
Copying blob sha256:b8554c5f1ad0265d1dc3a5f23b3b52e93fa1cdeda0c6b54618d3f9168e6ed01b
Copying blob sha256:f637881d1138581d892d9eb942c56e0ccc7758fe3bdc0f1e6cd66059fdfd8185
Copying blob sha256:71a39d0d04b2893246ec57f9cf1b074a63fd0f094098a8b1741d0e625f4009c1
Copying blob sha256:8e049f0fd1511eaabb03da73d0582501fd3a012ddb00620ff653b1a13b646310
Copying blob sha256:e6918dcfd20da0647335265f4647268123ce772646f9dea11cae650f26be0276
Copying blob sha256:bc1d7488b05ed88bc5975378fd4ef0f1ea4b6114d13fa5cbeec6a572588e0c00
Copying blob sha256:3e300a7cb18c79c3ddadf170ae2c540c8feafdf7fcdc6cd5d5a3cd229fb0cada
Copying config sha256:c318e336065b17ff460aeac6d14bce5d0b13e35f25d5cb1843b635359fc00c9a
Writing manifest to image destination
STEP 2/11: LABEL maintainer="hxstrive@outlook.com"
--> 0049ed606a3e
STEP 3/11: LABEL description="Custom Nginx image with custom config and static files"
--> 0c02adbbff11
STEP 4/11: RUN apk update &&     apk add --no-cache curl &&     rm -rf /var/cache/apk/*  # 清理缓存,减小镜像体积
fetch https://dl-cdn.alpinelinux.org/alpine/v3.21/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.21/community/x86_64/APKINDEX.tar.gz
v3.21.5-75-g1ace668154e [https://dl-cdn.alpinelinux.org/alpine/v3.21/main]
v3.21.5-74-g3749f9c5659 [https://dl-cdn.alpinelinux.org/alpine/v3.21/community]
OK: 25403 distinct packages available
fetch https://dl-cdn.alpinelinux.org/alpine/v3.21/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.21/community/x86_64/APKINDEX.tar.gz
OK: 45 MiB in 68 packages
--> 9cf27c3c03a0
STEP 5/11: COPY nginx.conf /etc/nginx/nginx.conf
--> 148fc1c6a7d4
STEP 6/11: COPY conf.d/ /etc/nginx/conf.d/
--> 23eff84b5691
STEP 7/11: COPY html/ /usr/share/nginx/html/
--> 3bbd2dd53cd6
STEP 8/11: RUN chown -R nginx:nginx /usr/share/nginx/html /var/log/nginx &&     chmod -R 755 /usr/share/nginx/html
--> f958cc426b09
STEP 9/11: RUN ln -sf /dev/stdout /var/log/nginx/access.log &&     ln -sf /dev/stderr /var/log/nginx/error.log
--> ce9018e4f573
STEP 10/11: EXPOSE 80
--> 87d20abd7d01
STEP 11/11: CMD ["nginx", "-g", "daemon off;"]
COMMIT myapp:1.0
--> e53e79369d55
Successfully tagged localhost/myapp:1.0
e53e79369d55d7cbe0a7cb1db20fb40350957f0d069ae1565834b128bf8e35d5

D:\Podman> podman images
REPOSITORY               TAG            IMAGE ID      CREATED        SIZE
localhost/myapp          1.0            e53e79369d55  6 seconds ago  49.9 MB
docker.io/library/nginx  stable-alpine  c318e336065b  6 months ago   49.7 MB

  

传递构建参数

假设 Containerfile 中定义了 ARG APP_PORT,构建时可以通过 --build-arg 选项传入参数并指定端口:

podman build --build-arg APP_PORT=8080 -t myapp:with-port .

为了演示传递构建参数,这里特意提供一个 Containerfile 示例,演示如何在构建镜像时传递和使用构建参数(build arguments):

# 基于官方Alpine镜像
FROM alpine:latest

# 定义构建参数(ARG),可以设置默认值
ARG APP_VERSION=1.0.0
ARG APP_ENV=production
ARG AUTHOR_NAME=Unknown

# 将构建参数设置为环境变量
ENV APP_VERSION=${APP_VERSION}
ENV APP_ENV=${APP_ENV}
ENV AUTHOR_NAME=${AUTHOR_NAME}

# 使用构建参数执行命令
RUN echo "Building application version: ${APP_VERSION}" && \
    echo "Environment: ${APP_ENV}" && \
    echo "Author: ${AUTHOR_NAME}" > /app_info.txt

# 显示构建信息
RUN cat /app_info.txt

# 先输出信息,然后启动交互式shell
CMD ["sh", "-c", "echo \"App Version: $APP_VERSION, Env: $APP_ENV, Author: $AUTHOR_NAME\"; exec /bin/sh"]

使用 podman build 构建镜像且传递 APP_VERSION、APP_ENV 等参数,如下:

D:\Podman\args> podman build --build-arg APP_VERSION=2.1.5 --build-arg APP_ENV=development --build-arg AUTHOR_NAME="John Doe" -t arg-demo:custom .
STEP 1/10: FROM alpine:latest
STEP 2/10: ARG APP_VERSION=1.0.0
--> Using cache 7d31d5763f3a0c2e672f344fc8630d34859eda22c7849edb4b9e346640f4ebd8
--> 7d31d5763f3a
STEP 3/10: ARG APP_ENV=production
--> Using cache 357f196753f1a51188319421c64decc720dea96be89502811334ec818eae6594
--> 357f196753f1
STEP 4/10: ARG AUTHOR_NAME=Unknown
--> Using cache 63cf892404920f1204ebfbccd4f4866a01b9c95debaf920055d94e3b432bfe07
--> 63cf89240492
STEP 5/10: ENV APP_VERSION=${APP_VERSION}
--> Using cache e7216956349555d7d92967c9c749a4c0c6b47eaed275e00305549798c97d463a
--> e72169563495
STEP 6/10: ENV APP_ENV=${APP_ENV}
--> Using cache 58ee43658c71921037d1dfd7c36a1a8b13f51d8ffd1f49c2e6cbea7e0597eac9
--> 58ee43658c71
STEP 7/10: ENV AUTHOR_NAME=${AUTHOR_NAME}
--> a3159f99e73c
STEP 8/10: RUN echo "Building application version: ${APP_VERSION}" &&     echo "Environment: ${APP_ENV}" &&     echo "Author: ${AUTHOR_NAME}" > /app_info.txt
Building application version: 2.1.5
Environment: development
--> 80599f2ed74e
STEP 9/10: RUN cat /app_info.txt
Author: John Doe
--> 0ac675f753ca
STEP 10/10: CMD ["sh", "-c", "echo \"App Version: $APP_VERSION, Env: $APP_ENV, Author: $AUTHOR_NAME\"; exec /bin/sh"]
COMMIT arg-demo:custom
--> c3ee6177e88b
Successfully tagged localhost/arg-demo:custom
c3ee6177e88be1b3079a08bcfcda6135d666c154fafa25edb1d6a7269ca94ed3

运行容器,验证参数是否传递到镜像中,如下:

D:\Podman\args> podman run --rm arg-demo:custom
App Version: 2.1.5, Env: development, Author: John Doe

从输出可以看到,App 的版本信息、环境、作者信息

  

不使用缓存强制构建

避免因缓存导致的旧依赖残留,强制重新执行所有步骤:

podman build --no-cache -t myapp:fresh .

  

构建多标签镜像

同时为镜像添加 v2 和 latest 标签:

podman build -t myapp:v2 -t myapp:latest .

例如:

D:\Podman\nginx-custom> podman build -t myapp:v2 -t myapp:latest .
STEP 1/11: FROM nginx:stable-alpine
Resolving "nginx" using unqualified-search registries (/home/user/.config/containers/registries.conf)
Trying to pull docker.io/library/nginx:stable-alpine...
Getting image source signatures
Copying blob sha256:c4fca37af7b3b885e76d1a14e76d630444c2868b27ff67848e077142d9771faa
Copying blob sha256:71a39d0d04b2893246ec57f9cf1b074a63fd0f094098a8b1741d0e625f4009c1
Copying blob sha256:b8554c5f1ad0265d1dc3a5f23b3b52e93fa1cdeda0c6b54618d3f9168e6ed01b
Copying blob sha256:f637881d1138581d892d9eb942c56e0ccc7758fe3bdc0f1e6cd66059fdfd8185
Copying blob sha256:e6918dcfd20da0647335265f4647268123ce772646f9dea11cae650f26be0276
Copying blob sha256:8e049f0fd1511eaabb03da73d0582501fd3a012ddb00620ff653b1a13b646310
Copying blob sha256:bc1d7488b05ed88bc5975378fd4ef0f1ea4b6114d13fa5cbeec6a572588e0c00
Copying blob sha256:3e300a7cb18c79c3ddadf170ae2c540c8feafdf7fcdc6cd5d5a3cd229fb0cada
Copying config sha256:c318e336065b17ff460aeac6d14bce5d0b13e35f25d5cb1843b635359fc00c9a
Writing manifest to image destination
STEP 2/11: LABEL maintainer="hxstrive@outlook.com"
--> b10d73cf4e86
STEP 3/11: LABEL description="Custom Nginx image with custom config and static files"
--> bbc21c026aca
STEP 4/11: RUN apk update &&     apk add --no-cache curl &&     rm -rf /var/cache/apk/*  # 清理缓存,减小镜像体积
fetch https://dl-cdn.alpinelinux.org/alpine/v3.21/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.21/community/x86_64/APKINDEX.tar.gz
v3.21.5-75-g1ace668154e [https://dl-cdn.alpinelinux.org/alpine/v3.21/main]
v3.21.5-74-g3749f9c5659 [https://dl-cdn.alpinelinux.org/alpine/v3.21/community]
OK: 25403 distinct packages available
fetch https://dl-cdn.alpinelinux.org/alpine/v3.21/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.21/community/x86_64/APKINDEX.tar.gz
OK: 45 MiB in 68 packages
--> 352316f64f6b
STEP 5/11: COPY nginx.conf /etc/nginx/nginx.conf
--> 371f65551712
STEP 6/11: COPY conf.d/ /etc/nginx/conf.d/
--> 3e03ca7c5c83
STEP 7/11: COPY html/ /usr/share/nginx/html/
--> 391659dfee22
STEP 8/11: RUN chown -R nginx:nginx /usr/share/nginx/html /var/log/nginx &&     chmod -R 755 /usr/share/nginx/html
--> 2cd9f973b0de
STEP 9/11: RUN ln -sf /dev/stdout /var/log/nginx/access.log &&     ln -sf /dev/stderr /var/log/nginx/error.log
--> 8dfb79679b22
STEP 10/11: EXPOSE 80
--> 9949b484705a
STEP 11/11: CMD ["nginx", "-g", "daemon off;"]
COMMIT myapp:v2
--> cca6bb653dae
Successfully tagged localhost/myapp:latest
Successfully tagged localhost/myapp:v2
cca6bb653dae7b35893d62486e305b5324c3326d258266292e7715a471dcad66

D:\Podman\nginx-custom> podman images
REPOSITORY               TAG            IMAGE ID      CREATED        SIZE
localhost/myapp          latest         cca6bb653dae  6 seconds ago  49.9 MB
localhost/myapp          v2             cca6bb653dae  6 seconds ago  49.9 MB
docker.io/library/nginx  stable-alpine  c318e336065b  6 months ago   49.7 MB

注意:podman build 完全兼容 Docker 的构建逻辑,因此基于 Dockerfile 的现有构建流程可无缝迁移到 Podman 中使用。

更多内容请参考官方网文档。

  

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号