【docker基础】第三课:镜像管理与Dockerfile基础

📚前言

👀回顾,系统学习docker系列已发布内容:

【docker基础】0、系统学习docker之总计划

【docker基础】第一课、从零开始理解容器技术

【docker基础】第二课:安装、配置与基础命令

🔗相关文档:

windows下安装docker

【docker基础】Ubuntu 安装 Docker 超详细小白教程

本文,是计划的第三周的内容,内容纲要如下:

第3周:镜像管理

  1. 镜像操作
    • 拉取镜像:docker pull
    • 查看镜像:docker images
    • 删除镜像:docker rmi
    • 构建镜像:docker build
  2. 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

逻辑是:

  1. 本地没有 nginx 镜像
  2. Docker 去 Docker Hub 下载
  3. 下载后存到你电脑本地
  4. 以后再用就不用重新下载

这就像:
从应用商店下载 APP 到手机


1.4、第二层逻辑:本地怎么存?(分层存储)

这是 Docker 最牛的设计,必须懂

镜像不是一个大文件,而是多层叠加

例如:

  • 第一层:基础 Linux 系统(很小)
  • 第二层:依赖库
  • 第三层:nginx 程序
  • 第四层:默认配置

好处:

  1. 共享底层
    比如 nginx 和 node 都用同一个基础层,只存一份,不重复占用空间。
  2. 下载更快
    只下载你没有的层。
  3. 体积小

你可以理解成:
积木堆叠,共用底层积木


1.5、第三层逻辑:镜像和容器的关系(最容易混淆)

镜像 = 安装包(只读,不能改)
容器 = 运行起来的软件(可写,活的实例)

关系逻辑:

  • 一个镜像可以启动 N 个容器
  • 容器死掉,镜像还在
  • 镜像不动,容器随便删、随便建

比喻最准确:

  • 镜像 = 游戏安装包
  • 容器 = 打开运行的游戏

你不会因为关了游戏,安装包就没了。


1.6、第四层逻辑:本地镜像怎么管理?

常用命令就是围绕这 4 件事:

  1. 查看本地有哪些镜像

    docker images

逻辑:列出本地已经下载的所有镜像。

  1. 下载镜像

    docker pull 名字:版本

例如:

复制代码
docker pull nginx:latest
  1. 删除不用的镜像

    docker rmi 镜像ID或名字

逻辑:

  • 必须先删除依赖它的容器,否则不让删
  • 镜像一旦删除,下次要用必须重新拉取
  1. 搜索镜像

    docker search nginx

逻辑:去 Docker Hub 搜索可用镜像。


1.7、第五层逻辑:镜像版本与标签(tag)

镜像不是只有一个,而是有版本

格式:

复制代码
名字:标签

例如:

  • nginx:latest 最新版
  • nginx:1.25 固定版本
  • ubuntu:22.04

逻辑:

  • 不写标签默认 latest
  • 不同标签 = 不同镜像
  • 可以同时存在本地多个版本

1.8、完整流程串起来(最清晰总结)

  1. 你要运行软件
  2. Docker 先看本地有没有镜像
  3. 没有 → 去远程仓库(Docker Hub)拉取
  4. 拉到本地,按分层存储
  5. 用镜像创建并启动容器
  6. 容器运行
  7. 不用了可以删除容器 / 删除镜像

📖二、原理:本地镜像构建

当我们需要自己本地容器形成镜像时,Docker 是怎么做的,下面分解一下。


2.1、一句话核心逻辑

创建本地镜像 = 给当前的容器"拍个快照",把它固化成一个只读安装包。


2.2、先搞懂 2 种创建镜像的方式(必须分清)

Docker 只有 2 种制作本地镜像的方法:

方式1:docker commit(最直观、最简单)

从正在运行的容器直接打包成镜像

就像给虚拟机拍快照

方式2:docker build(标准、正式、企业都用)

通过 Dockerfile 文件自动构建镜像

就像写好安装脚本,让电脑自动一键安装打包


2.3、方式1:docker commit 打包逻辑(快照式)

逻辑流程(超级简单)

  1. 你启动一个容器(比如 Ubuntu)
  2. 进入容器,装软件、改配置
  3. 你觉得现在状态很好,想保存下来
  4. docker commit 把容器打包成新镜像
  5. 打包完成 → 本地出现一个新镜像

核心原理

把容器当前的所有改动(读写层)合并成一个新的只读层 → 生成新镜像。

比喻

容器 = 你正在画的画

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 构建逻辑(脚本式,最常用)

逻辑流程(标准工作流)

  1. 你写一个 Dockerfile(纯文本,告诉 Docker 怎么装环境)
  2. Docker 读取 Dockerfile 里的命令(FROM、RUN、COPY 等)
  3. Docker 自动启动临时容器执行每一步
  4. 每执行一行就生成一层镜像
  5. 全部执行完 → 自动合并成最终镜像
  6. 镜像保存到本地

核心原理

分层构建 + 缓存复用

每一行命令 = 一层

下次构建,没变的层直接用缓存,速度超快。

比喻

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:表示镜像的各个层正在被拉取,每个层都有一个唯一的ID
  • Digest:镜像的哈希值,用于验证镜像的完整性
  • 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到3
  • FROM ubuntu:20.04:使用Ubuntu 20.04作为基础镜像
  • RUN apt-get update && apt-get install -y nginx:执行命令安装nginx
  • Running in 9f7a5c5a5b4f:在临时容器中运行命令
  • Removing intermediate container:移除临时容器
  • Successfully built:构建成功,返回镜像ID
  • Successfully 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"]

ℹ️ℹ️命令分解说明:

第一行命令:

  1. RUN

Dockerfile 专用指令 意思:在构建镜像时,执行下面的 Linux 命令

  1. apt-get update

Ubuntu 系统命令意思:刷新软件源列表(让系统知道最新的软件版本)

  1. &&

意思:前面命令成功,再执行后面的

  1. apt-get install -y nginx

意思:自动安装 Nginx 网页服务器

  • -y = 自动确认安装(不用手动按回车)

整句大白话

构建镜像时,自动刷新软件源,并且自动安装 Nginx。

第二行命令:

  1. RUN

还是:执行命令

  1. "mkdir"

Linux 命令 = make directory 创建文件夹

  1. "-p"

参数,表示:如果文件夹不存在就创建,如果已存在就不报错

  1. "/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 多阶段构建

优势
  1. 减小镜像体积:只包含运行所需的文件,不包含构建工具和依赖。
  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;"]

解释

  1. 第一阶段使用node:14作为基础镜像,安装依赖并构建应用。
  2. 第二阶段使用nginx:alpine作为基础镜像,从第一阶段复制构建产物到nginx的默认静态文件目录。
  3. 最终的镜像只包含nginx和构建产物,不包含node.js和构建依赖,体积更小。

3. 实践练习

3.1 练习1:拉取并查看镜像

  1. 拉取Ubuntu 20.04镜像:docker pull ubuntu:20.04
  2. 拉取Nginx Alpine镜像:docker pull nginx:alpine
  3. 查看所有镜像:docker images
  4. 尝试删除其中一个镜像:docker rmi ubuntu:20.04
  5. 再次查看镜像:docker images

3.2 练习2:构建简单的Web应用镜像

  1. 创建一个新目录:mkdir my-webapp && cd my-webapp

  2. 创建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>
  3. 创建Dockerfile文件:

    复制代码
    FROM nginx:alpine
    COPY index.html /usr/share/nginx/html/
    EXPOSE 80
  4. 构建镜像:docker build -t my-webapp:v1 .

  5. 查看构建的镜像:docker images my-webapp

3.3 练习3:使用多阶段构建

  1. 创建一个新目录:mkdir multi-stage && cd multi-stage

  2. 创建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"
      }
    }
  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
  4. 构建镜像:docker build -t my-react-app:v1 .

  5. 查看构建的镜像大小: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来构建和管理应用。

相关推荐
老虎06272 小时前
Nginx
运维·nginx
loriloy2 小时前
Docker 部署 Docmost 详细教程
docker·docmost
阿沁QWQ2 小时前
docker使用
docker·容器·perl
lwx9148529 小时前
Linux-特殊权限SUID,SGID,SBIT
linux·运维·服务器
炘爚11 小时前
深入解析printf缓冲区与fork进程复制机制
linux·运维·算法
workflower11 小时前
注塑机行业目前自动化现状分析
运维·人工智能·语言模型·自动化·集成测试·软件工程·软件需求
小义_12 小时前
随笔 3(Linux)
linux·运维·服务器·云原生·红帽
杨浦老苏12 小时前
开源的AI编程工作站HolyClaude
人工智能·docker·ai·编辑器·开发·群晖
#六脉神剑12 小时前
MySQL参数调优:十个关键参数助力数据库性能数倍提升
运维·mysql