跳转到内容
搜索 Fedora 文档

    浏览当前文档目录

    Containerfile 与多阶段构建:在 Fedora 上用 Podman 打镜像

    Fedora 上构建镜像不需要 Docker:podman build 直接读 Containerfile(Dockerfile 语法完全兼容)。

    Terminal window
    podman --version
    dnf list --available buildah | tail -1
    podman version 6.1.0
    buildah.x86_64 2:1.45.1-1.fc45 fedora

    多阶段构建把 builder 与 runtime 分开,最终镜像 11.1 MB

    两个名字都行,内容语法一样。Podman 默认找 Containerfile,找不到再找 Dockerfile。

    Terminal window
    podman build -t myapp:1 .
    podman build -f Containerfile -t myapp:1 .

    习惯上:给 Podman/Buildah 用 Containerfile,给 Docker 用 Dockerfile。混用不会出错。

    编译型语言(Go/Rust/Java)的构建依赖很大,但运行时不需要它们。多阶段构建把”编译环境”和”运行环境”分开,最终镜像只留二进制。

    实测一个 Go 程序:

    Terminal window
    mkdir -p /tmp/cf && cd /tmp/cf
    cat > Containerfile <<'EOF'
    FROM docker.io/library/golang:1.27-alpine AS build
    WORKDIR /src
    RUN echo 'package main' > main.go && echo 'import "fmt"' >> main.go && echo 'func main(){ fmt.Println("built in stage 1") }' >> main.go
    RUN go build -o /out/hello main.go
    FROM docker.io/library/alpine:latest
    COPY --from=build /out/hello /usr/local/bin/hello
    CMD ["hello"]
    EOF
    podman build -t demo:1 .
    Terminal window
    podman images --format "{{.Repository}}:{{.Tag}} {{.Size}}" | grep demo
    podman run --rm demo:1
    localhost/demo:1 11.1 MB
    built in stage 1

    最终镜像 11.1 MB——如果用单阶段,会带上整个 Go 工具链(数百 MB)。

    写法最终体积说明
    单阶段(golang 基础镜像)数百 MB编译器和源码都留在镜像里
    多阶段(实测)11.1 MB只保留二进制与 alpine 基础层

    COPY --from=build 是关键字:从前一个阶段取文件,那个阶段本身不进最终镜像。

    每一行 RUN/COPY 是一层,层顺序决定缓存命中:

    # 差:改一行代码就重装全部依赖
    COPY . /app
    RUN npm install
    # 好:先装依赖,代码后拷
    COPY package.json package-lock.json /app/
    RUN npm install
    COPY . /app

    实测的缓存效果:

    Terminal window
    podman build -t demo:1 . # 第一次:全量
    podman build -t demo:2 . # 第二次:每层都命中
    STEP 1/3: FROM ...
    --> Using cache

    --> Using cache 就是命中。改代码后只有 COPY . /app 之后的层重建。

    工具适合
    podman build日常构建,最常用
    buildah脚本化、无守护进程精细操作、CI 里按步构建
    podman buildx多架构构建
    Terminal window
    sudo dnf install buildah
    buildah --version

    buildah 的典型用法是不写 Containerfile 也能构建:

    Terminal window
    ctr=$(buildah from alpine)
    buildah run $ctr -- apk add --no-cache curl
    buildah commit $ctr mycurl:1
    buildah rm $ctr

    想给别人/别的机器用,可以起一个本地 registry:

    Terminal window
    podman run -d --name registry -p 5000:5000 docker.io/library/registry:2
    curl -s http://127.0.0.1:5000/v2/_catalog

    打标签并推送:

    Terminal window
    podman tag demo:1 127.0.0.1:5000/demo:1
    podman push 127.0.0.1:5000/demo:1
    curl -s http://127.0.0.1:5000/v2/_catalog
    {"repositories":["demo"]}
    现象原因
    podman build 拉基础镜像超时没配 registry 镜像,见国内加速源
    镜像巨大用了单阶段,编译工具链留在镜像里
    改了代码但构建没变缓存命中了不该命中的层,检查 COPY 顺序或用 --no-cache
    COPY --from=build 报找不到阶段名写错,AS build 的名字要一致
    推送 5000 端口失败registry 未起,或 SElinux/防火墙拦了端口
    多架构构建失败需要 qemu-user-static 与 podman build --platform