【Docker】解决:构建(docker build)或重新运行容器时,丢失apt-get update问题
一、解决:构建(docker build)或重新运行容器时,丢失apt-get update问题
在 Docker 容器中,每次构建(docker build
)或重新运行容器时,默认情况下所有更改都会丢失,因为容器是基于镜像的临时实例。要保留 apt-get update
和安装的工具,你需要将这些操作固化到 Docker 镜像中,而不是在容器运行时执行。以下是几种方法:
方法 1:在 Dockerfile 中固化更新和安装
将 apt-get update
和安装命令写入 Dockerfile
,这样每次构建镜像时都会自动执行这些操作,并保留在镜像中。
示例 Dockerfile
FROM ubuntu:22.04 # 替换成你的基础镜像# 更新 apt 缓存并安装工具(推荐合并 RUN 以减少层数)
RUN apt-get update && \apt-get install -y \curl \wget \vim \git \&& \rm -rf /var/lib/apt/lists/* # 清理缓存减小镜像体积# 其他操作...
CMD ["bash"]
构建镜像
docker build -t my-custom-image .
运行容器
docker run -it my-custom-image
优点:
- 所有更改都会固化到镜像中,后续运行容器时无需重新安装。
- 适合长期使用的环境。
方法 2:使用 docker commit
保存临时更改
如果你已经在运行的容器中执行了 apt-get update
和安装工具,可以通过 docker commit
将当前容器状态保存为新镜像:
# 1. 启动一个临时容器
docker run -it ubuntu:22.04 bash# 2. 在容器内执行更新和安装
apt-get update && apt-get install -y curl wget# 3. 在另一个终端中提交容器为新镜像
docker ps # 查看容器ID
docker commit <CONTAINER_ID> my-updated-image# 4. 之后可以用新镜像运行
docker run -it my-updated-image
适用场景:
- 临时调试后需要保存状态。
- 不适合生产环境(推荐用 Dockerfile)。
方法 3:挂载卷(Volume)持久化数据
如果某些工具或配置文件需要持久化(如 /var/cache/apt
),可以使用 Docker 卷(Volume):
# 创建卷
docker volume create apt-cache# 运行容器并挂载卷
docker run -it -v apt-cache:/var/cache/apt ubuntu:22.04 bash
适用场景:
- 缓存
apt
数据加速后续安装(但工具仍需重新安装)。 - 不适合固化已安装的工具。
方法 4:使用 docker build --cache-from
重用缓存
如果频繁构建镜像,可以利用 Docker 缓存避免重复下载:
# 首次构建(缓存会存储)
docker build -t my-image .# 后续构建时重用缓存
docker build --cache-from my-image -t my-image .
适用场景:
- 加速构建过程,但不会改变镜像内容。
最佳实践总结
场景 | 推荐方法 |
---|---|
固化工具到镜像 | 在 Dockerfile 中写 RUN apt-get update && apt-get install |
临时修改后保存 | docker commit (仅调试用) |
持久化缓存 | 挂载 Volume(如 /var/cache/apt ) |
加速构建 | docker build --cache-from |
关键点:
- Docker 容器是无状态的:所有运行时修改都会在容器停止后丢失。
- 镜像才是持久化的载体:通过
Dockerfile
或docker commit
将更改保存到镜像。
如果你的目标是让容器每次启动时都自动安装工具(不推荐),可以在启动脚本中写入安装命令(如 ENTRYPOINT
),但这会显著增加启动时间。
二、实战
要在 Dockerfile 中固化 apt-get update
和安装工具,同时保持与你的 docker-compose.yaml
兼容,你可以按照以下步骤操作:
1. 创建自定义 Nginx 镜像的 Dockerfile
在你的项目目录中创建一个 Dockerfile
,基于 nginx:1.17.6
并添加所需的工具(如 vim
、curl
等):
# 使用你的 Nginx 基础镜像
FROM nginx:1.17.6# 更新 apt 缓存并安装工具(合并 RUN 以减少镜像层数)
RUN apt-get update && \apt-get install -y \vim \curl \wget \net-tools \ # 包含 ifconfig 等网络工具&& \rm -rf /var/lib/apt/lists/* # 清理缓存减小镜像体积# 复制你的 Nginx 配置文件(如果和 docker-compose.yaml 的 volumes 冲突,可注释掉)
# COPY nginx.conf /etc/nginx/nginx.conf# 声明容器启动时执行的命令(可省略,因为基础镜像已有 CMD)
# CMD ["nginx", "-g", "daemon off;"]
2. 修改 docker-compose.yaml
使用自定义镜像
更新 docker-compose.yaml
,将 image: nginx:1.17.6
替换为你构建的自定义镜像:
version: '3.1'services:nginx:restart: alwayscontainer_name: nginx-basebuild: . # 使用当前目录的 Dockerfile 构建镜像# image: nginx:1.17.6 # 注释掉,改用 buildtty: trueports:- 2500:2500- 3001:3001# ...(其他端口映射保持不变)volumes:- ./nginx.conf:/etc/nginx/nginx.conf- ./log:/var/log/nginx- ./html:/etc/nginx/html- ./cert:/etc/nginx/certnetworks:default:external:name: xph_network
3. 构建并启动容器
运行以下命令构建自定义镜像并启动服务:
docker-compose build # 构建镜像(仅第一次或 Dockerfile 变更时需要)
docker-compose up -d # 启动容器
4. 验证工具是否已安装
进入容器检查工具是否生效:
docker exec -it nginx-base bash
# 在容器内测试工具
vim --version
curl --version
关键注意事项
-
volumes
会覆盖镜像中的文件:- 如果你的
Dockerfile
中有COPY nginx.conf /etc/nginx/nginx.conf
,但docker-compose.yaml
又挂载了./nginx.conf:/etc/nginx/nginx.conf
,则挂载的配置文件会覆盖镜像中的文件。 - 如果不需要动态修改配置文件,建议直接在
Dockerfile
中固化配置。
- 如果你的
-
减少镜像层数:
- 将多个
RUN
命令合并为一个(如示例中用&&
连接),避免生成过多镜像层。
- 将多个
-
清理缓存:
rm -rf /var/lib/apt/lists/*
可以显著减小镜像体积。
-
生产环境建议:
- 如果工具只是调试用,建议通过
docker exec
手动安装,而不是固化到镜像中。
- 如果工具只是调试用,建议通过
扩展:多阶段构建(如需复杂工具)
如果安装过程较复杂(如需要编译),可以使用多阶段构建优化镜像大小:
FROM nginx:1.17.6 as builderRUN apt-get update && \apt-get install -y build-essential && \# 编译某些工具...rm -rf /var/lib/apt/lists/*FROM nginx:1.17.6COPY --from=builder /usr/local/bin/some-tool /usr/local/bin/
这样最终镜像只包含必要的工具,不保留编译环境。