mirror of
https://github.com/yeasy/docker_practice.git
synced 2026-03-15 06:11:11 +00:00
Fix and update
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
## 获取镜像
|
||||
|
||||
## 获取镜像
|
||||
|
||||
从 Docker 镜像仓库获取镜像可谓是 Docker 运作的第一步。本节将介绍如何使用 `docker pull` 命令下载镜像,以及如何理解下载过程。
|
||||
|
||||
### docker pull 命令
|
||||
|
||||
从镜像仓库获取镜像的命令是 `docker pull`:
|
||||
@@ -10,6 +14,10 @@ docker pull [选项] [Registry地址/]仓库名[:标签]
|
||||
|
||||
#### 镜像名称格式
|
||||
|
||||
#### 镜像名称格式
|
||||
|
||||
Docker 镜像名称由 Registry 地址、用户名、仓库名和标签组成。其标准格式如下:
|
||||
|
||||
```
|
||||
docker.io / library / ubuntu : 24.04
|
||||
────┬──── ───┬─── ──┬─── ──┬──
|
||||
@@ -27,23 +35,31 @@ Registry地址 用户名 仓库名 标签
|
||||
|
||||
#### 示例
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
## 完整格式
|
||||
|
||||
$ docker pull docker.io/library/ubuntu:24.04
|
||||
|
||||
## 省略 Registry(默认 Docker Hub)
|
||||
|
||||
$ docker pull library/ubuntu:24.04
|
||||
|
||||
## 省略 library(官方镜像)
|
||||
|
||||
$ docker pull ubuntu:24.04
|
||||
|
||||
## 省略标签(默认 latest)
|
||||
|
||||
$ docker pull ubuntu
|
||||
|
||||
## 拉取第三方镜像
|
||||
|
||||
$ docker pull bitnami/redis:latest
|
||||
|
||||
## 从其他 Registry 拉取
|
||||
|
||||
$ docker pull ghcr.io/username/myapp:v1.0
|
||||
```
|
||||
|
||||
@@ -51,6 +67,10 @@ $ docker pull ghcr.io/username/myapp:v1.0
|
||||
|
||||
### 下载过程解析
|
||||
|
||||
当我们执行 `docker pull` 命令时,Docker 会输出详细的下载进度。让我们以 `ubuntu:24.04` 为例来解析这些信息。
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
$ docker pull ubuntu:24.04
|
||||
24.04: Pulling from library/ubuntu
|
||||
@@ -93,6 +113,8 @@ docker.io/library/ubuntu:24.04
|
||||
|
||||
### 常用选项
|
||||
|
||||
`docker pull` 命令支持多种选项来满足不同的下载需求,例如下载所有标签、指定平台架构等。
|
||||
|
||||
| 选项 | 说明 | 示例 |
|
||||
|------|------|------|
|
||||
| `--all-tags, -a` | 拉取所有标签 | `docker pull -a ubuntu` |
|
||||
@@ -115,9 +137,11 @@ $ docker pull --platform linux/amd64 nginx
|
||||
|
||||
```bash
|
||||
## 拉取镜像
|
||||
|
||||
$ docker pull ubuntu:24.04
|
||||
|
||||
## 运行容器
|
||||
|
||||
$ docker run -it --rm ubuntu:24.04 bash
|
||||
root@e7009c6ce357:/# cat /etc/os-release
|
||||
PRETTY_NAME="Ubuntu 24.04 LTS"
|
||||
@@ -155,6 +179,8 @@ root@e7009c6ce357:/# exit
|
||||
|
||||
```bash
|
||||
$ sudo systemctl restart docker # Linux
|
||||
## 或在 Docker Desktop 中重启
|
||||
|
||||
## 或在 Docker Desktop 中重启
|
||||
```
|
||||
|
||||
@@ -164,8 +190,12 @@ $ sudo systemctl restart docker # Linux
|
||||
|
||||
### 验证镜像完整性
|
||||
|
||||
为了确保下载的镜像没有被篡改且内容一致,我们可以校验镜像的摘要(Digest)。
|
||||
|
||||
#### 查看镜像摘要
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
$ docker images --digests ubuntu
|
||||
REPOSITORY TAG DIGEST IMAGE ID
|
||||
@@ -186,6 +216,8 @@ $ docker pull ubuntu@sha256:4bc3ae6596938cb0d9e5ac51a1152ec9dcac2a1c50829c74abd9
|
||||
|
||||
### 常见问题
|
||||
|
||||
在使用 `docker pull` 过程中,可能会遇到下载速度慢、镜像不存在或磁盘空间不足等问题。以下是一些常见问题的排查思路。
|
||||
|
||||
#### Q: 下载速度很慢
|
||||
|
||||
1. 配置镜像加速器
|
||||
@@ -194,6 +226,8 @@ $ docker pull ubuntu@sha256:4bc3ae6596938cb0d9e5ac51a1152ec9dcac2a1c50829c74abd9
|
||||
|
||||
#### Q: 提示镜像不存在
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
Error: pull access denied, repository does not exist
|
||||
```
|
||||
@@ -205,11 +239,15 @@ Error: pull access denied, repository does not exist
|
||||
|
||||
#### Q: 磁盘空间不足
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
## 清理未使用的镜像
|
||||
|
||||
$ docker image prune
|
||||
|
||||
## 清理所有未使用资源
|
||||
|
||||
$ docker system prune
|
||||
```
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
## 列出镜像
|
||||
|
||||
## 列出镜像
|
||||
|
||||
在下载了镜像后,我们可以使用 `docker image ls` 命令列出本地主机上的镜像。
|
||||
|
||||
### 基本用法
|
||||
|
||||
查看本地已下载的镜像:
|
||||
@@ -19,6 +23,8 @@ ubuntu noble 329ed837d508 3 days ago 78MB
|
||||
|
||||
### 输出字段说明
|
||||
|
||||
`docker image ls` 命令默认输出的列表包含仓库名、标签、镜像 ID、创建时间和占用空间等信息。
|
||||
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| **REPOSITORY** | 仓库名 |
|
||||
@@ -35,6 +41,8 @@ ubuntu noble 329ed837d508 3 days ago 78MB
|
||||
|
||||
### 理解镜像大小
|
||||
|
||||
Docker 镜像的大小可能与我们通常理解的文件大小有所不同,这涉及到分层存储的概念。
|
||||
|
||||
#### 本地大小 vs Hub 显示大小
|
||||
|
||||
| 位置 | 显示大小 | 说明 |
|
||||
@@ -58,6 +66,8 @@ ubuntu:24.04 nginx:latest redis:latest
|
||||
|
||||
#### 查看实际空间占用
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
$ docker system df
|
||||
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
|
||||
@@ -71,10 +81,15 @@ Build Cache 0 0 0B 0B
|
||||
|
||||
### 过滤镜像
|
||||
|
||||
随着本地镜像数量的增加,我们需要更有效的方式来查找特定的镜像。Docker 提供了多种过滤方式。
|
||||
|
||||
#### 按仓库名过滤
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
## 列出所有 ubuntu 镜像
|
||||
|
||||
$ docker images ubuntu
|
||||
REPOSITORY TAG IMAGE ID SIZE
|
||||
ubuntu 24.04 329ed837d508 78MB
|
||||
@@ -84,6 +99,8 @@ ubuntu 22.04 a1b2c3d4e5f6 72MB
|
||||
|
||||
#### 按仓库名和标签过滤
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
$ docker images ubuntu:24.04
|
||||
REPOSITORY TAG IMAGE ID SIZE
|
||||
@@ -102,12 +119,15 @@ ubuntu 24.04 329ed837d508 78MB
|
||||
|
||||
```bash
|
||||
## 列出 nginx 之后创建的镜像
|
||||
|
||||
$ docker images -f since=nginx:latest
|
||||
|
||||
## 列出所有带 latest 标签的镜像
|
||||
|
||||
$ docker images -f reference='*:latest'
|
||||
|
||||
## 列出带特定 LABEL 的镜像
|
||||
|
||||
$ docker images -f label=maintainer=example@email.com
|
||||
```
|
||||
|
||||
@@ -115,6 +135,8 @@ $ docker images -f label=maintainer=example@email.com
|
||||
|
||||
### 虚悬镜像(Dangling Images)
|
||||
|
||||
在镜像列表里,你可能会看到一些仓库名和标签都为 `<none>` 的镜像,这类镜像被称为虚悬镜像。
|
||||
|
||||
#### 什么是虚悬镜像
|
||||
|
||||
仓库名和标签都显示为 `<none>` 的镜像:
|
||||
@@ -132,11 +154,15 @@ REPOSITORY TAG IMAGE ID SIZE
|
||||
|
||||
#### 处理虚悬镜像
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
## 列出虚悬镜像
|
||||
|
||||
$ docker images -f dangling=true
|
||||
|
||||
## 删除虚悬镜像
|
||||
|
||||
$ docker image prune
|
||||
```
|
||||
|
||||
@@ -144,8 +170,12 @@ $ docker image prune
|
||||
|
||||
### 中间层镜像
|
||||
|
||||
除了虚悬镜像,`docker image ls` 默认列出的只是顶层镜像。还有一种镜像是为了加速镜像构建、重复利用资源而存在的中间层镜像。
|
||||
|
||||
#### 查看所有镜像(包含中间层)
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
$ docker images -a
|
||||
```
|
||||
@@ -158,8 +188,12 @@ $ docker images -a
|
||||
|
||||
### 格式化输出
|
||||
|
||||
为了配合脚本使用或展示更关注的信息,我们可以使用 `--format` 参数来自定义输出格式。
|
||||
|
||||
#### 只输出 ID
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
$ docker images -q
|
||||
5f515359c7f8
|
||||
@@ -171,20 +205,26 @@ $ docker images -q
|
||||
|
||||
```bash
|
||||
## 删除所有镜像
|
||||
|
||||
$ docker rmi $(docker images -q)
|
||||
|
||||
## 删除所有 redis 镜像
|
||||
|
||||
$ docker rmi $(docker images -q redis)
|
||||
```
|
||||
|
||||
#### 显示完整 ID
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
$ docker images --no-trunc
|
||||
```
|
||||
|
||||
#### 显示摘要
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
$ docker images --digests
|
||||
REPOSITORY TAG DIGEST IMAGE ID
|
||||
@@ -197,12 +237,14 @@ nginx latest sha256:b4f0e0bdeb5... e43d811ce2f4
|
||||
|
||||
```bash
|
||||
## 只显示 ID 和仓库名
|
||||
|
||||
$ docker images --format "{{.ID}}: {{.Repository}}"
|
||||
5f515359c7f8: redis
|
||||
05a60462f8ba: nginx
|
||||
329ed837d508: ubuntu
|
||||
|
||||
## 表格形式(带标题)
|
||||
|
||||
$ docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
|
||||
REPOSITORY TAG SIZE
|
||||
redis latest 183MB
|
||||
@@ -226,14 +268,19 @@ ubuntu 24.04 78MB
|
||||
|
||||
### 常用命令组合
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
## 列出所有镜像及其大小,按大小排序(需要系统 sort 命令)
|
||||
|
||||
$ docker images --format "{{.Size}}\t{{.Repository}}:{{.Tag}}" | sort -h
|
||||
|
||||
## 查找大于 500MB 的镜像
|
||||
|
||||
$ docker images --format "{{.Size}}\t{{.Repository}}:{{.Tag}}" | grep -E "^[0-9]+GB|^[5-9][0-9]{2}MB"
|
||||
|
||||
## 导出镜像列表
|
||||
|
||||
$ docker images --format "{{.Repository}}:{{.Tag}}" > images.txt
|
||||
```
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
## 删除本地镜像
|
||||
|
||||
当不再需要某个镜像时,我们可以将其删除以释放存储空间。本节介绍删除镜像的常用方法。
|
||||
|
||||
### 基本用法
|
||||
|
||||
使用 `docker image rm` 删除本地镜像:
|
||||
@@ -25,6 +27,8 @@ $ docker image rm [选项] <镜像1> [<镜像2> ...]
|
||||
|
||||
#### 使用短 ID 删除
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
$ docker image ls
|
||||
REPOSITORY TAG IMAGE ID SIZE
|
||||
@@ -32,6 +36,7 @@ redis alpine 501ad78535f0 30MB
|
||||
nginx latest e43d811ce2f4 142MB
|
||||
|
||||
## 只需输入足够区分的前几位
|
||||
|
||||
$ docker rmi 501
|
||||
Untagged: redis:alpine
|
||||
Deleted: sha256:501ad78535f0...
|
||||
@@ -39,6 +44,8 @@ Deleted: sha256:501ad78535f0...
|
||||
|
||||
#### 使用镜像名删除
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
$ docker rmi redis:alpine
|
||||
Untagged: redis:alpine
|
||||
@@ -51,11 +58,13 @@ Deleted: sha256:501ad78535f0...
|
||||
|
||||
```bash
|
||||
## 查看镜像摘要
|
||||
|
||||
$ docker images --digests
|
||||
REPOSITORY TAG DIGEST IMAGE ID
|
||||
nginx latest sha256:b4f0e0bdeb5... e43d811ce2f4
|
||||
|
||||
## 使用摘要删除
|
||||
|
||||
$ docker rmi nginx@sha256:b4f0e0bdeb578043c1ea6862f0d40cc4afe32a4a582f3be235a3b164422be228
|
||||
```
|
||||
|
||||
@@ -63,7 +72,9 @@ $ docker rmi nginx@sha256:b4f0e0bdeb578043c1ea6862f0d40cc4afe32a4a582f3be235a3b1
|
||||
|
||||
### 理解输出信息
|
||||
|
||||
删除镜像时会看到两类信息:**Untagged** 和 **Deleted**
|
||||
执行删除命令后,Docker 会输出一系列的操作记录,理解这些信息有助于我们掌握镜像删除的机制。
|
||||
|
||||
删除镜像时会看到两类信息:**Untagged**和**Deleted**
|
||||
|
||||
```bash
|
||||
$ docker rmi redis:alpine
|
||||
@@ -83,6 +94,10 @@ Deleted: sha256:32770d1dcf835f192cafd6b9263b7b597a1778a403a109e2cc2ee866f74adf23
|
||||
|
||||
#### 删除流程
|
||||
|
||||
#### 删除流程
|
||||
|
||||
Docker 会检测镜像是否有容器依赖或其他标签指向,只有在确认为无用资源时才会真正删除存储层。
|
||||
|
||||
```
|
||||
docker rmi redis:alpine
|
||||
│
|
||||
@@ -108,41 +123,55 @@ docker rmi redis:alpine
|
||||
|
||||
### 批量删除
|
||||
|
||||
手动一个一个删除镜像非常繁琐,Docker 提供了 `image prune` 命令和 shell 组合命令来实现批量清理。
|
||||
|
||||
#### 删除所有虚悬镜像
|
||||
|
||||
虚悬镜像(dangling):没有标签的镜像,通常是旧版本被新版本覆盖后产生的
|
||||
|
||||
```bash
|
||||
## 查看虚悬镜像
|
||||
|
||||
$ docker images -f dangling=true
|
||||
|
||||
## 删除虚悬镜像
|
||||
|
||||
$ docker image prune
|
||||
|
||||
## 不提示确认
|
||||
|
||||
$ docker image prune -f
|
||||
```
|
||||
|
||||
#### 删除所有未使用的镜像
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
## 删除所有没有被容器使用的镜像
|
||||
|
||||
$ docker image prune -a
|
||||
|
||||
## 保留最近 24 小时的
|
||||
|
||||
$ docker image prune -a --filter "until=24h"
|
||||
```
|
||||
|
||||
#### 按条件删除
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
## 删除所有 redis 镜像
|
||||
|
||||
$ docker rmi $(docker images -q redis)
|
||||
|
||||
## 删除 mongo:8.0 之前的所有镜像
|
||||
|
||||
$ docker rmi $(docker images -q -f before=mongo:8.0)
|
||||
|
||||
## 删除某个时间之前的镜像
|
||||
|
||||
$ docker image prune -a --filter "until=168h" # 7天前
|
||||
```
|
||||
|
||||
@@ -150,8 +179,12 @@ $ docker image prune -a --filter "until=168h" # 7天前
|
||||
|
||||
### 删除失败的常见原因
|
||||
|
||||
在删除镜像时,Docker 可能会提示错误并拒绝执行。这通常是为了防止误删正在使用的资源。
|
||||
|
||||
#### 原因一:有容器依赖
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
$ docker rmi nginx
|
||||
Error: conflict: unable to remove repository reference "nginx"
|
||||
@@ -162,15 +195,19 @@ Error: conflict: unable to remove repository reference "nginx"
|
||||
|
||||
```bash
|
||||
## 方案1:先删除依赖的容器
|
||||
|
||||
$ docker rm abc123
|
||||
$ docker rmi nginx
|
||||
|
||||
## 方案2:强制删除镜像(容器仍可运行,但无法再创建新容器)
|
||||
|
||||
$ docker rmi -f nginx
|
||||
```
|
||||
|
||||
#### 原因二:多个标签指向同一镜像
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
$ docker images
|
||||
REPOSITORY TAG IMAGE ID
|
||||
@@ -180,10 +217,17 @@ ubuntu latest ca2b0f26964c # 同一个镜像
|
||||
$ docker rmi ubuntu:24.04
|
||||
Untagged: ubuntu:24.04
|
||||
## 只是移除标签,镜像仍存在(因为还有 ubuntu:latest 指向它)
|
||||
|
||||
#### 原因二:多个标签指向同一镜像
|
||||
|
||||
当同一个镜像有多个标签时,`docker rmi` 只是删除指定的标签,不会删除镜像本身。
|
||||
|
||||
```
|
||||
|
||||
#### 原因三:被其他镜像依赖(中间层)
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
$ docker rmi some_base_image
|
||||
Error: image has dependent child images
|
||||
@@ -207,25 +251,36 @@ Error: image has dependent child images
|
||||
|
||||
### 清理策略
|
||||
|
||||
针对不同的环境(开发环境 vs 生产环境),我们应该采用不同的镜像清理策略。
|
||||
|
||||
#### 开发环境
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
## 定期清理虚悬镜像
|
||||
|
||||
$ docker image prune -f
|
||||
|
||||
## 一键清理所有未使用资源
|
||||
|
||||
$ docker system prune -a
|
||||
```
|
||||
|
||||
#### CI/CD 环境
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
## 只保留最近使用的镜像
|
||||
|
||||
$ docker image prune -a --filter "until=72h" -f
|
||||
```
|
||||
|
||||
#### 查看空间占用
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
$ docker system df
|
||||
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
|
||||
|
||||
@@ -190,6 +190,7 @@ Sending build context to Docker daemon 2.048 kB
|
||||
|
||||
```bash
|
||||
## $env:DOCKER_BUILDKIT=0
|
||||
|
||||
## export DOCKER_BUILDKIT=0
|
||||
|
||||
$ docker build -t hello-world https://github.com/docker-library/hello-world.git#master:amd64/hello-world
|
||||
@@ -209,6 +210,8 @@ Successfully built 038ad4142d2b
|
||||
|
||||
#### 用给定的 tar 压缩包构建
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
$ docker build http://server/context.tar.gz
|
||||
```
|
||||
@@ -217,6 +220,8 @@ $ docker build http://server/context.tar.gz
|
||||
|
||||
#### 从标准输入中读取 Dockerfile 进行构建
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
docker build - < Dockerfile
|
||||
```
|
||||
@@ -231,6 +236,8 @@ cat Dockerfile | docker build -
|
||||
|
||||
#### 从标准输入中读取上下文压缩包进行构建
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
$ docker build - < context.tar.gz
|
||||
```
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
|
||||
Docker 运行容器前需要本地存在对应的镜像,如果本地不存在该镜像,Docker 会从镜像仓库下载该镜像。
|
||||
|
||||
## 本章内容
|
||||
|
||||
本章将介绍更多关于镜像的内容,包括:
|
||||
|
||||
* 从仓库获取镜像;
|
||||
|
||||
* 管理本地主机上的镜像;
|
||||
|
||||
* 介绍镜像实现的基本原理。
|
||||
* [从仓库获取镜像](4.1_pull.md)
|
||||
* [列出镜像](4.2_list.md)
|
||||
* [删除本地镜像](4.3_rm.md)
|
||||
* [利用 commit 理解镜像构成](4.4_commit.md)
|
||||
* [使用 Dockerfile 定制镜像](4.5_build.md)
|
||||
* [其它制作镜像的方式](4.6_other.md)
|
||||
* [镜像的实现原理](4.7_internal.md)
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
## Dockerfile 指令详解
|
||||
# Dockerfile 指令详解
|
||||
|
||||
我们已经介绍了 `FROM`,`RUN`,还提及了 `COPY`, `ADD`,其实 `Dockerfile` 功能很强大,它提供了十多个指令。下面我们继续讲解其他的指令。
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
### 基本语法
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
ADD [选项] <源路径>... <目标路径>
|
||||
ADD [选项] ["<源路径>", ... "<目标路径>"]
|
||||
@@ -31,8 +33,11 @@ ADD [选项] ["<源路径>", ... "<目标路径>"]
|
||||
|
||||
#### 基本用法
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 自动解压 tar.gz 到目标目录
|
||||
|
||||
ADD app.tar.gz /app/
|
||||
```
|
||||
|
||||
@@ -53,6 +58,8 @@ ADD ubuntu-noble-core-cloudimg-amd64-root.tar.gz /
|
||||
|
||||
#### 解压过程
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```
|
||||
ADD app.tar.gz /app/
|
||||
│
|
||||
@@ -72,8 +79,11 @@ app.tar.gz 包含: /app/ 目录结果:
|
||||
|
||||
#### 基本用法
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 从 URL 下载文件
|
||||
|
||||
ADD https://example.com/app.zip /app/app.zip
|
||||
```
|
||||
|
||||
@@ -88,12 +98,16 @@ ADD https://example.com/app.zip /app/app.zip
|
||||
|
||||
#### 推荐替代方案
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ❌ 不推荐:使用 ADD 下载
|
||||
|
||||
ADD https://example.com/app.tar.gz /tmp/
|
||||
RUN tar -xzf /tmp/app.tar.gz -C /app && rm /tmp/app.tar.gz
|
||||
|
||||
## ✅ 推荐:使用 RUN + curl
|
||||
|
||||
RUN curl -fsSL https://example.com/app.tar.gz | tar -xz -C /app
|
||||
```
|
||||
|
||||
@@ -106,6 +120,8 @@ RUN curl -fsSL https://example.com/app.tar.gz | tar -xz -C /app
|
||||
|
||||
### 修改文件所有者
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
ADD --chown=node:node app.tar.gz /app/
|
||||
ADD --chown=1000:1000 files/ /app/
|
||||
@@ -117,27 +133,36 @@ ADD --chown=1000:1000 files/ /app/
|
||||
|
||||
#### ✅ 适合使用 ADD
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 解压本地 tar 文件
|
||||
|
||||
FROM scratch
|
||||
ADD rootfs.tar.gz /
|
||||
|
||||
## 解压应用包
|
||||
|
||||
ADD dist.tar.gz /app/
|
||||
```
|
||||
|
||||
#### ❌ 不适合使用 ADD
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 复制普通文件(用 COPY)
|
||||
|
||||
ADD package.json /app/ # ❌
|
||||
COPY package.json /app/ # ✅
|
||||
|
||||
## 下载文件(用 RUN + curl)
|
||||
|
||||
ADD https://example.com/file / # ❌
|
||||
RUN curl -fsSL ... -o /file # ✅
|
||||
|
||||
## 需要保留 tar 不解压(用 COPY)
|
||||
|
||||
ADD archive.tar.gz /archives/ # ❌ 会解压
|
||||
COPY archive.tar.gz /archives/ # ✅ 保持原样
|
||||
```
|
||||
@@ -150,6 +175,7 @@ ADD 可能导致构建缓存失效:
|
||||
|
||||
```docker
|
||||
## 如果 app.tar.gz 内容变化,此层及后续层都需重建
|
||||
|
||||
ADD app.tar.gz /app/
|
||||
RUN npm install
|
||||
```
|
||||
@@ -158,10 +184,12 @@ RUN npm install
|
||||
|
||||
```docker
|
||||
## 先复制依赖文件
|
||||
|
||||
COPY package*.json /app/
|
||||
RUN npm install
|
||||
|
||||
## 再添加应用代码
|
||||
|
||||
ADD app.tar.gz /app/
|
||||
```
|
||||
|
||||
@@ -171,32 +199,45 @@ ADD app.tar.gz /app/
|
||||
|
||||
#### 1. 默认使用 COPY
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ✅ 大多数场景使用 COPY
|
||||
|
||||
COPY . /app/
|
||||
```
|
||||
|
||||
#### 2. 仅在需要解压时使用 ADD
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ✅ 自动解压场景
|
||||
|
||||
ADD app.tar.gz /app/
|
||||
```
|
||||
|
||||
#### 3. 不要用 ADD 下载文件
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ❌ 避免
|
||||
|
||||
ADD https://example.com/file.tar.gz /tmp/
|
||||
|
||||
## ✅ 推荐
|
||||
|
||||
RUN curl -fsSL https://example.com/file.tar.gz | tar -xz -C /app
|
||||
```
|
||||
|
||||
#### 4. 解压后清理
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 如果需要控制解压过程
|
||||
|
||||
COPY app.tar.gz /tmp/
|
||||
RUN tar -xzf /tmp/app.tar.gz -C /app && \
|
||||
rm /tmp/app.tar.gz
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
### 基本语法
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
ARG <参数名>[=<默认值>]
|
||||
```
|
||||
@@ -35,22 +37,30 @@ ARG <参数名>[=<默认值>]
|
||||
|
||||
#### 定义和使用
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 定义有默认值的 ARG
|
||||
|
||||
ARG NODE_VERSION=20
|
||||
|
||||
## 使用 ARG
|
||||
|
||||
FROM node:${NODE_VERSION}-alpine
|
||||
RUN echo "Using Node.js $NODE_VERSION"
|
||||
```
|
||||
|
||||
#### 构建时覆盖
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
## 使用默认值
|
||||
|
||||
$ docker build -t myapp .
|
||||
|
||||
## 覆盖默认值
|
||||
|
||||
$ docker build --build-arg NODE_VERSION=18 -t myapp .
|
||||
```
|
||||
|
||||
@@ -60,41 +70,52 @@ $ docker build --build-arg NODE_VERSION=18 -t myapp .
|
||||
|
||||
#### FROM 之前的 ARG
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## FROM 之前的 ARG 只能用于 FROM 指令
|
||||
|
||||
ARG REGISTRY=docker.io
|
||||
ARG IMAGE_NAME=node
|
||||
|
||||
FROM ${REGISTRY}/${IMAGE_NAME}:20
|
||||
|
||||
## ❌ 这里无法使用上面的 ARG
|
||||
|
||||
RUN echo $REGISTRY # 输出空
|
||||
```
|
||||
|
||||
#### FROM 之后重新声明
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
ARG NODE_VERSION=20
|
||||
|
||||
FROM node:${NODE_VERSION}-alpine
|
||||
|
||||
## 需要再次声明才能使用
|
||||
|
||||
ARG NODE_VERSION
|
||||
RUN echo "Node version: $NODE_VERSION"
|
||||
```
|
||||
|
||||
#### 多阶段构建中的 ARG
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
ARG BASE_VERSION=alpine
|
||||
|
||||
FROM node:20-${BASE_VERSION} AS builder
|
||||
## 需要重新声明
|
||||
|
||||
ARG NODE_VERSION=20
|
||||
RUN echo "Building with Node $NODE_VERSION"
|
||||
|
||||
FROM node:20-${BASE_VERSION}
|
||||
## 每个阶段都需要重新声明
|
||||
|
||||
ARG NODE_VERSION=20
|
||||
RUN echo "Running with Node $NODE_VERSION"
|
||||
```
|
||||
@@ -105,6 +126,8 @@ RUN echo "Running with Node $NODE_VERSION"
|
||||
|
||||
#### 1. 控制基础镜像版本
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
ARG ALPINE_VERSION=3.19
|
||||
FROM alpine:${ALPINE_VERSION}
|
||||
@@ -116,6 +139,8 @@ $ docker build --build-arg ALPINE_VERSION=3.18 .
|
||||
|
||||
#### 2. 设置软件版本
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
ARG NGINX_VERSION=1.25.0
|
||||
|
||||
@@ -124,6 +149,8 @@ RUN curl -fsSL https://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz | tar -x
|
||||
|
||||
#### 3. 配置构建环境
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
ARG BUILD_ENV=production
|
||||
ARG ENABLE_DEBUG=false
|
||||
@@ -137,6 +164,8 @@ RUN if [ "$ENABLE_DEBUG" = "true" ]; then \
|
||||
|
||||
#### 4. 配置私有仓库
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
ARG NPM_TOKEN
|
||||
|
||||
@@ -147,6 +176,7 @@ RUN echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc && \
|
||||
|
||||
```bash
|
||||
## 构建时传入 token
|
||||
|
||||
$ docker build --build-arg NPM_TOKEN=xxx .
|
||||
```
|
||||
|
||||
@@ -160,9 +190,11 @@ $ docker build --build-arg NPM_TOKEN=xxx .
|
||||
ARG VERSION=1.0.0
|
||||
|
||||
## 将 ARG 传递给 ENV
|
||||
|
||||
ENV APP_VERSION=$VERSION
|
||||
|
||||
## 运行时可用
|
||||
|
||||
CMD echo "App version: $APP_VERSION"
|
||||
```
|
||||
|
||||
@@ -181,6 +213,7 @@ Docker 提供了一些预定义的 ARG,无需声明即可使用:
|
||||
|
||||
```bash
|
||||
## 构建时使用代理
|
||||
|
||||
$ docker build --build-arg HTTP_PROXY=http://proxy:8080 .
|
||||
```
|
||||
|
||||
@@ -190,32 +223,48 @@ $ docker build --build-arg HTTP_PROXY=http://proxy:8080 .
|
||||
|
||||
#### 1. 为 ARG 提供合理默认值
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ✅ 好:有默认值
|
||||
|
||||
ARG NODE_VERSION=20
|
||||
|
||||
## ⚠️ 需要每次传入
|
||||
|
||||
ARG NODE_VERSION
|
||||
```
|
||||
|
||||
#### 2. 不要用 ARG 存储敏感信息
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ❌ 错误:密码会被记录在镜像历史中
|
||||
|
||||
ARG DB_PASSWORD
|
||||
RUN echo "password=$DB_PASSWORD" > /app/.env
|
||||
|
||||
## ✅ 正确:使用 secrets 或运行时环境变量
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```
|
||||
|
||||
#### 3. 使用 ARG 提高构建灵活性
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
ARG BASE_IMAGE=python:3.12-slim
|
||||
FROM ${BASE_IMAGE}
|
||||
|
||||
## 可以构建不同基础镜像的版本
|
||||
|
||||
## docker build --build-arg BASE_IMAGE=python:3.11-alpine .
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -14,12 +14,14 @@ CMD 有三种格式:
|
||||
|
||||
| 格式 | 语法 | 推荐程度 |
|
||||
|------|------|---------|
|
||||
| **exec 格式** | `CMD ["可执行文件", "参数1", "参数2"]` | ✅ **推荐** |
|
||||
| **exec 格式**| `CMD ["可执行文件", "参数1", "参数2"]` | ✅**推荐** |
|
||||
| **shell 格式** | `CMD 命令 参数1 参数2` | ⚠️ 简单场景 |
|
||||
| **参数格式** | `CMD ["参数1", "参数2"]` | 配合 ENTRYPOINT |
|
||||
|
||||
#### exec 格式(推荐)
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
CMD ["python", "app.py"]
|
||||
@@ -33,6 +35,8 @@ CMD ["node", "server.js"]
|
||||
|
||||
#### shell 格式
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
CMD echo "Hello World"
|
||||
CMD nginx -g "daemon off;"
|
||||
@@ -42,9 +46,11 @@ CMD nginx -g "daemon off;"
|
||||
|
||||
```docker
|
||||
## 你写的
|
||||
|
||||
CMD echo $HOME
|
||||
|
||||
## 实际执行的
|
||||
|
||||
CMD ["sh", "-c", "echo $HOME"]
|
||||
```
|
||||
|
||||
@@ -64,15 +70,23 @@ CMD ["sh", "-c", "echo $HOME"]
|
||||
|
||||
#### 信号传递问题示例
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ❌ shell 格式:docker stop 会超时
|
||||
|
||||
CMD node server.js
|
||||
## 实际是 sh -c "node server.js"
|
||||
|
||||
## SIGTERM 发给 sh,不会传递给 node
|
||||
|
||||
## ✅ exec 格式:docker stop 正常工作
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
## SIGTERM 直接发给 node
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
@@ -83,6 +97,7 @@ CMD ["node", "server.js"]
|
||||
|
||||
```bash
|
||||
## ubuntu 默认 CMD 是 /bin/bash
|
||||
|
||||
$ docker run -it ubuntu # 进入 bash
|
||||
$ docker run ubuntu cat /etc/os-release # 覆盖为 cat 命令
|
||||
```
|
||||
@@ -102,13 +117,18 @@ CMD ["/bin/bash"] + cat /etc/os-release
|
||||
|
||||
#### 错误示例
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ❌ 容器启动后立即退出
|
||||
|
||||
CMD service nginx start
|
||||
```
|
||||
|
||||
#### 原因分析
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```
|
||||
1. CMD service nginx start
|
||||
↓ 被转换为
|
||||
@@ -125,8 +145,11 @@ CMD service nginx start
|
||||
|
||||
#### 正确做法
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ✅ 让 nginx 在前台运行
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
```
|
||||
|
||||
@@ -136,13 +159,16 @@ CMD ["nginx", "-g", "daemon off;"]
|
||||
|
||||
| 指令 | 用途 | 运行时行为 |
|
||||
|------|------|-----------|
|
||||
| **CMD** | 默认命令 | `docker run` 参数会**覆盖**它 |
|
||||
| **ENTRYPOINT** | 入口点 | `docker run` 参数会**追加**到它后面 |
|
||||
| **CMD**| 默认命令 | `docker run` 参数会**覆盖**它 |
|
||||
| **ENTRYPOINT**| 入口点 | `docker run` 参数会**追加**到它后面 |
|
||||
|
||||
#### 单独使用 CMD
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## Dockerfile
|
||||
|
||||
CMD ["curl", "-s", "http://example.com"]
|
||||
```
|
||||
|
||||
@@ -153,8 +179,11 @@ $ docker run myimage curl -v ... # 完全覆盖
|
||||
|
||||
#### 搭配 ENTRYPOINT
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## Dockerfile
|
||||
|
||||
ENTRYPOINT ["curl", "-s"]
|
||||
CMD ["http://example.com"]
|
||||
```
|
||||
@@ -172,45 +201,61 @@ $ docker run myimage http://other.com # curl -s http://other.com(参数覆盖
|
||||
|
||||
#### 1. 优先使用 exec 格式
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ✅ 推荐
|
||||
|
||||
CMD ["python", "app.py"]
|
||||
|
||||
## ⚠️ 仅在需要 shell 特性时使用
|
||||
|
||||
CMD ["sh", "-c", "echo $PATH && python app.py"]
|
||||
```
|
||||
|
||||
#### 2. 确保应用在前台运行
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ✅ 前台运行
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
CMD ["apache2ctl", "-D", "FOREGROUND"]
|
||||
CMD ["java", "-jar", "app.jar"]
|
||||
|
||||
## ❌ 不要使用后台服务命令
|
||||
|
||||
CMD service nginx start
|
||||
CMD systemctl start nginx
|
||||
```
|
||||
|
||||
#### 3. 使用双引号
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ✅ 正确:双引号
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
|
||||
## ❌ 错误:单引号(JSON 不支持)
|
||||
|
||||
CMD ['node', 'server.js']
|
||||
```
|
||||
|
||||
#### 4. 配合 ENTRYPOINT 使用
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 用于可配置参数的场景
|
||||
|
||||
ENTRYPOINT ["python", "app.py"]
|
||||
CMD ["--port", "8080"]
|
||||
|
||||
## 运行时可以覆盖端口
|
||||
|
||||
$ docker run myapp --port 9000
|
||||
```
|
||||
|
||||
@@ -229,11 +274,15 @@ CMD ["echo", "second"] # 只有这个生效
|
||||
|
||||
#### Q: 如何在 CMD 中使用环境变量?
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 方法1:使用 shell 格式
|
||||
|
||||
CMD echo "Port is $PORT"
|
||||
|
||||
## 方法2:显式使用 sh -c
|
||||
|
||||
CMD ["sh", "-c", "echo Port is $PORT"]
|
||||
```
|
||||
|
||||
@@ -243,9 +292,11 @@ CMD ["sh", "-c", "echo Port is $PORT"]
|
||||
|
||||
```docker
|
||||
## ❌ 信号无法传递
|
||||
|
||||
CMD python app.py
|
||||
|
||||
## ✅ 信号正确传递
|
||||
|
||||
CMD ["python", "app.py"]
|
||||
```
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
### 基本语法
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
COPY [选项] <源路径>... <目标路径>
|
||||
COPY [选项] ["<源路径1>", "<源路径2>", ... "<目标路径>"]
|
||||
@@ -15,29 +17,40 @@ COPY [选项] ["<源路径1>", "<源路径2>", ... "<目标路径>"]
|
||||
|
||||
#### 复制单个文件
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 复制文件到指定目录
|
||||
|
||||
COPY package.json /app/
|
||||
|
||||
## 复制文件并重命名
|
||||
|
||||
COPY config.json /app/settings.json
|
||||
```
|
||||
|
||||
#### 复制多个文件
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 复制多个指定文件
|
||||
|
||||
COPY package.json package-lock.json /app/
|
||||
|
||||
## 使用通配符
|
||||
|
||||
COPY *.json /app/
|
||||
COPY src/*.js /app/src/
|
||||
```
|
||||
|
||||
#### 复制目录
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 复制整个目录的内容(不是目录本身)
|
||||
|
||||
COPY src/ /app/src/
|
||||
```
|
||||
|
||||
@@ -75,12 +88,16 @@ COPY app[0-9].js /app/ # app0.js ~ app9.js
|
||||
|
||||
#### 绝对路径
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
COPY app.js /usr/src/app/
|
||||
```
|
||||
|
||||
#### 相对路径(基于 WORKDIR)
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
WORKDIR /app
|
||||
COPY package.json ./ # 复制到 /app/package.json
|
||||
@@ -93,6 +110,7 @@ COPY src/ ./src/ # 复制到 /app/src/
|
||||
|
||||
```docker
|
||||
## /app/config/ 不存在也会自动创建
|
||||
|
||||
COPY settings.json /app/config/
|
||||
```
|
||||
|
||||
@@ -104,12 +122,15 @@ COPY settings.json /app/config/
|
||||
|
||||
```docker
|
||||
## 使用用户名和组名
|
||||
|
||||
COPY --chown=node:node package.json /app/
|
||||
|
||||
## 使用 UID 和 GID
|
||||
|
||||
COPY --chown=1000:1000 . /app/
|
||||
|
||||
## 只指定用户
|
||||
|
||||
COPY --chown=node . /app/
|
||||
```
|
||||
|
||||
@@ -127,6 +148,7 @@ COPY 会保留源文件的元数据:
|
||||
|
||||
```docker
|
||||
## start.sh 的可执行权限会被保留
|
||||
|
||||
COPY start.sh /app/
|
||||
```
|
||||
|
||||
@@ -143,10 +165,12 @@ COPY start.sh /app/
|
||||
|
||||
```docker
|
||||
## 推荐:使用 COPY
|
||||
|
||||
COPY app.tar.gz /app/
|
||||
RUN tar -xzf /app/app.tar.gz
|
||||
|
||||
## ADD 会自动解压(行为不明显,不推荐)
|
||||
|
||||
ADD app.tar.gz /app/
|
||||
```
|
||||
|
||||
@@ -158,8 +182,11 @@ ADD app.tar.gz /app/
|
||||
|
||||
#### 从其他构建阶段复制
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 构建阶段
|
||||
|
||||
FROM node:20 AS builder
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
@@ -168,14 +195,18 @@ COPY . .
|
||||
RUN npm run build
|
||||
|
||||
## 生产阶段
|
||||
|
||||
FROM nginx:alpine
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
```
|
||||
|
||||
#### 使用 --link 优化缓存(BuildKit)
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 使用 --link 后,文件以独立层添加,不依赖前序指令
|
||||
|
||||
COPY --link --from=builder /app/dist /usr/share/nginx/html
|
||||
```
|
||||
|
||||
@@ -192,6 +223,7 @@ COPY --link --from=builder /app/dist /usr/share/nginx/html
|
||||
|
||||
```gitignore
|
||||
## .dockerignore
|
||||
|
||||
node_modules
|
||||
.git
|
||||
.env
|
||||
@@ -211,33 +243,47 @@ Dockerfile
|
||||
|
||||
#### 1. 利用缓存,先复制依赖文件
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ✅ 好:先复制依赖定义,再安装,最后复制代码
|
||||
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm install
|
||||
COPY . .
|
||||
|
||||
## ❌ 差:一次性复制所有文件,代码变更会导致重新 npm install
|
||||
|
||||
COPY . .
|
||||
RUN npm install
|
||||
```
|
||||
|
||||
#### 2. 使用 .dockerignore
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 确保 node_modules 不被复制
|
||||
|
||||
COPY . .
|
||||
## .dockerignore 中应包含 node_modules
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```
|
||||
|
||||
#### 3. 明确复制路径
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ✅ 好:明确的路径
|
||||
|
||||
COPY src/ /app/src/
|
||||
COPY package.json /app/
|
||||
|
||||
## ❌ 差:过于宽泛
|
||||
|
||||
COPY . .
|
||||
```
|
||||
|
||||
|
||||
@@ -12,14 +12,16 @@
|
||||
|
||||
| 格式 | 语法 | 推荐程度 |
|
||||
|------|------|---------|
|
||||
| **exec 格式** | `ENTRYPOINT ["可执行文件", "参数1"]` | ✅ **推荐** |
|
||||
| **exec 格式**| `ENTRYPOINT ["可执行文件", "参数1"]` | ✅**推荐** |
|
||||
| **shell 格式** | `ENTRYPOINT 命令 参数` | ⚠️ 不推荐 |
|
||||
|
||||
```docker
|
||||
## exec 格式(推荐)
|
||||
|
||||
ENTRYPOINT ["nginx", "-g", "daemon off;"]
|
||||
|
||||
## shell 格式(不推荐)
|
||||
|
||||
ENTRYPOINT nginx -g "daemon off;"
|
||||
```
|
||||
|
||||
@@ -38,8 +40,11 @@ ENTRYPOINT nginx -g "daemon off;"
|
||||
|
||||
#### 行为对比
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 只用 CMD
|
||||
|
||||
CMD ["curl", "-s", "http://example.com"]
|
||||
```
|
||||
|
||||
@@ -51,6 +56,7 @@ $ docker run myimage curl -v ... # curl -v ...(完全替换)
|
||||
|
||||
```docker
|
||||
## 只用 ENTRYPOINT
|
||||
|
||||
ENTRYPOINT ["curl", "-s"]
|
||||
```
|
||||
|
||||
@@ -61,6 +67,7 @@ $ docker run myimage http://example.com # curl -s http://example.com ✓
|
||||
|
||||
```docker
|
||||
## ENTRYPOINT + CMD 组合(推荐)
|
||||
|
||||
ENTRYPOINT ["curl", "-s"]
|
||||
CMD ["http://example.com"]
|
||||
```
|
||||
@@ -81,6 +88,8 @@ $ docker run myimage -v http://other.com # curl -s -v http://other.com ✓
|
||||
|
||||
#### 使用 CMD 的问题
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
FROM ubuntu:24.04
|
||||
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
|
||||
@@ -94,10 +103,15 @@ $ docker run myip # ✓ 正常工作
|
||||
$ docker run myip -i # ✗ 错误!
|
||||
exec: "-i": executable file not found
|
||||
## -i 替换了整个 CMD,被当作可执行文件
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```
|
||||
|
||||
#### 使用 ENTRYPOINT 解决
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
FROM ubuntu:24.04
|
||||
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
|
||||
@@ -116,6 +130,8 @@ HTTP/1.1 200 OK
|
||||
|
||||
#### 交互图示
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```
|
||||
ENTRYPOINT ["curl", "-s", "http://myip.ipip.net"]
|
||||
│
|
||||
@@ -137,6 +153,8 @@ curl -s http://myip.ipip.net -i
|
||||
|
||||
#### 实现方式
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
FROM redis:7-alpine
|
||||
COPY docker-entrypoint.sh /usr/local/bin/
|
||||
@@ -151,20 +169,25 @@ CMD ["redis-server"]
|
||||
set -e
|
||||
|
||||
## 准备工作
|
||||
|
||||
echo "Initializing..."
|
||||
|
||||
## 如果第一个参数是 redis-server,以 redis 用户运行
|
||||
|
||||
if [ "$1" = 'redis-server' ]; then
|
||||
chown -R redis:redis /data
|
||||
exec gosu redis "$@"
|
||||
fi
|
||||
|
||||
## 其他命令直接执行
|
||||
|
||||
exec "$@"
|
||||
```
|
||||
|
||||
#### 工作流程
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```
|
||||
docker run redis docker run redis bash
|
||||
│ │
|
||||
@@ -187,6 +210,8 @@ docker-entrypoint.sh redis-server docker-entrypoint.sh bash
|
||||
|
||||
### 场景三:带参数的应用
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
FROM python:3.12-slim
|
||||
WORKDIR /app
|
||||
@@ -199,16 +224,22 @@ CMD ["--host", "0.0.0.0", "--port", "8080"]
|
||||
|
||||
```bash
|
||||
## 使用默认参数
|
||||
|
||||
$ docker run myapp
|
||||
## 执行: python app.py --host 0.0.0.0 --port 8080
|
||||
|
||||
## 覆盖参数
|
||||
|
||||
$ docker run myapp --host 0.0.0.0 --port 9000
|
||||
## 执行: python app.py --host 0.0.0.0 --port 9000
|
||||
|
||||
## 完全不同的参数
|
||||
|
||||
$ docker run myapp --help
|
||||
## 执行: python app.py --help
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
@@ -219,12 +250,15 @@ $ docker run myapp --help
|
||||
|
||||
```bash
|
||||
## 正常运行
|
||||
|
||||
$ docker run myimage
|
||||
|
||||
## 覆盖 ENTRYPOINT 进入 shell 调试
|
||||
|
||||
$ docker run --entrypoint /bin/sh myimage
|
||||
|
||||
## 覆盖 ENTRYPOINT 并传入参数
|
||||
|
||||
$ docker run --entrypoint /bin/cat myimage /etc/os-release
|
||||
```
|
||||
|
||||
@@ -248,16 +282,22 @@ $ docker run --entrypoint /bin/cat myimage /etc/os-release
|
||||
|
||||
#### 1. 使用 exec 格式
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ✅ 推荐
|
||||
|
||||
ENTRYPOINT ["python", "app.py"]
|
||||
|
||||
## ❌ 避免 shell 格式
|
||||
|
||||
ENTRYPOINT python app.py
|
||||
```
|
||||
|
||||
#### 2. 提供有意义的默认参数
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
ENTRYPOINT ["nginx"]
|
||||
CMD ["-g", "daemon off;"]
|
||||
@@ -265,11 +305,14 @@ CMD ["-g", "daemon off;"]
|
||||
|
||||
#### 3. 入口脚本使用 exec
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
## 准备工作...
|
||||
|
||||
## 使用 exec 替换当前进程
|
||||
|
||||
exec "$@"
|
||||
```
|
||||
|
||||
@@ -282,10 +325,12 @@ exec "$@"
|
||||
trap 'kill -TERM $PID' TERM INT
|
||||
|
||||
## 启动应用
|
||||
|
||||
app "$@" &
|
||||
PID=$!
|
||||
|
||||
## 等待应用退出
|
||||
|
||||
wait $PID
|
||||
```
|
||||
|
||||
|
||||
@@ -2,11 +2,15 @@
|
||||
|
||||
### 基本语法
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 格式一:单个变量
|
||||
|
||||
ENV <key> <value>
|
||||
|
||||
## 格式二:多个变量(推荐)
|
||||
|
||||
ENV <key1>=<value1> <key2>=<value2> ...
|
||||
```
|
||||
|
||||
@@ -16,6 +20,8 @@ ENV <key1>=<value1> <key2>=<value2> ...
|
||||
|
||||
#### 设置单个变量
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
ENV NODE_VERSION 20.10.0
|
||||
ENV APP_ENV production
|
||||
@@ -23,6 +29,8 @@ ENV APP_ENV production
|
||||
|
||||
#### 设置多个变量
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
ENV NODE_VERSION=20.10.0 \
|
||||
APP_ENV=production \
|
||||
@@ -37,23 +45,30 @@ ENV NODE_VERSION=20.10.0 \
|
||||
|
||||
#### 1. 后续指令中使用
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
ENV NODE_VERSION=20.10.0
|
||||
|
||||
## 在 RUN 中使用
|
||||
|
||||
RUN curl -fsSL https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz \
|
||||
| tar -xJ -C /usr/local --strip-components=1
|
||||
|
||||
## 在 WORKDIR 中使用
|
||||
|
||||
ENV APP_HOME=/app
|
||||
WORKDIR $APP_HOME
|
||||
|
||||
## 在 COPY 中使用
|
||||
|
||||
COPY . $APP_HOME
|
||||
```
|
||||
|
||||
#### 2. 容器运行时使用
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
ENV DATABASE_URL=postgres://localhost/mydb
|
||||
```
|
||||
@@ -97,19 +112,25 @@ const dbUrl = process.env.DATABASE_URL;
|
||||
|
||||
```bash
|
||||
## 覆盖单个变量
|
||||
|
||||
$ docker run -e APP_ENV=development myimage
|
||||
|
||||
## 覆盖多个变量
|
||||
|
||||
$ docker run -e APP_ENV=development -e DEBUG=true myimage
|
||||
|
||||
## 从环境变量文件读取
|
||||
|
||||
$ docker run --env-file .env myimage
|
||||
```
|
||||
|
||||
#### .env 文件格式
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
## .env
|
||||
|
||||
APP_ENV=development
|
||||
DEBUG=true
|
||||
DATABASE_URL=postgres://localhost/mydb
|
||||
@@ -128,19 +149,25 @@ DATABASE_URL=postgres://localhost/mydb
|
||||
|
||||
#### 组合使用
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ARG 接收构建时参数
|
||||
|
||||
ARG NODE_VERSION=20
|
||||
|
||||
## ENV 保存到运行时
|
||||
|
||||
ENV NODE_VERSION=$NODE_VERSION
|
||||
|
||||
## 后续指令使用
|
||||
|
||||
RUN curl -fsSL https://nodejs.org/dist/v${NODE_VERSION}/...
|
||||
```
|
||||
|
||||
```bash
|
||||
## 构建时指定版本
|
||||
|
||||
$ docker build --build-arg NODE_VERSION=18 -t myapp .
|
||||
```
|
||||
|
||||
@@ -150,8 +177,11 @@ $ docker build --build-arg NODE_VERSION=18 -t myapp .
|
||||
|
||||
#### 1. 统一管理版本号
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ✅ 好:版本集中管理
|
||||
|
||||
ENV NGINX_VERSION=1.25.0 \
|
||||
NODE_VERSION=20.10.0 \
|
||||
PYTHON_VERSION=3.12.0
|
||||
@@ -159,21 +189,31 @@ ENV NGINX_VERSION=1.25.0 \
|
||||
RUN apt-get install nginx=${NGINX_VERSION}
|
||||
|
||||
## ❌ 差:版本分散在各处
|
||||
|
||||
RUN apt-get install nginx=1.25.0
|
||||
```
|
||||
|
||||
#### 2. 不要存储敏感信息
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ❌ 错误:密码写入镜像
|
||||
|
||||
ENV DB_PASSWORD=secret123
|
||||
|
||||
## ✅ 正确:运行时传入
|
||||
|
||||
## docker run -e DB_PASSWORD=xxx myimage
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```
|
||||
|
||||
#### 3. 为应用提供合理默认值
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
ENV APP_ENV=production \
|
||||
APP_PORT=8080 \
|
||||
@@ -182,12 +222,16 @@ ENV APP_ENV=production \
|
||||
|
||||
#### 4. 使用有意义的变量名
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ✅ 好:清晰的命名
|
||||
|
||||
ENV REDIS_HOST=localhost \
|
||||
REDIS_PORT=6379
|
||||
|
||||
## ❌ 差:模糊的命名
|
||||
|
||||
ENV HOST=localhost \
|
||||
PORT=6379
|
||||
```
|
||||
@@ -202,14 +246,18 @@ exec 格式不会自动展开环境变量:
|
||||
|
||||
```docker
|
||||
## ❌ 不会展开 $PORT
|
||||
|
||||
CMD ["python", "app.py", "--port", "$PORT"]
|
||||
|
||||
## ✅ 使用 shell 格式或显式调用 sh
|
||||
|
||||
CMD ["sh", "-c", "python app.py --port $PORT"]
|
||||
```
|
||||
|
||||
#### Q: 如何查看容器的环境变量
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
$ docker inspect mycontainer --format '{{json .Config.Env}}'
|
||||
$ docker exec mycontainer env
|
||||
@@ -217,13 +265,17 @@ $ docker exec mycontainer env
|
||||
|
||||
#### Q: 多行 ENV 还是多个 ENV
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ✅ 推荐:减少层数
|
||||
|
||||
ENV VAR1=value1 \
|
||||
VAR2=value2 \
|
||||
VAR3=value3
|
||||
|
||||
## ⚠️ 多个 ENV 会创建多层
|
||||
|
||||
ENV VAR1=value1
|
||||
ENV VAR2=value2
|
||||
ENV VAR3=value3
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
### 基本语法
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
EXPOSE <端口> [<端口>/<协议>...]
|
||||
```
|
||||
@@ -12,14 +14,19 @@ EXPOSE <端口> [<端口>/<协议>...]
|
||||
|
||||
### 基本用法
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 声明单个端口
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
## 声明多个端口
|
||||
|
||||
EXPOSE 80 443
|
||||
|
||||
## 声明 TCP 和 UDP 端口
|
||||
|
||||
EXPOSE 80/tcp
|
||||
EXPOSE 53/udp
|
||||
```
|
||||
@@ -34,11 +41,13 @@ EXPOSE 53/udp
|
||||
|
||||
```docker
|
||||
## 使用者一看就知道这是 web 应用
|
||||
|
||||
EXPOSE 80 443
|
||||
```
|
||||
|
||||
```bash
|
||||
## 查看镜像暴露的端口
|
||||
|
||||
$ docker inspect nginx --format '{{.Config.ExposedPorts}}'
|
||||
map[80/tcp:{}]
|
||||
```
|
||||
@@ -49,6 +58,7 @@ map[80/tcp:{}]
|
||||
|
||||
```docker
|
||||
## Dockerfile
|
||||
|
||||
EXPOSE 80
|
||||
```
|
||||
|
||||
@@ -87,14 +97,21 @@ $ docker port $(docker ps -q)
|
||||
|
||||
#### 没有 EXPOSE 也能 -p
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 即使没有 EXPOSE,也可以使用 -p
|
||||
|
||||
FROM nginx
|
||||
## 没有 EXPOSE
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```
|
||||
|
||||
```bash
|
||||
## 仍然可以映射端口
|
||||
|
||||
$ docker run -p 8080:80 mynginx
|
||||
```
|
||||
|
||||
@@ -104,8 +121,11 @@ $ docker run -p 8080:80 mynginx
|
||||
|
||||
#### 误解:EXPOSE 会打开端口
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ❌ 错误理解:这不会让容器可从外部访问
|
||||
|
||||
EXPOSE 80
|
||||
```
|
||||
|
||||
@@ -118,14 +138,18 @@ EXPOSE 只是元数据声明。容器是否实际监听该端口,取决于容
|
||||
|
||||
#### 正确理解
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## Dockerfile
|
||||
|
||||
FROM nginx
|
||||
EXPOSE 80 # 1. 声明:这个容器会在 80 端口提供服务
|
||||
```
|
||||
|
||||
```bash
|
||||
## 运行:需要 -p 才能从外部访问
|
||||
|
||||
$ docker run -p 8080:80 nginx # 2. 映射:宿主机 8080 → 容器 80
|
||||
```
|
||||
|
||||
@@ -135,42 +159,56 @@ $ docker run -p 8080:80 nginx # 2. 映射:宿主机 8080 → 容器 80
|
||||
|
||||
#### 1. 总是声明应用使用的端口
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## Web 服务
|
||||
|
||||
FROM nginx
|
||||
EXPOSE 80 443
|
||||
|
||||
## 数据库
|
||||
|
||||
FROM postgres
|
||||
EXPOSE 5432
|
||||
|
||||
## Redis
|
||||
|
||||
FROM redis
|
||||
EXPOSE 6379
|
||||
```
|
||||
|
||||
#### 2. 使用明确的协议
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 默认是 TCP
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
## 明确指定 UDP
|
||||
|
||||
EXPOSE 53/udp
|
||||
|
||||
## 同时支持 TCP 和 UDP
|
||||
|
||||
EXPOSE 53/tcp 53/udp
|
||||
```
|
||||
|
||||
#### 3. 与应用实际端口保持一致
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ✅ 好:EXPOSE 与应用端口一致
|
||||
|
||||
ENV PORT=3000
|
||||
EXPOSE 3000
|
||||
CMD ["node", "server.js"]
|
||||
|
||||
## ❌ 差:EXPOSE 与应用端口不一致(误导)
|
||||
|
||||
EXPOSE 80
|
||||
CMD ["node", "server.js"] # 实际监听 3000
|
||||
```
|
||||
@@ -179,6 +217,8 @@ CMD ["node", "server.js"] # 实际监听 3000
|
||||
|
||||
### 使用环境变量
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
ARG PORT=80
|
||||
EXPOSE $PORT
|
||||
@@ -188,6 +228,8 @@ EXPOSE $PORT
|
||||
|
||||
### 在 Compose 中
|
||||
|
||||
在 Compose 中 配置如下:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
web:
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
### 基本语法
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
HEALTHCHECK [选项] CMD <命令>
|
||||
HEALTHCHECK NONE
|
||||
@@ -36,6 +38,8 @@ Starting ──成功──> Healthy ──失败N次──> Unhealthy
|
||||
|
||||
#### Web 服务检查
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
FROM nginx
|
||||
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
|
||||
@@ -80,24 +84,32 @@ HEALTHCHECK NONE
|
||||
|
||||
```docker
|
||||
## 使用 curl
|
||||
|
||||
HEALTHCHECK CMD curl -f http://localhost/ || exit 1
|
||||
|
||||
## 使用 wget (Alpine 默认包含)
|
||||
## 使用 wget(Alpine 默认包含)
|
||||
|
||||
HEALTHCHECK CMD wget -q --spider http://localhost/ || exit 1
|
||||
```
|
||||
|
||||
#### 数据库
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## MySQL
|
||||
|
||||
HEALTHCHECK CMD mysqladmin ping -h localhost || exit 1
|
||||
|
||||
## Redis
|
||||
|
||||
HEALTHCHECK CMD redis-cli ping || exit 1
|
||||
```
|
||||
|
||||
#### 自定义脚本
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
COPY healthcheck.sh /usr/local/bin/
|
||||
HEALTHCHECK CMD ["healthcheck.sh"]
|
||||
@@ -139,14 +151,18 @@ services:
|
||||
|
||||
### 查看健康状态
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
## 查看容器状态(包含健康信息)
|
||||
|
||||
$ docker ps
|
||||
CONTAINER ID STATUS
|
||||
abc123 Up 1 minute (healthy)
|
||||
def456 Up 2 minutes (unhealthy)
|
||||
|
||||
## 查看详细健康日志
|
||||
|
||||
$ docker inspect --format '{{json .State.Health}}' mycontainer | jq
|
||||
{
|
||||
"Status": "healthy",
|
||||
@@ -180,6 +196,7 @@ $ docker inspect --format '{{json .State.Health}}' mycontainer | jq
|
||||
|
||||
```docker
|
||||
## 给应用 1 分钟启动时间
|
||||
|
||||
HEALTHCHECK --start-period=60s CMD curl -f http://localhost/ || exit 1
|
||||
```
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
### 基本语法
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
LABEL <key>=<value> <key>=<value> ...
|
||||
```
|
||||
@@ -23,6 +25,8 @@ LABEL <key>=<value> <key>=<value> ...
|
||||
|
||||
#### 定义单个标签
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
LABEL version="1.0"
|
||||
LABEL description="这是一个 Web 应用服务器"
|
||||
@@ -30,6 +34,8 @@ LABEL description="这是一个 Web 应用服务器"
|
||||
|
||||
#### 定义多个标签(推荐)
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
LABEL maintainer="user@example.com" \
|
||||
version="1.2.0" \
|
||||
@@ -41,7 +47,7 @@ LABEL maintainer="user@example.com" \
|
||||
|
||||
---
|
||||
|
||||
### 常用标签规范 (OCI Annotations)
|
||||
### 常用标签规范(OCI Annotations)
|
||||
|
||||
为了标准和互操作性,推荐使用 [OCI Image Format Specification](https://github.com/opencontainers/image-spec/blob/main/annotations.md#pre-defined-annotation-keys) 定义的标准标签:
|
||||
|
||||
@@ -59,6 +65,8 @@ LABEL maintainer="user@example.com" \
|
||||
|
||||
#### 示例
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
LABEL org.opencontainers.image.authors="yeasy" \
|
||||
org.opencontainers.image.documentation="https://yeasy.gitbooks.io" \
|
||||
@@ -74,6 +82,7 @@ LABEL org.opencontainers.image.authors="yeasy" \
|
||||
|
||||
```docker
|
||||
## ❌ 已弃用
|
||||
|
||||
MAINTAINER user@example.com
|
||||
```
|
||||
|
||||
@@ -81,8 +90,10 @@ MAINTAINER user@example.com
|
||||
|
||||
```docker
|
||||
## ✅ 推荐
|
||||
|
||||
LABEL maintainer="user@example.com"
|
||||
## 或
|
||||
|
||||
LABEL org.opencontainers.image.authors="user@example.com"
|
||||
```
|
||||
|
||||
@@ -130,9 +141,11 @@ $ docker inspect nginx --format '{{json .Config.Labels}}' | jq
|
||||
|
||||
```bash
|
||||
## 列出作者是 yeasy 的所有镜像
|
||||
|
||||
$ docker images --filter "label=org.opencontainers.image.authors=yeasy"
|
||||
|
||||
## 删除所有带有特定标签的镜像
|
||||
|
||||
$ docker rmi $(docker images -q --filter "label=stage=builder")
|
||||
```
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
### 基本语法
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
ONBUILD <其它指令>
|
||||
```
|
||||
@@ -34,6 +36,7 @@ FROM node:20-alpine
|
||||
WORKDIR /app
|
||||
|
||||
## 这些指令将在子镜像构建时执行
|
||||
|
||||
ONBUILD COPY package*.json ./
|
||||
ONBUILD RUN npm install
|
||||
ONBUILD COPY . .
|
||||
@@ -46,13 +49,19 @@ CMD ["npm", "start"]
|
||||
```docker
|
||||
FROM my-node-base
|
||||
## 只需要一行!
|
||||
|
||||
## 构建时会自动执行 COPY 和 RUN
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 执行机制
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```
|
||||
基础镜像构建:
|
||||
Dockerfile (含 ONBUILD) ──build──> 基础镜像 (记录了 ONBUILD 触发器)
|
||||
@@ -68,24 +77,33 @@ FROM 基础镜像 ──build──> 读取基础镜像触发器 ──> 执行
|
||||
|
||||
#### 1. 自动处理依赖安装
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## Python 基础镜像
|
||||
|
||||
ONBUILD COPY requirements.txt ./
|
||||
ONBUILD RUN pip install -r requirements.txt
|
||||
```
|
||||
|
||||
#### 2. 自动编译代码
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## Go 基础镜像
|
||||
|
||||
ONBUILD COPY . .
|
||||
ONBUILD RUN go build -o app main.go
|
||||
```
|
||||
|
||||
#### 3. 处理静态资源
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## Nginx 静态网站基础镜像
|
||||
|
||||
ONBUILD COPY dist/ /usr/share/nginx/html/
|
||||
```
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
### 基本语法
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
RUN <command>
|
||||
RUN ["executable", "param1", "param2"]
|
||||
@@ -15,6 +17,8 @@ RUN ["executable", "param1", "param2"]
|
||||
|
||||
#### 1. Shell 格式
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
RUN apt-get update
|
||||
```
|
||||
@@ -28,6 +32,8 @@ RUN apt-get update
|
||||
|
||||
#### 2. Exec 格式
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
RUN ["apt-get", "update"]
|
||||
```
|
||||
@@ -82,6 +88,7 @@ RUN apt-get update && \
|
||||
|
||||
```docker
|
||||
## 如果下载失败,gzip 可能会报错,但如果不影响后续,构建可能继续
|
||||
|
||||
RUN wget http://error-url | gzip -d > file
|
||||
```
|
||||
|
||||
@@ -98,6 +105,8 @@ RUN wget http://url | gzip -d > file
|
||||
|
||||
#### Q: 为什么 `RUN cd /app` 不生效?
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
RUN cd /app
|
||||
RUN touch hello.txt
|
||||
@@ -116,6 +125,8 @@ RUN touch hello.txt
|
||||
|
||||
#### Q: 环境变量不生效?
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
RUN export MY_VAR=hello
|
||||
RUN echo $MY_VAR
|
||||
@@ -142,6 +153,7 @@ BuildKit 支持在 `RUN` 指令中使用 `--mount` 挂载缓存,加速构建
|
||||
|
||||
```docker
|
||||
## 缓存 apt 包
|
||||
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||
apt-get update && apt-get install -y gcc
|
||||
@@ -149,6 +161,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
|
||||
```docker
|
||||
## 缓存 Go 模块
|
||||
|
||||
RUN --mount=type=cache,target=/go/pkg/mod \
|
||||
go build -o app
|
||||
```
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
### 基本语法
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
SHELL ["executable", "parameters"]
|
||||
```
|
||||
@@ -24,18 +26,21 @@ SHELL ["executable", "parameters"]
|
||||
FROM ubuntu:24.04
|
||||
|
||||
## 切换到 bash
|
||||
|
||||
SHELL ["/bin/bash", "-c"]
|
||||
|
||||
## 现在可以使用 bash 特性了
|
||||
|
||||
RUN echo {a..z}
|
||||
```
|
||||
|
||||
#### 2. 增强错误处理 (pipefail)
|
||||
#### 2. 增强错误处理(pipefail)
|
||||
|
||||
默认情况下,管道命令 `cmd1 | cmd2` 只要 `cmd2` 成功,整个指令就视为成功。这可能掩盖构建错误。
|
||||
|
||||
```docker
|
||||
## ❌ 这里的 wget 失败了,但构建继续(因为 tar 成功了)
|
||||
|
||||
RUN wget -O - https://invalid-url | tar xz
|
||||
```
|
||||
|
||||
@@ -43,9 +48,11 @@ RUN wget -O - https://invalid-url | tar xz
|
||||
|
||||
```docker
|
||||
## ✅ 启用 pipefail
|
||||
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
|
||||
## 如果 wget 失败,整个 RUN 就会失败
|
||||
|
||||
RUN wget -O - https://invalid-url | tar xz
|
||||
```
|
||||
|
||||
@@ -57,13 +64,16 @@ RUN wget -O - https://invalid-url | tar xz
|
||||
FROM mcr.microsoft.com/windows/servercore:ltsc2022
|
||||
|
||||
## 默认是 cmd
|
||||
|
||||
RUN echo Default shell is cmd
|
||||
|
||||
## 切换到 powershell
|
||||
|
||||
SHELL ["powershell", "-command"]
|
||||
RUN Write-Host "Hello from PowerShell"
|
||||
|
||||
## 切回 cmd
|
||||
|
||||
SHELL ["cmd", "/S", "/C"]
|
||||
```
|
||||
|
||||
@@ -77,14 +87,17 @@ SHELL ["cmd", "/S", "/C"]
|
||||
FROM ubuntu:24.04
|
||||
|
||||
## 使用默认 sh
|
||||
|
||||
RUN echo "Using sh"
|
||||
|
||||
SHELL ["/bin/bash", "-c"]
|
||||
## 使用 bash
|
||||
|
||||
RUN echo "Using bash"
|
||||
|
||||
SHELL ["/bin/sh", "-c"]
|
||||
## 回到 sh
|
||||
|
||||
RUN echo "Using sh again"
|
||||
```
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
### 基本语法
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
USER <用户名>[:<用户组>]
|
||||
USER <UID>[:<GID>]
|
||||
@@ -37,28 +39,37 @@ root 用户运行的风险:
|
||||
|
||||
#### 创建并切换用户
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
FROM node:20-alpine
|
||||
|
||||
## 1. 创建用户和组
|
||||
|
||||
RUN addgroup -g 1001 appgroup && \
|
||||
adduser -u 1001 -G appgroup -D appuser
|
||||
|
||||
## 2. 设置目录权限
|
||||
|
||||
WORKDIR /app
|
||||
COPY --chown=appuser:appgroup . .
|
||||
|
||||
## 3. 切换用户
|
||||
|
||||
USER appuser
|
||||
|
||||
## 4. 后续命令以 appuser 身份运行
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
```
|
||||
|
||||
#### 使用 UID/GID
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 也可以使用数字
|
||||
|
||||
USER 1001:1001
|
||||
```
|
||||
|
||||
@@ -70,10 +81,12 @@ USER 1001:1001
|
||||
|
||||
```docker
|
||||
## ❌ 错误:用户不存在
|
||||
|
||||
USER nonexistent
|
||||
## Error: unable to find user nonexistent
|
||||
|
||||
## ✅ 正确:先创建用户
|
||||
|
||||
RUN useradd -r -s /bin/false appuser
|
||||
USER appuser
|
||||
```
|
||||
@@ -114,9 +127,11 @@ RUN addgroup -g 1001 -S appgroup && \
|
||||
FROM debian:bookworm
|
||||
|
||||
## 创建用户
|
||||
|
||||
RUN groupadd -r redis && useradd -r -g redis redis
|
||||
|
||||
## 安装 gosu
|
||||
|
||||
RUN apt-get update && apt-get install -y gosu && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY docker-entrypoint.sh /usr/local/bin/
|
||||
@@ -131,9 +146,11 @@ CMD ["redis-server"]
|
||||
set -e
|
||||
|
||||
## 以 root 执行初始化
|
||||
|
||||
chown -R redis:redis /data
|
||||
|
||||
## 用 gosu 切换到 redis 用户运行服务
|
||||
|
||||
exec gosu redis "$@"
|
||||
```
|
||||
|
||||
@@ -154,9 +171,11 @@ exec gosu redis "$@"
|
||||
|
||||
```bash
|
||||
## 以指定用户运行
|
||||
|
||||
$ docker run -u 1001:1001 myimage
|
||||
|
||||
## 以 root 运行(调试时)
|
||||
|
||||
$ docker run -u root myimage
|
||||
```
|
||||
|
||||
@@ -170,15 +189,19 @@ $ docker run -u root myimage
|
||||
FROM node:20-alpine
|
||||
|
||||
## 创建用户
|
||||
|
||||
RUN adduser -D -u 1001 appuser
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
## 方式1:使用 --chown
|
||||
|
||||
COPY --chown=appuser:appuser . .
|
||||
|
||||
## 方式2:手动 chown(减少层数)
|
||||
|
||||
## COPY . .
|
||||
|
||||
## RUN chown -R appuser:appuser /app
|
||||
|
||||
USER appuser
|
||||
@@ -191,13 +214,17 @@ CMD ["node", "server.js"]
|
||||
|
||||
#### 1. 始终使用非 root 用户
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ✅ 推荐
|
||||
|
||||
RUN adduser -D appuser
|
||||
USER appuser
|
||||
CMD ["myapp"]
|
||||
|
||||
## ❌ 避免
|
||||
|
||||
CMD ["myapp"] # 以 root 运行
|
||||
```
|
||||
|
||||
@@ -207,6 +234,7 @@ CMD ["myapp"] # 以 root 运行
|
||||
|
||||
```docker
|
||||
## 使用常见的非 root UID
|
||||
|
||||
RUN addgroup -g 1000 -S appgroup && \
|
||||
adduser -u 1000 -S -G appgroup appuser
|
||||
USER 1000:1000
|
||||
@@ -214,14 +242,18 @@ USER 1000:1000
|
||||
|
||||
#### 3. 多阶段构建中的 USER
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 构建阶段可以用 root
|
||||
|
||||
FROM node:20 AS builder
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN npm install && npm run build
|
||||
|
||||
## 生产阶段用非 root
|
||||
|
||||
FROM node:20-alpine
|
||||
RUN adduser -D appuser
|
||||
WORKDIR /app
|
||||
@@ -236,6 +268,8 @@ CMD ["node", "server.js"]
|
||||
|
||||
#### Q: 权限被拒绝
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
permission denied: '/app/data.log'
|
||||
```
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
### 基本语法
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
VOLUME ["/路径1", "/路径2"]
|
||||
VOLUME /路径
|
||||
@@ -38,6 +40,8 @@ VOLUME /路径
|
||||
|
||||
#### 定义单个卷
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
FROM mysql:8.0
|
||||
VOLUME /var/lib/mysql
|
||||
@@ -45,6 +49,8 @@ VOLUME /var/lib/mysql
|
||||
|
||||
#### 定义多个卷
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
FROM myapp
|
||||
VOLUME ["/data", "/logs", "/config"]
|
||||
@@ -67,15 +73,21 @@ local a1b2c3d4e5f6... # 自动创建的匿名卷
|
||||
|
||||
#### 2. 可被命名卷覆盖
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
## 使用命名卷替代匿名卷
|
||||
|
||||
$ docker run -v mysql_data:/var/lib/mysql mysql:8.0
|
||||
```
|
||||
|
||||
#### 3. 可被 Bind Mount 覆盖
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
## 使用宿主机目录替代
|
||||
|
||||
$ docker run -v /my/data:/var/lib/mysql mysql:8.0
|
||||
```
|
||||
|
||||
@@ -90,6 +102,7 @@ FROM ubuntu
|
||||
VOLUME /data
|
||||
|
||||
## ❌ 这个文件不会出现在镜像中!
|
||||
|
||||
RUN echo "hello" > /data/test.txt
|
||||
```
|
||||
|
||||
@@ -97,13 +110,17 @@ RUN echo "hello" > /data/test.txt
|
||||
|
||||
#### 正确做法
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
FROM ubuntu
|
||||
|
||||
## ✅ 先写入文件
|
||||
|
||||
RUN mkdir -p /data && echo "hello" > /data/test.txt
|
||||
|
||||
## 再声明 VOLUME
|
||||
|
||||
VOLUME /data
|
||||
```
|
||||
|
||||
@@ -113,6 +130,8 @@ VOLUME /data
|
||||
|
||||
#### 数据库持久化
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
FROM postgres:15
|
||||
VOLUME /var/lib/postgresql/data
|
||||
@@ -120,6 +139,8 @@ VOLUME /var/lib/postgresql/data
|
||||
|
||||
#### 日志目录
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
FROM nginx
|
||||
VOLUME /var/log/nginx
|
||||
@@ -127,6 +148,8 @@ VOLUME /var/log/nginx
|
||||
|
||||
#### 上传文件目录
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
FROM myapp
|
||||
VOLUME /app/uploads
|
||||
@@ -136,14 +159,18 @@ VOLUME /app/uploads
|
||||
|
||||
### 查看 VOLUME 定义
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
## 查看镜像定义的 VOLUME
|
||||
|
||||
$ docker inspect mysql:8.0 --format '{{json .Config.Volumes}}' | jq
|
||||
{
|
||||
"/var/lib/mysql": {}
|
||||
}
|
||||
|
||||
## 查看容器挂载的卷
|
||||
|
||||
$ docker inspect mycontainer --format '{{json .Mounts}}' | jq
|
||||
```
|
||||
|
||||
@@ -162,6 +189,8 @@ $ docker inspect mycontainer --format '{{json .Mounts}}' | jq
|
||||
|
||||
### 在 Compose 中
|
||||
|
||||
在 Compose 中 配置如下:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
db:
|
||||
@@ -182,10 +211,16 @@ volumes:
|
||||
|
||||
#### 匿名卷可能导致数据丢失
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
## 使用 --rm 运行的容器,匿名卷会在容器删除时一起删除
|
||||
|
||||
$ docker run --rm mysql:8.0
|
||||
## 容器停止后,数据丢失!
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```
|
||||
|
||||
**解决**:始终使用命名卷
|
||||
@@ -200,31 +235,42 @@ $ docker run -v mysql_data:/var/lib/mysql mysql:8.0
|
||||
|
||||
#### 1. 定义必须持久化的路径
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 数据库必须使用卷
|
||||
|
||||
FROM postgres:15
|
||||
VOLUME /var/lib/postgresql/data
|
||||
```
|
||||
|
||||
#### 2. 不要在 VOLUME 后修改目录
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ❌ 避免
|
||||
|
||||
VOLUME /app/data
|
||||
RUN cp init-data.json /app/data/
|
||||
|
||||
## ✅ 正确
|
||||
|
||||
RUN mkdir -p /app/data && cp init-data.json /app/data/
|
||||
VOLUME /app/data
|
||||
```
|
||||
|
||||
#### 3. 文档中说明 VOLUME 用途
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 持久化用户上传的文件
|
||||
|
||||
VOLUME /app/uploads
|
||||
|
||||
## 持久化数据库数据
|
||||
|
||||
VOLUME /var/lib/mysql
|
||||
```
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
### 基本语法
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
WORKDIR <工作目录路径>
|
||||
```
|
||||
@@ -12,6 +14,8 @@ WORKDIR <工作目录路径>
|
||||
|
||||
### 基本用法
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
WORKDIR /app
|
||||
|
||||
@@ -26,14 +30,19 @@ COPY . . # 复制到 /app/
|
||||
|
||||
#### 常见错误
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ❌ 错误:cd 在下一个 RUN 中无效
|
||||
|
||||
RUN cd /app
|
||||
RUN echo "hello" > world.txt # 文件在根目录!
|
||||
```
|
||||
|
||||
#### 原因分析
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```
|
||||
RUN cd /app
|
||||
↓
|
||||
@@ -49,8 +58,11 @@ RUN echo "hello" > world.txt
|
||||
|
||||
#### 正确做法
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ✅ 正确:使用 WORKDIR
|
||||
|
||||
WORKDIR /app
|
||||
RUN echo "hello" > world.txt # 创建 /app/world.txt
|
||||
```
|
||||
@@ -73,6 +85,8 @@ RUN pwd # 输出 /a/b/c
|
||||
|
||||
### 使用环境变量
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
ENV APP_HOME=/app
|
||||
WORKDIR $APP_HOME
|
||||
@@ -84,8 +98,11 @@ RUN pwd # 输出 /app
|
||||
|
||||
### 多阶段构建中的 WORKDIR
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 构建阶段
|
||||
|
||||
FROM node:20 AS builder
|
||||
WORKDIR /build
|
||||
COPY package*.json ./
|
||||
@@ -94,6 +111,7 @@ COPY . .
|
||||
RUN npm run build
|
||||
|
||||
## 生产阶段
|
||||
|
||||
FROM nginx:alpine
|
||||
WORKDIR /usr/share/nginx/html
|
||||
COPY --from=builder /build/dist .
|
||||
@@ -105,6 +123,8 @@ COPY --from=builder /build/dist .
|
||||
|
||||
#### 1. 尽早设置 WORKDIR
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
FROM node:20
|
||||
WORKDIR /app # 尽早设置
|
||||
@@ -117,33 +137,46 @@ CMD ["node", "server.js"]
|
||||
|
||||
#### 2. 使用绝对路径
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ✅ 推荐:绝对路径,意图明确
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
## ⚠️ 避免:相对路径可能造成混淆
|
||||
|
||||
WORKDIR app
|
||||
```
|
||||
|
||||
#### 3. 不要用 RUN cd
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ❌ 避免
|
||||
|
||||
RUN cd /app && echo "hello" > world.txt
|
||||
|
||||
## ✅ 推荐
|
||||
|
||||
WORKDIR /app
|
||||
RUN echo "hello" > world.txt
|
||||
```
|
||||
|
||||
#### 4. 适时重置 WORKDIR
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
WORKDIR /app
|
||||
## ... 应用相关操作 ...
|
||||
|
||||
WORKDIR /data
|
||||
## ... 数据相关操作 ...
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
## 多阶段构建
|
||||
# 多阶段构建
|
||||
|
||||
### 之前的做法
|
||||
## 之前的做法
|
||||
|
||||
在 Docker 17.05 版本之前,我们构建 Docker 镜像时,通常会采用两种方式:
|
||||
|
||||
#### 全部放入一个 Dockerfile
|
||||
### 全部放入一个 Dockerfile
|
||||
|
||||
一种方式是将所有的构建过程编包含在一个 `Dockerfile` 中,包括项目及其依赖库的编译、测试、打包等流程,这里可能会带来的一些问题:
|
||||
|
||||
@@ -51,7 +51,7 @@ CMD ["./app"]
|
||||
$ docker build -t go/helloworld:1 -f Dockerfile.one .
|
||||
```
|
||||
|
||||
#### 分散到多个 Dockerfile
|
||||
### 分散到多个 Dockerfile
|
||||
|
||||
另一种方式,就是我们事先在一个 `Dockerfile` 将项目及其依赖库编译测试打包好后,再将其拷贝到运行环境中,这种方式需要我们编写两个 `Dockerfile` 和一些编译脚本才能将其两个阶段自动整合起来,这种方式虽然可以很好地规避第一种方式存在的风险,但明显部署过程较复杂。
|
||||
|
||||
@@ -120,7 +120,7 @@ go/helloworld 2 f7cf3465432c 22 seconds ago 6.47MB
|
||||
go/helloworld 1 f55d3e16affc 2 minutes ago 295MB
|
||||
```
|
||||
|
||||
### 使用多阶段构建
|
||||
## 使用多阶段构建
|
||||
|
||||
为解决以上问题,Docker v17.05 开始支持多阶段构建 (`multistage builds`)。使用多阶段构建我们就可以很容易解决前面提到的问题,并且只需要编写一个 `Dockerfile`:
|
||||
|
||||
@@ -169,7 +169,7 @@ go/helloworld 1 f55d3e16affc 2 minutes ago 295MB
|
||||
|
||||
很明显使用多阶段构建的镜像体积小,同时也完美解决了上边提到的问题。
|
||||
|
||||
#### 只构建某一阶段的镜像
|
||||
### 只构建某一阶段的镜像
|
||||
|
||||
我们可以使用 `as` 来为某一阶段命名,例如
|
||||
|
||||
@@ -183,7 +183,7 @@ FROM golang:alpine as builder
|
||||
$ docker build --target builder -t username/imagename:tag .
|
||||
```
|
||||
|
||||
#### 构建时从其他镜像复制文件
|
||||
### 构建时从其他镜像复制文件
|
||||
|
||||
上面例子中我们使用 `COPY --from=0 /go/src/github.com/go/helloworld/app .` 从上一阶段的镜像中复制文件,我们也可以复制任意镜像中的文件。
|
||||
|
||||
|
||||
@@ -26,6 +26,9 @@ bootstrap/cache/*
|
||||
storage/
|
||||
|
||||
## 自行添加其他需要排除的文件,例如 .env.* 文件
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```
|
||||
|
||||
在 `laravel.conf` 文件中写入 nginx 配置。
|
||||
@@ -120,6 +123,8 @@ RUN set -x ; cd ${LARAVEL_PATH} \
|
||||
|
||||
### 最后一个阶段构建 NGINX 镜像
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
FROM nginx:alpine as nginx
|
||||
|
||||
|
||||
Reference in New Issue
Block a user