mirror of
https://github.com/yeasy/docker_practice.git
synced 2026-03-25 11:15:39 +00:00
Remove blank lines after code block markers
This commit is contained in:
@@ -9,7 +9,6 @@
|
||||
```bash
|
||||
docker pull [选项] [Registry地址/]仓库名[:标签]
|
||||
```
|
||||
|
||||
#### 镜像名称格式
|
||||
|
||||
Docker 镜像名称由 Registry 地址、用户名、仓库名和标签组成。其标准格式如下:
|
||||
@@ -21,7 +20,6 @@ docker.io / library / ubuntu : 24.04
|
||||
Registry地址 用户名 仓库名 标签
|
||||
(可省略) (可省略)
|
||||
```
|
||||
|
||||
| 组成部分 | 说明 | 默认值 |
|
||||
|---------|------|--------|
|
||||
| Registry 地址 | 镜像仓库地址 | `docker.io` (Docker Hub)|
|
||||
@@ -32,7 +30,6 @@ Registry地址 用户名 仓库名 标签
|
||||
#### 示例
|
||||
|
||||
```bash
|
||||
|
||||
## 完整格式
|
||||
|
||||
$ docker pull docker.io/library/ubuntu:24.04
|
||||
@@ -57,7 +54,6 @@ $ docker pull bitnami/redis:latest
|
||||
|
||||
$ docker pull ghcr.io/username/myapp:v1.0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4.1.2 下载过程解析
|
||||
@@ -74,7 +70,6 @@ Digest: sha256:4bc3ae6596938cb0d9e5ac51a1152ec9dcac2a1c50829c74abd9c4361e321b26
|
||||
Status: Downloaded newer image for ubuntu:24.04
|
||||
docker.io/library/ubuntu:24.04
|
||||
```
|
||||
|
||||
#### 输出解读
|
||||
|
||||
| 输出内容 | 说明 |
|
||||
@@ -98,7 +93,6 @@ flowchart TD
|
||||
L3 --- L2 --- L1
|
||||
end
|
||||
```
|
||||
|
||||
如果本地已有相同的层,Docker 会跳过下载,节省带宽和时间。
|
||||
|
||||
---
|
||||
@@ -120,7 +114,6 @@ flowchart TD
|
||||
```bash
|
||||
$ docker pull --platform linux/amd64 nginx
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4.1.4 拉取后运行
|
||||
@@ -128,7 +121,6 @@ $ docker pull --platform linux/amd64 nginx
|
||||
拉取镜像后,可以基于它启动容器:
|
||||
|
||||
```bash
|
||||
|
||||
## 拉取镜像
|
||||
|
||||
$ docker pull ubuntu:24.04
|
||||
@@ -141,7 +133,6 @@ PRETTY_NAME="Ubuntu 24.04 LTS"
|
||||
...
|
||||
root@e7009c6ce357:/# exit
|
||||
```
|
||||
|
||||
**参数说明**:
|
||||
|
||||
| 参数 | 说明 |
|
||||
@@ -167,7 +158,6 @@ root@e7009c6ce357:/# exit
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
配置后重启 Docker:
|
||||
|
||||
```bash
|
||||
@@ -175,7 +165,6 @@ $ sudo systemctl restart docker # Linux
|
||||
|
||||
## 或在 Docker Desktop 中重启
|
||||
```
|
||||
|
||||
详见[镜像加速器](../03_install/3.9_mirror.md)章节。
|
||||
|
||||
---
|
||||
@@ -191,7 +180,6 @@ $ docker images --digests ubuntu
|
||||
REPOSITORY TAG DIGEST IMAGE ID
|
||||
ubuntu 24.04 sha256:4bc3ae6596938cb0d9e5ac51a1152ec9dcac2a1c50829c74abd9c4361e321b26 ca2b0f26964c
|
||||
```
|
||||
|
||||
#### 使用摘要拉取
|
||||
|
||||
用摘要拉取可确保获取完全相同的镜像:
|
||||
@@ -199,7 +187,6 @@ ubuntu 24.04 sha256:4bc3ae6596938cb0d9e5ac51a1152ec9dcac2a1c50829c74abd9
|
||||
```bash
|
||||
$ docker pull ubuntu@sha256:4bc3ae6596938cb0d9e5ac51a1152ec9dcac2a1c50829c74abd9c4361e321b26
|
||||
```
|
||||
|
||||
> 笔者建议:生产环境使用摘要而非标签,因为标签可能被覆盖,摘要则是不可变的。
|
||||
|
||||
---
|
||||
@@ -219,7 +206,6 @@ $ docker pull ubuntu@sha256:4bc3ae6596938cb0d9e5ac51a1152ec9dcac2a1c50829c74abd9
|
||||
```bash
|
||||
Error: pull access denied, repository does not exist
|
||||
```
|
||||
|
||||
可能原因:
|
||||
|
||||
- 镜像名拼写错误
|
||||
@@ -229,7 +215,6 @@ Error: pull access denied, repository does not exist
|
||||
#### Q:磁盘空间不足
|
||||
|
||||
```bash
|
||||
|
||||
## 清理未使用的镜像
|
||||
|
||||
$ docker image prune
|
||||
@@ -238,5 +223,4 @@ $ docker image prune
|
||||
|
||||
$ docker system prune
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -14,7 +14,6 @@ nginx latest 05a60462f8ba 5 days ago 181MB
|
||||
ubuntu 24.04 329ed837d508 3 days ago 78MB
|
||||
ubuntu noble 329ed837d508 3 days ago 78MB
|
||||
```
|
||||
|
||||
> 💡 `docker images` 是 `docker image ls` 的简写,两者等效。
|
||||
|
||||
---
|
||||
@@ -59,7 +58,6 @@ ubuntu:24.04 nginx:latest redis:latest
|
||||
▼ │
|
||||
共享基础层 ◄───────────────────┘
|
||||
```
|
||||
|
||||
因此,`docker image ls` 中各镜像大小之和 > 实际磁盘占用。
|
||||
|
||||
#### 查看实际空间占用
|
||||
@@ -72,7 +70,6 @@ Containers 5 2 100MB 80MB (80%)
|
||||
Local Volumes 8 2 500MB 400MB (80%)
|
||||
Build Cache 0 0 0B 0B
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4.2.4 过滤镜像
|
||||
@@ -82,7 +79,6 @@ Build Cache 0 0 0B 0B
|
||||
#### 按仓库名过滤
|
||||
|
||||
```bash
|
||||
|
||||
## 列出所有 ubuntu 镜像
|
||||
|
||||
$ docker images ubuntu
|
||||
@@ -91,7 +87,6 @@ ubuntu 24.04 329ed837d508 78MB
|
||||
ubuntu noble 329ed837d508 78MB
|
||||
ubuntu 22.04 a1b2c3d4e5f6 72MB
|
||||
```
|
||||
|
||||
#### 按仓库名和标签过滤
|
||||
|
||||
```bash
|
||||
@@ -99,7 +94,6 @@ $ docker images ubuntu:24.04
|
||||
REPOSITORY TAG IMAGE ID SIZE
|
||||
ubuntu 24.04 329ed837d508 78MB
|
||||
```
|
||||
|
||||
#### 使用过滤器 --filter
|
||||
|
||||
| 过滤条件 | 说明 | 示例 |
|
||||
@@ -111,7 +105,6 @@ ubuntu 24.04 329ed837d508 78MB
|
||||
| `reference=pattern` | 按名称模式 | `-f reference='*:latest'` |
|
||||
|
||||
```bash
|
||||
|
||||
## 列出 nginx 之后创建的镜像
|
||||
|
||||
$ docker images -f since=nginx:latest
|
||||
@@ -124,7 +117,6 @@ $ docker images -f reference='*:latest'
|
||||
|
||||
$ docker images -f label=maintainer=example@email.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4.2.5 虚悬镜像
|
||||
@@ -140,7 +132,6 @@ $ docker images
|
||||
REPOSITORY TAG IMAGE ID SIZE
|
||||
<none> <none> 00285df0df87 342MB
|
||||
```
|
||||
|
||||
#### 产生原因
|
||||
|
||||
1. **镜像重新构建**:新镜像使用了旧镜像的标签,旧镜像标签被移除
|
||||
@@ -149,7 +140,6 @@ REPOSITORY TAG IMAGE ID SIZE
|
||||
#### 处理虚悬镜像
|
||||
|
||||
```bash
|
||||
|
||||
## 列出虚悬镜像
|
||||
|
||||
$ docker images -f dangling=true
|
||||
@@ -158,7 +148,6 @@ $ docker images -f dangling=true
|
||||
|
||||
$ docker image prune
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4.2.6 中间层镜像
|
||||
@@ -170,7 +159,6 @@ $ docker image prune
|
||||
```bash
|
||||
$ docker images -a
|
||||
```
|
||||
|
||||
会显示很多无标签镜像——这些是构建过程中产生的中间层,被其他镜像依赖。
|
||||
|
||||
> ⚠️ 不要删除中间层镜像。它们是其他镜像的依赖,删除会导致上层镜像无法使用。删除顶层镜像时会自动清理不再需要的中间层。
|
||||
@@ -189,11 +177,9 @@ $ docker images -q
|
||||
05a60462f8ba
|
||||
329ed837d508
|
||||
```
|
||||
|
||||
常用于配合其他命令:
|
||||
|
||||
```bash
|
||||
|
||||
## 删除所有镜像
|
||||
|
||||
$ docker rmi $(docker images -q)
|
||||
@@ -202,13 +188,11 @@ $ docker rmi $(docker images -q)
|
||||
|
||||
$ docker rmi $(docker images -q redis)
|
||||
```
|
||||
|
||||
#### 显示完整 ID
|
||||
|
||||
```bash
|
||||
$ docker images --no-trunc
|
||||
```
|
||||
|
||||
#### 显示摘要
|
||||
|
||||
```bash
|
||||
@@ -216,13 +200,11 @@ $ docker images --digests
|
||||
REPOSITORY TAG DIGEST IMAGE ID
|
||||
nginx latest sha256:b4f0e0bdeb5... e43d811ce2f4
|
||||
```
|
||||
|
||||
#### 自定义格式
|
||||
|
||||
使用 Go 模板语法自定义输出:
|
||||
|
||||
```bash
|
||||
|
||||
## 只显示 ID 和仓库名
|
||||
|
||||
$ docker images --format "{{.ID}}: {{.Repository}}"
|
||||
@@ -238,7 +220,6 @@ redis latest 183MB
|
||||
nginx latest 181MB
|
||||
ubuntu 24.04 78MB
|
||||
```
|
||||
|
||||
#### 可用模板字段
|
||||
|
||||
| 字段 | 说明 |
|
||||
@@ -256,7 +237,6 @@ ubuntu 24.04 78MB
|
||||
### 4.2.8 常用命令组合
|
||||
|
||||
```bash
|
||||
|
||||
## 列出所有镜像及其大小,按大小排序(需要系统 sort 命令)
|
||||
|
||||
$ docker images --format "{{.Size}}\t{{.Repository}}:{{.Tag}}" | sort -h
|
||||
@@ -269,5 +249,4 @@ $ docker images --format "{{.Size}}\t{{.Repository}}:{{.Tag}}" | grep -E "^[0-9]
|
||||
|
||||
$ docker images --format "{{.Repository}}:{{.Tag}}" > images.txt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
```bash
|
||||
$ docker image rm [选项] <镜像1> [<镜像2> ...]
|
||||
```
|
||||
|
||||
> 💡 `docker rmi` 是 `docker image rm` 的简写,两者等效。
|
||||
|
||||
---
|
||||
@@ -39,7 +38,6 @@ $ docker rmi 501
|
||||
Untagged: redis:alpine
|
||||
Deleted: sha256:501ad78535f0...
|
||||
```
|
||||
|
||||
#### 使用镜像名删除
|
||||
|
||||
```bash
|
||||
@@ -47,13 +45,11 @@ $ docker rmi redis:alpine
|
||||
Untagged: redis:alpine
|
||||
Deleted: sha256:501ad78535f0...
|
||||
```
|
||||
|
||||
#### 使用摘要删除
|
||||
|
||||
摘要删除最精确,适用于 CI/CD 场景:
|
||||
|
||||
```bash
|
||||
|
||||
## 查看镜像摘要
|
||||
|
||||
$ docker images --digests
|
||||
@@ -64,7 +60,6 @@ nginx latest sha256:b4f0e0bdeb5... e43d811ce2f4
|
||||
|
||||
$ docker rmi nginx@sha256:b4f0e0bdeb578043c1ea6862f0d40cc4afe32a4a582f3be235a3b164422be228
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4.3.3 理解输出信息
|
||||
@@ -81,7 +76,6 @@ Deleted: sha256:501ad78535f015d88872e13fa87a828425117e3d28075d0c117932b05bf189b7
|
||||
Deleted: sha256:96167737e29ca8e9d74982ef2a0dda76ed7b430da55e321c071f0dbff8c2899b
|
||||
Deleted: sha256:32770d1dcf835f192cafd6b9263b7b597a1778a403a109e2cc2ee866f74adf23
|
||||
```
|
||||
|
||||
#### Untagged vs Deleted
|
||||
|
||||
| 操作 | 含义 |
|
||||
@@ -114,7 +108,6 @@ flowchart TD
|
||||
Step4 -- "未使用" --> Delete["Deleted (删除该层)"]
|
||||
end
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4.3.4 批量删除
|
||||
@@ -126,7 +119,6 @@ flowchart TD
|
||||
虚悬镜像 (dangling):没有标签的镜像,通常是旧版本被新版本覆盖后产生的
|
||||
|
||||
```bash
|
||||
|
||||
## 查看虚悬镜像
|
||||
|
||||
$ docker images -f dangling=true
|
||||
@@ -139,11 +131,9 @@ $ docker image prune
|
||||
|
||||
$ docker image prune -f
|
||||
```
|
||||
|
||||
#### 删除所有未使用的镜像
|
||||
|
||||
```bash
|
||||
|
||||
## 删除所有没有被容器使用的镜像
|
||||
|
||||
$ docker image prune -a
|
||||
@@ -152,11 +142,9 @@ $ docker image prune -a
|
||||
|
||||
$ docker image prune -a --filter "until=24h"
|
||||
```
|
||||
|
||||
#### 按条件删除
|
||||
|
||||
```bash
|
||||
|
||||
## 删除所有 redis 镜像
|
||||
|
||||
$ docker rmi $(docker images -q redis)
|
||||
@@ -169,7 +157,6 @@ $ docker rmi $(docker images -q -f before=mongo:8.0)
|
||||
|
||||
$ docker image prune -a --filter "until=168h" # 7天前
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4.3.5 删除失败的常见原因
|
||||
@@ -183,11 +170,9 @@ $ docker rmi nginx
|
||||
Error: conflict: unable to remove repository reference "nginx"
|
||||
(must force) - container abc123 is using its referenced image
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
|
||||
```bash
|
||||
|
||||
## 方案1:先删除依赖的容器
|
||||
|
||||
$ docker rm abc123
|
||||
@@ -197,7 +182,6 @@ $ docker rmi nginx
|
||||
|
||||
$ docker rmi -f nginx
|
||||
```
|
||||
|
||||
#### 原因二:多个标签指向同一镜像
|
||||
|
||||
```bash
|
||||
@@ -211,7 +195,6 @@ Untagged: ubuntu:24.04
|
||||
|
||||
## 只是移除标签,镜像仍存在(因为还有 ubuntu:latest 指向它)
|
||||
```
|
||||
|
||||
当同一个镜像有多个标签时,`docker rmi` 只是删除指定的标签,不会删除镜像本身。
|
||||
|
||||
#### 原因三:被其他镜像依赖:中间层
|
||||
@@ -220,7 +203,6 @@ Untagged: ubuntu:24.04
|
||||
$ docker rmi some_base_image
|
||||
Error: image has dependent child images
|
||||
```
|
||||
|
||||
中间层镜像被其他镜像依赖,无法删除。需要先删除依赖它的镜像。
|
||||
|
||||
---
|
||||
@@ -244,7 +226,6 @@ Error: image has dependent child images
|
||||
#### 开发环境
|
||||
|
||||
```bash
|
||||
|
||||
## 定期清理虚悬镜像
|
||||
|
||||
$ docker image prune -f
|
||||
@@ -253,16 +234,13 @@ $ docker image prune -f
|
||||
|
||||
$ docker system prune -a
|
||||
```
|
||||
|
||||
#### CI/CD 环境
|
||||
|
||||
```bash
|
||||
|
||||
## 只保留最近使用的镜像
|
||||
|
||||
$ docker image prune -a --filter "until=72h" -f
|
||||
```
|
||||
|
||||
#### 查看空间占用
|
||||
|
||||
```bash
|
||||
@@ -273,5 +251,4 @@ Containers 5 2 100MB 80MB (80%)
|
||||
Local Volumes 8 2 500MB 400MB (80%)
|
||||
Build Cache 0 0 0B 0B
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
```bash
|
||||
$ docker run --name webserver -d -p 80:80 nginx
|
||||
```
|
||||
|
||||
这条命令会用 `nginx` 镜像启动一个容器,命名为 `webserver`,并且映射了 80 端口,这样我们可以用浏览器去访问这个 `nginx` 服务器。
|
||||
|
||||
如果是在本机运行的 Docker,那么可以直接访问:`http://localhost`,如果是在虚拟机、云服务器上安装的 Docker,则需要将 `localhost` 换为虚拟机地址或者实际云服务器地址。
|
||||
@@ -30,7 +29,6 @@ root@3729b97e8226:/# echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/inde
|
||||
root@3729b97e8226:/# exit
|
||||
exit
|
||||
```
|
||||
|
||||
我们以交互式终端方式进入 `webserver` 容器,并执行了 `bash` 命令,也就是获得一个可操作的 Shell。
|
||||
|
||||
然后,我们用 `<h1>Hello, Docker!</h1>` 覆盖了 `/usr/share/nginx/html/index.html` 的内容。
|
||||
@@ -60,7 +58,6 @@ A /var/cache/nginx/proxy_temp
|
||||
A /var/cache/nginx/scgi_temp
|
||||
A /var/cache/nginx/uwsgi_temp
|
||||
```
|
||||
|
||||
现在我们定制好了变化,我们希望能将其保存下来形成镜像。
|
||||
|
||||
要知道,当我们运行一个容器的时候 (如果不使用卷的话),我们做的任何文件修改都会被记录于容器存储层里。而 Docker 提供了一个 `docker commit` 命令,可以将容器的存储层保存下来成为镜像。换句话说,就是在原有镜像的基础上,再叠加上容器的存储层,并构成新的镜像。以后我们运行这个新镜像的时候,就会拥有原有容器最后的文件变化。
|
||||
@@ -70,7 +67,6 @@ A /var/cache/nginx/uwsgi_temp
|
||||
```bash
|
||||
docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]
|
||||
```
|
||||
|
||||
我们可以用下面的命令将容器保存为镜像:
|
||||
|
||||
```bash
|
||||
@@ -81,7 +77,6 @@ $ docker commit \
|
||||
nginx:v2
|
||||
sha256:07e33465974800ce65751acc279adc6ed2dc5ed4e0838f8b86f0c87aa1795214
|
||||
```
|
||||
|
||||
其中 `--author` 是指定修改的作者,而 `--message` 则是记录本次修改的内容。这点和 `git` 版本控制相似,不过这里这些信息可以省略留空。
|
||||
|
||||
我们可以在 `docker image ls` 中看到这个新定制的镜像:
|
||||
@@ -93,7 +88,6 @@ nginx v2 07e334659748 9 seconds ago
|
||||
nginx 1.27 05a60462f8ba 12 days ago 181.5 MB
|
||||
nginx latest e43d811ce2f4 4 weeks ago 181.5 MB
|
||||
```
|
||||
|
||||
我们还可以用 `docker history` 具体查看镜像内的历史记录,如果比较 `nginx:latest` 的历史记录,我们会发现新增了我们刚刚提交的这一层。
|
||||
|
||||
```bash
|
||||
@@ -109,13 +103,11 @@ e43d811ce2f4 4 weeks ago /bin/sh -c #(nop) CMD ["nginx" "-g" "da
|
||||
<missing> 4 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0 B
|
||||
<missing> 4 weeks ago /bin/sh -c #(nop) ADD file:23aa4f893e3288698c 123 MB
|
||||
```
|
||||
|
||||
新的镜像定制好后,我们可以来运行这个镜像。
|
||||
|
||||
```bash
|
||||
docker run --name web2 -d -p 81:80 nginx:v2
|
||||
```
|
||||
|
||||
这里我们命名为新的服务为 `web2`,并且映射到 `81` 端口。访问 `http://localhost:81` 看到结果,其内容应该和之前修改后的 `webserver` 一样。
|
||||
|
||||
至此,我们第一次完成了定制镜像,使用的是 `docker commit` 命令,手动操作给旧的镜像添加了新的一层,形成新的镜像,对镜像多层存储应该有了更直观的感觉。
|
||||
|
||||
@@ -11,7 +11,6 @@ Docker 提供了 `docker init` 命令,可以根据项目类型自动生成 Doc
|
||||
```bash
|
||||
$ docker init
|
||||
```
|
||||
|
||||
该命令会交互式地询问项目类型 (如 Go、Node.js、Python、Rust 等),并生成符合最佳实践的配置文件。对于新项目,这是推荐的起步方式。
|
||||
|
||||
### 4.5.2 手动创建 Dockerfile
|
||||
@@ -25,14 +24,12 @@ $ mkdir mynginx
|
||||
$ cd mynginx
|
||||
$ touch Dockerfile
|
||||
```
|
||||
|
||||
其内容为:
|
||||
|
||||
```docker
|
||||
FROM nginx
|
||||
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
|
||||
```
|
||||
|
||||
这个 Dockerfile 很简单,一共就两行。涉及到了两条指令,`FROM` 和 `RUN`。
|
||||
|
||||
### 4.5.3 FROM 指定基础镜像
|
||||
@@ -49,7 +46,6 @@ RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
|
||||
FROM scratch
|
||||
...
|
||||
```
|
||||
|
||||
如果你以 `scratch` 为基础镜像的话,意味着你不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。
|
||||
|
||||
不以任何系统为基础,直接将可执行文件复制进镜像的做法并不罕见,对于 Linux 下静态编译的程序来说,并不需要有操作系统提供运行时支持,所需的一切库都已经在可执行文件里了,因此直接 `FROM scratch` 会让镜像体积更加小巧。使用 [Go 语言](https://golang.google.cn/)开发的应用很多会使用这种方式来制作镜像,这也是有人认为 Go 是特别适合容器微服务架构的语言的原因之一。
|
||||
@@ -63,7 +59,6 @@ FROM scratch
|
||||
```docker
|
||||
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
|
||||
```
|
||||
|
||||
* *exec* 格式:`RUN [“可执行文件”, “参数1”, “参数2”]`,这更像是函数调用中的格式。
|
||||
|
||||
Dockerfile 中每一个指令都会建立一层,`RUN` 也不例外。每一个 `RUN` 的行为,就和刚才我们手工建立镜像的过程一样:新建立一层,在其上执行这些命令,执行结束后,`commit` 这一层的修改,构成新的镜像。
|
||||
@@ -93,7 +88,6 @@ Step 2 : RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
|
||||
Removing intermediate container 9cdc27646c7b
|
||||
Successfully built 44aa4490ce2c
|
||||
```
|
||||
|
||||
从命令的输出结果中,我们可以清晰的看到镜像的构建过程。在 `Step 2` 中,如同我们之前所说的那样,`RUN` 指令启动了一个容器 `9cdc27646c7b`,执行了所要求的命令,并最后提交了这一层 `44aa4490ce2c`,随后删除了所用到的这个容器 `9cdc27646c7b`。
|
||||
|
||||
这里我们使用了 `docker build` 命令进行镜像构建。其格式为:
|
||||
@@ -101,7 +95,6 @@ Successfully built 44aa4490ce2c
|
||||
```bash
|
||||
docker build [选项] <上下文路径/URL/->
|
||||
```
|
||||
|
||||
在这里我们指定了最终镜像的名称 `-t nginx:v3`,构建成功后,我们可以像之前运行 `nginx:v2` 那样来运行这个镜像,其结果会和 `nginx:v2` 一样。
|
||||
|
||||
### 4.5.6 镜像构建上下文
|
||||
@@ -119,7 +112,6 @@ docker build [选项] <上下文路径/URL/->
|
||||
```docker
|
||||
COPY ./package.json /app/
|
||||
```
|
||||
|
||||
这并不是要复制执行 `docker build` 命令所在的目录下的 `package.json`,也不是复制 `Dockerfile` 所在目录下的 `package.json`,而是复制 **上下文 (context)** 目录下的 `package.json`。
|
||||
|
||||
因此,`COPY` 这类指令中的源文件的路径都是*相对路径*。这也是初学者经常会问的为什么 `COPY ../package.json /app` 或者 `COPY /opt/xxxx /app` 无法工作的原因,因为这些路径已经超出了上下文的范围,Docker 引擎无法获得这些位置的文件。如果真的需要那些文件,应该将它们复制到上下文目录中去。
|
||||
@@ -133,7 +125,6 @@ $ docker build -t nginx:v3 .
|
||||
Sending build context to Docker daemon 2.048 kB
|
||||
...
|
||||
```
|
||||
|
||||
理解构建上下文对于镜像构建是很重要的,避免犯一些不应该的错误。比如有些初学者在发现 `COPY /opt/xxxx /app` 不工作后,于是干脆将 `Dockerfile` 放到了硬盘根目录去构建,结果发现 `docker build` 执行后,在发送一个几十 GB 的东西,极为缓慢而且很容易构建失败。那是因为这种做法是在让 `docker build` 打包整个硬盘,这显然是使用错误。
|
||||
|
||||
一般来说,应该会将 `Dockerfile` 置于一个空目录下,或者项目根目录下。如果该目录下没有所需文件,那么应该把所需文件复制一份过来。如果目录下有些东西确实不希望构建时传给 Docker 引擎,那么可以用 `.gitignore` 一样的语法写一个 `.dockerignore`,该文件是用于剔除不需要作为上下文传递给 Docker 引擎的。
|
||||
@@ -151,7 +142,6 @@ Sending build context to Docker daemon 2.048 kB
|
||||
或许你已经注意到了,`docker build` 还支持从 URL 构建,比如可以直接从 Git repo 中构建:
|
||||
|
||||
```bash
|
||||
|
||||
## $env:DOCKER_BUILDKIT=0
|
||||
|
||||
## export DOCKER_BUILDKIT=0
|
||||
@@ -168,7 +158,6 @@ Removing intermediate container d2a513a760ed
|
||||
---> 038ad4142d2b
|
||||
Successfully built 038ad4142d2b
|
||||
```
|
||||
|
||||
这行命令指定了构建所需的 Git repo,并且指定分支为 `master`,构建目录为 `/amd64/hello-world/`,然后 Docker 就会自己去 `git clone` 这个项目、切换到指定分支、并进入到指定目录后开始构建。
|
||||
|
||||
#### 用给定的 tar 压缩包构建
|
||||
@@ -176,7 +165,6 @@ Successfully built 038ad4142d2b
|
||||
```bash
|
||||
$ docker build http://server/context.tar.gz
|
||||
```
|
||||
|
||||
如果所给出的 URL 不是个 Git repo,而是个 `tar` 压缩包,那么 Docker 引擎会下载这个包,并自动解压缩,以其作为上下文,开始构建。
|
||||
|
||||
#### 从标准输入中读取 Dockerfile 进行构建
|
||||
@@ -184,13 +172,11 @@ $ docker build http://server/context.tar.gz
|
||||
```bash
|
||||
docker build - < Dockerfile
|
||||
```
|
||||
|
||||
或
|
||||
|
||||
```bash
|
||||
cat Dockerfile | docker build -
|
||||
```
|
||||
|
||||
如果标准输入传入的是文本文件,则将其视为 `Dockerfile`,并开始构建。这种形式由于直接从标准输入中读取 Dockerfile 的内容,它没有上下文,因此不可以像其他方法那样可以将本地文件 `COPY` 进镜像之类的事情。
|
||||
|
||||
#### 从标准输入中读取上下文压缩包进行构建
|
||||
@@ -198,5 +184,4 @@ cat Dockerfile | docker build -
|
||||
```bash
|
||||
$ docker build - < context.tar.gz
|
||||
```
|
||||
|
||||
如果发现标准输入的文件格式是 `gzip`、`bzip2` 以及 `xz` 的话,将会使其为上下文压缩包,直接将其展开,将里面视为上下文,并开始构建。
|
||||
|
||||
@@ -18,7 +18,6 @@ $ docker import \
|
||||
Downloading from http://download.openvz.org/template/precreated/ubuntu-16.04-x86_64.tar.gz
|
||||
sha256:412b8fc3e3f786dca0197834a698932b9c51b69bd8cf49e100c35d38c9879213
|
||||
```
|
||||
|
||||
这条命令自动下载了 `ubuntu-16.04-x86_64.tar.gz` 文件,并且作为根文件系统展开导入,并保存为镜像 `openvz/ubuntu:16.04`。
|
||||
|
||||
导入成功后,我们可以用 `docker image ls` 看到这个导入的镜像:
|
||||
@@ -28,7 +27,6 @@ $ docker image ls openvz/ubuntu
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
openvz/ubuntu 16.04 412b8fc3e3f7 55 seconds ago 505MB
|
||||
```
|
||||
|
||||
如果我们查看其历史的话,会看到描述中有导入的文件链接:
|
||||
|
||||
```bash
|
||||
@@ -36,7 +34,6 @@ $ docker history openvz/ubuntu:16.04
|
||||
IMAGE CREATED CREATED BY SIZE COMMENT
|
||||
f477a6e18e98 About a minute ago 214.9 MB Imported from http://download.openvz.org/template/precreated/ubuntu-16.04-x86_64.tar.gz
|
||||
```
|
||||
|
||||
### 4.6.2 Docker 镜像的导入和导出 `docker save` 和 `docker load`
|
||||
|
||||
Docker 还提供了 `docker save` 和 `docker load` 命令,用以将镜像保存为一个文件,然后传输到另一个位置上,再加载进来。这是在没有 Docker Registry 时的做法,现在已经不推荐,镜像迁移应该直接使用 Docker Registry,无论是直接使用 Docker Hub 还是使用内网私有 Registry 都可以。
|
||||
@@ -52,7 +49,6 @@ $ docker image ls alpine
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
alpine latest baa5d63471ea 5 weeks ago 4.803 MB
|
||||
```
|
||||
|
||||
保存镜像的命令为:
|
||||
|
||||
```bash
|
||||
@@ -60,7 +56,6 @@ $ docker save alpine -o filename
|
||||
$ file filename
|
||||
filename: POSIX tar archive
|
||||
```
|
||||
|
||||
这里的 filename 可以为任意名称甚至任意后缀名,但文件的本质都是归档文件
|
||||
|
||||
**注意:如果同名则会覆盖 (没有警告)**
|
||||
@@ -70,14 +65,12 @@ filename: POSIX tar archive
|
||||
```bash
|
||||
$ docker save alpine | gzip > alpine-latest.tar.gz
|
||||
```
|
||||
|
||||
然后我们将 `alpine-latest.tar.gz` 文件复制到了到了另一个机器上,可以用下面这个命令加载镜像:
|
||||
|
||||
```bash
|
||||
$ docker load -i alpine-latest.tar.gz
|
||||
Loaded image: alpine:latest
|
||||
```
|
||||
|
||||
如果我们结合这两个命令以及 `ssh` 甚至 `pv` 的话,利用 Linux 强大的管道,我们可以写一个命令完成从一个机器将镜像迁移到另一个机器,并且带进度条的功能:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -38,7 +38,6 @@ flowchart TD
|
||||
end
|
||||
Note["所有的写操作都在容器层这里"] -.-> L4
|
||||
```
|
||||
|
||||
* **读取文件**:当容器需要读取文件时,Docker 会从最上层 (容器层) 开始向下层 (镜像层) 寻找,直到找到该文件为止。
|
||||
* **修改文件**:当容器需要修改某个文件时,Docker 会从下层镜像中将该文件复制到上层的容器层,然后对副本进行修改。这被称为 **写时复制 (Copy-on-Write,CoW)** 策略。
|
||||
* **删除文件**:当容器删除某个文件时,Docker 并不是真的去下层删除它 (因为下层是只读的),而是在容器层创建一个特殊的 “白障 (Whiteout)” 文件,用来标记该文件已被删除,从而在容器视图中隐藏它。
|
||||
|
||||
Reference in New Issue
Block a user