📚前言
👀回顾,系统学习docker系列已发布内容:
🔗相关文档:
【docker基础】Ubuntu 安装 Docker 超详细小白教程
本文,是计划的第三周的内容,内容纲要如下:
第3周:镜像管理
- 镜像操作 :
- 拉取镜像:
docker pull - 查看镜像:
docker images - 删除镜像:
docker rmi - 构建镜像:
docker build
- 拉取镜像:
- Dockerfile 基础 :
- 基础指令:FROM、RUN、CMD、ENTRYPOINT
- 构建上下文与 .dockerignore
- 多阶段构建
🌍Docker第三周:镜像管理与Dockerfile基础
镜像管理和Dockerfile的基础知识,这些是Docker使用的核心技能。
👆一、原理:镜像管理逻辑
1.1、回顾:镜像到底是什么?
一句话:
Docker 镜像 = 软件 + 运行环境 + 配置 的"压缩包/安装包"
比如:
nginx镜像 = Nginx 服务器 + 运行它需要的 Linux 环境mysql镜像 = MySQL 数据库 + 依赖库 + 默认配置hello-world镜像 = 一个小测试程序
你不用自己装环境,镜像里已经打包好了一切。
1.2、Docker 镜像管理的核心逻辑
整个逻辑就 4 步:
拉取 → 本地存储 → 基于镜像启动容器 → 删除/清理
1.3、第一层逻辑:从哪里来?(远程仓库)
Docker 默认有一个官方仓库:Docker Hub
全世界的镜像都放这里。
你执行:
docker pull nginx
逻辑是:
- 本地没有 nginx 镜像
- Docker 去 Docker Hub 下载
- 下载后存到你电脑本地
- 以后再用就不用重新下载
这就像:
从应用商店下载 APP 到手机
1.4、第二层逻辑:本地怎么存?(分层存储)
这是 Docker 最牛的设计,必须懂。
镜像不是一个大文件,而是多层叠加。
例如:
- 第一层:基础 Linux 系统(很小)
- 第二层:依赖库
- 第三层:nginx 程序
- 第四层:默认配置
好处:
- 共享底层
比如 nginx 和 node 都用同一个基础层,只存一份,不重复占用空间。 - 下载更快
只下载你没有的层。 - 体积小
你可以理解成:
积木堆叠,共用底层积木
1.5、第三层逻辑:镜像和容器的关系(最容易混淆)
镜像 = 安装包(只读,不能改)
容器 = 运行起来的软件(可写,活的实例)
关系逻辑:
- 一个镜像可以启动 N 个容器
- 容器死掉,镜像还在
- 镜像不动,容器随便删、随便建
比喻最准确:
- 镜像 = 游戏安装包
- 容器 = 打开运行的游戏
你不会因为关了游戏,安装包就没了。
1.6、第四层逻辑:本地镜像怎么管理?
常用命令就是围绕这 4 件事:
-
查看本地有哪些镜像
docker images
逻辑:列出本地已经下载的所有镜像。
-
下载镜像
docker pull 名字:版本
例如:
docker pull nginx:latest
-
删除不用的镜像
docker rmi 镜像ID或名字
逻辑:
- 必须先删除依赖它的容器,否则不让删
- 镜像一旦删除,下次要用必须重新拉取
-
搜索镜像
docker search nginx
逻辑:去 Docker Hub 搜索可用镜像。
1.7、第五层逻辑:镜像版本与标签(tag)
镜像不是只有一个,而是有版本。
格式:
名字:标签
例如:
nginx:latest最新版nginx:1.25固定版本ubuntu:22.04
逻辑:
- 不写标签默认
latest - 不同标签 = 不同镜像
- 可以同时存在本地多个版本
1.8、完整流程串起来(最清晰总结)
- 你要运行软件
- Docker 先看本地有没有镜像
- 没有 → 去远程仓库(Docker Hub)拉取
- 拉到本地,按分层存储
- 用镜像创建并启动容器
- 容器运行
- 不用了可以删除容器 / 删除镜像
📖二、原理:本地镜像构建
当我们需要自己本地容器形成镜像时,Docker 是怎么做的,下面分解一下。
2.1、一句话核心逻辑
创建本地镜像 = 给当前的容器"拍个快照",把它固化成一个只读安装包。
2.2、先搞懂 2 种创建镜像的方式(必须分清)
Docker 只有 2 种制作本地镜像的方法:
方式1:docker commit(最直观、最简单)
从正在运行的容器直接打包成镜像
就像给虚拟机拍快照。
方式2:docker build(标准、正式、企业都用)
通过 Dockerfile 文件自动构建镜像
就像写好安装脚本,让电脑自动一键安装打包。
2.3、方式1:docker commit 打包逻辑(快照式)
逻辑流程(超级简单)
- 你启动一个容器(比如 Ubuntu)
- 进入容器,装软件、改配置
- 你觉得现在状态很好,想保存下来
- 用
docker commit把容器打包成新镜像 - 打包完成 → 本地出现一个新镜像
核心原理
把容器当前的所有改动(读写层)合并成一个新的只读层 → 生成新镜像。
比喻
容器 = 你正在画的画
commit = 把这幅画保存成图片文件
图片文件 = 新的本地镜像
commit 打包示例
# 1. 运行一个容器
docker run -it ubuntu
# 2. 在里面装东西(举例)
apt update && apt install -y vim
# 3. 退出容器
exit
# 4. 把容器打包成新镜像
docker commit 容器ID 我的镜像名
2.4、方式2:docker build 构建逻辑(脚本式,最常用)
逻辑流程(标准工作流)
- 你写一个 Dockerfile(纯文本,告诉 Docker 怎么装环境)
- Docker 读取 Dockerfile 里的命令(FROM、RUN、COPY 等)
- Docker 自动启动临时容器执行每一步
- 每执行一行就生成一层镜像
- 全部执行完 → 自动合并成最终镜像
- 镜像保存到本地
核心原理
分层构建 + 缓存复用
每一行命令 = 一层
下次构建,没变的层直接用缓存,速度超快。
比喻
Dockerfile = 菜谱
docker build = 按照菜谱一步步做菜
最终镜像 = 做好的成品菜
Dockerfile 构建(标准做法)
1、创建文件 Dockerfile
FROM ubuntu
RUN apt update && apt install -y vim
2、构建
docker build -t 我的镜像名 .
2.5、最关键的底层逻辑(一定要懂)
1. 镜像是只读的
你不能直接改镜像,只能:
- 基于镜像启动容器
- 在容器里修改
- 再打包成新镜像
2. 镜像永远是分层的
无论 commit 还是 build,都是加一层,不会破坏底层。
3. 本地镜像存在哪里?
存在你电脑本地的 Docker 仓库里。
可以用 docker images 看到。
4. 构建镜像不会影响原来的镜像
比如你基于 nginx 打包出新镜像 my-nginx
原来的 nginx 镜像还在,不动。
🚇三、命令详解
1. 镜像操作
1.1 docker pull - 拉取镜像
功能:从Docker Hub或其他镜像仓库拉取镜像到本地。
语法 :docker pull [选项] [镜像名:标签]
示例:
# 拉取最新版的Ubuntu镜像
docker pull ubuntu
# 拉取指定版本的Ubuntu镜像
docker pull ubuntu:20.04
# 拉取指定仓库的镜像
docker pull nginx:alpine
命令输出解释 :
当执行docker pull ubuntu:20.04时,输出类似:
20.04: Pulling from library/ubuntu
5e0b432e8ba9: Pull complete
7d2f8da89488: Pull complete
9898bd3c8293: Pull complete
1966ea362d23: Pull complete
Digest: sha256:4c972423568361b624a598a89a88f55f3643336776233985f7a936e19f20b752
Status: Downloaded newer image for ubuntu:20.04
docker.io/library/ubuntu:20.04
Pulling from library/ubuntu:表示从官方库拉取Ubuntu镜像5e0b432e8ba9: Pull complete:表示镜像的各个层正在被拉取,每个层都有一个唯一的IDDigest:镜像的哈希值,用于验证镜像的完整性Status:拉取状态docker.io/library/ubuntu:20.04:完整的镜像引用
1.2 docker images - 查看镜像
功能:列出本地所有的镜像。
语法 :docker images [选项] [镜像名]
示例:
# 查看所有镜像
docker images
# 查看指定镜像
docker images ubuntu
# 查看所有镜像,包括中间层镜像
docker images -a
# 以精简模式查看镜像
docker images --format "{{.ID}} {{.Repository}} {{.Tag}} {{.Size}}"
命令输出解释 :
执行docker images时,输出类似:
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 20.04 1e4467b07108 2 weeks ago 72.9MB
ubuntu latest 1e4467b07108 2 weeks ago 72.9MB
nginx alpine a1523e859360 3 weeks ago 22.1MB
REPOSITORY:镜像的仓库名TAG:镜像的标签,通常用于表示版本IMAGE ID:镜像的唯一标识符CREATED:镜像的创建时间SIZE:镜像的大小
1.3 docker rmi - 删除镜像
功能:删除本地的镜像。
语法 :docker rmi [选项] 镜像名/ID [镜像名/ID...]
示例:
# 通过镜像ID删除镜像
docker rmi 1e4467b07108
# 通过镜像名和标签删除镜像
docker rmi ubuntu:20.04
# 强制删除镜像(即使有容器正在使用)
docker rmi -f ubuntu:20.04
# 删除所有未使用的镜像
docker image prune -a
命令输出解释 :
执行docker rmi ubuntu:20.04时,输出类似:
udocker rmi ubuntu:20.04
Untagged: ubuntu:20.04
Untagged: ubuntu@sha256:4c972423568361b624a598a89a88f55f3643336776233985f7a936e19f20b752
Deleted: sha256:1e4467b07108685d9f31e232b69b946b58766173b3f93b29563a139ee7687a4b
Deleted: sha256:f0749404a60b7311769f6f2e5d88b2b1980a4351944273966550b23f42d2336a
Untagged:表示解除了镜像的标签Deleted:表示删除了镜像的各个层
1.4 docker build - 构建镜像
功能:根据Dockerfile构建镜像。
语法 :docker build [选项] 构建上下文路径
示例:
# 在当前目录构建镜像,标签为myapp:v1
docker build -t myapp:v1 .
# 指定Dockerfile文件路径
docker build -t myapp:v1 -f Dockerfile.dev .
# 从URL构建镜像
docker build -t myapp:v1 https://github.com/username/repo.git#branch
命令输出解释 :
执行docker build -t myapp:v1 .时,输出类似:
Sending build context to Docker daemon 2.048kB
Step 1/3 : FROM ubuntu:20.04
---> 1e4467b07108
Step 2/3 : RUN apt-get update && apt-get install -y nginx
---> Running in 9f7a5c5a5b4f
...
Removing intermediate container 9f7a5c5a5b4f
---> 8a7b3c2f3c4d
Step 3/3 : CMD ["nginx", "-g", "daemon off;"]
---> Running in 2d9c17e6b8d9
Removing intermediate container 2d9c17e6b8d9
---> 3e2a8b93a8d5
Successfully built 3e2a8b93a8d5
Successfully tagged myapp:v1
Sending build context:发送构建上下文到Docker守护进程Step 1/3:构建步骤,从1到3FROM ubuntu:20.04:使用Ubuntu 20.04作为基础镜像RUN apt-get update && apt-get install -y nginx:执行命令安装nginxRunning in 9f7a5c5a5b4f:在临时容器中运行命令Removing intermediate container:移除临时容器Successfully built:构建成功,返回镜像IDSuccessfully tagged:标记镜像为myapp:v1
2. Dockerfile基础
2.1 基础指令
FROM
作用 :指定基础镜像。
语法 :FROM <镜像名:标签>
示例:
FROM ubuntu:20.04
FROM nginx:alpine
说明:每个Dockerfile必须以FROM指令开始,指定构建镜像的基础镜像。
RUN
作用 :在构建过程中执行命令。
语法 :RUN <命令> 或 RUN ["可执行文件", "参数1", "参数2"]
示例:
RUN apt-get update && apt-get install -y nginx
RUN ["mkdir", "-p", "/app"]
ℹ️ℹ️命令分解说明:
第一行命令:
RUNDockerfile 专用指令 意思:在构建镜像时,执行下面的 Linux 命令
apt-get updateUbuntu 系统命令意思:刷新软件源列表(让系统知道最新的软件版本)
&&意思:前面命令成功,再执行后面的
apt-get install -y nginx意思:自动安装 Nginx 网页服务器
-y= 自动确认安装(不用手动按回车)整句大白话
构建镜像时,自动刷新软件源,并且自动安装 Nginx。
第二行命令:
RUN还是:执行命令
"mkdir"Linux 命令 = make directory 创建文件夹
"-p"参数,表示:如果文件夹不存在就创建,如果已存在就不报错
"/app"要创建的目录路径 = 在根目录下创建 app 文件夹
整句大白话
构建镜像时,自动在容器里创建 /app 目录。
📒两种写法对比(非常重要)
第一行写法 (shell 模式)
dockerfile
RUN apt-get update && apt-get install -y nginx📌shell 格式 :Docker 会调用
/bin/sh -c "命令"相当于在终端里执行第二行写法 (exec 模式,推荐)
dockerfile
RUN ["mkdir", "-p", "/app"]📌exec 模式:直接调用命令,不经过 shell更干净、更稳定
功能一样,只是写法不同!
📌说明 :RUN指令在构建过程中创建新的镜像层,多个RUN指令会创建多个层,建议使用&&将多个命令组合在一个RUN指令中,以减少镜像层数。
CMD
作用 :指定容器启动时执行的命令。
语法 :CMD <命令> 或 CMD ["可执行文件", "参数1", "参数2"]
示例:
CMD ["nginx", "-g", "daemon off;"]
CMD echo "Hello World"
说明:每个Dockerfile只能有一个CMD指令,如果有多个,只有最后一个生效。CMD指令可以被docker run命令后的参数覆盖。
📌注意区别:
- RUN:构建镜像时执行(打包阶段)
- CMD:容器运行时执行(启动阶段)
创建目录是打包环境 ,不是启动命令,所以必须用 RUN。
ENTRYPOINT
作用 :指定容器启动时执行的命令,与CMD类似,但不可被docker run命令后的参数覆盖。
语法 :ENTRYPOINT <命令> 或 ENTRYPOINT ["可执行文件", "参数1", "参数2"]
示例:
ENTRYPOINT ["nginx", "-g", "daemon off;"]
说明:
告诉 Docker:容器启动后,必须直接运行这条完整命令:
nginx -g "daemon off;"
而且谁也覆盖不掉,容器一运行就执行它。
daemon off,让Nginx 在前台一直运行 → 容器保持运行 → 服务正常使用;否则,Nginx 会默认后台运行 → 运行完直接退出 → 容器认为任务结束 → 容器立刻停止
📌CMD与ENTRYPOINT的对比:
- CMD:给容器提供默认命令 / 默认参数 **(可被覆盖)**
- ENTRYPOINT:给容器指定固定入口程序 **(不会被覆盖)**
- 最佳实践:两者一起用!ENTRYPOINT 写程序,CMD 写默认参数
COPY
作用 :将构建上下文中的文件复制到镜像中。
语法 :COPY <源路径> <目标路径>
示例:
COPY . /app
COPY package.json /app/
说明:COPY指令可以复制本地文件到镜像中,源路径是相对于构建上下文的路径。
ADD
作用 :与COPY类似,但支持URL和压缩文件。
语法 :ADD <源路径> <目标路径>
示例:
ADD https://example.com/file.tar.gz /app
ADD file.tar.gz /app
说明:ADD指令会自动解压压缩文件,而COPY不会。
WORKDIR
作用 :设置工作目录。
语法 :WORKDIR <路径>
示例:
WORKDIR /app
说明:WORKDIR指令设置的目录会成为后续RUN、CMD、ENTRYPOINT等指令的工作目录。
ENV
作用 :设置环境变量。
语法 :ENV <变量名> <值> 或 ENV <变量名>=<值>
示例:
ENV NODE_ENV=production
ENV PATH=/app/node_modules/.bin:$PATH
说明:环境变量可以在构建过程中使用,也可以在容器运行时使用。
2.2 构建上下文与.dockerignore
构建上下文
定义 :构建上下文是指docker build命令指定的路径下的所有文件和目录。
作用 :Docker守护进程会将构建上下文发送到自身,然后在其中执行构建操作。
示例:
# 当前目录作为构建上下文
docker build -t myapp:v1 .
# 指定其他目录作为构建上下文
docker build -t myapp:v1 /path/to/context
注意:构建上下文的大小会影响构建速度,因此应尽量减小构建上下文的大小。
.dockerignore文件
作用 :用于指定构建上下文目录中哪些文件或目录应该被排除,不发送到Docker守护进程。
示例:
# 排除所有.git目录
.git
# 排除所有node_modules目录
node_modules
# 排除所有.log文件
*.log
# 排除构建产物
dist/
build/
# 排除本地配置文件
.env.local
说明:使用.dockerignore文件可以减小构建上下文的大小,提高构建速度,同时避免将敏感文件复制到镜像中。
2.3 多阶段构建
优势
- 减小镜像体积:只包含运行所需的文件,不包含构建工具和依赖。
- 提高安全性:减少镜像中的攻击面。
- 简化构建流程:在一个Dockerfile中完成构建和打包。
示例
# 第一阶段:构建阶段
FROM node:14 as builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 第二阶段:运行阶段
FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
解释:
- 第一阶段使用node:14作为基础镜像,安装依赖并构建应用。
- 第二阶段使用nginx:alpine作为基础镜像,从第一阶段复制构建产物到nginx的默认静态文件目录。
- 最终的镜像只包含nginx和构建产物,不包含node.js和构建依赖,体积更小。
3. 实践练习
3.1 练习1:拉取并查看镜像
- 拉取Ubuntu 20.04镜像:
docker pull ubuntu:20.04 - 拉取Nginx Alpine镜像:
docker pull nginx:alpine - 查看所有镜像:
docker images - 尝试删除其中一个镜像:
docker rmi ubuntu:20.04 - 再次查看镜像:
docker images
3.2 练习2:构建简单的Web应用镜像
-
创建一个新目录:
mkdir my-webapp && cd my-webapp -
创建index.html文件:
<!DOCTYPE html> <html> <head> <title>My Web App</title> </head> <body> <h1>Hello Docker!</h1> <p>This is a simple web app running in a Docker container.</p> </body> </html> -
创建Dockerfile文件:
FROM nginx:alpine COPY index.html /usr/share/nginx/html/ EXPOSE 80 -
构建镜像:
docker build -t my-webapp:v1 . -
查看构建的镜像:
docker images my-webapp
3.3 练习3:使用多阶段构建
-
创建一个新目录:
mkdir multi-stage && cd multi-stage -
创建package.json文件:
{ "name": "my-react-app", "version": "1.0.0", "scripts": { "build": "echo 'Building React app...' && mkdir -p build && echo '<h1>React App</h1>' > build/index.html" } } -
创建Dockerfile文件:
# 构建阶段 FROM node:14 as builder WORKDIR /app COPY package*.json ./ RUN npm install COPY . . RUN npm run build # 运行阶段 FROM nginx:alpine COPY --from=builder /app/build /usr/share/nginx/html EXPOSE 80 -
构建镜像:
docker build -t my-react-app:v1 . -
查看构建的镜像大小:
docker images my-react-app
4. 总结
通过本周的学习,我们掌握了Docker镜像的基本操作:
- 拉取镜像 :使用
docker pull从仓库获取镜像 - 查看镜像 :使用
docker images查看本地镜像 - 删除镜像 :使用
docker rmi删除不需要的镜像 - 构建镜像 :使用
docker build根据Dockerfile构建镜像
同时,我们也学习了Dockerfile的基础指令和最佳实践:
- 基础指令:FROM、RUN、CMD、ENTRYPOINT等
- 构建上下文:理解构建上下文的概念和作用
- .dockerignore:使用.dockerignore减小构建上下文
- 多阶段构建:使用多阶段构建减小镜像体积
这些知识是Docker使用的基础,掌握这些操作后,我们可以更加灵活地使用Docker来构建和管理应用。