mirror of
https://github.com/yeasy/docker_practice.git
synced 2026-08-10 16:37:34 +00:00
Add blank lines around headers
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
```html
|
||||
<h1>Hello, Docker!</h1>
|
||||
```
|
||||
|
||||
### 1.1.2 编写 Dockerfile
|
||||
|
||||
在同级目录下创建一个名为 `Dockerfile` (无后缀) 的文件:
|
||||
@@ -17,6 +18,7 @@
|
||||
FROM nginx:alpine
|
||||
COPY index.html /usr/share/nginx/html/index.html
|
||||
```
|
||||
|
||||
### 1.1.3 构建镜像
|
||||
|
||||
打开终端,进入该目录,执行构建命令:
|
||||
|
||||
@@ -40,6 +40,7 @@ flowchart LR
|
||||
end
|
||||
A == 一致 ==> C
|
||||
```
|
||||
|
||||
### 1.2.3 Docker vs 虚拟机
|
||||
|
||||
很多人第一次接触 Docker 时会问:**“这不就是虚拟机吗?”** 答案是:**不是,而且差别很大。**
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
├── Day 4:问老同事怎么配的,他也忘了
|
||||
└── Day 5:终于能跑起来了!但不知道为什么……
|
||||
```
|
||||
|
||||
#### 场景三:服务器迁移的恐惧
|
||||
|
||||
```bash
|
||||
@@ -41,6 +42,7 @@
|
||||
运维:"当时是一个已经离职的同事配的……"
|
||||
所有人:😱
|
||||
```
|
||||
|
||||
### 1.3.2 Docker 如何解决这些问题
|
||||
|
||||
Docker 的出现为上述问题提供了完美的解决方案。它通过 “一次构建,到处运行” 的核心理念,从根本上改变了软件交付的方式。
|
||||
@@ -54,6 +56,7 @@ flowchart LR
|
||||
test -- "有问题<br/>反馈修改和更新" --> dev
|
||||
test -- "没问题<br/>发布" --> prod["生产环境"]
|
||||
```
|
||||
|
||||
### 1.3.3 Docker 的核心优势
|
||||
|
||||
除了解决上述痛点,Docker 还拥有诸多显著的技术优势,包括环境一致性、秒级启动、高效的资源利用等。
|
||||
@@ -76,6 +79,7 @@ $ docker compose up
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
#### 2. 秒级启动
|
||||
|
||||
传统虚拟机启动需要几分钟 (引导操作系统),而 Docker 容器启动通常只需要 **几秒甚至几百毫秒**。
|
||||
@@ -126,6 +130,7 @@ flowchart TD
|
||||
Server2 --- Containers
|
||||
end
|
||||
```
|
||||
|
||||
#### 4. 持续交付和部署
|
||||
|
||||
Docker 完美契合 DevOps 的工作流程:
|
||||
@@ -182,6 +187,7 @@ flowchart TD
|
||||
Worker --> DB
|
||||
end
|
||||
```
|
||||
|
||||
### 1.3.4 Docker 不适合的场景
|
||||
|
||||
笔者认为,技术选型要客观。Docker 并非银弹,以下场景可能不太适合:
|
||||
|
||||
@@ -79,6 +79,7 @@ flowchart TD
|
||||
AppC --> Ubuntu
|
||||
end
|
||||
```
|
||||
|
||||
#### 分层是如何工作的?
|
||||
|
||||
笔者用一个实际的 Dockerfile 来解释分层:
|
||||
@@ -135,6 +136,7 @@ RUN apt-get update && \
|
||||
## 在同一层完成安装、使用、清理
|
||||
|
||||
```
|
||||
|
||||
#### 查看镜像的分层
|
||||
|
||||
```bash
|
||||
@@ -150,6 +152,7 @@ a6bd71f48f68 2 weeks ago CMD ["nginx" "-g" "daemon off;"] 0B
|
||||
<missing> 2 weeks ago COPY 30-tune-worker-processes.sh /docker-ent… 4.62kB
|
||||
...
|
||||
```
|
||||
|
||||
### 2.1.5 镜像的标识
|
||||
|
||||
Docker 镜像有多种标识方式:
|
||||
@@ -172,6 +175,7 @@ ubuntu:24.04
|
||||
|
||||
nginx # 等同于 nginx:latest
|
||||
```
|
||||
|
||||
#### 2. 镜像 ID:Content-Addressable 标识
|
||||
|
||||
每个镜像有一个基于内容计算的唯一 ID:
|
||||
@@ -182,6 +186,7 @@ REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
nginx latest a6bd71f48f68 2 weeks ago 187MB
|
||||
ubuntu 24.04 ca2b0f26964c 3 weeks ago 78.1MB
|
||||
```
|
||||
|
||||
#### 3. 镜像摘要
|
||||
|
||||
更精确的标识,基于镜像内容的 SHA256 哈希:
|
||||
|
||||
@@ -92,6 +92,7 @@ flowchart TD
|
||||
|
||||
ContainerLayer --> ImageLayerN --> ImageLayerN1 --> Dots --> ImageLayer1
|
||||
```
|
||||
|
||||
#### Copy-on-Write:写时复制
|
||||
|
||||
当容器需要修改镜像层中的文件时:
|
||||
@@ -104,6 +105,7 @@ flowchart TD
|
||||
读取文件:直接从镜像层读取(共享,高效)
|
||||
修改文件:复制到容器层,然后修改(只有这个容器能看到修改)
|
||||
```
|
||||
|
||||
#### ⚠️ 容器存储层的生命周期
|
||||
|
||||
> **笔者特别强调**:这是新手最容易踩的坑!**容器存储层与容器生命周期绑定。容器删除,数据就没了!**
|
||||
@@ -122,6 +124,7 @@ $ docker rm abc123
|
||||
## 数据丢了!没有任何办法恢复!
|
||||
|
||||
```
|
||||
|
||||
#### 正确的数据持久化方式
|
||||
|
||||
按照 Docker 最佳实践,容器存储层应该保持 **无状态**。需要持久化的数据应该使用:
|
||||
@@ -190,6 +193,7 @@ $ docker unpause abc123 # 恢复
|
||||
$ docker rm abc123 # 删除已停止的容器
|
||||
$ docker rm -f abc123 # 强制删除运行中的容器
|
||||
```
|
||||
|
||||
### 2.2.6 容器与进程的关系
|
||||
|
||||
> **核心概念**:容器的生命周期 = 主进程 (PID 1) 的生命周期
|
||||
|
||||
@@ -110,6 +110,7 @@ $ docker pull bitnami/redis # 第三方镜像
|
||||
$ docker login
|
||||
$ docker push username/myapp:v1.0
|
||||
```
|
||||
|
||||
#### 其他公共 Registry
|
||||
|
||||
除了 Docker Hub,还有以下几个常见的公共 Registry:
|
||||
@@ -160,6 +161,7 @@ $ docker push localhost:5000/myapp:v1.0
|
||||
|
||||
$ docker pull localhost:5000/myapp:v1.0
|
||||
```
|
||||
|
||||
#### 企业级解决方案
|
||||
|
||||
官方 Registry 功能较为基础,企业环境常用以下方案:
|
||||
@@ -225,6 +227,7 @@ $ docker push registry.example.com/myteam/myapp:v1.0
|
||||
|
||||
$ docker logout
|
||||
```
|
||||
|
||||
### 2.3.7 镜像的安全性
|
||||
|
||||
在使用公共镜像或维护私有镜像时,安全性是不容忽视的重要环节。
|
||||
@@ -245,6 +248,7 @@ redis # ✅ 官方
|
||||
bitnami/redis # ⚠️ 需要评估
|
||||
someuser/myapp # ⚠️ 需要评估
|
||||
```
|
||||
|
||||
#### 镜像签名
|
||||
|
||||
当前更推荐使用 Sigstore / Notation 体系进行镜像签名与验证。`Docker Content Trust (DCT)` 已进入退场阶段,不建议作为新项目主方案。
|
||||
@@ -265,6 +269,7 @@ $ cosign generate-key-pair
|
||||
$ cosign sign --key cosign.key $IMAGE
|
||||
$ cosign verify --key cosign.pub $IMAGE
|
||||
```
|
||||
|
||||
#### 漏洞扫描
|
||||
|
||||
```bash
|
||||
|
||||
@@ -36,6 +36,7 @@ do
|
||||
sudo apt remove $pkg;
|
||||
done
|
||||
```
|
||||
|
||||
### 3.1.2 使用 APT 安装
|
||||
|
||||
由于 `apt` 源使用 HTTPS 以确保软件下载过程中不被篡改。因此,我们首先需要添加使用 HTTPS 传输的软件包以及 CA 证书。
|
||||
@@ -83,6 +84,7 @@ $ sudo apt update
|
||||
|
||||
$ sudo apt install docker-ce docker-ce-cli containerd.io
|
||||
```
|
||||
|
||||
### 3.1.3 使用脚本自动安装
|
||||
|
||||
在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,Ubuntu 系统上可以使用这套脚本安装,另外可以通过 `--mirror` 选项使用国内源进行安装:
|
||||
@@ -105,6 +107,7 @@ $ sudo sh get-docker.sh --mirror Aliyun
|
||||
$ sudo systemctl enable docker
|
||||
$ sudo systemctl start docker
|
||||
```
|
||||
|
||||
### 3.1.5 建立 docker 用户组
|
||||
|
||||
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好的做法是将需要使用 `docker` 的用户加入 `docker` 用户组。
|
||||
|
||||
@@ -25,6 +25,7 @@ $ sudo apt-get remove docker \
|
||||
docker-engine \
|
||||
docker.io
|
||||
```
|
||||
|
||||
### 3.2.2 使用 APT 安装
|
||||
|
||||
由于 apt 源使用 HTTPS 以确保软件下载过程中不被篡改。因此,我们首先需要添加使用 HTTPS 传输的软件包以及 CA 证书。
|
||||
@@ -74,6 +75,7 @@ $ sudo apt-get update
|
||||
|
||||
$ sudo apt-get install docker-ce docker-ce-cli containerd.io
|
||||
```
|
||||
|
||||
### 3.2.3 使用脚本自动安装
|
||||
|
||||
在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,Debian 系统上可以使用这套脚本安装,另外可以通过 `--mirror` 选项使用国内源进行安装:
|
||||
@@ -96,6 +98,7 @@ $ sudo sh get-docker.sh --mirror Aliyun
|
||||
$ sudo systemctl enable docker
|
||||
$ sudo systemctl start docker
|
||||
```
|
||||
|
||||
### 3.2.5 建立 docker 用户组
|
||||
|
||||
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好的做法是将需要使用 `docker` 的用户加入 `docker` 用户组。
|
||||
|
||||
@@ -32,6 +32,7 @@ $ sudo dnf remove docker \
|
||||
docker-engine-selinux \
|
||||
docker-engine
|
||||
```
|
||||
|
||||
### 3.3.2 使用 dnf 安装
|
||||
|
||||
使用 dnf 包管理器安装是推荐的方式,便于后续的更行和管理。
|
||||
@@ -67,6 +68,7 @@ $ sudo dnf config-manager --set-enabled docker-ce-test
|
||||
```bash
|
||||
$ sudo dnf config-manager --set-disabled docker-ce-test
|
||||
```
|
||||
|
||||
#### 安装 Docker
|
||||
|
||||
更新 `dnf` 软件源缓存,并安装 `docker-ce`。
|
||||
@@ -84,6 +86,7 @@ docker-ce.x86_64 18.06.1.ce-3.fc28 docker-ce-stable
|
||||
|
||||
$ sudo dnf -y install docker-ce-18.06.1.ce
|
||||
```
|
||||
|
||||
### 3.3.3 使用脚本自动安装
|
||||
|
||||
在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,Fedora 系统上可以使用这套脚本安装,另外可以通过 `--mirror` 选项使用国内源进行安装:
|
||||
@@ -106,6 +109,7 @@ $ sudo sh get-docker.sh --mirror Aliyun
|
||||
$ sudo systemctl enable docker
|
||||
$ sudo systemctl start docker
|
||||
```
|
||||
|
||||
### 3.3.5 建立 docker 用户组
|
||||
|
||||
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好的做法是将需要使用 `docker` 的用户加入 `docker` 用户组。
|
||||
|
||||
@@ -34,6 +34,7 @@ $ sudo yum remove docker \
|
||||
docker-ce-cli \
|
||||
containerd.io
|
||||
```
|
||||
|
||||
### 3.4.2 使用 yum 安装
|
||||
|
||||
使用 yum/dnf 安装是管理 Docker 生命周期的标准方式。
|
||||
@@ -64,6 +65,7 @@ $ sudo sed -i 's/download.docker.com/mirrors.aliyun.com\/docker-ce/g' /etc/yum.r
|
||||
```bash
|
||||
$ sudo dnf config-manager --set-enabled docker-ce-test
|
||||
```
|
||||
|
||||
#### 安装 Docker
|
||||
|
||||
更新 `dnf` 软件源缓存,并安装 `docker-ce`。
|
||||
@@ -71,6 +73,7 @@ $ sudo dnf config-manager --set-enabled docker-ce-test
|
||||
```bash
|
||||
$ sudo dnf install docker-ce docker-ce-cli containerd.io
|
||||
```
|
||||
|
||||
### 3.4.3 CentOS8 额外设置
|
||||
|
||||
CentOS 8/Stream 默认使用 `nftables`。Docker 在新版本中已提供 `nftables` 实验支持,但在一些环境下仍可能遇到兼容性问题。若你遇到容器网络异常,可以先切换回 `iptables` 后端:
|
||||
@@ -89,6 +92,7 @@ $ firewall-cmd --permanent --zone=trusted --add-interface=docker0
|
||||
|
||||
$ firewall-cmd --reload
|
||||
```
|
||||
|
||||
### 3.4.4 使用脚本自动安装
|
||||
|
||||
在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,CentOS 系统上可以使用这套脚本安装,另外可以通过 `--mirror` 选项使用国内源进行安装:
|
||||
@@ -112,6 +116,7 @@ $ sudo sh get-docker.sh --mirror Aliyun
|
||||
$ sudo systemctl enable docker
|
||||
$ sudo systemctl start docker
|
||||
```
|
||||
|
||||
### 3.4.6 建立 docker 用户组
|
||||
|
||||
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好的做法是将需要使用 `docker` 的用户加入 `docker` 用户组。
|
||||
@@ -192,6 +197,7 @@ EOF
|
||||
```bash
|
||||
$ sudo sysctl -p
|
||||
```
|
||||
|
||||
### 3.4.10 参考文档
|
||||
|
||||
* [Docker 官方 CentOS 安装文档](https://docs.docker.com/engine/install/centos/)。
|
||||
|
||||
@@ -89,6 +89,7 @@ $ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docke
|
||||
# $ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/raspbian $(lsb_release -cs) stable" | sudo tee -a /etc/apt/sources.list
|
||||
|
||||
```
|
||||
|
||||
#### 安装 Docker
|
||||
|
||||
更新 apt 软件包缓存,并安装 `docker-ce`。
|
||||
@@ -98,6 +99,7 @@ $ sudo apt-get update
|
||||
|
||||
$ sudo apt-get install docker-ce
|
||||
```
|
||||
|
||||
### 3.5.3 使用脚本自动安装
|
||||
|
||||
在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,Raspberry Pi OS 系统上可以使用这套脚本安装,另外可以通过 `--mirror` 选项使用国内源进行安装:
|
||||
@@ -121,6 +123,7 @@ $ sudo sh get-docker.sh --mirror Aliyun
|
||||
$ sudo systemctl enable docker
|
||||
$ sudo systemctl start docker
|
||||
```
|
||||
|
||||
### 3.5.5 建立 docker 用户组
|
||||
|
||||
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好的做法是将需要使用 `docker` 的用户加入 `docker` 用户组。
|
||||
|
||||
@@ -41,6 +41,7 @@ docker-ce.x86_64 3:19.03.2-3.el7 docker-ce-stable
|
||||
docker-ce.x86_64 3:19.03.1-3.el7 docker-ce-stable
|
||||
....
|
||||
```
|
||||
|
||||
##### 下载到指定文件夹
|
||||
|
||||
```bash
|
||||
@@ -74,6 +75,7 @@ Background downloading packages, then exiting:
|
||||
Total 118 MB/s | 87 MB 00:00:00
|
||||
exiting because "Download Only" specified
|
||||
```
|
||||
|
||||
##### 复制到目标服务器之后进入文件夹安装:C-N
|
||||
|
||||
* 离线安装时,必须使用 rpm 命令不检查依赖的方式安装
|
||||
@@ -81,6 +83,7 @@ exiting because "Download Only" specified
|
||||
```bash
|
||||
rpm -Uvh *.rpm --nodeps --force
|
||||
```
|
||||
|
||||
##### 锁定软件版本:C-N
|
||||
|
||||
**下载锁定版本软件**
|
||||
@@ -130,6 +133,7 @@ versionlock deleted: 1
|
||||
```bash
|
||||
sudo yum versionlock delete all
|
||||
```
|
||||
|
||||
#### YUM 本地源服务器搭建安装 Docker
|
||||
|
||||
##### 挂载 ISO 镜像搭建本地 File 源
|
||||
@@ -161,6 +165,7 @@ EOF
|
||||
yum clean all
|
||||
yum install createrepo -y
|
||||
```
|
||||
|
||||
##### 根据本地文件搭建 BASE 网络源
|
||||
|
||||
```bash
|
||||
@@ -183,6 +188,7 @@ createrepo /var/www/html/base/
|
||||
systemctl enable httpd
|
||||
systemctl start httpd
|
||||
```
|
||||
|
||||
##### 下载 Docker-CE 镜像仓库
|
||||
|
||||
在有网络的服务器上下载 Docker-ce 镜像
|
||||
@@ -202,6 +208,7 @@ mkdir /tmp/docker-ce/
|
||||
|
||||
reposync -r docker-ce-stable -p /tmp/docker-ce/
|
||||
```
|
||||
|
||||
##### 创建仓库索引
|
||||
|
||||
把下载的 docker-ce 文件夹复制到离线的服务器
|
||||
@@ -213,6 +220,7 @@ reposync -r docker-ce-stable -p /tmp/docker-ce/
|
||||
|
||||
createrepo /var/www/html/docker-ce/
|
||||
```
|
||||
|
||||
##### YUM 客户端设置:C...N
|
||||
|
||||
```bash
|
||||
@@ -239,6 +247,7 @@ proxy=_none_
|
||||
EOF
|
||||
|
||||
```
|
||||
|
||||
##### Docker 安装:C...N
|
||||
|
||||
```bash
|
||||
|
||||
@@ -18,6 +18,7 @@ Docker Desktop 为 Mac 用户提供了无缝的 Docker 体验。你可以选择
|
||||
```bash
|
||||
$ brew install --cask docker
|
||||
```
|
||||
|
||||
#### 手动下载安装
|
||||
|
||||
如果需要手动下载,请点击以下[链接](https://desktop.docker.com/mac/main/amd64/Docker.dmg)下载 Docker Desktop for Mac。
|
||||
@@ -63,6 +64,7 @@ $ docker run -d -p 80:80 --name webserver nginx
|
||||
$ docker stop webserver
|
||||
$ docker rm webserver
|
||||
```
|
||||
|
||||
### 3.7.4 镜像加速
|
||||
|
||||
如果在使用过程中发现拉取 Docker 镜像十分缓慢,可以配置 Docker [国内镜像加速](3.9_mirror.md)。
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
```powershell
|
||||
$ winget install Docker.DockerDesktop
|
||||
```
|
||||
|
||||
### 3.8.3 在 WSL2 运行 Docker
|
||||
|
||||
若你的 Windows 版本为 Windows 10 专业版或家庭版 v1903 及以上版本可以使用 WSL2 运行 Docker,具体请查看 [Docker Desktop WSL 2 backend](https://docs.docker.com/docker-for-windows/wsl/)。
|
||||
|
||||
@@ -19,6 +19,7 @@ Docker 支持在多种平台上安装和使用,选择合适的安装方式是
|
||||
$ docker version
|
||||
$ docker run --rm hello-world
|
||||
```
|
||||
|
||||
### 延伸阅读
|
||||
|
||||
- [镜像加速器](3.9_mirror.md):解决国内拉取镜像慢的问题
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
```bash
|
||||
docker pull [选项] [Registry地址/]仓库名[:标签]
|
||||
```
|
||||
|
||||
#### 镜像名称格式
|
||||
|
||||
Docker 镜像名称由 Registry 地址、用户名、仓库名和标签组成。其标准格式如下:
|
||||
@@ -70,6 +71,7 @@ Digest: sha256:4bc3ae6596938cb0d9e5ac51a1152ec9dcac2a1c50829c74abd9c4361e321b26
|
||||
Status: Downloaded newer image for ubuntu:24.04
|
||||
docker.io/library/ubuntu:24.04
|
||||
```
|
||||
|
||||
#### 输出解读
|
||||
|
||||
| 输出内容 | 说明 |
|
||||
@@ -180,6 +182,7 @@ $ docker images --digests ubuntu
|
||||
REPOSITORY TAG DIGEST IMAGE ID
|
||||
ubuntu 24.04 sha256:4bc3ae6596938cb0d9e5ac51a1152ec9dcac2a1c50829c74abd9c4361e321b26 ca2b0f26964c
|
||||
```
|
||||
|
||||
#### 使用摘要拉取
|
||||
|
||||
用摘要拉取可确保获取完全相同的镜像:
|
||||
|
||||
@@ -87,6 +87,7 @@ ubuntu 24.04 329ed837d508 78MB
|
||||
ubuntu noble 329ed837d508 78MB
|
||||
ubuntu 22.04 a1b2c3d4e5f6 72MB
|
||||
```
|
||||
|
||||
#### 按仓库名和标签过滤
|
||||
|
||||
```bash
|
||||
@@ -94,6 +95,7 @@ $ docker images ubuntu:24.04
|
||||
REPOSITORY TAG IMAGE ID SIZE
|
||||
ubuntu 24.04 329ed837d508 78MB
|
||||
```
|
||||
|
||||
#### 使用过滤器 --filter
|
||||
|
||||
| 过滤条件 | 说明 | 示例 |
|
||||
@@ -132,6 +134,7 @@ $ docker images
|
||||
REPOSITORY TAG IMAGE ID SIZE
|
||||
<none> <none> 00285df0df87 342MB
|
||||
```
|
||||
|
||||
#### 产生原因
|
||||
|
||||
1. **镜像重新构建**:新镜像使用了旧镜像的标签,旧镜像标签被移除
|
||||
@@ -188,11 +191,13 @@ $ docker rmi $(docker images -q)
|
||||
|
||||
$ docker rmi $(docker images -q redis)
|
||||
```
|
||||
|
||||
#### 显示完整 ID
|
||||
|
||||
```bash
|
||||
$ docker images --no-trunc
|
||||
```
|
||||
|
||||
#### 显示摘要
|
||||
|
||||
```bash
|
||||
@@ -200,6 +205,7 @@ $ docker images --digests
|
||||
REPOSITORY TAG DIGEST IMAGE ID
|
||||
nginx latest sha256:b4f0e0bdeb5... e43d811ce2f4
|
||||
```
|
||||
|
||||
#### 自定义格式
|
||||
|
||||
使用 Go 模板语法自定义输出:
|
||||
@@ -220,6 +226,7 @@ redis latest 183MB
|
||||
nginx latest 181MB
|
||||
ubuntu 24.04 78MB
|
||||
```
|
||||
|
||||
#### 可用模板字段
|
||||
|
||||
| 字段 | 说明 |
|
||||
|
||||
@@ -38,6 +38,7 @@ $ docker rmi 501
|
||||
Untagged: redis:alpine
|
||||
Deleted: sha256:501ad78535f0...
|
||||
```
|
||||
|
||||
#### 使用镜像名删除
|
||||
|
||||
```bash
|
||||
@@ -45,6 +46,7 @@ $ docker rmi redis:alpine
|
||||
Untagged: redis:alpine
|
||||
Deleted: sha256:501ad78535f0...
|
||||
```
|
||||
|
||||
#### 使用摘要删除
|
||||
|
||||
摘要删除最精确,适用于 CI/CD 场景:
|
||||
@@ -76,6 +78,7 @@ Deleted: sha256:501ad78535f015d88872e13fa87a828425117e3d28075d0c117932b05bf189b7
|
||||
Deleted: sha256:96167737e29ca8e9d74982ef2a0dda76ed7b430da55e321c071f0dbff8c2899b
|
||||
Deleted: sha256:32770d1dcf835f192cafd6b9263b7b597a1778a403a109e2cc2ee866f74adf23
|
||||
```
|
||||
|
||||
#### Untagged vs Deleted
|
||||
|
||||
| 操作 | 含义 |
|
||||
@@ -131,6 +134,7 @@ $ docker image prune
|
||||
|
||||
$ docker image prune -f
|
||||
```
|
||||
|
||||
#### 删除所有未使用的镜像
|
||||
|
||||
```bash
|
||||
@@ -142,6 +146,7 @@ $ docker image prune -a
|
||||
|
||||
$ docker image prune -a --filter "until=24h"
|
||||
```
|
||||
|
||||
#### 按条件删除
|
||||
|
||||
```bash
|
||||
@@ -182,6 +187,7 @@ $ docker rmi nginx
|
||||
|
||||
$ docker rmi -f nginx
|
||||
```
|
||||
|
||||
#### 原因二:多个标签指向同一镜像
|
||||
|
||||
```bash
|
||||
@@ -234,6 +240,7 @@ $ docker image prune -f
|
||||
|
||||
$ docker system prune -a
|
||||
```
|
||||
|
||||
#### CI/CD 环境
|
||||
|
||||
```bash
|
||||
@@ -241,6 +248,7 @@ $ docker system prune -a
|
||||
|
||||
$ docker image prune -a --filter "until=72h" -f
|
||||
```
|
||||
|
||||
#### 查看空间占用
|
||||
|
||||
```bash
|
||||
|
||||
@@ -34,6 +34,7 @@ $ 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 都可以。
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
```bash
|
||||
docker run [选项] 镜像 [命令] [参数...]
|
||||
```
|
||||
|
||||
#### 最简单的例子
|
||||
|
||||
输出 “Hello World” 后容器自动终止:
|
||||
@@ -53,6 +54,7 @@ root@af8bae53bdd3:/# ls
|
||||
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
|
||||
root@af8bae53bdd3:/# exit # 退出容器
|
||||
```
|
||||
|
||||
### 5.1.3 docker run 的完整流程
|
||||
|
||||
执行 `docker run` 时,Docker 在后台完成以下操作:
|
||||
@@ -73,6 +75,7 @@ flowchart TD
|
||||
Step4["4. 启动容器,执行指定命令"] --> Step5
|
||||
Step5["5. 命令执行完毕,容器停止"]
|
||||
```
|
||||
|
||||
### 5.1.4 常用启动选项
|
||||
|
||||
#### 基础选项
|
||||
@@ -99,6 +102,7 @@ $ docker run -d -P nginx
|
||||
|
||||
$ docker run -d -p 127.0.0.1:8080:80 nginx
|
||||
```
|
||||
|
||||
#### 数据卷挂载
|
||||
|
||||
```bash
|
||||
@@ -114,6 +118,7 @@ $ docker run -v /host/path:/container/path nginx
|
||||
|
||||
$ docker run -v /host/path:/container/path:ro nginx
|
||||
```
|
||||
|
||||
#### 环境变量
|
||||
|
||||
```bash
|
||||
@@ -125,6 +130,7 @@ $ docker run -e MYSQL_ROOT_PASSWORD=secret mysql
|
||||
|
||||
$ docker run --env-file .env myapp
|
||||
```
|
||||
|
||||
#### 资源限制
|
||||
|
||||
```bash
|
||||
@@ -136,6 +142,7 @@ $ docker run -m 512m nginx
|
||||
|
||||
$ docker run --cpus=1.5 nginx
|
||||
```
|
||||
|
||||
### 5.1.5 启动已终止容器
|
||||
|
||||
使用 `docker start` 重新启动已停止的容器:
|
||||
@@ -155,6 +162,7 @@ $ docker start myubuntu
|
||||
|
||||
$ docker start -ai myubuntu
|
||||
```
|
||||
|
||||
### 5.1.6 容器内进程的特点
|
||||
|
||||
容器内只运行指定的应用程序及其必需资源:
|
||||
@@ -199,6 +207,7 @@ $ docker run -d nginx
|
||||
|
||||
$ docker run -d -p 80:80 nginx
|
||||
```
|
||||
|
||||
#### Q:容器内修改的文件丢失
|
||||
|
||||
**原因**:未使用数据卷,数据保存在容器存储层
|
||||
|
||||
@@ -92,6 +92,7 @@ $ docker container ls
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
77b2dc01fe0f ubuntu:24.04 /bin/sh -c 'while tr 2 minutes ago Up 1 minute agitated_wright
|
||||
```
|
||||
|
||||
#### 查看容器输出日志
|
||||
|
||||
```bash
|
||||
@@ -106,6 +107,7 @@ hello world
|
||||
```bash
|
||||
$ docker container logs -f 77b2dc01fe0f
|
||||
```
|
||||
|
||||
#### 查看已停止的容器
|
||||
|
||||
```bash
|
||||
@@ -130,6 +132,7 @@ $ docker run -d -p 3306:3306 mysql:8
|
||||
|
||||
$ docker run -d -p 6379:6379 redis
|
||||
```
|
||||
|
||||
#### 2. 调试时先用前台模式
|
||||
|
||||
当容器启动有问题时,**去掉 `-d` 参数** 可以直接看到输出和错误:
|
||||
@@ -139,6 +142,7 @@ $ docker run -d -p 6379:6379 redis
|
||||
|
||||
$ docker run myimage:latest
|
||||
```
|
||||
|
||||
#### 3. 使用 --rm 自动清理
|
||||
|
||||
对于一次性任务,使用 `--rm` 参数让容器退出后自动删除:
|
||||
@@ -151,6 +155,7 @@ Hello, World!
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
#### 4. 配合日志查看
|
||||
|
||||
```bash
|
||||
@@ -170,6 +175,7 @@ $ docker logs -f myapp
|
||||
|
||||
$ docker logs -t myapp
|
||||
```
|
||||
|
||||
### 5.2.6 常见问题排查
|
||||
|
||||
#### Q:容器启动后立即退出
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
```bash
|
||||
$ docker stop 容器名或ID
|
||||
```
|
||||
|
||||
#### 工作原理
|
||||
|
||||
```mermaid
|
||||
@@ -29,6 +30,7 @@ flowchart TD
|
||||
A --> B["2. 等待容器优雅退出 (默认 10 秒)"]
|
||||
B --> C["3. 如果超时仍未退出,发送 SIGKILL 强制终止"]
|
||||
```
|
||||
|
||||
#### 自定义超时时间
|
||||
|
||||
```bash
|
||||
@@ -40,6 +42,7 @@ $ docker stop -t 30 mycontainer
|
||||
|
||||
$ docker stop -t 0 mycontainer
|
||||
```
|
||||
|
||||
#### 停止多个容器
|
||||
|
||||
```bash
|
||||
@@ -60,6 +63,7 @@ $ docker stop $(docker ps -q)
|
||||
```bash
|
||||
$ docker kill 容器名或ID
|
||||
```
|
||||
|
||||
#### 与 stop 的区别
|
||||
|
||||
| 命令 | 信号 | 使用场景 |
|
||||
@@ -127,6 +131,7 @@ $ docker start 容器名或ID
|
||||
|
||||
$ docker start -ai 容器名
|
||||
```
|
||||
|
||||
#### 重启运行中的容器
|
||||
|
||||
```bash
|
||||
@@ -166,11 +171,13 @@ stateDiagram-v2
|
||||
```bash
|
||||
$ docker stop $(docker ps -q)
|
||||
```
|
||||
|
||||
#### 删除所有已停止的容器
|
||||
|
||||
```bash
|
||||
$ docker container prune
|
||||
```
|
||||
|
||||
#### 停止并删除所有容器
|
||||
|
||||
```bash
|
||||
@@ -204,6 +211,7 @@ FROM node:22
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
```
|
||||
|
||||
#### Q:容器无法停止
|
||||
|
||||
```bash
|
||||
|
||||
@@ -35,6 +35,7 @@ $ docker exec -it 容器名 /bin/bash
|
||||
|
||||
$ docker exec -it 容器名 /bin/sh
|
||||
```
|
||||
|
||||
#### 参数说明
|
||||
|
||||
| 参数 | 作用 |
|
||||
@@ -67,6 +68,7 @@ $ docker ps
|
||||
CONTAINER ID IMAGE STATUS NAMES
|
||||
69d137adef7a ubuntu Up 2 minutes myubuntu
|
||||
```
|
||||
|
||||
#### 执行单条命令
|
||||
|
||||
不进入交互模式,直接执行命令:
|
||||
@@ -84,6 +86,7 @@ $ docker exec myubuntu cat /etc/nginx/nginx.conf
|
||||
|
||||
$ docker exec -u root myubuntu apt update
|
||||
```
|
||||
|
||||
#### 只用 -i 不用 -t 的区别
|
||||
|
||||
```bash
|
||||
@@ -112,6 +115,7 @@ root@69d137adef7a:/# # 有提示符
|
||||
```bash
|
||||
$ docker attach 容器名
|
||||
```
|
||||
|
||||
#### 工作原理
|
||||
|
||||
`attach` 会附加到容器的 **主进程** (PID 1) 的标准输入输出:
|
||||
@@ -126,6 +130,7 @@ flowchart LR
|
||||
end
|
||||
Attach["docker attach"] -->|"附加到这里"| P1
|
||||
```
|
||||
|
||||
#### docker attach 示例
|
||||
|
||||
```bash
|
||||
@@ -139,6 +144,7 @@ $ docker run -dit --name myubuntu ubuntu
|
||||
$ docker attach myubuntu
|
||||
root@243c32535da7:/#
|
||||
```
|
||||
|
||||
#### ⚠️ 重要警告
|
||||
|
||||
**从 attach 会话中输入 `exit` 或按 `Ctrl+D` 会导致容器停止!**
|
||||
@@ -224,6 +230,7 @@ $ docker exec myapp tail -f /var/log/app.log
|
||||
|
||||
$ docker exec myapp python manage.py migrate
|
||||
```
|
||||
|
||||
#### 2. 生产环境避免进入容器
|
||||
|
||||
笔者建议:生产环境应尽量避免进入容器直接操作,而是通过:
|
||||
@@ -261,6 +268,7 @@ $ docker debug myapp
|
||||
```bash
|
||||
$ docker exec -it myapp /bin/sh
|
||||
```
|
||||
|
||||
#### Q:需要 root 权限
|
||||
|
||||
```bash
|
||||
|
||||
@@ -27,6 +27,7 @@ $ docker rm 容器名或ID
|
||||
$ docker rm mycontainer
|
||||
mycontainer
|
||||
```
|
||||
|
||||
#### 强制删除运行中的容器
|
||||
|
||||
```bash
|
||||
@@ -73,6 +74,7 @@ Total reclaimed space: 150MB
|
||||
|
||||
$ docker container prune -f
|
||||
```
|
||||
|
||||
#### 删除所有容器:包括运行中的
|
||||
|
||||
```bash
|
||||
@@ -85,6 +87,7 @@ $ docker rm $(docker ps -aq)
|
||||
|
||||
$ docker rm -f $(docker ps -aq)
|
||||
```
|
||||
|
||||
#### 按条件删除
|
||||
|
||||
```bash
|
||||
@@ -158,6 +161,7 @@ $ docker container prune -f
|
||||
|
||||
$ docker system prune -f
|
||||
```
|
||||
|
||||
#### 生产环境
|
||||
|
||||
```bash
|
||||
@@ -171,6 +175,7 @@ $ docker run --rm ubuntu echo "Hello"
|
||||
|
||||
$ docker container prune --filter "until=168h" # 保留 7 天内的
|
||||
```
|
||||
|
||||
#### 完整清理脚本
|
||||
|
||||
```bash
|
||||
@@ -212,6 +217,7 @@ $ docker rm mycontainer
|
||||
|
||||
$ docker rm -f mycontainer
|
||||
```
|
||||
|
||||
#### Q:删除后磁盘空间没释放
|
||||
|
||||
可能原因:
|
||||
|
||||
@@ -37,6 +37,7 @@ centos The official build of CentOS. 7000+ [OK]
|
||||
```bash
|
||||
$ docker pull nginx:alpine
|
||||
```
|
||||
|
||||
#### 3. 推送镜像
|
||||
|
||||
需要先登录:
|
||||
@@ -108,6 +109,7 @@ $ docker push username/myapp:v1
|
||||
```bash
|
||||
$ echo "dckr_pat_xxxxxxx" | docker login --username username --password-stdin
|
||||
```
|
||||
|
||||
#### 3. 关注镜像漏洞
|
||||
|
||||
Docker Hub 会对官方镜像和付费用户的镜像进行安全扫描。在镜像标签页可以看到漏洞扫描结果。
|
||||
|
||||
@@ -25,6 +25,7 @@ $ docker run -d \
|
||||
-v /opt/data/registry:/var/lib/registry \
|
||||
registry
|
||||
```
|
||||
|
||||
### 6.2.2 在私有仓库上传、搜索、下载镜像
|
||||
|
||||
创建好私有仓库之后,就可以使用 `docker tag` 来标记一个镜像,然后推送它到仓库。例如私有仓库地址为 `127.0.0.1:5000`。
|
||||
@@ -86,6 +87,7 @@ $ docker image ls
|
||||
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
|
||||
127.0.0.1:5000/ubuntu:latest latest ba5877dc9bec 6 weeks ago 192.7 MB
|
||||
```
|
||||
|
||||
### 6.2.3 配置非 https 仓库地址
|
||||
|
||||
如果你不想使用 `127.0.0.1:5000` 作为仓库地址,比如想让本网段的其他主机也能把镜像推送到私有仓库。你就得把例如 `192.168.199.100:5000` 这样的内网地址作为私有仓库地址,这时你会发现无法成功推送镜像。
|
||||
|
||||
@@ -114,6 +114,7 @@ health:
|
||||
interval: 10s
|
||||
threshold: 3
|
||||
```
|
||||
|
||||
### 6.3.3 生成 http 认证文件
|
||||
|
||||
```bash
|
||||
@@ -143,6 +144,7 @@ services:
|
||||
volumes:
|
||||
registry-data:
|
||||
```
|
||||
|
||||
### 6.3.5 修改 Hosts 文件
|
||||
|
||||
编辑 `/etc/hosts`
|
||||
@@ -150,6 +152,7 @@ volumes:
|
||||
```bash
|
||||
127.0.0.1 docker.domain.com
|
||||
```
|
||||
|
||||
### 6.3.6 启动
|
||||
|
||||
```bash
|
||||
|
||||
@@ -107,6 +107,7 @@ server {
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
}
|
||||
```
|
||||
|
||||
### 6.4.5 Docker 主机访问镜像仓库
|
||||
|
||||
如果不启用 SSL 加密可以通过[前面章节](6.2_registry.md)的方法添加非 https 仓库地址到 Docker 的配置文件中然后重启 Docker。
|
||||
|
||||
@@ -30,6 +30,7 @@ COPY . . # 复制到 /app/
|
||||
RUN cd /app
|
||||
RUN echo "hello" > world.txt # 文件在根目录!
|
||||
```
|
||||
|
||||
#### 原因分析
|
||||
|
||||
```dockerfile
|
||||
@@ -110,6 +111,7 @@ RUN npm install
|
||||
COPY . .
|
||||
CMD ["node", "server.js"]
|
||||
```
|
||||
|
||||
#### 2. 使用绝对路径
|
||||
|
||||
```docker
|
||||
@@ -121,6 +123,7 @@ WORKDIR /app
|
||||
|
||||
WORKDIR app
|
||||
```
|
||||
|
||||
#### 3. 不要用 RUN cd
|
||||
|
||||
```docker
|
||||
@@ -133,6 +136,7 @@ RUN cd /app && echo "hello" > world.txt
|
||||
WORKDIR /app
|
||||
RUN echo "hello" > world.txt
|
||||
```
|
||||
|
||||
#### 4. 适时重置 WORKDIR
|
||||
|
||||
```docker
|
||||
|
||||
@@ -55,6 +55,7 @@ USER appuser
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
```
|
||||
|
||||
#### 使用 UID/GID
|
||||
|
||||
```docker
|
||||
@@ -80,6 +81,7 @@ USER nonexistent
|
||||
RUN useradd -r -s /bin/false appuser
|
||||
USER appuser
|
||||
```
|
||||
|
||||
#### 创建用户的方式
|
||||
|
||||
**Debian/Ubuntu**:
|
||||
@@ -139,6 +141,7 @@ chown -R redis:redis /data
|
||||
|
||||
exec gosu redis "$@"
|
||||
```
|
||||
|
||||
#### 为什么不用 su/sudo
|
||||
|
||||
| 问题 | su/sudo | gosu |
|
||||
@@ -208,6 +211,7 @@ CMD ["myapp"]
|
||||
|
||||
CMD ["myapp"] # 以 root 运行
|
||||
```
|
||||
|
||||
#### 2. 使用固定 UID/GID
|
||||
|
||||
便于在宿主机和容器间共享文件:
|
||||
@@ -219,6 +223,7 @@ RUN addgroup -g 1000 -S appgroup && \
|
||||
adduser -u 1000 -S -G appgroup appuser
|
||||
USER 1000:1000
|
||||
```
|
||||
|
||||
#### 3. 多阶段构建中的 USER
|
||||
|
||||
```docker
|
||||
@@ -252,6 +257,7 @@ permission denied: '/app/data.log'
|
||||
```docker
|
||||
RUN mkdir -p /app/data && chown appuser:appuser /app/data
|
||||
```
|
||||
|
||||
#### Q:无法绑定低于 1024 的端口
|
||||
|
||||
非 root 用户无法绑定 80、443 等端口。
|
||||
|
||||
@@ -40,6 +40,7 @@ RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
|
||||
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
|
||||
CMD curl -fs http://localhost/ || exit 1
|
||||
```
|
||||
|
||||
#### 命令返回值
|
||||
|
||||
- `0`:成功 (healthy)
|
||||
@@ -82,6 +83,7 @@ HEALTHCHECK CMD curl -f http://localhost/ || exit 1
|
||||
|
||||
HEALTHCHECK CMD wget -q --spider http://localhost/ || exit 1
|
||||
```
|
||||
|
||||
#### 数据库
|
||||
|
||||
```docker
|
||||
@@ -93,6 +95,7 @@ HEALTHCHECK CMD mysqladmin ping -h localhost || exit 1
|
||||
|
||||
HEALTHCHECK CMD redis-cli ping || exit 1
|
||||
```
|
||||
|
||||
#### 自定义脚本
|
||||
|
||||
```docker
|
||||
@@ -178,6 +181,7 @@ $ docker inspect --format '{{json .State.Health}}' mycontainer | jq
|
||||
|
||||
HEALTHCHECK --start-period=60s CMD curl -f http://localhost/ || exit 1
|
||||
```
|
||||
|
||||
#### 4. 只检查核心依赖
|
||||
|
||||
健康检查应主要关注 **当前服务** 是否可用,而不是检查其下游依赖 (数据库等)。下游依赖的检查应由应用逻辑处理。
|
||||
|
||||
@@ -76,6 +76,7 @@ FROM 基础镜像 ──build──> 读取基础镜像触发器 ──> 执行
|
||||
ONBUILD COPY requirements.txt ./
|
||||
ONBUILD RUN pip install -r requirements.txt
|
||||
```
|
||||
|
||||
#### 2. 自动编译代码
|
||||
|
||||
```docker
|
||||
@@ -84,6 +85,7 @@ ONBUILD RUN pip install -r requirements.txt
|
||||
ONBUILD COPY . .
|
||||
ONBUILD RUN go build -o app main.go
|
||||
```
|
||||
|
||||
#### 3. 处理静态资源
|
||||
|
||||
```docker
|
||||
@@ -127,6 +129,7 @@ ONBUILD COPY dist/ /usr/share/nginx/html/
|
||||
node:20-onbuild
|
||||
python:3.12-onbuild
|
||||
```
|
||||
|
||||
#### 2. 避免执行耗时操作
|
||||
|
||||
尽量不要在 `ONBUILD` 中执行过于耗时或不确定的操作 (如更新系统软件),这会让子镜像构建变得缓慢且不可控。
|
||||
|
||||
@@ -26,6 +26,7 @@ LABEL <key>=<value> <key>=<value> ...
|
||||
LABEL version="1.0"
|
||||
LABEL description="这是一个 Web 应用服务器"
|
||||
```
|
||||
|
||||
#### 定义多个标签:推荐
|
||||
|
||||
```docker
|
||||
@@ -119,6 +120,7 @@ $ docker inspect nginx --format '{{json .Config.Labels}}' | jq
|
||||
"maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
|
||||
}
|
||||
```
|
||||
|
||||
#### 过滤器
|
||||
|
||||
可以使用标签过滤镜像:
|
||||
|
||||
@@ -31,6 +31,7 @@ SHELL ["/bin/bash", "-c"]
|
||||
|
||||
RUN echo {a..z}
|
||||
```
|
||||
|
||||
#### 2. 增强错误处理
|
||||
|
||||
默认情况下,管道命令 `cmd1 | cmd2` 只要 `cmd2` 成功,整个指令就视为成功。这可能掩盖构建错误。
|
||||
@@ -51,6 +52,7 @@ SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
|
||||
RUN wget -O - https://invalid-url | tar xz
|
||||
```
|
||||
|
||||
#### 3. Windows 环境
|
||||
|
||||
在 Windows 容器中,经常需要在 `cmd` 和 `powershell` 之间切换。
|
||||
@@ -122,6 +124,7 @@ RUN echo "Using sh again"
|
||||
```docker
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
```
|
||||
|
||||
#### 2. 明确意图
|
||||
|
||||
如果由于脚本需求必须更改 shell,最好在 Dockerfile 中显式声明,而不是依赖默认行为。
|
||||
|
||||
@@ -46,6 +46,7 @@ CMD ["./app"]
|
||||
```bash
|
||||
$ docker build -t go/helloworld:1 -f Dockerfile.one .
|
||||
```
|
||||
|
||||
### 7.17.2 分散到多个 Dockerfile
|
||||
|
||||
另一种方式,就是我们事先在一个 `Dockerfile` 将项目及其依赖库编译测试打包好后,再将其拷贝到运行环境中,这种方式需要我们编写两个 `Dockerfile` 和一些编译脚本才能将其两个阶段自动整合起来,这种方式虽然可以很好地规避第一种方式存在的风险,但明显部署过程较复杂。
|
||||
@@ -110,6 +111,7 @@ REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
go/helloworld 2 f7cf3465432c 22 seconds ago 6.47MB
|
||||
go/helloworld 1 f55d3e16affc 2 minutes ago 295MB
|
||||
```
|
||||
|
||||
### 7.17.3 使用多阶段构建
|
||||
|
||||
为解决以上问题,Docker v17.05 开始支持多阶段构建 (`multistage builds`)。使用多阶段构建我们就可以很容易解决前面提到的问题,并且只需要编写一个 `Dockerfile`:
|
||||
@@ -168,6 +170,7 @@ FROM golang:alpine as builder
|
||||
```bash
|
||||
$ docker build --target builder -t username/imagename:tag .
|
||||
```
|
||||
|
||||
### 7.17.5 构建时从其他镜像复制文件
|
||||
|
||||
上面例子中我们使用 `COPY --from=0 /go/src/github.com/go/helloworld/app .` 从上一阶段的镜像中复制文件,我们也可以复制任意镜像中的文件。
|
||||
|
||||
@@ -54,6 +54,7 @@ server {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7.18.2 前端构建
|
||||
|
||||
第一阶段进行前端构建。
|
||||
@@ -74,6 +75,7 @@ RUN set -x ; cd /app \
|
||||
&& mkdir -p public \
|
||||
&& npm run production
|
||||
```
|
||||
|
||||
### 7.18.3 安装 Composer 依赖
|
||||
|
||||
第二阶段安装 Composer 依赖。
|
||||
@@ -93,6 +95,7 @@ RUN set -x ; cd /app \
|
||||
--no-scripts \
|
||||
--prefer-dist
|
||||
```
|
||||
|
||||
### 7.18.4 整合以上阶段所生成的文件
|
||||
|
||||
第三阶段对以上阶段生成的文件进行整合。
|
||||
@@ -118,6 +121,7 @@ RUN set -x ; cd ${LARAVEL_PATH} \
|
||||
&& chmod -R 777 storage \
|
||||
&& php artisan package:discover
|
||||
```
|
||||
|
||||
### 7.18.5 最后一个阶段构建 NGINX 镜像
|
||||
|
||||
```docker
|
||||
@@ -128,6 +132,7 @@ ARG LARAVEL_PATH=/app/laravel
|
||||
COPY laravel.conf /etc/nginx/conf.d/
|
||||
COPY --from=laravel ${LARAVEL_PATH}/public ${LARAVEL_PATH}/public
|
||||
```
|
||||
|
||||
### 7.18.6 构建 Laravel 及 Nginx 镜像
|
||||
|
||||
使用 `docker build` 命令构建镜像。
|
||||
@@ -137,6 +142,7 @@ $ docker build -t my/laravel --target=laravel .
|
||||
|
||||
$ docker build -t my/nginx --target=nginx .
|
||||
```
|
||||
|
||||
### 7.18.7 启动容器并测试
|
||||
|
||||
新建 Docker 网络
|
||||
|
||||
@@ -55,6 +55,7 @@ RUN apt-get update && \
|
||||
apt-get install -y nginx && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
```
|
||||
|
||||
#### 2. 清理缓存
|
||||
|
||||
在安装完软件后,立即清除缓存,可以显著减小镜像体积。
|
||||
@@ -103,6 +104,7 @@ RUN touch hello.txt
|
||||
WORKDIR /app
|
||||
RUN touch hello.txt
|
||||
```
|
||||
|
||||
#### Q:环境变量不生效?
|
||||
|
||||
```docker
|
||||
@@ -136,6 +138,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
RUN --mount=type=cache,target=/go/pkg/mod \
|
||||
go build -o app
|
||||
```
|
||||
|
||||
#### 2. 挂载密钥
|
||||
|
||||
安全地使用 SSH 密钥或 Token,而不将其记录在镜像中。
|
||||
|
||||
@@ -23,6 +23,7 @@ COPY package.json /app/
|
||||
|
||||
COPY config.json /app/settings.json
|
||||
```
|
||||
|
||||
#### 复制多个文件
|
||||
|
||||
```docker
|
||||
@@ -35,6 +36,7 @@ COPY package.json package-lock.json /app/
|
||||
COPY *.json /app/
|
||||
COPY src/*.js /app/src/
|
||||
```
|
||||
|
||||
#### 复制目录
|
||||
|
||||
```docker
|
||||
@@ -77,6 +79,7 @@ COPY app[0-9].js /app/ # app0.js ~ app9.js
|
||||
```docker
|
||||
COPY app.js /usr/src/app/
|
||||
```
|
||||
|
||||
#### 相对路径:基于 WORKDIR
|
||||
|
||||
```docker
|
||||
@@ -84,6 +87,7 @@ WORKDIR /app
|
||||
COPY package.json ./ # 复制到 /app/package.json
|
||||
COPY src/ ./src/ # 复制到 /app/src/
|
||||
```
|
||||
|
||||
#### 自动创建目录
|
||||
|
||||
如果目标目录不存在,Docker 会自动创建:
|
||||
@@ -174,6 +178,7 @@ RUN npm run build
|
||||
FROM nginx:alpine
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
```
|
||||
|
||||
#### 使用 --link 优化缓存
|
||||
|
||||
```docker
|
||||
@@ -227,6 +232,7 @@ COPY . .
|
||||
COPY . .
|
||||
RUN npm install
|
||||
```
|
||||
|
||||
#### 2. 使用 .dockerignore
|
||||
|
||||
```docker
|
||||
@@ -238,6 +244,7 @@ COPY . .
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
#### 3. 明确复制路径
|
||||
|
||||
```docker
|
||||
|
||||
@@ -51,6 +51,7 @@ ADD 会识别并解压以下格式:
|
||||
FROM scratch
|
||||
ADD ubuntu-noble-core-cloudimg-amd64-root.tar.gz /
|
||||
```
|
||||
|
||||
#### 解压过程
|
||||
|
||||
```bash
|
||||
@@ -76,6 +77,7 @@ app.tar.gz 包含: /app/ 目录结果:
|
||||
|
||||
ADD https://example.com/app.zip /app/app.zip
|
||||
```
|
||||
|
||||
#### 为什么不推荐
|
||||
|
||||
| 问题 | 说明 |
|
||||
@@ -127,6 +129,7 @@ ADD rootfs.tar.gz /
|
||||
|
||||
ADD dist.tar.gz /app/
|
||||
```
|
||||
|
||||
#### ❌ 不适合使用 ADD
|
||||
|
||||
```docker
|
||||
@@ -180,6 +183,7 @@ ADD app.tar.gz /app/
|
||||
|
||||
COPY . /app/
|
||||
```
|
||||
|
||||
#### 2. 仅在需要解压时使用 ADD
|
||||
|
||||
```docker
|
||||
@@ -187,6 +191,7 @@ COPY . /app/
|
||||
|
||||
ADD app.tar.gz /app/
|
||||
```
|
||||
|
||||
#### 3. 不要用 ADD 下载文件
|
||||
|
||||
```docker
|
||||
@@ -198,6 +203,7 @@ ADD https://example.com/file.tar.gz /tmp/
|
||||
|
||||
RUN curl -fsSL https://example.com/file.tar.gz | tar -xz -C /app
|
||||
```
|
||||
|
||||
#### 4. 解压后清理
|
||||
|
||||
```docker
|
||||
|
||||
@@ -111,6 +111,7 @@ CMD ["/bin/bash"] + cat /etc/os-release
|
||||
|
||||
CMD service nginx start
|
||||
```
|
||||
|
||||
#### 原因分析
|
||||
|
||||
```bash
|
||||
@@ -126,6 +127,7 @@ CMD service nginx start
|
||||
↓
|
||||
6. 容器主进程(sh)退出 → 容器停止
|
||||
```
|
||||
|
||||
#### 正确做法
|
||||
|
||||
```docker
|
||||
@@ -153,6 +155,7 @@ CMD ["curl", "-s", "http://example.com"]
|
||||
$ docker run myimage # 执行默认命令
|
||||
$ docker run myimage curl -v ... # 完全覆盖
|
||||
```
|
||||
|
||||
#### 搭配 ENTRYPOINT
|
||||
|
||||
```docker
|
||||
@@ -182,6 +185,7 @@ CMD ["python", "app.py"]
|
||||
|
||||
CMD ["sh", "-c", "echo $PATH && python app.py"]
|
||||
```
|
||||
|
||||
#### 2. 确保应用在前台运行
|
||||
|
||||
```docker
|
||||
@@ -196,6 +200,7 @@ CMD ["java", "-jar", "app.jar"]
|
||||
CMD service nginx start
|
||||
CMD systemctl start nginx
|
||||
```
|
||||
|
||||
#### 3. 使用双引号
|
||||
|
||||
```docker
|
||||
@@ -207,6 +212,7 @@ CMD ["node", "server.js"]
|
||||
|
||||
CMD ['node', 'server.js']
|
||||
```
|
||||
|
||||
#### 4. 配合 ENTRYPOINT 使用
|
||||
|
||||
```docker
|
||||
@@ -233,6 +239,7 @@ $ docker run myapp --port 9000
|
||||
CMD ["echo", "first"]
|
||||
CMD ["echo", "second"] # 只有这个生效
|
||||
```
|
||||
|
||||
#### Q:如何在 CMD 中使用环境变量?
|
||||
|
||||
```docker
|
||||
@@ -244,6 +251,7 @@ CMD echo "Port is $PORT"
|
||||
|
||||
CMD ["sh", "-c", "echo Port is $PORT"]
|
||||
```
|
||||
|
||||
#### Q:为什么我的容器不响应 Ctrl+C?
|
||||
|
||||
可能是使用了 shell 格式,信号被 sh 吃掉了:
|
||||
|
||||
@@ -95,6 +95,7 @@ exec: "-i": executable file not found
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
#### 使用 ENTRYPOINT 解决
|
||||
|
||||
```docker
|
||||
@@ -111,6 +112,7 @@ HTTP/1.1 200 OK
|
||||
...
|
||||
当前 IP:61.148.226.66
|
||||
```
|
||||
|
||||
#### 交互图示
|
||||
|
||||
```bash
|
||||
@@ -160,6 +162,7 @@ fi
|
||||
|
||||
exec "$@"
|
||||
```
|
||||
|
||||
#### 工作流程
|
||||
|
||||
```bash
|
||||
@@ -173,6 +176,7 @@ docker-entrypoint.sh redis-server docker-entrypoint.sh bash
|
||||
└─ exec gosu redis redis-server └─ exec bash
|
||||
(以 redis 用户运行) (以 root 用户运行)
|
||||
```
|
||||
|
||||
#### 关键点
|
||||
|
||||
1. **exec “$@”**:用传入的参数替换当前进程,确保信号正确传递
|
||||
@@ -261,12 +265,14 @@ ENTRYPOINT ["python", "app.py"]
|
||||
|
||||
ENTRYPOINT python app.py
|
||||
```
|
||||
|
||||
#### 2. 提供有意义的默认参数
|
||||
|
||||
```docker
|
||||
ENTRYPOINT ["nginx"]
|
||||
CMD ["-g", "daemon off;"]
|
||||
```
|
||||
|
||||
#### 3. 入口脚本使用 exec
|
||||
|
||||
```bash
|
||||
@@ -278,6 +284,7 @@ CMD ["-g", "daemon off;"]
|
||||
|
||||
exec "$@"
|
||||
```
|
||||
|
||||
#### 4. 处理信号
|
||||
|
||||
确保 ENTRYPOINT 脚本能正确传递信号:
|
||||
|
||||
@@ -21,6 +21,7 @@ ENV <key1>=<value1> <key2>=<value2> ...
|
||||
ENV NODE_VERSION 20.10.0
|
||||
ENV APP_ENV production
|
||||
```
|
||||
|
||||
#### 设置多个变量
|
||||
|
||||
```docker
|
||||
@@ -53,6 +54,7 @@ WORKDIR $APP_HOME
|
||||
|
||||
COPY . $APP_HOME
|
||||
```
|
||||
|
||||
#### 2. 容器运行时使用
|
||||
|
||||
```docker
|
||||
@@ -106,6 +108,7 @@ $ docker run -e APP_ENV=development -e DEBUG=true myimage
|
||||
|
||||
$ docker run --env-file .env myimage
|
||||
```
|
||||
|
||||
#### .env 文件格式
|
||||
|
||||
```bash
|
||||
@@ -165,6 +168,7 @@ RUN apt-get install nginx=${NGINX_VERSION}
|
||||
|
||||
RUN apt-get install nginx=1.25.0
|
||||
```
|
||||
|
||||
#### 2. 不要存储敏感信息
|
||||
|
||||
```docker
|
||||
@@ -178,6 +182,7 @@ ENV DB_PASSWORD=secret123
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
#### 3. 为应用提供合理默认值
|
||||
|
||||
```docker
|
||||
@@ -185,6 +190,7 @@ ENV APP_ENV=production \
|
||||
APP_PORT=8080 \
|
||||
LOG_LEVEL=info
|
||||
```
|
||||
|
||||
#### 4. 使用有意义的变量名
|
||||
|
||||
```docker
|
||||
@@ -215,12 +221,14 @@ CMD ["python", "app.py", "--port", "$PORT"]
|
||||
|
||||
CMD ["sh", "-c", "python app.py --port $PORT"]
|
||||
```
|
||||
|
||||
#### Q:如何查看容器的环境变量
|
||||
|
||||
```bash
|
||||
$ docker inspect mycontainer --format '{{json .Config.Env}}'
|
||||
$ docker exec mycontainer env
|
||||
```
|
||||
|
||||
#### Q:多行 ENV 还是多个 ENV
|
||||
|
||||
```docker
|
||||
|
||||
@@ -43,6 +43,7 @@ ARG NODE_VERSION=20
|
||||
FROM node:${NODE_VERSION}-alpine
|
||||
RUN echo "Using Node.js $NODE_VERSION"
|
||||
```
|
||||
|
||||
#### 构建时覆盖
|
||||
|
||||
```bash
|
||||
@@ -72,6 +73,7 @@ FROM ${REGISTRY}/${IMAGE_NAME}:20
|
||||
|
||||
RUN echo $REGISTRY # 输出空
|
||||
```
|
||||
|
||||
#### FROM 之后重新声明
|
||||
|
||||
```docker
|
||||
@@ -84,6 +86,7 @@ FROM node:${NODE_VERSION}-alpine
|
||||
ARG NODE_VERSION
|
||||
RUN echo "Node version: $NODE_VERSION"
|
||||
```
|
||||
|
||||
#### 多阶段构建中的 ARG
|
||||
|
||||
```docker
|
||||
@@ -116,6 +119,7 @@ FROM alpine:${ALPINE_VERSION}
|
||||
```bash
|
||||
$ docker build --build-arg ALPINE_VERSION=3.18 .
|
||||
```
|
||||
|
||||
#### 2. 设置软件版本
|
||||
|
||||
```docker
|
||||
@@ -123,6 +127,7 @@ ARG NGINX_VERSION=1.25.0
|
||||
|
||||
RUN curl -fsSL https://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz | tar -xz
|
||||
```
|
||||
|
||||
#### 3. 配置构建环境
|
||||
|
||||
```docker
|
||||
@@ -135,6 +140,7 @@ RUN if [ "$ENABLE_DEBUG" = "true" ]; then \
|
||||
npm install --production; \
|
||||
fi
|
||||
```
|
||||
|
||||
#### 4. 配置私有仓库
|
||||
|
||||
```docker
|
||||
@@ -199,6 +205,7 @@ ARG NODE_VERSION=20
|
||||
|
||||
ARG NODE_VERSION
|
||||
```
|
||||
|
||||
#### 2. 不要用 ARG 存储敏感信息
|
||||
|
||||
```docker
|
||||
@@ -211,6 +218,7 @@ RUN echo "password=$DB_PASSWORD" > /app/.env
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
#### 3. 使用 ARG 提高构建灵活性
|
||||
|
||||
```docker
|
||||
|
||||
@@ -47,6 +47,7 @@ flowchart LR
|
||||
FROM mysql:8.0
|
||||
VOLUME /var/lib/mysql
|
||||
```
|
||||
|
||||
#### 定义多个卷
|
||||
|
||||
```docker
|
||||
@@ -67,6 +68,7 @@ $ docker volume ls
|
||||
DRIVER VOLUME NAME
|
||||
local a1b2c3d4e5f6... # 自动创建的匿名卷
|
||||
```
|
||||
|
||||
#### 2. 可被命名卷覆盖
|
||||
|
||||
```bash
|
||||
@@ -74,6 +76,7 @@ local a1b2c3d4e5f6... # 自动创建的匿名卷
|
||||
|
||||
$ docker run -v mysql_data:/var/lib/mysql mysql:8.0
|
||||
```
|
||||
|
||||
#### 3. 可被 Bind Mount 覆盖
|
||||
|
||||
```bash
|
||||
@@ -120,12 +123,14 @@ VOLUME /data
|
||||
FROM postgres:16
|
||||
VOLUME /var/lib/postgresql/data
|
||||
```
|
||||
|
||||
#### 日志目录
|
||||
|
||||
```docker
|
||||
FROM nginx
|
||||
VOLUME /var/log/nginx
|
||||
```
|
||||
|
||||
#### 上传文件目录
|
||||
|
||||
```docker
|
||||
@@ -212,6 +217,7 @@ $ docker run -v mysql_data:/var/lib/mysql mysql:8.0
|
||||
FROM postgres:16
|
||||
VOLUME /var/lib/postgresql/data
|
||||
```
|
||||
|
||||
#### 2. 不要在 VOLUME 后修改目录
|
||||
|
||||
```docker
|
||||
@@ -225,6 +231,7 @@ RUN cp init-data.json /app/data/
|
||||
RUN mkdir -p /app/data && cp init-data.json /app/data/
|
||||
VOLUME /app/data
|
||||
```
|
||||
|
||||
#### 3. 文档中说明 VOLUME 用途
|
||||
|
||||
```docker
|
||||
|
||||
@@ -44,6 +44,7 @@ EXPOSE 80 443
|
||||
$ docker inspect nginx --format '{{.Config.ExposedPorts}}'
|
||||
map[80/tcp:{}]
|
||||
```
|
||||
|
||||
#### 2. 配合 -P 使用
|
||||
|
||||
使用 `docker run -P` 时,Docker 会自动映射 EXPOSE 的端口到宿主机随机端口:
|
||||
@@ -75,6 +76,7 @@ flowchart TD
|
||||
Run["docker run -p<br/>实际端口映射<br/>宿主机 ←→ 容器"]
|
||||
Expose ~~~ Run
|
||||
```
|
||||
|
||||
#### 没有 EXPOSE 也能 -p
|
||||
|
||||
```docker
|
||||
@@ -145,6 +147,7 @@ EXPOSE 5432
|
||||
FROM redis
|
||||
EXPOSE 6379
|
||||
```
|
||||
|
||||
#### 2. 使用明确的协议
|
||||
|
||||
```docker
|
||||
@@ -160,6 +163,7 @@ EXPOSE 53/udp
|
||||
|
||||
EXPOSE 53/tcp 53/udp
|
||||
```
|
||||
|
||||
#### 3. 与应用实际端口保持一致
|
||||
|
||||
```docker
|
||||
|
||||
@@ -41,6 +41,7 @@ graph TD
|
||||
Lifecycle[生命周期 = 容器生命周期] -.-> Container
|
||||
Delete[容器删除] -->|导致| DataLost[数据丢失 ❌]
|
||||
```
|
||||
|
||||
#### 数据卷:推荐
|
||||
|
||||
```mermaid
|
||||
@@ -65,6 +66,7 @@ graph TD
|
||||
```bash
|
||||
$ docker volume create my-vol
|
||||
```
|
||||
|
||||
#### 列出所有数据卷
|
||||
|
||||
```bash
|
||||
@@ -74,6 +76,7 @@ local my-vol
|
||||
local postgres_data
|
||||
local redis_data
|
||||
```
|
||||
|
||||
#### 查看数据卷详情
|
||||
|
||||
```bash
|
||||
@@ -182,6 +185,7 @@ $ docker run -d \
|
||||
-v postgres_data:/var/lib/postgresql/data \
|
||||
postgres:16
|
||||
```
|
||||
|
||||
#### 场景二:多容器共享数据
|
||||
|
||||
```bash
|
||||
@@ -201,6 +205,7 @@ $ docker run --rm \
|
||||
-v shared-data:/data \
|
||||
alpine cat /data/log.txt
|
||||
```
|
||||
|
||||
#### 场景三:配置文件持久化
|
||||
|
||||
```bash
|
||||
@@ -227,6 +232,7 @@ $ docker volume rm my-vol
|
||||
|
||||
$ docker rm -v container_name
|
||||
```
|
||||
|
||||
#### 清理未使用的数据卷
|
||||
|
||||
```bash
|
||||
@@ -279,6 +285,7 @@ $ docker run --rm \
|
||||
-v $(pwd):/backup:ro \
|
||||
alpine tar xzf /backup/my-vol-backup.tar.gz -C /target
|
||||
```
|
||||
|
||||
#### 备份脚本示例
|
||||
|
||||
```bash
|
||||
@@ -331,6 +338,7 @@ $ docker run -v /host/path:/app/data nginx
|
||||
```bash
|
||||
$ docker inspect container_name --format '{{json .Mounts}}' | jq
|
||||
```
|
||||
|
||||
#### Q:数据卷的数据在哪里?
|
||||
|
||||
```bash
|
||||
|
||||
@@ -58,6 +58,7 @@ $ docker run -d \
|
||||
--mount type=bind,source=/宿主机路径,target=/容器路径 \
|
||||
nginx
|
||||
```
|
||||
|
||||
#### 使用 -v:简写
|
||||
|
||||
```bash
|
||||
@@ -65,6 +66,7 @@ $ docker run -d \
|
||||
-v /宿主机路径:/容器路径 \
|
||||
nginx
|
||||
```
|
||||
|
||||
#### 两种语法对比
|
||||
|
||||
| 特性 | --mount | -v |
|
||||
@@ -97,6 +99,7 @@ $ echo "Hello" > src/index.html
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
#### 场景二:配置文件挂载
|
||||
|
||||
```bash
|
||||
@@ -106,6 +109,7 @@ $ docker run -d \
|
||||
--mount type=bind,source=/path/to/nginx.conf,target=/etc/nginx/nginx.conf,readonly \
|
||||
nginx
|
||||
```
|
||||
|
||||
#### 场景三:日志收集
|
||||
|
||||
```bash
|
||||
@@ -115,6 +119,7 @@ $ docker run -d \
|
||||
--mount type=bind,source=/var/log/myapp,target=/app/logs \
|
||||
myapp
|
||||
```
|
||||
|
||||
#### 场景四:共享 SSH 密钥
|
||||
|
||||
```bash
|
||||
@@ -227,6 +232,7 @@ $ docker run -u root ...
|
||||
|
||||
$ docker run -u $(id -u):$(id -g) ...
|
||||
```
|
||||
|
||||
#### Q:macOS/Windows 性能问题
|
||||
|
||||
在 Docker Desktop 上,Bind Mount 性能较差 (需要跨文件系统同步):
|
||||
@@ -253,6 +259,7 @@ $ docker run -v /host/path:/container/path:cached myapp
|
||||
|
||||
$ docker run -v $(pwd):/app -p 3000:3000 node npm run dev
|
||||
```
|
||||
|
||||
#### 2. 生产环境使用 Volume
|
||||
|
||||
```bash
|
||||
@@ -260,11 +267,13 @@ $ docker run -v $(pwd):/app -p 3000:3000 node npm run dev
|
||||
|
||||
$ docker run -v mysql_data:/var/lib/mysql mysql
|
||||
```
|
||||
|
||||
#### 3. 配置文件使用只读挂载
|
||||
|
||||
```bash
|
||||
$ docker run -v /config/nginx.conf:/etc/nginx/nginx.conf:ro nginx
|
||||
```
|
||||
|
||||
#### 4. 注意路径安全
|
||||
|
||||
```bash
|
||||
|
||||
@@ -49,6 +49,7 @@ Docker 守护进程在 `127.0.0.11` 运行了一个 DNS 服务器。容器内的
|
||||
$ docker run -it --dns=114.114.114.114 ubuntu cat /etc/resolv.conf
|
||||
nameserver 114.114.114.114
|
||||
```
|
||||
|
||||
#### 2. --dns-search
|
||||
|
||||
指定 DNS 搜索域。例如设置为 `example.com`,则 `ping host` 会尝试解析 `host.example.com`。
|
||||
@@ -56,6 +57,7 @@ nameserver 114.114.114.114
|
||||
```bash
|
||||
$ docker run --dns-search=example.com myapp
|
||||
```
|
||||
|
||||
#### 3. --hostname 与 -h
|
||||
|
||||
设置容器的主机名。
|
||||
|
||||
@@ -9,6 +9,7 @@ abc123... bridge bridge local
|
||||
def456... host host local
|
||||
ghi789... none null local
|
||||
```
|
||||
|
||||
### 9.2.1 网络类型对比
|
||||
|
||||
各网络类型的特点和适用场景如下:
|
||||
@@ -52,6 +53,7 @@ $ docker run -it --network none alpine ip addr
|
||||
1: lo: <LOOPBACK,UP,LOWER_UP> ...
|
||||
inet 127.0.0.1/8 scope host lo
|
||||
```
|
||||
|
||||
### 9.2.5 数据流向
|
||||
|
||||
容器网络中的数据流向可以分为以下几种情况:
|
||||
|
||||
@@ -25,6 +25,7 @@ $ docker network create mynet
|
||||
|
||||
$ docker network inspect mynet
|
||||
```
|
||||
|
||||
### 9.3.3 使用自定义网络
|
||||
|
||||
启动容器时通过 `--network` 参数指定连接的网络:
|
||||
@@ -41,6 +42,7 @@ $ docker exec web ping db
|
||||
PING db (172.18.0.3): 56 data bytes
|
||||
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.083 ms
|
||||
```
|
||||
|
||||
### 9.3.4 容器名 DNS 解析
|
||||
|
||||
自定义网络自动提供 DNS 服务。Docker 守护进程在 `127.0.0.11` 运行了一个嵌入式 DNS 服务器,容器内的 DNS 请求会被转发到这里:
|
||||
@@ -55,6 +57,7 @@ flowchart LR
|
||||
Web["web<br/>172.18.0.2"] -- "DNS: 'db' → 172.18.0.3" --> DB["db<br/>172.18.0.3"]
|
||||
end
|
||||
```
|
||||
|
||||
### 9.3.5 常用网络命令
|
||||
|
||||
以下是 Docker 网络管理中常用的命令:
|
||||
|
||||
@@ -20,6 +20,7 @@ $ docker run -d --name app --network app-net myapp
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
### 9.4.2 连接到多个网络
|
||||
|
||||
一个容器可以同时连接到多个网络,这对于需要跨网络通信的中间件容器特别有用:
|
||||
@@ -37,6 +38,7 @@ $ docker network connect backend multi-net-container
|
||||
|
||||
$ docker inspect multi-net-container --format '{{json .NetworkSettings.Networks}}'
|
||||
```
|
||||
|
||||
### 9.4.3 ⚠️ --link 已废弃
|
||||
|
||||
`--link` 是 Docker 早期用于容器互联的方式,**已经被废弃**,不建议在新项目中使用。请使用自定义网络替代:
|
||||
|
||||
@@ -75,6 +75,7 @@ $ docker port mycontainer
|
||||
80/tcp -> 0.0.0.0:8080
|
||||
80/tcp -> [::]:8080
|
||||
```
|
||||
|
||||
#### docker ps
|
||||
|
||||
运行 `docker ps` 可以查看到所有容器的端口映射列表:
|
||||
@@ -101,6 +102,7 @@ abc123456 nginx 0.0.0.0:8080->80/tcp web
|
||||
|
||||
$ docker run -d -p 127.0.0.1:3306:3306 mysql
|
||||
```
|
||||
|
||||
#### 2. 避免端口冲突
|
||||
|
||||
如果宿主机 8080 已经被占用了,容器将无法启动。
|
||||
|
||||
@@ -25,6 +25,7 @@ $ docker run -d --name db --network backend postgres
|
||||
$ docker exec web ping db
|
||||
ping: db: Name or service not known
|
||||
```
|
||||
|
||||
### 9.6.2 安全优势
|
||||
|
||||
这种隔离机制带来以下安全优势:
|
||||
|
||||
@@ -29,6 +29,7 @@ veth 对
|
||||
↓
|
||||
容器 B (192.168.0.3,不同宿主机)
|
||||
```
|
||||
|
||||
#### 创建和使用 Overlay 网络
|
||||
|
||||
**Docker Swarm 模式下的 Overlay 网络:**
|
||||
@@ -73,6 +74,7 @@ docker exec container1 curl http://container2
|
||||
# 检查网络配置
|
||||
docker network inspect custom-overlay
|
||||
```
|
||||
|
||||
#### Overlay 网络性能优化
|
||||
|
||||
```bash
|
||||
@@ -107,6 +109,7 @@ networks:
|
||||
driver_opts:
|
||||
com.docker.network.driver.mtu: 1450
|
||||
```
|
||||
|
||||
### 9.7.2 CNI 插件生态概览
|
||||
|
||||
容器网络接口(CNI)是容器编排平台(尤其是 Kubernetes)的标准化网络接口。不同的 CNI 插件提供不同的网络能力。
|
||||
@@ -255,6 +258,7 @@ Docker 内嵌 DNS 服务器 (127.0.0.11)
|
||||
↓
|
||||
DNS 响应 → 容器缓存 → 应用
|
||||
```
|
||||
|
||||
#### 配置容器 DNS
|
||||
|
||||
**在运行时指定 DNS:**
|
||||
@@ -317,6 +321,7 @@ networks:
|
||||
"registry-mirrors": ["https://mirror.example.com"]
|
||||
}
|
||||
```
|
||||
|
||||
#### 自定义服务发现
|
||||
|
||||
**使用 Docker 内建 DNS 的服务发现:**
|
||||
@@ -361,6 +366,7 @@ services:
|
||||
# frontend 容器可以直接访问 http://backend:8080
|
||||
# backend 容器可以直接访问 postgres://database:5432
|
||||
```
|
||||
|
||||
#### DNS 性能优化
|
||||
|
||||
```bash
|
||||
@@ -393,6 +399,7 @@ kubectl patch deployment -n kube-system coredns --patch '{
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
### 9.7.4 网络策略实践
|
||||
|
||||
网络策略定义了容器间的流量控制规则,是微服务架构中的安全基础。
|
||||
@@ -473,6 +480,7 @@ spec:
|
||||
- protocol: TCP
|
||||
port: 443
|
||||
```
|
||||
|
||||
#### 微服务网络策略示例
|
||||
|
||||
```yaml
|
||||
@@ -597,6 +605,7 @@ spec:
|
||||
- protocol: TCP
|
||||
port: 5432
|
||||
```
|
||||
|
||||
#### 使用 Calico/Cilium 的高级网络策略
|
||||
|
||||
**L7 应用层策略(仅 Cilium 支持):**
|
||||
@@ -630,6 +639,7 @@ spec:
|
||||
sourceIPs:
|
||||
- "10.0.0.0/8"
|
||||
```
|
||||
|
||||
### 9.7.5 跨主机容器通信方案对比
|
||||
|
||||
#### 方案对比表
|
||||
@@ -661,6 +671,7 @@ helm install cilium cilium/cilium --namespace kube-system
|
||||
|
||||
# 5. 需要多云/跨域:使用 Weave
|
||||
```
|
||||
|
||||
### 9.7.6 网络故障排查
|
||||
|
||||
**常见网络问题诊断:**
|
||||
|
||||
@@ -110,6 +110,7 @@ RUN --mount=type=cache,target=/tmp/dist,from=builder,source=/app/dist \
|
||||
RUN --mount=type=bind,from=php:alpine,source=/usr/local/bin/docker-php-entrypoint,target=/docker-php-entrypoint \
|
||||
cat /docker-php-entrypoint
|
||||
```
|
||||
|
||||
#### `RUN --mount=type=tmpfs`
|
||||
|
||||
该指令可以将一个 `tmpfs` 文件系统挂载到指定位置。
|
||||
@@ -120,6 +121,7 @@ RUN --mount=type=bind,from=php:alpine,source=/usr/local/bin/docker-php-entrypoin
|
||||
RUN --mount=type=tmpfs,target=/temp \
|
||||
mount | grep /temp
|
||||
```
|
||||
|
||||
#### `RUN --mount=type=secret`
|
||||
|
||||
该指令可以将一个文件 (例如密钥) 挂载到指定位置。
|
||||
@@ -133,6 +135,7 @@ RUN --mount=type=secret,id=aws,target=/root/.aws/credentials \
|
||||
```bash
|
||||
$ docker build -t test --secret id=aws,src=$HOME/.aws/credentials .
|
||||
```
|
||||
|
||||
#### `RUN --mount=type=ssh`
|
||||
|
||||
该指令可以挂载 `ssh` 密钥。
|
||||
@@ -151,6 +154,7 @@ $ ssh-add ~/.ssh/id_rsa
|
||||
(Input your passphrase here)
|
||||
$ docker build -t test --ssh default=$SSH_AUTH_SOCK .
|
||||
```
|
||||
|
||||
### 10.1.2 使用 `docker compose build` 与 BuildKit
|
||||
|
||||
Docker Compose 同样支持 BuildKit,这使得多服务应用的构建更加高效。
|
||||
|
||||
@@ -26,6 +26,7 @@ $ docker buildx bake
|
||||
|
||||
$ docker buildx bake web
|
||||
```
|
||||
|
||||
#### 生成 SBOM
|
||||
|
||||
Buildx 支持在构建时直接生成 SBOM (Software Bill of Materials),这对于软件供应链安全至关重要。
|
||||
|
||||
@@ -39,6 +39,7 @@ $ docker manifest inspect hello-world
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 10.3.2 使用 `docker buildx` 构建多架构镜像
|
||||
|
||||
`docker buildx` 是构建多架构镜像的最佳实践工具,它屏蔽了底层的复杂性,提供了一键构建多架构镜像的能力。
|
||||
@@ -53,6 +54,7 @@ $ docker manifest inspect hello-world
|
||||
$ docker buildx create --name mybuilder --use
|
||||
$ docker buildx inspect --bootstrap
|
||||
```
|
||||
|
||||
#### 构建和推送
|
||||
|
||||
使用 `docker buildx build` 命令并指定 `--platform` 参数,可以同时构建支持多种架构的镜像。`--push` 参数会将构建好的镜像和 manifest list 推送到 Docker 仓库。
|
||||
@@ -96,6 +98,7 @@ COPY bin/dist-${TARGETOS}-${TARGETARCH} /dist
|
||||
|
||||
ENTRYPOINT ["/dist"]
|
||||
```
|
||||
|
||||
### 10.3.3 使用 `docker manifest`:底层工具
|
||||
|
||||
除了 `docker buildx`,我们也可以直接操作 Manifest List 来手动组合不同架构的镜像。
|
||||
@@ -120,6 +123,7 @@ $ docker manifest create your-username/my-app:latest \
|
||||
|
||||
$ docker manifest push your-username/my-app:latest
|
||||
```
|
||||
|
||||
#### 检查 manifest list
|
||||
|
||||
你可以使用 `docker manifest inspect` 来查看一个 manifest list 的详细信息,如上文所示。
|
||||
|
||||
@@ -30,17 +30,20 @@ $ curl -SL https://github.com/docker/compose/releases/download/v5.1.0/docker-com
|
||||
```bash
|
||||
$ chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
|
||||
```
|
||||
|
||||
### 11.2.2 测试安装
|
||||
|
||||
```bash
|
||||
$ docker compose version
|
||||
Docker Compose version v5.1.0
|
||||
```
|
||||
|
||||
### 11.2.3 bash 补全命令
|
||||
|
||||
```bash
|
||||
$ curl -L https://raw.githubusercontent.com/docker/compose/v5.1.0/contrib/completion/bash/docker-compose | sudo tee /etc/bash_completion.d/docker-compose > /dev/null
|
||||
```
|
||||
|
||||
### 11.2.4 卸载
|
||||
|
||||
如果是二进制包方式安装的,删除二进制文件即可。
|
||||
|
||||
@@ -37,6 +37,7 @@ def hello():
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", debug=True)
|
||||
```
|
||||
|
||||
#### Dockerfile
|
||||
|
||||
编写 `Dockerfile` 文件,内容为
|
||||
@@ -48,6 +49,7 @@ WORKDIR /code
|
||||
RUN pip install redis flask
|
||||
CMD ["python", "app.py"]
|
||||
```
|
||||
|
||||
#### compose.yaml
|
||||
|
||||
编写 `compose.yaml` 文件,这是 Compose 推荐使用的主模板文件 (也兼容 `docker-compose.yml` 等历史文件名)。
|
||||
@@ -62,6 +64,7 @@ services:
|
||||
redis:
|
||||
image: "redis:alpine"
|
||||
```
|
||||
|
||||
#### 运行 compose 项目
|
||||
|
||||
```bash
|
||||
@@ -77,11 +80,13 @@ $ docker compose up
|
||||
```bash
|
||||
$ docker compose up -d
|
||||
```
|
||||
|
||||
#### 停止
|
||||
|
||||
```bash
|
||||
$ docker compose stop
|
||||
```
|
||||
|
||||
#### 进入服务
|
||||
|
||||
```bash
|
||||
@@ -90,31 +95,37 @@ $ docker compose exec redis sh
|
||||
127.0.0.1:6379> get hits
|
||||
"9"
|
||||
```
|
||||
|
||||
#### 查看日志
|
||||
|
||||
```bash
|
||||
$ docker compose logs -f
|
||||
```
|
||||
|
||||
#### 构建镜像
|
||||
|
||||
```bash
|
||||
$ docker compose build
|
||||
```
|
||||
|
||||
#### 启动服务
|
||||
|
||||
```bash
|
||||
$ docker compose start
|
||||
```
|
||||
|
||||
#### 运行一次性命令
|
||||
|
||||
```bash
|
||||
$ docker compose run web python app.py
|
||||
```
|
||||
|
||||
#### 验证 Compose 文件
|
||||
|
||||
```bash
|
||||
$ docker compose config
|
||||
```
|
||||
|
||||
#### 删除项目
|
||||
|
||||
```bash
|
||||
|
||||
@@ -13,6 +13,7 @@ Docker Compose 提供了丰富的命令来管理项目和容器。本节将详
|
||||
```bash
|
||||
docker compose [-f=<arg>...] [options] [COMMAND] [ARGS...]
|
||||
```
|
||||
|
||||
### 11.4.2 命令选项
|
||||
|
||||
* `-f, --file FILE` 指定使用的 Compose 模板文件。默认会自动识别 `compose.yaml` (也兼容 `docker-compose.yml` 等),并且可以多次指定。
|
||||
@@ -74,6 +75,7 @@ docker compose [-f=<arg>...] [options] [COMMAND] [ARGS...]
|
||||
```bash
|
||||
$ docker compose kill -s SIGINT
|
||||
```
|
||||
|
||||
#### `logs`
|
||||
|
||||
格式为 `docker compose logs [options] [SERVICE...]`。
|
||||
|
||||
@@ -52,6 +52,7 @@ build:
|
||||
- alpine:latest
|
||||
- corp/web_app:3.14
|
||||
```
|
||||
|
||||
### 11.5.2 `cap_add, cap_drop`
|
||||
|
||||
指定容器的内核能力 (capacity) 分配。
|
||||
@@ -68,6 +69,7 @@ cap_add:
|
||||
cap_drop:
|
||||
- NET_ADMIN
|
||||
```
|
||||
|
||||
### 11.5.3 `command`
|
||||
|
||||
覆盖容器启动后默认执行的命令。
|
||||
@@ -75,6 +77,7 @@ cap_drop:
|
||||
```yaml
|
||||
command: echo "hello world"
|
||||
```
|
||||
|
||||
### 11.5.4 `configs`
|
||||
|
||||
`configs` 来自 Compose Specification。它在 Swarm 中是原生对象;在本地 `docker compose` 模式下通常以文件挂载的形式实现,具体能力取决于 Compose 版本与运行平台。
|
||||
@@ -88,6 +91,7 @@ command: echo "hello world"
|
||||
```yaml
|
||||
cgroup_parent: cgroups_1
|
||||
```
|
||||
|
||||
### 11.5.6 `container_name`
|
||||
|
||||
指定容器名称。默认将会使用 `项目名称_服务名称_序号` 这样的格式。
|
||||
@@ -109,6 +113,7 @@ container_name: docker-web-container
|
||||
devices:
|
||||
- "/dev/ttyUSB1:/dev/ttyUSB0"
|
||||
```
|
||||
|
||||
### 11.5.9 `depends_on`
|
||||
|
||||
解决容器的依赖、启动先后的问题。以下例子中会先启动 `redis` `db` 再启动 `web`
|
||||
@@ -140,6 +145,7 @@ dns:
|
||||
- 8.8.8.8
|
||||
- 114.114.114.114
|
||||
```
|
||||
|
||||
### 11.5.11 `dns_search`
|
||||
|
||||
配置 `DNS` 搜索域。可以是一个值,也可以是一个列表。
|
||||
@@ -151,6 +157,7 @@ dns_search:
|
||||
- domain1.example.com
|
||||
- domain2.example.com
|
||||
```
|
||||
|
||||
### 11.5.12 `tmpfs`
|
||||
|
||||
挂载一个 tmpfs 文件系统到容器。
|
||||
@@ -161,6 +168,7 @@ tmpfs:
|
||||
- /run
|
||||
- /tmp
|
||||
```
|
||||
|
||||
### 11.5.13 `env_file`
|
||||
|
||||
从文件中获取环境变量,可以为单独的文件路径或列表。
|
||||
@@ -184,6 +192,7 @@ env_file:
|
||||
|
||||
PROG_ENV=development
|
||||
```
|
||||
|
||||
### 11.5.14 `environment`
|
||||
|
||||
设置环境变量。你可以使用数组或字典两种格式。
|
||||
@@ -204,6 +213,7 @@ environment:
|
||||
```bash
|
||||
y|Y|yes|Yes|YES|n|N|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF
|
||||
```
|
||||
|
||||
### 11.5.15 `expose`
|
||||
|
||||
暴露端口,但不映射到宿主机,只被连接的服务访问。
|
||||
@@ -215,6 +225,7 @@ expose:
|
||||
- "3000"
|
||||
- "8000"
|
||||
```
|
||||
|
||||
### 11.5.16 `external_links`
|
||||
|
||||
> 注意:不建议使用该指令。
|
||||
@@ -227,6 +238,7 @@ external_links:
|
||||
- project_db_1:mysql
|
||||
- project_db_1:postgresql
|
||||
```
|
||||
|
||||
### 11.5.17 `extra_hosts`
|
||||
|
||||
类似 Docker 中的 `--add-host` 参数,指定额外的 host 名称映射信息。
|
||||
@@ -242,6 +254,7 @@ extra_hosts:
|
||||
8.8.8.8 googledns
|
||||
52.1.157.61 dockerhub
|
||||
```
|
||||
|
||||
### 11.5.18 `healthcheck`
|
||||
|
||||
通过命令检查容器是否健康运行。
|
||||
@@ -253,6 +266,7 @@ healthcheck:
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
```
|
||||
|
||||
### 11.5.19 `image`
|
||||
|
||||
指定为镜像名称或镜像 ID。如果镜像在本地不存在,`Compose` 将会尝试拉取这个镜像。
|
||||
@@ -262,6 +276,7 @@ image: ubuntu
|
||||
image: orchardup/postgresql
|
||||
image: a4bc65fd
|
||||
```
|
||||
|
||||
### 11.5.20 `labels`
|
||||
|
||||
为容器添加 Docker 元数据 (metadata) 信息。例如可以为容器添加辅助说明信息。
|
||||
@@ -272,6 +287,7 @@ labels:
|
||||
com.startupteam.department: "devops department"
|
||||
com.startupteam.release: "rc3 for v1.0"
|
||||
```
|
||||
|
||||
### 11.5.21 `links`
|
||||
|
||||
> 注意:不推荐使用该指令。容器之间应通过 Docker 网络 (networks) 进行互联。
|
||||
@@ -300,6 +316,7 @@ options:
|
||||
max-size: "200k"
|
||||
max-file: "10"
|
||||
```
|
||||
|
||||
### 11.5.23 `network_mode`
|
||||
|
||||
设置网络模式。使用和 `docker run` 的 `--network` 参数一样的值。
|
||||
@@ -311,6 +328,7 @@ network_mode: "none"
|
||||
network_mode: "service:[service name]"
|
||||
network_mode: "container:[container name/id]"
|
||||
```
|
||||
|
||||
### 11.5.24 `networks`
|
||||
|
||||
配置容器连接的网络。
|
||||
@@ -327,6 +345,7 @@ networks:
|
||||
some-network:
|
||||
other-network:
|
||||
```
|
||||
|
||||
### 11.5.25 `pid`
|
||||
|
||||
跟主机系统共享进程命名空间。打开该选项的容器之间,以及容器和宿主机系统之间可以通过进程 ID 来相互访问和操作。
|
||||
@@ -334,6 +353,7 @@ networks:
|
||||
```yaml
|
||||
pid: "host"
|
||||
```
|
||||
|
||||
### 11.5.26 `ports`
|
||||
|
||||
暴露端口信息。
|
||||
@@ -370,6 +390,7 @@ secrets:
|
||||
my_other_secret:
|
||||
external: true
|
||||
```
|
||||
|
||||
### 11.5.28 `security_opt`
|
||||
|
||||
指定容器模板标签 (label) 机制的默认属性 (用户、角色、类型、级别等)。例如配置标签的用户名和角色名。
|
||||
@@ -379,6 +400,7 @@ security_opt:
|
||||
- label:user:USER
|
||||
- label:role:ROLE
|
||||
```
|
||||
|
||||
### 11.5.29 `stop_signal`
|
||||
|
||||
设置另一个信号来停止容器。在默认情况下使用的是 SIGTERM 停止容器。
|
||||
@@ -386,6 +408,7 @@ security_opt:
|
||||
```yaml
|
||||
stop_signal: SIGUSR1
|
||||
```
|
||||
|
||||
### 11.5.30 `sysctls`
|
||||
|
||||
配置容器内核参数。
|
||||
@@ -399,6 +422,7 @@ sysctls:
|
||||
- net.core.somaxconn=1024
|
||||
- net.ipv4.tcp_syncookies=0
|
||||
```
|
||||
|
||||
### 11.5.31 `ulimits`
|
||||
|
||||
指定容器的 ulimits 限制值。
|
||||
@@ -412,6 +436,7 @@ sysctls:
|
||||
soft: 20000
|
||||
hard: 40000
|
||||
```
|
||||
|
||||
### 11.5.32 `volumes`
|
||||
|
||||
数据卷所挂载路径设置。可以设置为宿主机路径 (`HOST:CONTAINER`) 或者数据卷名称 (`VOLUME:CONTAINER`),并且可以设置访问模式 (`HOST:CONTAINER:ro`)。
|
||||
@@ -436,6 +461,7 @@ services:
|
||||
volumes:
|
||||
mysql_data:
|
||||
```
|
||||
|
||||
### 11.5.33 其它指令
|
||||
|
||||
此外,还有包括 `domainname, entrypoint, hostname, ipc, mac_address, privileged, read_only, shm_size, restart, stdin_open, tty, user, working_dir` 等指令,基本跟 `docker run` 中对应参数的功能一致。
|
||||
@@ -487,6 +513,7 @@ stdin_open: true
|
||||
```yaml
|
||||
tty: true
|
||||
```
|
||||
|
||||
### 11.5.34 读取变量
|
||||
|
||||
Compose 模板文件支持动态读取主机的系统环境变量和当前目录下的 `.env` 文件中的变量。
|
||||
|
||||
@@ -298,6 +298,7 @@ $ docker compose exec db psql -U django_user -d django_db
|
||||
$ docker compose ps
|
||||
$ docker compose logs db
|
||||
```
|
||||
|
||||
#### Q2:代码修改没有生效
|
||||
|
||||
**可能原因**:
|
||||
@@ -313,6 +314,7 @@ $ docker compose logs db
|
||||
|
||||
$ sudo chown -R $USER:$USER .
|
||||
```
|
||||
|
||||
### 11.6.11 开发 vs 生产:关键差异
|
||||
|
||||
笔者特别提醒,本节的配置是 **开发环境** 配置。生产环境需要以下调整:
|
||||
@@ -340,6 +342,7 @@ services:
|
||||
# ...
|
||||
|
||||
```
|
||||
|
||||
### 11.6.12 延伸阅读
|
||||
|
||||
- [Compose 模板文件详解](11.5_compose_file.md):深入理解 Compose 文件的所有配置项
|
||||
|
||||
@@ -88,6 +88,7 @@ gem 'rails', '~> 7.1'
|
||||
```bash
|
||||
$ touch Gemfile.lock
|
||||
```
|
||||
|
||||
### 11.7.5 步骤 3:创建 compose.yaml
|
||||
|
||||
配置如下:
|
||||
@@ -157,6 +158,7 @@ compose.yaml bin db public
|
||||
```bash
|
||||
$ docker compose build
|
||||
```
|
||||
|
||||
### 11.7.8 步骤 6:配置数据库连接
|
||||
|
||||
修改 `config/database.yml`:
|
||||
@@ -196,6 +198,7 @@ web-1 | => Run `bin/rails server --help` for more startup options
|
||||
web-1 | Puma starting in single mode...
|
||||
web-1 | * Listening on http://0.0.0.0:3000
|
||||
```
|
||||
|
||||
### 11.7.10 步骤 8:创建数据库
|
||||
|
||||
在另一个终端执行:
|
||||
@@ -230,6 +233,7 @@ $ docker compose exec web rails generate scaffold Post title:string body:text
|
||||
|
||||
$ docker compose exec web bash
|
||||
```
|
||||
|
||||
### 11.7.12 常见问题
|
||||
|
||||
#### Q:数据库连接失败
|
||||
@@ -240,6 +244,7 @@ $ docker compose exec web bash
|
||||
$ docker compose ps
|
||||
$ docker compose logs db
|
||||
```
|
||||
|
||||
#### Q:server.pid 文件导致启动失败
|
||||
|
||||
错误信息:`A server is already running`
|
||||
@@ -249,6 +254,7 @@ $ docker compose logs db
|
||||
```bash
|
||||
$ docker compose exec web rm -f tmp/pids/server.pid
|
||||
```
|
||||
|
||||
#### Q:Gem 安装失败
|
||||
|
||||
可能需要更新 bundler 或清理缓存:
|
||||
@@ -256,6 +262,7 @@ $ docker compose exec web rm -f tmp/pids/server.pid
|
||||
```bash
|
||||
$ docker compose run --rm web bundle update
|
||||
```
|
||||
|
||||
### 11.7.13 开发 vs 生产
|
||||
|
||||
| 配置项 | 开发环境 | 生产环境 |
|
||||
|
||||
@@ -154,6 +154,7 @@ $ docker exec wordpress_db mysqldump -u wordpress -pwordpress wordpress > backup
|
||||
networks:
|
||||
- wp_net
|
||||
```
|
||||
|
||||
#### 2. 使用 Nginx 反向代理
|
||||
|
||||
在生产环境中,不要直接暴露 WordPress 端口,而是通过 Nginx 进行反向代理并配置 SSL。
|
||||
|
||||
@@ -25,6 +25,7 @@ flowchart LR
|
||||
|
||||
H4 -. "(实际是宿主机的 1234)" .- C1
|
||||
```
|
||||
|
||||
### 12.2.2 Namespace 的类型
|
||||
|
||||
Linux 内核提供了以下几种 Namespace,Docker 容器使用了全部:
|
||||
@@ -65,6 +66,7 @@ PID USER COMMAND
|
||||
1 root nginx: master process ← 在容器内是 PID 1
|
||||
2 root nginx: worker process
|
||||
```
|
||||
|
||||
#### PID 关键点
|
||||
|
||||
- 容器内的 PID 1 进程特殊重要——它是容器的主进程,退出则容器停止
|
||||
@@ -99,6 +101,7 @@ flowchart LR
|
||||
|
||||
H2 <--> C2
|
||||
```
|
||||
|
||||
#### NET 关键点
|
||||
|
||||
- 每个容器有独立的网卡、IP、路由表、iptables 规则
|
||||
@@ -129,6 +132,7 @@ MNT Namespace 负责文件系统挂载点的隔离,确保容器看到独立的
|
||||
│ └── merged/ ────┼─── 这个目录成为容器的 /
|
||||
└── ... └── ...
|
||||
```
|
||||
|
||||
#### 与 chroot 的区别
|
||||
|
||||
| 特性 | chroot | MNT Namespace |
|
||||
@@ -212,6 +216,7 @@ flowchart LR
|
||||
C1 -- 映射 --> H1
|
||||
C2 -- 映射 --> H2
|
||||
```
|
||||
|
||||
#### 安全意义
|
||||
|
||||
容器内的 root 用户可以映射为宿主机上的普通用户,即使容器被突破,攻击者在宿主机上也只有普通权限。
|
||||
@@ -243,6 +248,7 @@ $ exit
|
||||
$ hostname
|
||||
my-server
|
||||
```
|
||||
|
||||
#### 实验 2:PID Namespace
|
||||
|
||||
```bash
|
||||
@@ -261,6 +267,7 @@ USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
|
||||
root 1 0.0 0.0 8960 4516 pts/0 S 10:00 0:00 /bin/bash
|
||||
root 8 0.0 0.0 10072 3200 pts/0 R+ 10:00 0:00 ps aux
|
||||
```
|
||||
|
||||
#### 实验 3:NET Namespace
|
||||
|
||||
```bash
|
||||
|
||||
@@ -117,6 +117,7 @@ $ docker run --device-read-bps /dev/sda:10mb myapp
|
||||
|
||||
$ docker run --device-write-iops /dev/sda:100 myapp
|
||||
```
|
||||
|
||||
#### 进程数限制
|
||||
|
||||
```bash
|
||||
@@ -165,6 +166,7 @@ abc123 Exited (137) 5 seconds ago hopeful_darwin
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
#### CPU 限制验证
|
||||
|
||||
```bash
|
||||
@@ -253,11 +255,13 @@ services:
|
||||
|
||||
$ docker run -m 1g myapp
|
||||
```
|
||||
|
||||
#### 2. 为关键应用设置 CPU 保证
|
||||
|
||||
```bash
|
||||
$ docker run --cpus=2 --cpu-shares=2048 critical-app
|
||||
```
|
||||
|
||||
#### 3. 监控资源使用
|
||||
|
||||
```bash
|
||||
|
||||
@@ -197,6 +197,7 @@ RUN apt-get update && \
|
||||
apt-get install -y nginx && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
```
|
||||
|
||||
#### 2. 避免在容器中写入大量数据
|
||||
|
||||
容器层的写入性能低于直接写入。大量数据应使用:
|
||||
|
||||
@@ -65,6 +65,7 @@ status:
|
||||
- type: Ready
|
||||
status: "True"
|
||||
```
|
||||
|
||||
#### 节点控制器
|
||||
|
||||
在 Kubernetes 控制平面中,节点控制器 (Node Controller) 负责管理节点的生命周期,主要包含:
|
||||
@@ -81,6 +82,7 @@ $ kubectl cordon worker-1
|
||||
## 排空节点上的 Pod
|
||||
$ kubectl drain worker-1 --ignore-daemonsets
|
||||
```
|
||||
|
||||
### 13.2.2 容器组
|
||||
|
||||
在 Kubernetes 中,使用的最小调度单位是容器组 (Pod),它是创建、调度、管理的最小单位。一个 Pod 包含一个或多个紧密协作的容器,它们共享网络命名空间和存储卷。
|
||||
|
||||
@@ -52,6 +52,7 @@ spec:
|
||||
type: Utilization
|
||||
averageUtilization: 50
|
||||
```
|
||||
|
||||
### 13.4.5 ConfigMap 与 Secret
|
||||
|
||||
* **ConfigMap**:存储非机密的配置数据 (配置文件、环境变量)。
|
||||
|
||||
@@ -40,6 +40,7 @@ spec:
|
||||
```bash
|
||||
kubectl apply -f nginx-deployment.yaml
|
||||
```
|
||||
|
||||
### 13.5.3 步骤 2:创建 Service
|
||||
|
||||
创建一个名为 `nginx-service.yaml` 的文件:
|
||||
@@ -82,6 +83,7 @@ kubectl apply -f nginx-deployment.yaml
|
||||
```bash
|
||||
kubectl rollout status deployment/nginx-deployment
|
||||
```
|
||||
|
||||
### 13.5.5 步骤 4:清理资源
|
||||
|
||||
练习结束后,记得清理资源:
|
||||
|
||||
@@ -17,6 +17,7 @@ $ sudo apt install containerd.io
|
||||
|
||||
$ sudo yum install containerd.io
|
||||
```
|
||||
|
||||
### 14.1.2 配置 containerd
|
||||
|
||||
新建 `/etc/systemd/system/cri-containerd.service` 文件
|
||||
@@ -230,6 +231,7 @@ oom_score = 0
|
||||
base_image_size = ""
|
||||
async_remove = false
|
||||
```
|
||||
|
||||
### 14.1.3 安装 **kubelet**、**kubeadm**、**kubectl**、**cri-tools**、**kubernetes-cni**
|
||||
|
||||
需要在每台机器上安装以下的软件包:
|
||||
@@ -253,6 +255,7 @@ $ sudo apt-get install -y kubelet kubeadm kubectl cri-tools kubernetes-cni
|
||||
|
||||
$ sudo apt-mark hold kubelet kubeadm kubectl
|
||||
```
|
||||
|
||||
#### CentOS/Fedora
|
||||
|
||||
```bash
|
||||
@@ -270,6 +273,7 @@ EOF
|
||||
|
||||
$ sudo yum install -y kubelet kubeadm kubectl cri-tools kubernetes-cni
|
||||
```
|
||||
|
||||
### 14.1.4 修改内核的运行参数
|
||||
|
||||
#### 加载内核模块
|
||||
@@ -283,6 +287,7 @@ EOF
|
||||
$ sudo modprobe overlay
|
||||
$ sudo modprobe br_netfilter
|
||||
```
|
||||
|
||||
#### 禁用 swap:必须
|
||||
|
||||
kubelet 默认要求禁用 swap,否则可能导致初始化失败或节点无法加入集群。
|
||||
@@ -303,6 +308,7 @@ EOF
|
||||
|
||||
$ sysctl --system
|
||||
```
|
||||
|
||||
### 14.1.5 配置 kubelet
|
||||
|
||||
为了让 kubelet 正确运行,我们需要对其进行一些必要的配置。
|
||||
@@ -325,6 +331,7 @@ ExecStartPre=-/sbin/modprobe ip_vs_sh
|
||||
```bash
|
||||
$ sudo systemctl daemon-reload
|
||||
```
|
||||
|
||||
### 14.1.6 部署
|
||||
|
||||
安装配置完成后,我们将分别在 Master 节点和 Worker 节点上进行部署操作。
|
||||
@@ -373,6 +380,7 @@ Then you can join any number of worker nodes by running the following on each as
|
||||
kubeadm join 192.168.199.100:6443 --token cz81zt.orsy9gm9v649e5lf \
|
||||
--discovery-token-ca-cert-hash sha256:5edb316fd0d8ea2792cba15cdf1c899a366f147aa03cba52d4e5c5884ad836fe
|
||||
```
|
||||
|
||||
#### node 工作节点
|
||||
|
||||
在 **另一主机** 重复 **部署** 小节以前的步骤,安装配置好 kubelet。根据提示,加入到集群。
|
||||
@@ -387,6 +395,7 @@ $ kubeadm join 192.168.199.100:6443 \
|
||||
--discovery-token-ca-cert-hash sha256:5edb316fd0d8ea2792cba15cdf1c899a366f147aa03cba52d4e5c5884ad836fe \
|
||||
--cri-socket /run/cri-containerd/cri-containerd.sock
|
||||
```
|
||||
|
||||
### 14.1.7 查看服务
|
||||
|
||||
所有服务启动后,通过 `crictl` 查看本地实际运行的容器。这些服务大概分为三类:主节点服务、工作节点服务和其它服务。
|
||||
@@ -394,6 +403,7 @@ $ kubeadm join 192.168.199.100:6443 \
|
||||
```bash
|
||||
CONTAINER_RUNTIME_ENDPOINT=/run/cri-containerd/cri-containerd.sock crictl ps -a
|
||||
```
|
||||
|
||||
#### 主节点服务
|
||||
|
||||
* `apiserver` 是整个系统的对外接口,提供 RESTful 方式供客户端和其它组件调用;
|
||||
@@ -437,6 +447,7 @@ $ kubectl get node -o yaml | grep CIDR
|
||||
```bash
|
||||
$ kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/v0.28.1/Documentation/kube-flannel.yml
|
||||
```
|
||||
|
||||
### 14.1.10 master 节点默认不能运行 pod
|
||||
|
||||
如果用 `kubeadm` 部署一个单节点集群,默认情况下无法使用,请执行以下命令解除限制
|
||||
@@ -454,6 +465,7 @@ $ kubectl taint nodes --all node-role.kubernetes.io/master-
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
### 14.1.11 参考文档
|
||||
|
||||
* [官方文档](https://kubernetes.io/zh/docs/setup/production-environment/tools/kubeadm/install-kubeadm/)
|
||||
|
||||
@@ -44,6 +44,7 @@ $ sudo systemctl start cri-docker
|
||||
|
||||
$ sudo /usr/local/bin/cri-dockerd --version
|
||||
```
|
||||
|
||||
#### CentOS/Fedora
|
||||
|
||||
```bash
|
||||
@@ -66,6 +67,7 @@ $ sudo systemctl daemon-reload
|
||||
$ sudo systemctl enable cri-docker
|
||||
$ sudo systemctl start cri-docker
|
||||
```
|
||||
|
||||
### 14.2.3 安装 **kubelet**、**kubeadm**、**kubectl**
|
||||
|
||||
需要在每台机器上安装以下的软件包:
|
||||
@@ -89,6 +91,7 @@ $ sudo apt-get install -y kubelet kubeadm kubectl
|
||||
|
||||
$ sudo apt-mark hold kubelet kubeadm kubectl
|
||||
```
|
||||
|
||||
#### CentOS/Fedora
|
||||
|
||||
```bash
|
||||
@@ -106,6 +109,7 @@ EOF
|
||||
|
||||
$ sudo yum install -y kubelet kubeadm kubectl
|
||||
```
|
||||
|
||||
### 14.2.4 修改内核的运行参数
|
||||
|
||||
#### 加载内核模块
|
||||
@@ -119,6 +123,7 @@ EOF
|
||||
$ sudo modprobe overlay
|
||||
$ sudo modprobe br_netfilter
|
||||
```
|
||||
|
||||
#### 禁用 swap:必须
|
||||
|
||||
kubelet 默认要求禁用 swap,否则可能导致初始化失败或节点无法加入集群。
|
||||
@@ -139,6 +144,7 @@ EOF
|
||||
|
||||
$ sysctl --system
|
||||
```
|
||||
|
||||
### 14.2.5 配置 kubelet
|
||||
|
||||
为了让 kubelet 正确运行,我们需要对其进行一些必要的配置。
|
||||
@@ -161,6 +167,7 @@ ExecStartPre=-/sbin/modprobe ip_vs_sh
|
||||
```bash
|
||||
$ sudo systemctl daemon-reload
|
||||
```
|
||||
|
||||
### 14.2.6 部署
|
||||
|
||||
安装配置完成后,我们将分别在 Master 节点和 Worker 节点上进行部署操作。
|
||||
@@ -205,6 +212,7 @@ Then you can join any number of worker nodes by running the following on each as
|
||||
kubeadm join 192.168.199.100:6443 --token cz81zt.orsy9gm9v649e5lf \
|
||||
--discovery-token-ca-cert-hash sha256:5edb316fd0d8ea2792cba15cdf1c899a366f147aa03cba52d4e5c5884ad836fe
|
||||
```
|
||||
|
||||
#### node 工作节点
|
||||
|
||||
在 **另一主机** 重复 **部署** 小节以前的步骤,安装配置好 kubelet。根据提示,加入到集群。
|
||||
@@ -213,6 +221,7 @@ kubeadm join 192.168.199.100:6443 --token cz81zt.orsy9gm9v649e5lf \
|
||||
$ kubeadm join 192.168.199.100:6443 --token cz81zt.orsy9gm9v649e5lf \
|
||||
--discovery-token-ca-cert-hash sha256:5edb316fd0d8ea2792cba15cdf1c899a366f147aa03cba52d4e5c5884ad836fe
|
||||
```
|
||||
|
||||
### 14.2.7 查看服务
|
||||
|
||||
所有服务启动后,查看本地实际运行的 Docker 容器。这些服务大概分为三类:主节点服务、工作节点服务和其它服务。
|
||||
@@ -260,6 +269,7 @@ $ kubectl get node -o yaml | grep CIDR
|
||||
```bash
|
||||
$ kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/v0.28.1/Documentation/kube-flannel.yml
|
||||
```
|
||||
|
||||
### 14.2.10 master 节点默认不能运行 pod
|
||||
|
||||
如果用 `kubeadm` 部署一个单节点集群,默认情况下无法使用,请执行以下命令解除限制
|
||||
@@ -277,6 +287,7 @@ $ kubectl taint nodes --all node-role.kubernetes.io/master-
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
### 14.2.11 参考文档
|
||||
|
||||
* [官方文档](https://kubernetes.io/zh/docs/setup/production-environment/tools/kubeadm/install-kubeadm/)
|
||||
|
||||
@@ -20,6 +20,7 @@ Kind 是一个二进制文件,并在 PATH 中即可使用。以下是不同系
|
||||
```bash
|
||||
brew install kind
|
||||
```
|
||||
|
||||
#### Linux / Windows
|
||||
|
||||
可以下载二进制文件:
|
||||
@@ -31,6 +32,7 @@ curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64
|
||||
chmod +x ./kind
|
||||
sudo mv ./kind /usr/local/bin/kind
|
||||
```
|
||||
|
||||
### 14.4.3 创建集群
|
||||
|
||||
最简单的创建方式:
|
||||
@@ -43,6 +45,7 @@ kind create cluster
|
||||
```bash
|
||||
kind create cluster --name my-cluster
|
||||
```
|
||||
|
||||
### 14.4.4 与集群交互
|
||||
|
||||
Kind 会自动将 kubeconfig 合并到 `~/.kube/config`。
|
||||
@@ -51,6 +54,7 @@ Kind 会自动将 kubeconfig 合并到 `~/.kube/config`。
|
||||
kubectl cluster-info --context kind-kind
|
||||
kubectl get nodes
|
||||
```
|
||||
|
||||
### 14.4.5 高级用法:配置集群
|
||||
|
||||
创建一个 `kind-config.yaml` 来定制集群,例如映射端口到宿主机:
|
||||
@@ -72,6 +76,7 @@ nodes:
|
||||
```bash
|
||||
kind create cluster --config kind-config.yaml
|
||||
```
|
||||
|
||||
### 14.4.6 删除集群
|
||||
|
||||
```bash
|
||||
|
||||
@@ -32,6 +32,7 @@ sudo k3s kubectl get nodes
|
||||
NAME STATUS ROLES AGE VERSION
|
||||
k3s-master Ready control-plane,master 1m v1.35.1+k3s1
|
||||
```
|
||||
|
||||
### 14.5.3 快速使用
|
||||
|
||||
K3s 内置了 `kubectl` 命令 (通过 `k3s kubectl` 调用),为了方便,通常会建立别名或配置 `KUBECONFIG`。
|
||||
@@ -45,6 +46,7 @@ export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
|
||||
|
||||
kubectl get pods -A
|
||||
```
|
||||
|
||||
### 14.5.4 清理卸载
|
||||
|
||||
```bash
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
/etc/systemd/system/kube-proxy.service
|
||||
/etc/systemd/system/kube-apiserver.service
|
||||
```
|
||||
|
||||
#### 常用命令
|
||||
|
||||
```bash
|
||||
@@ -48,6 +49,7 @@ sudo systemctl status kubelet
|
||||
# 设置开机自启
|
||||
sudo systemctl enable kubelet
|
||||
```
|
||||
|
||||
### 参考资源
|
||||
|
||||
详细的部署步骤和配置说明,可以参考以下项目:
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
```bash
|
||||
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml
|
||||
```
|
||||
|
||||
### 14.7.2 访问
|
||||
|
||||
通过命令行代理访问,执行以下命令:
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
kubectl [flags]
|
||||
kubectl [command]
|
||||
```
|
||||
|
||||
### 14.8.1 get
|
||||
|
||||
显示一个或多个资源
|
||||
|
||||
@@ -80,6 +80,7 @@ OPTIONS:
|
||||
--user="" username[:password] for authentication (prompt if password is not supplied)
|
||||
-w, --write-out="simple" set the output format (fields, json, protobuf, simple, table)
|
||||
```
|
||||
|
||||
### 15.4.1 数据库操作
|
||||
|
||||
数据库操作围绕对键值和目录的 CRUD (符合 REST 风格的一套操作:Create) 完整生命周期的管理。
|
||||
@@ -94,6 +95,7 @@ etcd 在键的组织上采用了层次化的空间结构 (类似于文件系统
|
||||
$ etcdctl put /testdir/testkey "Hello world"
|
||||
OK
|
||||
```
|
||||
|
||||
#### get
|
||||
|
||||
获取指定键的值。例如
|
||||
@@ -119,6 +121,7 @@ hello
|
||||
$ etcdctl del testkey
|
||||
1
|
||||
```
|
||||
|
||||
### 15.4.2 非数据库操作
|
||||
|
||||
#### watch
|
||||
@@ -133,6 +136,7 @@ PUT
|
||||
testkey
|
||||
2
|
||||
```
|
||||
|
||||
#### member
|
||||
|
||||
通过 `list`、`add`、`update`、`remove` 命令列出、添加、更新、删除 etcd 实例到 etcd 集群中。
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
export KUBECONFIG=/path/to/kubeconfig.yaml
|
||||
kubectl cluster-info
|
||||
```
|
||||
|
||||
#### 2. 部署容器应用
|
||||
|
||||
创建 Deployment 部署应用:
|
||||
@@ -67,6 +68,7 @@ kubectl apply -f deployment.yaml
|
||||
kubectl get pods
|
||||
kubectl get svc
|
||||
```
|
||||
|
||||
#### 3. 管理镜像
|
||||
|
||||
通过腾讯云容器镜像服务 (TCR) 存储和管理私有镜像:
|
||||
@@ -81,6 +83,7 @@ docker tag my-app:latest ccr.ccs.tencentyun.com/namespace/my-app:latest
|
||||
# 推送镜像到腾讯云
|
||||
docker push ccr.ccs.tencentyun.com/namespace/my-app:latest
|
||||
```
|
||||
|
||||
### 腾讯云 Docker 镜像加速器配置
|
||||
|
||||
为了加快镜像拉取速度,腾讯云提供了镜像加速服务。配置方法如下:
|
||||
@@ -116,6 +119,7 @@ sudo systemctl restart docker
|
||||
# 查看镜像源是否生效
|
||||
docker info | grep -A 5 "Registry Mirrors"
|
||||
```
|
||||
|
||||
#### Windows/Mac 配置
|
||||
|
||||
对于 Docker Desktop,在设置界面中:
|
||||
@@ -167,6 +171,7 @@ docker push ccr.ccs.tencentyun.com/my-namespace/my-app:v1.0
|
||||
FROM ccr.ccs.tencentyun.com/my-namespace/my-app:v1.0
|
||||
RUN echo "使用腾讯云镜像作为基础镜像"
|
||||
```
|
||||
|
||||
#### TKE 集群中使用 TCR 镜像
|
||||
|
||||
配置镜像拉取凭证后,在 Deployment 中直接引用 TCR 镜像:
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
export KUBECONFIG=/path/to/kubeconfig.yaml
|
||||
kubectl get nodes
|
||||
```
|
||||
|
||||
#### 2. 部署容器应用
|
||||
|
||||
通过 Deployment 部署应用示例:
|
||||
@@ -73,6 +74,7 @@ kubectl apply -f deployment.yaml
|
||||
kubectl get pods -o wide
|
||||
kubectl logs <pod-name>
|
||||
```
|
||||
|
||||
#### 3. 暴露服务
|
||||
|
||||
创建 Service 暴露应用:
|
||||
@@ -96,6 +98,7 @@ spec:
|
||||
kubectl apply -f service.yaml
|
||||
kubectl get svc web-service
|
||||
```
|
||||
|
||||
### 阿里云 Docker 镜像加速器配置
|
||||
|
||||
为了加快从阿里云镜像源拉取官方镜像的速度,可以配置镜像加速器。阿里云为容器服务 ACK 用户提供了免费的镜像加速服务。
|
||||
@@ -132,6 +135,7 @@ sudo systemctl restart docker
|
||||
```bash
|
||||
docker info | grep -A 5 "Registry Mirrors"
|
||||
```
|
||||
|
||||
#### Windows/Mac 配置
|
||||
|
||||
在 Docker Desktop 的 Settings 中:
|
||||
@@ -146,6 +150,7 @@ docker info | grep -A 5 "Registry Mirrors"
|
||||
docker pull nginx:latest
|
||||
time docker pull alpine:latest
|
||||
```
|
||||
|
||||
### 阿里云容器镜像服务:ACR
|
||||
|
||||
阿里云容器镜像服务 (ACR, Container Registry) 是企业级的容器镜像存储和分发平台:
|
||||
@@ -183,6 +188,7 @@ FROM registry.cn-hangzhou.aliyuncs.com/myapp/my-app:v1.0
|
||||
COPY . /app
|
||||
RUN echo "已成功使用阿里云镜像"
|
||||
```
|
||||
|
||||
#### ACK 集群中使用 ACR 镜像
|
||||
|
||||
在 ACK 集群中,需要先配置镜像拉取凭证(Secret),然后在 Deployment 中引用:
|
||||
@@ -233,6 +239,7 @@ spec:
|
||||
- web
|
||||
topologyKey: kubernetes.io/hostname
|
||||
```
|
||||
|
||||
#### 创建镜像拉取凭证
|
||||
|
||||
在 ACK 集群中创建 Secret,用于拉取私有镜像:
|
||||
@@ -249,6 +256,7 @@ kubectl create secret docker-registry acr-secret \
|
||||
kubectl get secret acr-secret
|
||||
kubectl describe secret acr-secret
|
||||
```
|
||||
|
||||
#### ACR 优势
|
||||
|
||||
- 在 ACK 集群中与镜像仓库无缝集成,简化身份认证
|
||||
|
||||
@@ -26,6 +26,7 @@ passwd:
|
||||
```bash
|
||||
$ docker run -i --rm quay.io/coreos/fcct:v0.5.0 --pretty --strict < example.fcc > example.ign
|
||||
```
|
||||
|
||||
### 17.2.4 挂载 ISO 启动虚拟机并安装
|
||||
|
||||
> 虚拟机需要分配 3GB 以上内存,否则会无法启动。
|
||||
|
||||
@@ -22,6 +22,7 @@ Podman 支持多种操作系统,安装过程也相对简单。
|
||||
```bash
|
||||
$ sudo yum -y install podman
|
||||
```
|
||||
|
||||
#### macOS
|
||||
|
||||
macOS 上需要安装 Podman Desktop 或通过 Homebrew 安装:
|
||||
@@ -31,6 +32,7 @@ $ brew install podman
|
||||
$ podman machine init
|
||||
$ podman machine start
|
||||
```
|
||||
|
||||
### 17.3.3 基本使用
|
||||
|
||||
`podman` 的命令行几乎与 `docker` 完全兼容,大多数情况下,你只需将 `docker` 替换为 `podman` 即可。
|
||||
@@ -42,16 +44,19 @@ $ podman machine start
|
||||
|
||||
$ podman run -d -p 80:80 nginx:alpine
|
||||
```
|
||||
|
||||
#### 列出容器
|
||||
|
||||
```bash
|
||||
$ podman ps
|
||||
```
|
||||
|
||||
#### 构建镜像
|
||||
|
||||
```bash
|
||||
$ podman build -t myimage .
|
||||
```
|
||||
|
||||
### 17.3.4 Pods 的概念
|
||||
|
||||
与 Docker 不同,Podman 支持“Pod”的概念 (类似于 Kubernetes 的 Pod),允许你在同一个网络命名空间中运行多个容器。
|
||||
@@ -65,6 +70,7 @@ $ podman pod create --name mypod -p 8080:80
|
||||
|
||||
$ podman run -d --pod mypod --name webbing nginx
|
||||
```
|
||||
|
||||
### 17.3.5 迁移到 Podman
|
||||
|
||||
如果你习惯使用 `docker` 命令,可以简单地设置别名:
|
||||
@@ -72,6 +78,7 @@ $ podman run -d --pod mypod --name webbing nginx
|
||||
```bash
|
||||
$ alias docker=podman
|
||||
```
|
||||
|
||||
#### Systemd 集成
|
||||
|
||||
Podman 可以生成 systemd 单元文件,让容器像普通系统服务一样管理。
|
||||
@@ -89,6 +96,7 @@ $ podman generate systemd --name myweb --files --new
|
||||
|
||||
$ systemctl --user enable --now container-myweb.service
|
||||
```
|
||||
|
||||
#### Podman Compose
|
||||
|
||||
虽然 Podman 兼容 Docker Compose,但在某些场景下你可能需要明确使用 `podman-compose`。
|
||||
|
||||
@@ -30,6 +30,7 @@ $ sudo dnf install -y buildah
|
||||
$ sudo apt-get update
|
||||
$ sudo apt-get -y install buildah
|
||||
```
|
||||
|
||||
### 基础用法示例
|
||||
|
||||
#### 1. 从现有的 Dockerfile 构建镜像
|
||||
|
||||
@@ -35,6 +35,7 @@ $ sudo apt-get -y install skopeo
|
||||
```bash
|
||||
$ brew install skopeo
|
||||
```
|
||||
|
||||
### 基础用法示例
|
||||
|
||||
#### 1. 远程检查镜像
|
||||
|
||||
@@ -60,6 +60,7 @@ dockremap:165536:65536
|
||||
```bash
|
||||
$ sudo systemctl restart docker
|
||||
```
|
||||
|
||||
#### 验证映射效果
|
||||
|
||||
我们可以运行一个简单的容器并执行 `sleep` 命令,同时在宿主机上观察进程的所有者:
|
||||
|
||||
@@ -53,6 +53,7 @@ $ docker run --rm -it \
|
||||
--security-opt apparmor=custom-nginx-profile \
|
||||
nginx
|
||||
```
|
||||
|
||||
### 18.5.3 容器镜像漏洞静态扫描
|
||||
|
||||
现代防护的防御已经不仅仅在运行阶段,而向“左”延伸至了构建与分发时期控制。很多安全隐患并不是用户代码中的直接逻辑异常,而是打包环境或者引入库的基础 `APT` 安装层面潜伏了开源界众所周知的历史漏洞。
|
||||
|
||||
@@ -41,6 +41,7 @@ trivy image --severity HIGH,CRITICAL \
|
||||
--exit-code 1 \
|
||||
myregistry.com/myapp:v1.0.0
|
||||
```
|
||||
|
||||
#### Grype - 支持多种软件包的扫描器
|
||||
|
||||
Grype 由 Anchore 开发,支持更广泛的软件包管理器和语言。
|
||||
@@ -67,6 +68,7 @@ grype sbom:sbom.json
|
||||
# 扫描特定目录
|
||||
grype dir:/path/to/app
|
||||
```
|
||||
|
||||
#### Snyk - 完整的安全平台
|
||||
|
||||
Snyk 提供了商业级的安全扫描服务,特别适合企业环境。
|
||||
@@ -130,6 +132,7 @@ syft dir:/path/to/app -o json > sbom.json
|
||||
# 从 OCI 镜像档案生成
|
||||
syft oci-archive:image.tar -o json > sbom.json
|
||||
```
|
||||
|
||||
#### CycloneDX 与 SPDX 格式
|
||||
|
||||
两种主流的 SBOM 格式:
|
||||
@@ -173,6 +176,7 @@ syft oci-archive:image.tar -o json > sbom.json
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### SBOM 的应用场景
|
||||
|
||||
**漏洞关联:**
|
||||
@@ -249,6 +253,7 @@ cosign verify myregistry.com/myapp:v1.0.0 \
|
||||
--certificate-identity https://github.com/myorg/myrepo/.github/workflows/build.yml@refs/heads/main \
|
||||
--certificate-oidc-issuer https://token.actions.githubusercontent.com
|
||||
```
|
||||
|
||||
#### Docker Content Trust 与 Notary
|
||||
|
||||
Docker Content Trust 使用 Notary 实现镜像签名,是 Docker 官方的签名解决方案。
|
||||
@@ -276,6 +281,7 @@ docker push --disable-content-trust myregistry.com/myapp:v1.0.0
|
||||
# 查看签名信息
|
||||
docker inspect --format='{{.RepoDigests}}' myregistry.com/myapp:v1.0.0
|
||||
```
|
||||
|
||||
### 18.6.4 供应链安全最佳实践
|
||||
|
||||
#### 1. 基础镜像安全
|
||||
@@ -289,6 +295,7 @@ RUN apt-get update && apt-get install -y curl
|
||||
FROM ubuntu:22.04@sha256:a6d2b38300ce017add71440577d5b0a90460d0e6e0e14...(完整 64 位哈希)
|
||||
RUN apt-get update && apt-get install -y curl=7.68.0-1ubuntu1
|
||||
```
|
||||
|
||||
#### 2. 构建时扫描
|
||||
|
||||
在 Dockerfile 中集成安全扫描:
|
||||
@@ -308,6 +315,7 @@ RUN go build -o app .
|
||||
FROM alpine:3.17@sha256:abcd1234...(请替换为实际完整的 64 位摘要哈希)
|
||||
COPY --from=builder /app/app /app
|
||||
```
|
||||
|
||||
#### 3. 运行时镜像扫描策略
|
||||
|
||||
```bash
|
||||
@@ -320,6 +328,7 @@ trivy image --severity HIGH,CRITICAL \
|
||||
# 定期扫描已部署的镜像
|
||||
trivy image --scanners vuln,misconfig registry:5000/myapp:latest
|
||||
```
|
||||
|
||||
#### 4. 镜像仓库安全配置
|
||||
|
||||
**Harbor(私有镜像仓库)的安全扫描:**
|
||||
@@ -335,6 +344,7 @@ trivy:
|
||||
scan_on_push: true # 推送时自动扫描
|
||||
scan_all: true # 扫描仓库中的所有镜像
|
||||
```
|
||||
|
||||
#### 5. 政策执行
|
||||
|
||||
在 Kubernetes 环境中使用 Admission Webhook 强制镜像签名和扫描:
|
||||
@@ -359,6 +369,7 @@ webhooks:
|
||||
admissionReviewVersions: ["v1"]
|
||||
sideEffects: None
|
||||
```
|
||||
|
||||
### 18.6.5 CI/CD 中集成安全扫描
|
||||
|
||||
#### GitHub Actions 工作流示例
|
||||
@@ -445,6 +456,7 @@ jobs:
|
||||
push: true
|
||||
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
||||
```
|
||||
|
||||
#### GitLab CI 工作流示例
|
||||
|
||||
```yaml
|
||||
@@ -509,6 +521,7 @@ push:
|
||||
only:
|
||||
- main
|
||||
```
|
||||
|
||||
### 18.6.6 常见问题与最佳实践
|
||||
|
||||
**Q: 扫描报告中有过时的 CVE,如何处理?**
|
||||
|
||||
@@ -23,6 +23,7 @@ flowchart LR
|
||||
Proc --> Mech
|
||||
end
|
||||
```
|
||||
|
||||
## 本章内容
|
||||
|
||||
本章涵盖 Docker 安全的多个层面,从内核隔离机制到运行时防护和供应链安全。
|
||||
|
||||
@@ -48,6 +48,7 @@ scrape_configs:
|
||||
rule_files:
|
||||
- /etc/prometheus/rules.yml
|
||||
```
|
||||
|
||||
#### 2. 编写 Docker Compose 文件
|
||||
|
||||
创建 `compose.yaml` (或 `docker-compose.yml`):
|
||||
@@ -105,6 +106,7 @@ networks:
|
||||
volumes:
|
||||
prometheus_data:
|
||||
```
|
||||
|
||||
#### 3. 启动服务
|
||||
|
||||
```bash
|
||||
|
||||
@@ -71,6 +71,7 @@ volumes:
|
||||
networks:
|
||||
logging:
|
||||
```
|
||||
|
||||
#### 2. 配置 Fluentd
|
||||
|
||||
创建 `fluentd/conf/fluent.conf`:
|
||||
@@ -101,6 +102,7 @@ networks:
|
||||
</store>
|
||||
</match>
|
||||
```
|
||||
|
||||
#### 3. 配置应用容器使用 fluentd 驱动
|
||||
|
||||
启动一个测试容器,指定日志驱动为 `fluentd`:
|
||||
|
||||
@@ -91,6 +91,7 @@ done
|
||||
# MEM % 接近 100%:容器即将 OOM,需要增加内存或排查内存泄漏
|
||||
# 如果 NET I/O 中 dropped 为非零:网络拥塞或丢包
|
||||
```
|
||||
|
||||
### 19.3.3 cAdvisor 容器监控系统
|
||||
|
||||
cAdvisor 是 Google 开发的容器监控工具,提供比 `docker stats` 更详细的性能数据。
|
||||
@@ -150,6 +151,7 @@ scrape_configs:
|
||||
- targets: ['localhost:8080']
|
||||
metrics_path: '/metrics'
|
||||
```
|
||||
|
||||
### 19.3.4 Prometheus 容器监控配置
|
||||
|
||||
使用 Prometheus 和 node-exporter 进行长期的容器性能监控。
|
||||
@@ -275,6 +277,7 @@ container_memory_cache_bytes / container_memory_usage_bytes
|
||||
# 按镜像统计容器数
|
||||
count(container_memory_usage_bytes) by (image)
|
||||
```
|
||||
|
||||
### 19.3.5 容器 OOM 排查与内存限制调优
|
||||
|
||||
#### OOM 问题诊断
|
||||
@@ -293,6 +296,7 @@ docker logs <container_id> 2>&1 | grep -i "out of memory\|oom"
|
||||
dmesg | grep -i "oom\|kill"
|
||||
journalctl -u docker -n 100 | grep -i "oom"
|
||||
```
|
||||
|
||||
#### 内存泄漏检测
|
||||
|
||||
使用专项工具分析应用内存使用:
|
||||
@@ -347,6 +351,7 @@ jstat -gc <pid> 1000 # 每秒采样一次
|
||||
# S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU
|
||||
# 6144 6144 0 6144 39424 12288 149504 84320 50552 47689 6464 5989
|
||||
```
|
||||
|
||||
#### 内存限制最佳实践
|
||||
|
||||
```bash
|
||||
@@ -385,6 +390,7 @@ services:
|
||||
memory: 2G
|
||||
memory_reservation: 1G # 预留 1GB,允许突发到 2GB
|
||||
```
|
||||
|
||||
### 19.3.6 镜像体积优化与多阶段构建
|
||||
|
||||
#### 镜像体积分析工具
|
||||
@@ -411,6 +417,7 @@ chmod +x hadolint
|
||||
# 检查 Dockerfile 最佳实践
|
||||
./hadolint Dockerfile
|
||||
```
|
||||
|
||||
#### 多阶段构建最佳实践
|
||||
|
||||
**Go 应用的最小化镜像构建:**
|
||||
@@ -528,6 +535,7 @@ EXPOSE 5000
|
||||
|
||||
CMD ["python", "app.py"]
|
||||
```
|
||||
|
||||
#### 镜像体积优化检查清单
|
||||
|
||||
```bash
|
||||
@@ -558,6 +566,7 @@ RUN apt-get update && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
```
|
||||
|
||||
### 19.3.7 常见性能问题及解决方案
|
||||
|
||||
**问题 1: 容器频繁被 OOM 杀死**
|
||||
|
||||
@@ -30,6 +30,7 @@ $ docker image ls
|
||||
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
|
||||
busybox latest e72ac664f4f0 6 weeks ago 2.433 MB
|
||||
```
|
||||
|
||||
### 20.1.3 运行 busybox
|
||||
|
||||
启动一个 `busybox` 容器,并在容器中执行 `grep` 命令。
|
||||
|
||||
@@ -25,6 +25,7 @@ debian latest 4d6ce913b130 84.98 MB
|
||||
ubuntu latest b39b81afc8ca 188.3 MB
|
||||
centos latest 8efe422e6104 210 MB
|
||||
```
|
||||
|
||||
### 20.2.2 获取并使用官方镜像
|
||||
|
||||
由于镜像很小,下载时间往往很短,读者可以直接使用 `docker run` 指令直接运行一个 `Alpine` 容器,并指定运行的 Linux 指令,例如:
|
||||
@@ -33,6 +34,7 @@ centos latest 8efe422e6104 210 MB
|
||||
$ docker run alpine echo '123'
|
||||
123
|
||||
```
|
||||
|
||||
### 20.2.3 迁移至 Alpine 基础镜像
|
||||
|
||||
目前,大部分 Docker 官方镜像都已经支持 `Alpine` 作为基础镜像,可以很容易进行迁移。
|
||||
@@ -60,6 +62,7 @@ $ apk --update add --no-cache <package>
|
||||
RUN sed -i "s/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g" /etc/apk/repositories \
|
||||
&& apk add --no-cache <package>
|
||||
```
|
||||
|
||||
### 20.2.4 相关资源
|
||||
|
||||
* `Alpine` 官网:https://www.alpinelinux.org/
|
||||
|
||||
@@ -28,6 +28,7 @@ Status: Downloaded newer image for centos:7
|
||||
[root@43eb3b194d48 /]# cat /etc/redhat-release
|
||||
CentOS Linux release 7.9.2009 (Core)
|
||||
```
|
||||
|
||||
### 20.4.2 Fedora 系统简介
|
||||
|
||||
下图直观地展示了本节内容:
|
||||
|
||||
@@ -35,6 +35,7 @@ WORKDIR /app
|
||||
COPY --from=builder /app/main .
|
||||
CMD ["./main"]
|
||||
```
|
||||
|
||||
#### 2. GitLab CI 配置
|
||||
|
||||
GitLab CI(`.gitlab-ci.yml`)配置如下:
|
||||
@@ -74,6 +75,7 @@ deploy_staging:
|
||||
only:
|
||||
- develop
|
||||
```
|
||||
|
||||
### 21.1.3 最佳实践
|
||||
|
||||
1. **不可变基础设施**:一旦镜像构建完成,在各个环境(Dev、Staging、Prod)中都应该使用同一个镜像 tag(通常是 commit hash),而不是重新构建。
|
||||
|
||||
@@ -46,6 +46,7 @@ jobs:
|
||||
with:
|
||||
args: go version
|
||||
```
|
||||
|
||||
## 21.2.3 参考资料
|
||||
|
||||
* [Actions Docs](https://docs.github.com/en/actions)
|
||||
|
||||
@@ -70,6 +70,7 @@ trigger:
|
||||
├── .drone.yml
|
||||
└── app.go
|
||||
```
|
||||
|
||||
## 21.3.3 推送项目源代码到 GitHub
|
||||
|
||||
```bash
|
||||
@@ -79,6 +80,7 @@ git commit -m "test drone ci"
|
||||
|
||||
git push origin master
|
||||
```
|
||||
|
||||
## 21.3.4 查看项目构建过程及结果
|
||||
|
||||
打开我们部署好的 `Drone` 网站或者 Drone Cloud,即可看到构建结果。
|
||||
|
||||
@@ -39,6 +39,7 @@ VS Code 会拉取镜像并启动容器,随后你就可以在容器内运行:
|
||||
```bash
|
||||
go test ./...
|
||||
```
|
||||
|
||||
## 21.6.3 结合 Docker Compose(可选)
|
||||
|
||||
如果项目同时依赖数据库/缓存(例如 Postgres/Redis),可以使用 `dockerComposeFile`
|
||||
|
||||
@@ -120,6 +120,7 @@ require (
|
||||
// 如果需要依赖
|
||||
)
|
||||
```
|
||||
|
||||
#### 带依赖的 Go 应用
|
||||
|
||||
**应用代码(使用 Gin 框架):**
|
||||
@@ -182,6 +183,7 @@ EXPOSE 8080
|
||||
|
||||
CMD ["./app"]
|
||||
```
|
||||
|
||||
### 21.7.2 Rust 应用的最小化镜像构建
|
||||
|
||||
Rust 因其性能和安全性在系统级应用中备受青睐。
|
||||
@@ -273,6 +275,7 @@ curl http://localhost:8080/health | jq .
|
||||
# Rust 应用通常比 Go 更小:5-20MB(取决于依赖)
|
||||
docker images rust-app
|
||||
```
|
||||
|
||||
### 21.7.3 数据库容器化最佳实践
|
||||
|
||||
#### PostgreSQL 生产部署
|
||||
@@ -455,6 +458,7 @@ services:
|
||||
volumes:
|
||||
postgres_data:
|
||||
```
|
||||
|
||||
#### MySQL/MariaDB 部署
|
||||
|
||||
```dockerfile
|
||||
@@ -495,6 +499,7 @@ server_id = 1
|
||||
log_bin = mysql-bin
|
||||
binlog_format = ROW
|
||||
```
|
||||
|
||||
#### Redis 缓存部署
|
||||
|
||||
```dockerfile
|
||||
@@ -545,6 +550,7 @@ client-output-buffer-limit normal 0 0 0
|
||||
client-output-buffer-limit slave 256mb 64mb 60
|
||||
client-output-buffer-limit pubsub 32mb 8mb 60
|
||||
```
|
||||
|
||||
### 21.7.4 微服务架构的 Docker Compose 编排
|
||||
|
||||
**三层微服务架构示例:**
|
||||
@@ -736,6 +742,7 @@ server {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 21.7.5 使用 VS Code Dev Containers
|
||||
|
||||
Dev Containers 让整个开发环境容器化,提升团队一致性。
|
||||
|
||||
@@ -33,6 +33,7 @@ $ git rebase upstream/master
|
||||
|
||||
$ git push -f origin master
|
||||
```
|
||||
|
||||
## 排版规范
|
||||
|
||||
本开源书籍遵循[中文排版指南](https://github.com/mzlogin/chinese-copywriting-guidelines)规范。
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user