自定义镜像与 Dockerfile 实践
这页要解决的不是“Docker 能不能做”,而是“我到底该用哪种方式做才不容易把后面的人坑到”。结论先放前面:
- 临时快照可以用
docker commit - 需要重复构建、交付、协作时,优先写
Dockerfile - 不要把“给 root 设密码”当成容器内获取高权限的默认做法
先分清 3 种常见需求
1. 临时调试环境
你只是想先起个容器进去试命令、装包、改文件,这时直接:
docker run --rm -it ubuntu:24.04 bash
2. 我已经在容器里手改好了,想先存个快照
这时可以用:
docker commit my-debug-container my-debug-image:temp
它适合:
- 临时保存排障现场
- 保留一次实验状态
- 快速做一版只给自己用 的快照
它不适合:
- 团队协作
- 可重复构建
- 长期维护
3. 我要把环境稳定复现出来
这时就应该上 Dockerfile。
一个更推荐的最小 Dockerfile
下面这个例子偏“Ubuntu 工具环境”,比直接在容器里一通手改更可复现:
FROM ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
bash \
ca-certificates \
curl \
git \
vim \
wget \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /workspace
CMD ["bash"]
构建和运行:
docker build -t ubuntu-tools:22.04 .
docker run --rm -it ubuntu-tools:22.04
同时准备 .dockerignore
很多构建慢、镜像上下文过大、误把缓存和大文件带进去的问题,都是因为没写 .dockerignore。
一个常见的最小例子:
.git
node_modules
dist
build
__pycache__
*.log
*.tar
*.zip
Dockerfile 里我更愿意默认采用的写法
固定基础镜像版本
比起:
FROM ubuntu:latest
我更推荐:
FROM ubuntu:22.04
这样版本漂移更少,排障也更容易复现。
把 apt-get update 和安装合到同一个 RUN
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
git \
&& rm -rf /var/lib/apt/lists/*
这样层次更清楚,也更不容易踩缓存问题。
需要非 root 运行时,用 USER
RUN useradd -m app
USER app
WORKDIR /home/app
如果只是偶尔需要 root 进入正在运行的容器,不要去给 root 配密码,直接:
docker exec -u root -it my-container bash
多阶段构建什么时候值得用
如果“编译环境”和“运行环境”不同,多阶段构建通常很值。
例如静态前端构建:
FROM node:22 AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:stable-alpine
COPY --from=build /app/dist /usr/share/nginx/html
好处是:
- 最终镜像更小
- 运行镜像里不需要
node_modules - 安全面也更干净
docker commit 的正确定位
如果你已经在容器里完成了一轮调试,确实可以先这样留一个快照:
docker commit my-container my-image:debug
docker image ls
但后续最好还是回到 Dockerfile,把真正需要保留的步骤写进构建过程。
否则时间一长,你只会记得“这个镜像能用”,却说不清它到底是怎么做出来的。
导出和导入镜像
导出
docker save -o my-image.tar my-image:1.0