在容器化时代,Docker 成为了开发、测试和部署的重要工具。Docker 镜像作为容器运行时的基础,承载了应用运行所需的全部内容。
本文将详细介绍 Docker 镜像的概念、常见操作以及如何利用 Dockerfile 构建和管理镜像。
一、什么是 Docker 镜像?
Docker 镜像是一个只读的模板,用于创建 Docker 容器。它包含了运行容器所需的所有文件系统结构和内容,如程序、库、资源及配置文件。镜像由多个只读层组成,每一层可以被多个容器共享,从而实现高效的存储和分发。
二、Docker 镜像的常见操作
1. 拉取镜像
从 Docker Hub 或其他注册表拉取指定的镜像到本地:
docker pull [IMAGE_NAME[:TAG]]
2. 重命名镜像
为现有镜像打上新的标签,实现重命名效果:
docker tag [SOURCE_IMAGE[:TAG]] [TARGET_IMAGE[:TAG]]
3. 查看镜像
列出本地存储的所有镜像:
docker image ls
# 或简写
docker images
4. 删除镜像
删除指定的镜像。如果镜像被容器引用,则需要先删除相关容器:
docker rmi [IMAGE_ID]
5. 构建镜像
构建镜像有两种常见方式:
5.1 使用 Dockerfile 构建
推荐使用 Dockerfile 构建镜像,因为它具有更好的可重复性和一致性。
docker build -t [IMAGE_NAME[:TAG]] [PATH_TO_DOCKERFILE]
5.2 使用 docker commit 构建
基于运行中的容器提交为镜像(不如 Dockerfile 方式规范):
docker commit [CONTAINER_ID] [IMAGE_NAME[:TAG]]
三、Dockerfile 关键指令详解
Dockerfile 是描述如何构建镜像的脚本文件。常用指令包括:
- FROM:指定基础镜像,是 Dockerfile 的必需指令。
- RUN:执行命令并创建新的镜像层。
- ADD 和 COPY:将本地文件或目录复制到镜像中。ADD 还支持自动解压和从 URL 下载文件。
- USER:指定运行容器时的用户。
- ENTRYPOINT 和 CMD:定义容器启动时执行的命令。ENTRYPOINT 设置容器的默认可执行程序,CMD 提供默认参数。
- ENV:设置环境变量,供容器内的应用使用。
- ARG:定义构建时的变量,可以在构建镜像时通过 --build-arg 参数传递值。
- EXPOSE:声明容器运行时监听的端口,但并不会自动映射到主机。
- WORKDIR:设置后续指令的工作目录。
四、Dockerfile 示例
示例 1:基本 Dockerfile
# 1. FROM:指定基础镜像
FROM ubuntu:20.04
# 2. ARG:构建时变量
ARG APP_VERSION=1.0.0
# 3. ENV:运行时环境变量
ENV APP_ENV=production
# 4. RUN:执行命令
RUN echo "Building version $APP_VERSION" >> /build.log
# 5. COPY:复制本地文件到镜像中
COPY app.sh /app/
# 6. WORKDIR:设置容器内默认工作目录
WORKDIR /app
# 7. ENTRYPOINT + CMD:启动命令的组合
ENTRYPOINT ["/app/app.sh"]
CMD ["start"]
# 8. EXPOSE:声明容器监听的端口
EXPOSE 8080
示例 2:ARG 与 ENV 的区别
# 定义 ARG(构建阶段变量)
ARG APP_VERSION=1.0.0
# 定义 ENV(运行时变量)
ENV APP_ENV=production
# 使用 ARG 写入文件(仅在构建阶段有效)
RUN echo "Version: $APP_VERSION" > /version.txt
# 使用 ENV 写入文件(容器内持久有效)
RUN echo "Env mode is $APP_ENV" > /env.log
构建和运行示例:
# 构建镜像时覆盖 ARG
docker build --build-arg APP_VERSION=2.0.0 -t my-app .
# 运行时覆盖 ENV
docker run -e APP_ENV=staging my-app
示例 3:ENTRYPOINT 与 CMD 的组合与覆盖
# 定义 ENTRYPOINT 和 CMD 的组合
ENTRYPOINT ["/app/app.sh"] # 固定主命令
CMD ["start"] # 默认参数
运行示例:
# 默认运行:执行 /app/app.sh start
docker run my-app
# 覆盖 CMD 的参数,执行 /app/app.sh stop
docker run my-app stop
# 完全覆盖 ENTRYPOINT,进入容器的 Shell
docker run --entrypoint /bin/bash my-app