mirror of
https://github.com/yeasy/docker_practice.git
synced 2026-03-10 20:04:36 +00:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d6fff9a3f7 | ||
|
|
fc276d3b4f | ||
|
|
40ded62baa | ||
|
|
89b0dc4425 | ||
|
|
330e084e00 | ||
|
|
e62b203f1a | ||
|
|
cb6bf74a2e | ||
|
|
a980e34276 | ||
|
|
3d33e00802 | ||
|
|
1a820c8c8b | ||
|
|
585b364574 | ||
|
|
a0a5de7f11 | ||
|
|
83ba6b7b47 | ||
|
|
53f20dede7 | ||
|
|
48c8b50cf7 | ||
|
|
70ef2cba58 | ||
|
|
f5cfa4140a | ||
|
|
d174cf327c | ||
|
|
6a9ce44c5a | ||
|
|
c09f66da55 | ||
|
|
635e05ad34 | ||
|
|
6f22d0f5f0 | ||
|
|
17517e26b7 | ||
|
|
9fcaff6673 | ||
|
|
a096947382 | ||
|
|
be09a95d0d | ||
|
|
3af007b176 | ||
|
|
551dcfd2cb | ||
|
|
0d2654fbf2 | ||
|
|
3894ba56bc | ||
|
|
0dd0d036a2 | ||
|
|
a9c4189c0c | ||
|
|
56deeaee0f | ||
|
|
0ff67cc893 |
12
.gitignore
vendored
12
.gitignore
vendored
@@ -21,11 +21,7 @@ docker-compose.override.yml
|
||||
__pycache__/
|
||||
|
||||
# Check scripts
|
||||
check_project_rules.py
|
||||
check_dashes.py
|
||||
checker.py
|
||||
find_lists_no_space.py
|
||||
fix_missing_spaces.py
|
||||
fix_project_rules.py
|
||||
fixer.py
|
||||
format_headings.py
|
||||
check*.py
|
||||
find*.py
|
||||
fix*.py
|
||||
format*.py
|
||||
|
||||
@@ -45,7 +45,7 @@ $ docker run -d -p 8080:80 my-hello-world
|
||||
|
||||
### 1.1.5 访问测试
|
||||
|
||||
打开浏览器访问 [http://localhost:8080](http://localhost:8080),你应该能看到 “Hello,Docker!”。
|
||||
打开浏览器访问 [http://localhost:8080](http://localhost:8080),你应该能看到 “Hello, Docker!”。
|
||||
|
||||
### 1.1.6 清理
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ $ docker compose up
|
||||
|
||||
Docker 容器共享宿主机内核,无需为每个应用运行完整的操作系统。以一台 64GB 内存的物理服务器为例:
|
||||
- **传统虚拟机方案**:每个虚拟机都需要运行完整的操作系统(每个额外占用如 2GB 内存),产生大量资源开销,实际可用于应用的内存可能只有约 18GB。
|
||||
- **Docker 方案**:容器直接共享宿主机系统,只需付出很少的基础开销(OS及引擎约 4GB),即可将约 60GB 的内存全部用于实际应用。
|
||||
- **Docker 方案**:容器直接共享宿主机系统,只需付出很少的基础开销(OS 及引擎约 4GB),即可将约 60GB 的内存全部用于实际应用。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
@@ -200,13 +200,7 @@ flowchart TD
|
||||
|
||||
### 1.3.5 与传统虚拟机的对比总结
|
||||
|
||||
下表对比了容器技术与传统虚拟机的区别:
|
||||
关于容器与虚拟机的详细特性对比,请参阅 [1.2.3 Docker vs 虚拟机](1.2_what.md) 中的对比表。总结来说:
|
||||
|
||||
| 特性 | Docker 容器 | 传统虚拟机 |
|
||||
|:------|:-----------|:-----------|
|
||||
| 启动速度 | 秒级 | 分钟级 |
|
||||
| 磁盘占用 | MB 级别 | GB 级别 |
|
||||
| 性能 | 接近原生 | 有 5-20% 损耗 |
|
||||
| 单机支持量 | 上千个容器 | 几十个虚拟机 |
|
||||
| 隔离性 | 进程级别 | 完全隔离 |
|
||||
| 最佳场景 | 微服务、CI/CD、开发环境 | 多租户、高安全需求 |
|
||||
- **性能差异**:虚拟机通常有 5-20% 的性能损耗,而容器接近原生性能。
|
||||
- **最佳场景**:Docker 容器适合微服务、CI/CD、开发环境;虚拟机适合多租户、高安全需求场景。
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
|
||||
本章将带领你进入 **Docker** 的世界。
|
||||
|
||||
> **版本提示**:本书内容及示例基于 **Docker Engine v29.x** 及以上版本。值得注意的是,自 Docker Engine v29 起,官方在全新安装场景下 **默认启用了 `containerd image store` 作为镜像存储后端**(取代了传统的经典存储引擎如 overlay2 graph driver)。这项底层革新极大增强了 Docker 对多架构镜像(Multi-platform)、以及软件供应链安全元数据(Attestations, SBOM, Provenance)的本地支持原生性。
|
||||
|
||||
## 本章内容
|
||||
|
||||
* [快速上手](1.1_quickstart.md)
|
||||
* 通过一个简单的 Web 应用例子,带你快速体验 Docker 的核心流程:构建镜像、运行容器。
|
||||
|
||||
* [什么是 Docker](1.2_what.md)
|
||||
* 介绍 Docker 的起源、发展历程以及其背后的核心技术 (Cgroups,Namespaces,UnionFS)。
|
||||
* 介绍 Docker 的起源、发展历程以及其背后的核心技术 (Cgroups,Namespaces,UnionFS,以及 `containerd` 引擎的演进)。
|
||||
* 了解 Docker 是如何改变软件交付方式的。
|
||||
|
||||
* [为什么要用 Docker](1.3_why.md)
|
||||
|
||||
@@ -6,3 +6,6 @@
|
||||
- Docker 推动了容器技术的标准化 (OCI) 和生态发展
|
||||
|
||||
Docker 的核心价值可以用一句话概括:**让应用的开发、测试、部署保持一致,同时极大提高资源利用效率。** 笔者认为,对于现代软件开发者来说,Docker 已经不是 “要不要学” 的问题,而是 **必备技能**。无论你是前端、后端、运维还是全栈开发者,掌握 Docker 都能让你的工作更高效。
|
||||
---
|
||||
|
||||
> 📝 **发现错误或有改进建议?** 欢迎提交 [Issue](https://github.com/yeasy/docker_practice/issues) 或 [PR](https://github.com/yeasy/docker_practice/pulls)。
|
||||
|
||||
@@ -123,7 +123,6 @@ RUN apt-get install -y build-essential # 安装编译工具(约 200MB)
|
||||
RUN make && make install # 编译应用
|
||||
RUN apt-get remove build-essential # 试图删除编译工具
|
||||
## 结果:镜像仍然包含 200MB 的编译工具!
|
||||
|
||||
```
|
||||
|
||||
```docker
|
||||
|
||||
@@ -56,7 +56,7 @@ flowchart TB
|
||||
一个完整的 Docker 镜像名称由 Registry 地址、用户名/组织名、仓库名和标签组成。了解其结构有助于我们更准确地定位镜像。基本格式如下:
|
||||
|
||||
```bash
|
||||
[registry地址/][用户名/]仓库名[:标签]
|
||||
[registry 地址/][用户名/]仓库名[:标签]
|
||||
```
|
||||
|
||||
示例:
|
||||
|
||||
@@ -7,3 +7,9 @@
|
||||
* **仓库** (`Repository`):镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry 就是这样的服务。
|
||||
|
||||
理解了这三个概念,就理解了 **Docker** 的整个生命周期。
|
||||
|
||||
## 本章内容
|
||||
|
||||
* [Docker 镜像](2.1_image.md)
|
||||
* [Docker 容器](2.2_container.md)
|
||||
* [Docker 仓库](2.3_repository.md)
|
||||
|
||||
@@ -1,40 +1,18 @@
|
||||
## 本章小结
|
||||
|
||||
本章介绍了 Docker 的三个核心概念:镜像、容器和仓库。
|
||||
|
||||
| 概念 | 要点 |
|
||||
|------|------|
|
||||
| **镜像是什么** | 只读的应用模板,包含运行所需的一切 |
|
||||
| **分层存储** | 多层叠加,共享基础层,节省空间 |
|
||||
| **只读特性** | 构建后不可修改,保证一致性 |
|
||||
| **层的陷阱** | 删除操作只是标记,不减小体积 |
|
||||
|
||||
理解了镜像,接下来让我们学习[容器](2.2_container.md)——镜像的运行实例。
|
||||
|
||||
### 2.4.1 延伸阅读
|
||||
|
||||
- [获取镜像](../04_image/4.1_pull.md):从 Registry 下载镜像
|
||||
- [使用 Dockerfile 定制镜像](../04_image/4.5_build.md):创建自己的镜像
|
||||
- [Dockerfile 最佳实践](../appendix/best_practices.md):构建高质量镜像的技巧
|
||||
- [底层实现 - 联合文件系统](../12_implementation/12.4_ufs.md):深入理解分层存储的技术原理
|
||||
|
||||
| 概念 | 要点 |
|
||||
|------|------|
|
||||
| **容器是什么** | 镜像的运行实例,本质是隔离的进程 |
|
||||
| **容器 vs 虚拟机** | 共享内核,更轻量,但隔离性较弱 |
|
||||
| **存储层** | 可写层随容器删除而消失 |
|
||||
| **数据持久化** | 使用 Volume 或 Bind Mount |
|
||||
| **生命周期** | 与主进程 (PID 1) 绑定 |
|
||||
|
||||
理解了镜像和容器,接下来让我们学习[仓库](2.3_repository.md)——存储和分发镜像的服务。
|
||||
|
||||
### 2.4.2 延伸阅读
|
||||
|
||||
- [启动容器](../05_container/5.1_run.md):详细的容器启动选项
|
||||
- [后台运行](../05_container/5.2_daemon.md):理解容器为什么会 “立即退出”
|
||||
- [进入容器](../05_container/5.4_attach_exec.md):如何操作运行中的容器
|
||||
- [数据管理](../08_data/README.md):Volume 和数据持久化详解
|
||||
|
||||
| 概念 | 要点 |
|
||||
|------|------|
|
||||
| **Registry** | 存储和分发镜像的服务 |
|
||||
| **仓库 (Repository)** | 同一软件的镜像集合 |
|
||||
| **标签 (Tag)** | 版本标识,默认为 latest |
|
||||
@@ -43,9 +21,20 @@
|
||||
|
||||
现在你已经了解了 Docker 的三个核心概念:[镜像](2.1_image.md)、[容器](2.2_container.md)和仓库。接下来,让我们开始[安装 Docker](../03_install/README.md),动手实践!
|
||||
|
||||
### 2.4.3 延伸阅读
|
||||
### 延伸阅读
|
||||
|
||||
- [获取镜像](../04_image/4.1_pull.md):从 Registry 下载镜像
|
||||
- [使用 Dockerfile 定制镜像](../04_image/4.5_build.md):创建自己的镜像
|
||||
- [Dockerfile 最佳实践](../appendix/best_practices.md):构建高质量镜像的技巧
|
||||
- [底层实现 - 联合文件系统](../12_implementation/12.4_ufs.md):深入理解分层存储的技术原理
|
||||
- [启动容器](../05_container/5.1_run.md):详细的容器启动选项
|
||||
- [后台运行](../05_container/5.2_daemon.md):理解容器为什么会“立即退出”
|
||||
- [进入容器](../05_container/5.4_attach_exec.md):如何操作运行中的容器
|
||||
- [数据管理](../08_data/README.md):Volume 和数据持久化详解
|
||||
- [Docker Hub](../06_repository/6.1_dockerhub.md):Docker Hub 的详细使用
|
||||
- [私有仓库](../06_repository/6.2_registry.md):搭建私有 Registry
|
||||
- [私有仓库高级配置](../06_repository/6.3_registry_auth.md):认证、TLS 配置
|
||||
- [镜像加速器](../03_install/3.9_mirror.md):配置镜像加速
|
||||
---
|
||||
|
||||
> 📝 **发现错误或有改进建议?** 欢迎提交 [Issue](https://github.com/yeasy/docker_practice/issues) 或 [PR](https://github.com/yeasy/docker_practice/pulls)。
|
||||
|
||||
@@ -122,7 +122,12 @@ $ 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` 用户组。
|
||||
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好的做法是将需要使用 `docker` 的用户加入 `docker` 用户组。
|
||||
|
||||
> ⚠️ **安全警告:`docker` 用户组等同于 `root` 权限**
|
||||
>
|
||||
> 将用户加入 `docker` 组免去了每次执行 `docker` 命令时输入 `sudo` 的繁琐,但这也意味着该用户可以轻易获取主机的最高 root 权限(例如通过挂载根目录运行容器)。
|
||||
> 如果你在一个多用户共享的生产系统上配置,切勿随意将普通用户加入此组。此时,更安全的替代方案是使用官方提供的 **[Rootless 模式 (Rootless mode)](https://docs.docker.com/engine/security/rootless/)**,它允许在没有任何 root 权限的情况下运行 Docker 守护进程和容器。
|
||||
|
||||
建立 `docker` 组:
|
||||
|
||||
|
||||
@@ -113,7 +113,12 @@ $ 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` 用户组。
|
||||
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好的做法是将需要使用 `docker` 的用户加入 `docker` 用户组。
|
||||
|
||||
> ⚠️ **安全警告:`docker` 用户组等同于 `root` 权限**
|
||||
>
|
||||
> 将用户加入 `docker` 组免去了每次执行 `docker` 命令时输入 `sudo` 的繁琐,但这也意味着该用户可以轻易获取主机的最高 root 权限(例如通过挂载根目录运行容器)。
|
||||
> 如果你在一个多用户共享的生产系统上配置,切勿随意将普通用户加入此组。此时,更安全的替代方案是使用官方提供的 **[Rootless 模式 (Rootless mode)](https://docs.docker.com/engine/security/rootless/)**,它允许在没有任何 root 权限的情况下运行 Docker 守护进程和容器。
|
||||
|
||||
建立 `docker` 组:
|
||||
|
||||
|
||||
@@ -121,7 +121,12 @@ $ 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` 用户组。
|
||||
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好的做法是将需要使用 `docker` 的用户加入 `docker` 用户组。
|
||||
|
||||
> ⚠️ **安全警告:`docker` 用户组等同于 `root` 权限**
|
||||
>
|
||||
> 将用户加入 `docker` 组免去了每次执行 `docker` 命令时输入 `sudo` 的繁琐,但这也意味着该用户可以轻易获取主机的最高 root 权限(例如通过挂载根目录运行容器)。
|
||||
> 如果你在一个多用户共享的生产系统上配置,切勿随意将普通用户加入此组。此时,更安全的替代方案是使用官方提供的 **[Rootless 模式 (Rootless mode)](https://docs.docker.com/engine/security/rootless/)**,它允许在没有任何 root 权限的情况下运行 Docker 守护进程和容器。
|
||||
|
||||
建立 `docker` 组:
|
||||
|
||||
|
||||
@@ -126,7 +126,12 @@ $ 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` 用户组。
|
||||
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好的做法是将需要使用 `docker` 的用户加入 `docker` 用户组。
|
||||
|
||||
> ⚠️ **安全警告:`docker` 用户组等同于 `root` 权限**
|
||||
>
|
||||
> 将用户加入 `docker` 组免去了每次执行 `docker` 命令时输入 `sudo` 的繁琐,但这也意味着该用户可以轻易获取主机的最高 root 权限(例如通过挂载根目录运行容器)。
|
||||
> 如果你在一个多用户共享的生产系统上配置,切勿随意将普通用户加入此组。此时,更安全的替代方案是使用官方提供的 **[Rootless 模式 (Rootless mode)](https://docs.docker.com/engine/security/rootless/)**,它允许在没有任何 root 权限的情况下运行 Docker 守护进程和容器。
|
||||
|
||||
建立 `docker` 组:
|
||||
|
||||
|
||||
@@ -140,7 +140,12 @@ $ 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` 用户组。
|
||||
默认情况下,`docker` 命令会使用 [Unix socket](https://en.wikipedia.org/wiki/Unix_domain_socket) 与 Docker 引擎通讯。而只有 `root` 用户和 `docker` 组的用户才可以访问 Docker 引擎的 Unix socket。出于安全考虑,一般 Linux 系统上不会直接使用 `root` 用户。因此,更好的做法是将需要使用 `docker` 的用户加入 `docker` 用户组。
|
||||
|
||||
> ⚠️ **安全警告:`docker` 用户组等同于 `root` 权限**
|
||||
>
|
||||
> 将用户加入 `docker` 组免去了每次执行 `docker` 命令时输入 `sudo` 的繁琐,但这也意味着该用户可以轻易获取主机的最高 root 权限(例如通过挂载根目录运行容器)。
|
||||
> 如果你在一个多用户共享的生产系统上配置,切勿随意将普通用户加入此组。此时,更安全的替代方案是使用官方提供的 **[Rootless 模式 (Rootless mode)](https://docs.docker.com/engine/security/rootless/)**,它允许在没有任何 root 权限的情况下运行 Docker 守护进程和容器。
|
||||
|
||||
建立 `docker` 组:
|
||||
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
## 3.6 Linux 离线安装
|
||||
|
||||
\[TOC]
|
||||
|
||||
生产环境中一般都是没有公网资源的,本文介绍如何在生产服务器上离线部署 `Docker`
|
||||
|
||||
括号内的字母表示该操作需要在哪些服务器上执行
|
||||
|
||||

|
||||
|
||||
### 3.6.1 概述
|
||||
|
||||
### 3.6.2 CentOS/Rocky/AlmaLinux 离线安装 Docker
|
||||
### 3.6.1 CentOS/Rocky/AlmaLinux 离线安装 Docker
|
||||
|
||||
在无法连接外网的安全环境中,离线安装是唯一的选择。本节介绍如何在 RHEL 系发行版中进行离线安装。
|
||||
|
||||
@@ -18,7 +14,7 @@
|
||||
|
||||
#### YUM 本地文件安装 (推荐)
|
||||
|
||||
推荐这种方式,是因为在生产环境种一般会选定某个指定的文档软件版本使用。
|
||||
推荐这种方式,是因为在生产环境中一般会选定某个指定的文档软件版本使用。
|
||||
|
||||
##### 查询可用的软件版本
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
### 3.7.1 系统要求
|
||||
|
||||
[Docker Desktop for Mac](https://docs.docker.com/docker-for-mac/) 要求系统最低为 macOS Sonora 14.0 或更高版本,建议升级到最新版本的 macOS。
|
||||
[Docker Desktop for Mac](https://docs.docker.com/docker-for-mac/) 要求系统最低为 macOS Sonoma 14.0 或更高版本,建议升级到最新版本的 macOS。
|
||||
|
||||
### 3.7.2 安装
|
||||
|
||||
@@ -47,7 +47,7 @@ $ brew install --cask docker
|
||||
|
||||
```bash
|
||||
$ docker --version
|
||||
Docker version 26.1.1, build 4cf5afa
|
||||
Docker version 27.0.3, build 7d4bcd8
|
||||
```
|
||||
|
||||
如果 `docker version`、`docker info` 都正常的话,可以尝试运行一个 [Nginx 服务器](https://hub.docker.com/_/nginx/):
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
下载好之后双击 `Docker Desktop Installer.exe` 开始安装。
|
||||
|
||||
**使用** [**winget**](https://docs.microsoft.com/zh-cn/windows/package-manager/) **安装**
|
||||
**使用**[**winget**](https://docs.microsoft.com/zh-cn/windows/package-manager/)**安装**
|
||||
|
||||
```powershell
|
||||
$ winget install Docker.DockerDesktop
|
||||
|
||||
Binary file not shown.
@@ -11,7 +11,7 @@ Docker 支持在多种平台上安装和使用,选择合适的安装方式是
|
||||
| **Raspberry Pi** | 官方安装脚本 | 支持 ARM 架构 |
|
||||
| **离线环境** | 二进制包安装 | 适用于无法联网的服务器 |
|
||||
|
||||
### 3.11.1 安装后验证
|
||||
### 安装后验证
|
||||
|
||||
安装完成后,运行以下命令验证 Docker 是否正常工作:
|
||||
|
||||
@@ -20,8 +20,11 @@ $ docker version
|
||||
$ docker run --rm hello-world
|
||||
```
|
||||
|
||||
### 3.11.2 延伸阅读
|
||||
### 延伸阅读
|
||||
|
||||
- [镜像加速器](3.9_mirror.md):解决国内拉取镜像慢的问题
|
||||
- [开启实验特性](3.10_experimental.md):使用最新功能
|
||||
- [Docker Hub](../06_repository/6.1_dockerhub.md):官方镜像仓库
|
||||
---
|
||||
|
||||
> 📝 **发现错误或有改进建议?** 欢迎提交 [Issue](https://github.com/yeasy/docker_practice/issues) 或 [PR](https://github.com/yeasy/docker_practice/pulls)。
|
||||
|
||||
@@ -171,9 +171,6 @@ root@e7009c6ce357:/# exit
|
||||
```bash
|
||||
$ sudo systemctl restart docker # Linux
|
||||
## 或在 Docker Desktop 中重启
|
||||
|
||||
## 或在 Docker Desktop 中重启
|
||||
|
||||
```
|
||||
|
||||
详见[镜像加速器](../03_install/3.9_mirror.md)章节。
|
||||
|
||||
@@ -204,11 +204,10 @@ ubuntu latest ca2b0f26964c # 同一个镜像
|
||||
$ docker rmi ubuntu:24.04
|
||||
Untagged: ubuntu:24.04
|
||||
## 只是移除标签,镜像仍存在(因为还有 ubuntu:latest 指向它)
|
||||
```
|
||||
|
||||
当同一个镜像有多个标签时,`docker rmi` 只是删除指定的标签,不会删除镜像本身。
|
||||
|
||||
```
|
||||
|
||||
#### 原因三:被其他镜像依赖 (中间层)
|
||||
|
||||
```bash
|
||||
|
||||
@@ -120,9 +120,7 @@ docker run --name web2 -d -p 81:80 nginx:v2
|
||||
|
||||
至此,我们第一次完成了定制镜像,使用的是 `docker commit` 命令,手动操作给旧的镜像添加了新的一层,形成新的镜像,对镜像多层存储应该有了更直观的感觉。
|
||||
|
||||
### 4.4.1 概述
|
||||
|
||||
### 4.4.2 慎用 `docker commit`
|
||||
### 4.4.1 慎用 `docker commit`
|
||||
|
||||
使用 `docker commit` 命令虽然可以比较直观的帮助理解镜像分层存储的概念,但是实际环境中并不会这样使用。
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Dockerfile 是一个文本文件,其内包含了一条条的 **指令 (Instruc
|
||||
|
||||
### 4.5.1 使用 docker init 快速创建 (推荐)
|
||||
|
||||
Docker 提供了 `docker init` 命令,可以根据项目类型自动生成 Dockerfile、。dockerignore 和 compose.yaml 文件:
|
||||
Docker 提供了 `docker init` 命令,可以根据项目类型自动生成 Dockerfile、.dockerignore 和 compose.yaml 文件:
|
||||
|
||||
```bash
|
||||
$ docker init
|
||||
|
||||
@@ -15,3 +15,8 @@ Docker 运行容器前需要本地存在对应的镜像,如果本地不存在
|
||||
* [使用 Dockerfile 定制镜像](4.5_build.md)
|
||||
* [其它制作镜像的方式](4.6_other.md)
|
||||
* [镜像的实现原理](4.7_internal.md)
|
||||
|
||||
> **版本提示:镜像存储后端的变迁**
|
||||
>
|
||||
> 在 Docker Engine v29 及后续版本中,Docker 全新安装默认启用了 **containerd image store**(替代了传统的 classic store)。这一底层架构级别的变迁,意味着 Docker 解锁了对 OCI Image Index 和 Attestations (例如原生的 provenance 来源证明与 SBOM 软件物料清单)的全量本地支持。
|
||||
> 读者在执行类似 `docker buildx build --provenance=mode=min --sbom=true` 甚至使用后续审查工具(如 `docker buildx imagetools inspect`)时,其元数据能够与镜像数据一并完好地管理于本地存储系统中,为供应链安全验证补齐了最后一块拼图。
|
||||
|
||||
@@ -1,21 +1,13 @@
|
||||
## 本章小结
|
||||
|
||||
本章介绍了 Docker 镜像的获取、列出、删除以及构建方式。
|
||||
|
||||
| 操作 | 命令 |
|
||||
|------|------|
|
||||
| 拉取镜像 | `docker pull 镜像名:标签` |
|
||||
| 拉取所有标签 | `docker pull -a 镜像名` |
|
||||
| 指定平台 | `docker pull --platform linux/amd64 镜像名` |
|
||||
| 用摘要拉取 | `docker pull 镜像名@sha256:...` |
|
||||
|
||||
### 4.8.1 延伸阅读
|
||||
|
||||
- [列出镜像](4.2_list.md):查看本地镜像
|
||||
- [删除镜像](4.3_rm.md):清理本地镜像
|
||||
- [镜像加速器](../03_install/3.9_mirror.md):加速镜像下载
|
||||
- [Docker Hub](../06_repository/6.1_dockerhub.md):官方镜像仓库
|
||||
|
||||
| 操作 | 命令 |
|
||||
|------|------|
|
||||
| 列出所有镜像 | `docker images` |
|
||||
| 按仓库名过滤 | `docker images nginx` |
|
||||
| 列出虚悬镜像 | `docker images -f dangling=true` |
|
||||
@@ -23,24 +15,22 @@
|
||||
| 显示摘要 | `docker images --digests` |
|
||||
| 自定义格式 | `docker images --format "..."` |
|
||||
| 查看空间占用 | `docker system df` |
|
||||
|
||||
### 4.8.2 延伸阅读
|
||||
|
||||
- [获取镜像](4.1_pull.md):从 Registry 拉取镜像
|
||||
- [删除镜像](4.3_rm.md):清理本地镜像
|
||||
- [镜像](../02_basic_concept/2.1_image.md):理解镜像概念
|
||||
|
||||
| 操作 | 命令 |
|
||||
|------|------|
|
||||
| 删除指定镜像 | `docker rmi 镜像名:标签` |
|
||||
| 强制删除 | `docker rmi -f 镜像名` |
|
||||
| 删除虚悬镜像 | `docker image prune` |
|
||||
| 删除未使用镜像 | `docker image prune -a` |
|
||||
| 批量删除 | `docker rmi $(docker images -q -f ...)` |
|
||||
| 查看空间占用 | `docker system df` |
|
||||
|
||||
### 4.8.3 延伸阅读
|
||||
### 延伸阅读
|
||||
|
||||
- [获取镜像](4.1_pull.md):从 Registry 拉取镜像
|
||||
- [列出镜像](4.2_list.md):查看和过滤镜像
|
||||
- [删除镜像](4.3_rm.md):清理本地镜像
|
||||
- [镜像加速器](../03_install/3.9_mirror.md):加速镜像下载
|
||||
- [Docker Hub](../06_repository/6.1_dockerhub.md):官方镜像仓库
|
||||
- [镜像](../02_basic_concept/2.1_image.md):理解镜像概念
|
||||
- [删除容器](../05_container/5.6_rm.md):清理容器
|
||||
- [数据卷](../08_data/8.1_volume.md):清理数据卷
|
||||
---
|
||||
|
||||
> 📝 **发现错误或有改进建议?** 欢迎提交 [Issue](https://github.com/yeasy/docker_practice/issues) 或 [PR](https://github.com/yeasy/docker_practice/pulls)。
|
||||
|
||||
@@ -1,55 +1,33 @@
|
||||
## 本章小结
|
||||
|
||||
本章介绍了 Docker 容器的启动、停止、进入和删除等核心操作。
|
||||
|
||||
| 操作 | 命令 | 说明 |
|
||||
|------|------|------|
|
||||
| 新建并运行 | `docker run` | 最常用的启动方式 |
|
||||
| 交互式启动 | `docker run -it` | 用于调试或临时操作 |
|
||||
| 后台运行 | `docker run -d` | 用于服务类应用 |
|
||||
| 启动已停止的容器 | `docker start` | 重用已有容器 |
|
||||
| 优雅停止 | `docker stop` | 先 SIGTERM,超时后 SIGKILL |
|
||||
| 强制停止 | `docker kill` | 直接 SIGKILL |
|
||||
| 重启 | `docker restart` | 停止后立即启动 |
|
||||
| 停止全部 | `docker stop $(docker ps -q)` | 停止所有运行中容器 |
|
||||
| 进入容器调试 | `docker exec -it 容器名 bash` | 推荐方式 |
|
||||
| 执行单条命令 | `docker exec 容器名 命令` | 不进入交互模式 |
|
||||
| 查看主进程输出 | `docker attach 容器名` | 慎用,退出可能停止容器 |
|
||||
| 删除已停止容器 | `docker rm 容器名` | 需先停止 |
|
||||
| 强制删除运行中容器 | `docker rm -f 容器名` | 直接删除 |
|
||||
| 删除容器及匿名卷 | `docker rm -v 容器名` | 同时清理匿名卷 |
|
||||
| 清理所有已停止容器 | `docker container prune` | 批量清理 |
|
||||
|
||||
### 5.7.1 延伸阅读
|
||||
### 延伸阅读
|
||||
|
||||
- [后台运行](5.2_daemon.md):理解 `-d` 参数和容器生命周期
|
||||
- [进入容器](5.4_attach_exec.md):操作运行中的容器
|
||||
- [网络配置](../09_network/README.md):理解端口映射的原理
|
||||
- [数据管理](../08_data/README.md):数据持久化方案
|
||||
|
||||
| 操作 | 命令 | 说明 |
|
||||
|------|------|------|
|
||||
| 优雅停止 | `docker stop` | 先 SIGTERM,超时后 SIGKILL |
|
||||
| 强制停止 | `docker kill` | 直接 SIGKILL |
|
||||
| 重新启动 | `docker start` | 启动已停止的容器 |
|
||||
| 重启 | `docker restart` | 停止后立即启动 |
|
||||
| 停止全部 | `docker stop $(docker ps -q)` | 停止所有运行中容器 |
|
||||
|
||||
### 5.7.2 延伸阅读
|
||||
|
||||
- [启动容器](../05_container/5.1_run.md):容器启动详解
|
||||
- [删除容器](5.6_rm.md):清理容器
|
||||
- [容器日志](5.2_daemon.md):排查停止原因
|
||||
|
||||
| 需求 | 推荐命令 |
|
||||
|------|---------|
|
||||
| 进入容器调试 | `docker exec -it 容器名 bash` |
|
||||
| 执行单条命令 | `docker exec 容器名 命令` |
|
||||
| 查看主进程输出 | `docker attach 容器名` (慎用)|
|
||||
|
||||
### 5.7.3 延伸阅读
|
||||
|
||||
- [后台运行](5.2_daemon.md):理解容器主进程
|
||||
- [查看容器](5.1_run.md):列出和过滤容器
|
||||
- [容器日志](5.2_daemon.md):查看容器输出
|
||||
|
||||
| 操作 | 命令 |
|
||||
|------|------|
|
||||
| 删除已停止容器 | `docker rm 容器名` |
|
||||
| 强制删除运行中容器 | `docker rm -f 容器名` |
|
||||
| 删除容器及匿名卷 | `docker rm -v 容器名` |
|
||||
| 清理所有已停止容器 | `docker container prune` |
|
||||
| 删除所有容器 | `docker rm -f $(docker ps -aq)` |
|
||||
|
||||
### 5.7.4 延伸阅读
|
||||
|
||||
- [终止容器](5.3_stop.md):优雅停止容器
|
||||
- [删除镜像](../04_image/4.3_rm.md):清理镜像
|
||||
- [数据卷](../08_data/8.1_volume.md):数据卷管理
|
||||
---
|
||||
|
||||
> 📝 **发现错误或有改进建议?** 欢迎提交 [Issue](https://github.com/yeasy/docker_practice/issues) 或 [PR](https://github.com/yeasy/docker_practice/pulls)。
|
||||
|
||||
@@ -45,7 +45,8 @@ $ docker pull nginx:alpine
|
||||
|
||||
```bash
|
||||
$ docker login
|
||||
## 输入用户名和密码
|
||||
## 默认情况下,不带其它参数进行 docker login 会自动走 Device Code Web Flow (浏览器认证)
|
||||
## 若在非交互 CI 环境中,推荐结合 --username 与 --password-stdin 参数使用
|
||||
|
||||
...
|
||||
```
|
||||
@@ -76,10 +77,18 @@ $ docker push username/myapp:v1
|
||||
| **免费账户** (已登录) | 每 6 小时 200 次请求 |
|
||||
| **Pro/Team 账户** | 无限制 |
|
||||
|
||||
> **提示**:如果在 CI/CD 环境中遇到 `toomanyrequests` 错误,建议:
|
||||
> 1. 在 CI 中配置 `docker login`
|
||||
> 2. 使用国内镜像加速器
|
||||
> 3. 搭建私有仓库代理
|
||||
#### 滥用限流
|
||||
|
||||
除了上述针对特定账号拉取镜像数量的 Pull Rate Limit 之外,Docker Hub 对所有用户(包含已认证及付费用户)还实施了 **滥用保护限流 (Abuse Rate Limiting)**。它是根据网络出口 IP (IPv4 或 IPv6 /64 子网) 计算整体请求频率,阈值动态触发(通常为每分钟数千级别请求)。
|
||||
|
||||
**两类的差异与排查方法**:
|
||||
- **Pull Rate Limit**:针对拉取量达到上限。报错返回 `429 Too Many Requests`,并且 HTTP 返回体/CLI 错误提示中会带有明确的 `toomanyrequests: You have reached your pull rate limit` 提示,常附有账户升级链接。
|
||||
- **Abuse Rate Limit**:防范接口频率打击。报错仅返回简化的 `429 Too Many Requests`。这一限流不分付费与否,常发生在“多终端共享出口 IP”的企业局域网或者第三方云 CI 服务(如 GitHub Actions 等)中,即使你已正常配置 `docker login` 也依旧可能触发。
|
||||
|
||||
> **提示**:如果在 CI/CD 等环境遇到 429 错误,建议:
|
||||
> 1. 先甄别具体是哪类限流:普通的 pull rate limit 只要在 CI 中配置 `docker login` (并使用有效账号) 就能解除匿名限制。
|
||||
> 2. 如果是 Abuse 频控导致,应考虑搭建私有仓库作为拉取缓存代理 (Registry pull-through cache),避免频繁直接请求官方 Hub。
|
||||
> 3. 使用国内镜像加速器。
|
||||
|
||||
---
|
||||
|
||||
@@ -94,13 +103,13 @@ $ docker push username/myapp:v1
|
||||
|
||||
#### 2. 使用 Access Token
|
||||
|
||||
不要在脚本或 CI/CD 中直接使用登录密码。
|
||||
> **⚠️ 警告**:绝不要在脚本或 CI/CD 系统中,直接使用 `-p` 参数传递密码或 Token (类似 `docker login -p xxx`)!这会导致凭证直接暴露在系统的命令历史、进程列表和终端输出中。
|
||||
|
||||
1. 在 Docker Hub -> Account Settings -> Security -> Access Tokens 创建 Token。
|
||||
2. 使用 Token 作为密码登录:
|
||||
1. 在 Docker Hub -> Account Settings -> Security -> Access Tokens 创建 Token (PAT)。
|
||||
2. 将 Token 通过标准输入 (stdin) 安全传递给 Docker:
|
||||
|
||||
```bash
|
||||
$ docker login -u username -p dckr_pat_xxxxxxx
|
||||
$ echo "dckr_pat_xxxxxxx" | docker login --username username --password-stdin
|
||||
```
|
||||
|
||||
#### 3. 关注镜像漏洞
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -5,3 +5,10 @@
|
||||
一个容易混淆的概念是注册服务器 (`Registry`)。实际上注册服务器是管理仓库的具体服务器,每个服务器上可以有多个仓库,而每个仓库下面有多个镜像。从这方面来说,仓库可以被认为是一个具体的项目或目录。例如对于仓库地址 `docker.io/ubuntu` 来说,`docker.io` 是注册服务器地址,`ubuntu` 是仓库名。
|
||||
|
||||
大部分时候,并不需要严格区分这两者的概念。
|
||||
|
||||
## 本章内容
|
||||
|
||||
* [Docker Hub](6.1_dockerhub.md)
|
||||
* [私有仓库](6.2_registry.md)
|
||||
* [私有仓库高级配置](6.3_registry_auth.md)
|
||||
* [Nexus 3](6.4_nexus3_registry.md)
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
## 本章小结
|
||||
|
||||
本章介绍了 Docker Hub 的使用、私有仓库的搭建以及 Nexus 3 等企业级方案。
|
||||
|
||||
| 功能 | 说明 |
|
||||
|------|------|
|
||||
| **官方镜像** | 优先使用的基础镜像 |
|
||||
| **拉取限制** | 匿名 100次/6h,登录 200次/6h |
|
||||
| **拉取限制** | 匿名 100 次/6h,登录 200 次/6h |
|
||||
| **安全** | 推荐开启 2FA 并使用 Access Token |
|
||||
| **自动化** | 支持 Webhooks 和自动构建 |
|
||||
|
||||
### 6.5.1 概述
|
||||
|
||||
### 6.5.2 延伸阅读
|
||||
### 延伸阅读
|
||||
|
||||
- [私有仓库](6.2_registry.md):搭建自己的 Registry
|
||||
- [镜像加速器](../03_install/3.9_mirror.md):加速下载
|
||||
---
|
||||
|
||||
> 📝 **发现错误或有改进建议?** 欢迎提交 [Issue](https://github.com/yeasy/docker_practice/issues) 或 [PR](https://github.com/yeasy/docker_practice/pulls)。
|
||||
|
||||
@@ -1,7 +1,36 @@
|
||||
## 7.16 参考文档
|
||||
|
||||
* `Dockerfile` 官方文档:https://docs.docker.com/engine/reference/builder/
|
||||
### 官方文档
|
||||
|
||||
* `Dockerfile` 最佳实践文档:https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
|
||||
* `Dockerfile` 官方参考手册:https://docs.docker.com/engine/reference/builder/
|
||||
|
||||
* `Docker` 官方镜像 `Dockerfile`:https://github.com/docker-library/docs
|
||||
* `Dockerfile` 最佳实践指南:https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
|
||||
|
||||
* `Docker` 官方镜像 `Dockerfile` 库:https://github.com/docker-library/docs
|
||||
|
||||
### 常用指令总结
|
||||
|
||||
Dockerfile 中的常用指令包括:
|
||||
|
||||
- **FROM**: 指定基础镜像,必须是第一条指令
|
||||
- **RUN**: 在镜像中执行命令,用于安装软件包等
|
||||
- **WORKDIR**: 设置工作目录
|
||||
- **COPY/ADD**: 复制文件到镜像中
|
||||
- **EXPOSE**: 声明容器监听的端口
|
||||
- **ENV**: 设置环境变量
|
||||
- **ENTRYPOINT**: 容器启动时的入口点
|
||||
- **CMD**: 容器默认执行的命令
|
||||
|
||||
### 最佳实践建议
|
||||
|
||||
1. 使用具体的基础镜像版本标签而非 latest
|
||||
2. 最小化镜像层数,合并 RUN 指令
|
||||
3. 使用 .dockerignore 文件排除不必要的文件
|
||||
4. 安装必要的软件包后清理缓存
|
||||
5. 使用多阶段构建减小最终镜像体积
|
||||
6. 避免以 root 身份运行容器应用
|
||||
|
||||
### 相关资源
|
||||
|
||||
- Docker 官方镜像库:https://hub.docker.com/
|
||||
- Docker 镜像构建最佳实践:https://docs.docker.com/build/building/best-practices/
|
||||
|
||||
@@ -118,7 +118,7 @@ go/helloworld 2 f7cf3465432c 22 seconds ago 6.47MB
|
||||
go/helloworld 1 f55d3e16affc 2 minutes ago 295MB
|
||||
```
|
||||
|
||||
## 7.17 使用多阶段构建
|
||||
### 7.17.3 使用多阶段构建
|
||||
|
||||
为解决以上问题,Docker v17.05 开始支持多阶段构建 (`multistage builds`)。使用多阶段构建我们就可以很容易解决前面提到的问题,并且只需要编写一个 `Dockerfile`:
|
||||
|
||||
@@ -167,7 +167,7 @@ go/helloworld 1 f55d3e16affc 2 minutes ago 295MB
|
||||
|
||||
很明显使用多阶段构建的镜像体积小,同时也完美解决了上边提到的问题。
|
||||
|
||||
### 7.17.1 只构建某一阶段的镜像
|
||||
### 7.17.4 只构建某一阶段的镜像
|
||||
|
||||
我们可以使用 `as` 来为某一阶段命名,例如
|
||||
|
||||
@@ -181,7 +181,7 @@ FROM golang:alpine as builder
|
||||
$ docker build --target builder -t username/imagename:tag .
|
||||
```
|
||||
|
||||
### 7.17.2 构建时从其他镜像复制文件
|
||||
### 7.17.5 构建时从其他镜像复制文件
|
||||
|
||||
上面例子中我们使用 `COPY --from=0 /go/src/github.com/go/helloworld/app .` 从上一阶段的镜像中复制文件,我们也可以复制任意镜像中的文件。
|
||||
|
||||
|
||||
@@ -268,3 +268,7 @@ COPY . .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
> **🔥 踩坑实录**
|
||||
>
|
||||
> 某公司在优化 Node.js 应用的 Docker 镜像时,发现构建出来的镜像体积超过了 2GB,远远超过生产部署的需求。排查发现,Dockerfile 中使用了 `COPY . .` 把整个构建上下文复制进镜像,导致 `node_modules/`、`.git/` 目录和大量测试数据全部被打包进镜像。最初他们没有创建 `.dockerignore` 文件,默认会复制所有文件。解决方案是添加一个 `.dockerignore` 文件,排除这些不必要的目录,使镜像缩小到了 200MB。这个教训深刻地说明了:`.dockerignore` 和 `.gitignore` 一样重要,应该在项目初始化时就创建,而不是等到出现问题时才想起来。建议的标准做法是先复制 `package.json` 和 `package-lock.json` 安装依赖,再复制应用代码,同时在 `.dockerignore` 中明确列出 `node_modules`、`.git`、test 目录等。
|
||||
|
||||
@@ -103,7 +103,7 @@ VOLUME /data
|
||||
RUN echo "hello" > /data/test.txt
|
||||
```
|
||||
|
||||
**原因**:VOLUME 指令之后,Docker 将该目录视为外部挂载点,不再记录对它的修改。
|
||||
**原因**:在构建过程中,VOLUME 指令会为该目录创建一个临时的匿名卷。后续 RUN 指令对该目录的写入实际发生在这个临时卷中,而非镜像层。当该 RUN 指令结束后,临时卷被丢弃,因此写入的内容不会保存到最终镜像中。注意:这与容器运行时创建的匿名卷是不同的——运行时创建的卷会在容器生命周期内持续存在。
|
||||
|
||||
#### 正确做法
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## 什么是 Dockerfile
|
||||
|
||||
Dockerfile 是一个文本文件,其內包含了一条条的 **指令 (Instruction)**,每一条指令构建一层,therefore 每一条指令的内容,就是描述该层应当如何构建。
|
||||
Dockerfile 是一个文本文件,其内包含了一条条的 **指令 (Instruction)**,每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
|
||||
|
||||
在[第四章](../04_image/README.md)中,我们通过 `docker commit` 学习了镜像的构成。但是,手动 `commit` 只能作为临时修补,并不适合作为生产环境镜像的构建方式。
|
||||
|
||||
@@ -21,6 +21,7 @@ Dockerfile 一般分为四部分:基础镜像信息、维护者信息、镜像
|
||||
|
||||
本章将详细讲解 Dockerfile 中的各个指令:
|
||||
|
||||
* [RUN 执行命令](7.1_run.md)
|
||||
* [COPY 复制文件](7.2_copy.md)
|
||||
* [ADD 更高级的复制文件](7.3_add.md)
|
||||
* [CMD 容器启动命令](7.4_cmd.md)
|
||||
@@ -35,7 +36,15 @@ Dockerfile 一般分为四部分:基础镜像信息、维护者信息、镜像
|
||||
* [ONBUILD 为他人作嫁衣裳](7.13_onbuild.md)
|
||||
* [LABEL 为镜像添加元数据](7.14_label.md)
|
||||
* [SHELL 指令](7.15_shell.md)
|
||||
* [RUN 执行命令](7.1_run.md)
|
||||
|
||||
### 高级特性
|
||||
|
||||
本章还将介绍 Dockerfile 的高级特性:
|
||||
|
||||
* [多阶段构建](7.17_multistage_builds.md)
|
||||
* [多阶段构建实战:Laravel 应用](7.18_multistage_builds_laravel.md)
|
||||
|
||||
### 参考与最佳实践
|
||||
|
||||
此外,我们还将介绍 Dockerfile 的最佳实践和常见问题。
|
||||
|
||||
|
||||
@@ -1,208 +1,33 @@
|
||||
## 本章小结
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
| **作用** | 设置后续指令的工作目录 |
|
||||
| **语法** | `WORKDIR /path` |
|
||||
| **自动创建** | 目录不存在会自动创建 |
|
||||
| **持久性** | 影响后续所有指令,直到下次 WORKDIR |
|
||||
| **不要用** | `RUN cd /path` (无效)|
|
||||
本章详细介绍了 Dockerfile 的所有核心指令,以下是各指令要点的速查表。
|
||||
|
||||
### 7.19.1 延伸阅读
|
||||
| 指令 | 作用 | 关键要点 |
|
||||
|------|------|---------|
|
||||
| **FROM** | 指定基础镜像 | 必须是第一条指令 |
|
||||
| **RUN** | 在新层执行命令 | 合并命令、清理缓存以减小体积 |
|
||||
| **COPY** | 复制文件 | 优先使用,支持 `--from` |
|
||||
| **ADD** | 更高级的复制 | 自动解压 tar,不推荐用于下载 |
|
||||
| **CMD** | 容器启动默认命令 | 可被 `docker run` 参数覆盖 |
|
||||
| **ENTRYPOINT** | 容器入口点 | 固定启动命令,CMD 作为默认参数 |
|
||||
| **ENV** | 设置环境变量 | 构建时 + 运行时均生效 |
|
||||
| **ARG** | 构建参数 | 仅构建时生效,FROM 后需重新声明 |
|
||||
| **VOLUME** | 定义匿名卷 | VOLUME 之后的修改会丢失 |
|
||||
| **EXPOSE** | 声明端口 | 仅文档作用,不自动映射 |
|
||||
| **WORKDIR** | 指定工作目录 | 替代 `RUN cd`,目录不存在会自动创建 |
|
||||
| **USER** | 指定运行用户 | 用户必须已存在,推荐 gosu |
|
||||
| **HEALTHCHECK** | 健康检查 | 支持 starting/healthy/unhealthy 状态 |
|
||||
| **ONBUILD** | 延迟执行指令 | 只继承一次,不可级联 |
|
||||
| **LABEL** | 添加元数据 | 推荐 OCI 标准标签,替代 MAINTAINER |
|
||||
| **SHELL** | 更改默认 shell | 推荐 `["/bin/bash", "-o", "pipefail", "-c"]` |
|
||||
|
||||
- [COPY 复制文件](7.2_copy.md):文件复制
|
||||
- [RUN 执行命令](../04_image/4.5_build.md):执行构建命令
|
||||
- [最佳实践](../appendix/best_practices.md):Dockerfile 编写指南
|
||||
### 延伸阅读
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
| **作用** | 切换后续指令的执行用户 |
|
||||
| **语法** | `USER username` 或 `USER UID:GID` |
|
||||
| **前提** | 用户必须已存在 |
|
||||
| **运行时覆盖** | `docker run -u` |
|
||||
| **切换工具** | 使用 gosu,不用 su/sudo |
|
||||
|
||||
### 7.19.2 延伸阅读
|
||||
|
||||
- [安全](../18_security/README.md):容器安全实践
|
||||
- [ENTRYPOINT](7.5_entrypoint.md):入口脚本中的用户切换
|
||||
- [最佳实践](../appendix/best_practices.md):Dockerfile 安全
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
| **作用** | 检测容器应用是否真实可用 |
|
||||
| **命令** | `HEALTHCHECK [选项] CMD command` |
|
||||
| **状态** | starting, healthy, unhealthy |
|
||||
| **Compose** | 支持 `condition: service_healthy` 依赖 |
|
||||
| **注意** | 避免副作用,节省资源 |
|
||||
|
||||
### 7.19.3 延伸阅读
|
||||
|
||||
- [CMD 容器启动命令](7.4_cmd.md):启动主进程
|
||||
- [Compose 模板文件](../11_compose/11.5_compose_file.md):Compose 中的健康检查
|
||||
- [Docker 调试](../appendix/debug.md):容器排障
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
| **作用** | 定义在子镜像构建时执行的指令 |
|
||||
| **语法** | `ONBUILD INSTRUCTION` |
|
||||
| **适用** | 基础架构镜像 (Node, Python, Go 等)|
|
||||
| **限制** | 只继承一次,不可级联 |
|
||||
| **规范** | 建议使用 `-onbuild` 标签后缀 |
|
||||
|
||||
### 7.19.4 延伸阅读
|
||||
|
||||
- [COPY 指令](7.2_copy.md):文件复制
|
||||
- [Dockerfile 最佳实践](../appendix/best_practices.md):基础镜像设计
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
| **作用** | 添加 key-value 元数据 |
|
||||
| **语法** | `LABEL k=v k=v ...` |
|
||||
| **规范** | 推荐使用 OCI 标准标签 |
|
||||
| **弃用** | 不要再使用 `MAINTAINER` |
|
||||
| **查看** | `docker inspect` |
|
||||
|
||||
### 7.19.5 延伸阅读
|
||||
|
||||
- [OCI 标签规范](https://github.com/opencontainers/image-spec/blob/main/annotations.md)
|
||||
- [Dockerfile 最佳实践](../appendix/best_practices.md)
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
| **作用** | 更改 RUN/CMD/ENTRYPOINT 的默认 shell |
|
||||
| **Linux 默认** | `["/bin/sh", "-c"]` |
|
||||
| **Windows 默认** | `["cmd", "/S", "/C"]` |
|
||||
| **推荐用法** | `SHELL ["/bin/bash", "-o", "pipefail", "-c"]` |
|
||||
| **影响范围** | 后续所有使用 shell 格式的指令 |
|
||||
|
||||
### 7.19.6 延伸阅读
|
||||
|
||||
- [RUN 指令](../04_image/4.5_build.md):执行命令
|
||||
- [Dockerfile 最佳实践](../appendix/best_practices.md):错误处理与调试
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
| **作用** | 在新层执行命令 |
|
||||
| **原则** | 合并命令,清理缓存 |
|
||||
| **格式** | Shell (常用) vs Exec |
|
||||
| **陷阱** | `cd` 不持久,环境变量不持久 |
|
||||
| **进阶** | 使用 Cache Mount 加速构建 |
|
||||
|
||||
### 7.19.7 延伸阅读
|
||||
|
||||
- [CMD 容器启动命令](7.4_cmd.md):容器启动时的命令
|
||||
- [WORKDIR 指定工作目录](7.10_workdir.md):改变目录
|
||||
- [Dockerfile 最佳实践](../appendix/best_practices.md)
|
||||
|
||||
| 操作 | 示例 |
|
||||
|------|------|
|
||||
| 复制文件 | `COPY app.js /app/` |
|
||||
| 复制多个文件 | `COPY *.json /app/` |
|
||||
| 复制目录内容 | `COPY src/ /app/src/` |
|
||||
| 修改所有者 | `COPY --chown=node:node . /app/` |
|
||||
| 从构建阶段复制 | `COPY --from=builder /app/dist ./` |
|
||||
|
||||
### 7.19.8 延伸阅读
|
||||
|
||||
- [ADD 指令](7.3_add.md):复制和解压
|
||||
- [WORKDIR 指令](7.10_workdir.md):设置工作目录
|
||||
- [使用 Dockerfile 定制镜像](../04_image/4.5_build.md):Dockerfile 入门
|
||||
- [多阶段构建](7.17_multistage_builds.md):优化镜像大小
|
||||
- [最佳实践](../appendix/best_practices.md):Dockerfile 编写指南
|
||||
- [Dockerfile 最佳实践](../appendix/best_practices.md):编写指南
|
||||
- [安全](../18_security/README.md):容器安全实践
|
||||
- [Compose 模板文件](../11_compose/11.5_compose_file.md):Compose 中的配置
|
||||
---
|
||||
|
||||
| 场景 | 推荐指令 |
|
||||
|------|---------|
|
||||
| 复制普通文件 | `COPY` |
|
||||
| 复制目录 | `COPY` |
|
||||
| 自动解压 tar | `ADD` |
|
||||
| 从 URL 下载 | `RUN curl` |
|
||||
| 保持 tar 不解压 | `COPY` |
|
||||
|
||||
### 7.19.9 延伸阅读
|
||||
|
||||
- [COPY 复制文件](7.2_copy.md):基本复制操作
|
||||
- [多阶段构建](7.17_multistage_builds.md):减少镜像体积
|
||||
- [最佳实践](../appendix/best_practices.md):Dockerfile 编写指南
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
| **作用** | 指定容器启动时的默认命令 |
|
||||
| **推荐格式** | exec 格式 `CMD [“程序”, “参数”]` |
|
||||
| **覆盖方式** | `docker run image 新命令` |
|
||||
| **与 ENTRYPOINT** | CMD 作为 ENTRYPOINT 的默认参数 |
|
||||
| **核心原则** | 应用必须在前台运行 |
|
||||
|
||||
### 7.19.10 延伸阅读
|
||||
|
||||
- [ENTRYPOINT 入口点](7.5_entrypoint.md):固定的启动命令
|
||||
- [后台运行](../05_container/5.2_daemon.md):容器前台/后台概念
|
||||
- [最佳实践](../appendix/best_practices.md):Dockerfile 编写指南
|
||||
|
||||
| ENTRYPOINT | CMD | 适用场景 |
|
||||
|------------|-----|---------|
|
||||
| ✓ | ✗ | 镜像作为固定命令使用 |
|
||||
| ✗ | ✓ | 简单的默认命令 |
|
||||
| ✓ | ✓ | **推荐**:固定命令 + 可配置参数 |
|
||||
|
||||
### 7.19.11 延伸阅读
|
||||
|
||||
- [CMD 容器启动命令](7.4_cmd.md):默认命令
|
||||
- [最佳实践](../appendix/best_practices.md):启动命令设计
|
||||
- [后台运行](../05_container/5.2_daemon.md):前台/后台概念
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
| **语法** | `ENV KEY=value` |
|
||||
| **作用范围** | 构建时 + 运行时 |
|
||||
| **覆盖方式** | `docker run -e KEY=value` |
|
||||
| **与 ARG** | ARG 仅构建时,ENV 持久化到运行时 |
|
||||
| **安全** | 不要存储敏感信息 |
|
||||
|
||||
### 7.19.12 延伸阅读
|
||||
|
||||
- [ARG 构建参数](7.7_arg.md):构建时变量
|
||||
- [Compose 环境变量](../11_compose/11.5_compose_file.md):Compose 中的环境变量
|
||||
- [最佳实践](../appendix/best_practices.md):Dockerfile 编写指南
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
| **作用** | 定义构建时变量 |
|
||||
| **语法** | `ARG NAME=value` |
|
||||
| **覆盖** | `docker build --build-arg NAME=value` |
|
||||
| **作用域** | FROM 之后需要重新声明 |
|
||||
| **vs ENV** | ARG 仅构建时,ENV 构建+运行时 |
|
||||
| **安全** | 不要存储敏感信息 |
|
||||
|
||||
### 7.19.13 延伸阅读
|
||||
|
||||
- [ENV 设置环境变量](7.6_env.md):运行时环境变量
|
||||
- [FROM 指令](../04_image/4.5_build.md):基础镜像指定
|
||||
- [多阶段构建](7.17_multistage_builds.md):复杂构建场景
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
| **作用** | 创建挂载点,标记为外部卷 |
|
||||
| **语法** | `VOLUME /path` |
|
||||
| **默认行为** | 自动创建匿名卷 |
|
||||
| **覆盖方式** | `docker run -v name:/path` |
|
||||
| **注意** | VOLUME 之后的修改会丢失 |
|
||||
|
||||
### 7.19.14 延伸阅读
|
||||
|
||||
- [数据卷](../08_data/8.1_volume.md):卷的管理和使用
|
||||
- [挂载主机目录](../08_data/8.2_bind-mounts.md):Bind Mount
|
||||
- [Compose 数据管理](../11_compose/11.5_compose_file.md):Compose 中的卷配置
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
| **作用** | 声明容器提供服务的端口 (文档)|
|
||||
| **不会** | 自动映射端口或开放外部访问 |
|
||||
| **配合** | `docker run -P` 自动映射 |
|
||||
| **外部访问** | 需要 `-p 宿主机端口:容器端口` |
|
||||
| **语法** | `EXPOSE 80` 或 `EXPOSE 80/tcp` |
|
||||
|
||||
### 7.19.15 延伸阅读
|
||||
|
||||
- [网络配置](../09_network/README.md):Docker 网络详解
|
||||
- [端口映射](../09_network/9.5_port_mapping.md):-p 参数详解
|
||||
- [Compose 端口](../11_compose/11.5_compose_file.md):Compose 中的端口配置
|
||||
> 📝 **发现错误或有改进建议?** 欢迎提交 [Issue](https://github.com/yeasy/docker_practice/issues) 或 [PR](https://github.com/yeasy/docker_practice/pulls)。
|
||||
|
||||
@@ -138,8 +138,11 @@ $ docker run -d \
|
||||
| 特性 | --mount | -v |
|
||||
|------|---------|-----|
|
||||
| 语法 | 键值对,更清晰 | 冒号分隔,更简洁 |
|
||||
| 自动创建卷 | source 不存在会报错 | 自动创建 |
|
||||
| 推荐程度 | ✅ 推荐 (更明确)| 常用 (更简洁)|
|
||||
| **数据卷 (Volume)** 挂载行为 | 卷不存在会自动创建,与 `-v` 结果一致 | 卷不存在会自动创建 |
|
||||
| **绑定挂载 (Bind Mount)** 行为 | ⭐**宿主机路径不存在会报错**,不会自动创建 | 宿主机路径不存在会 **自动创建为目录** |
|
||||
| 推荐程度 | ✅ 推荐 (更明确安全,避免误创建)| 常用 (更简洁)|
|
||||
|
||||
> **提示**:官方更推荐使用 `--mount`。除了语法格式可读性更好之外,最重要的行为差异发生在 **绑定挂载 (Bind Mount)** 时:如果挂载的宿主机源路径尚未存在,`-v` 会擅自将其自动创建为一个空目录;而 `--mount` 则会严格检查并直接报错。这能有效避免因路径拼写错误而在宿主机上留下垃圾目录(以及导致的容器访问空目录问题)。而对于本节的 **数据卷 (Volume)** 挂载而言,两者在目标指定的卷不存在时皆会自动创建卷,产生的结果是 **完全一致** 的。
|
||||
|
||||
#### 只读挂载
|
||||
|
||||
|
||||
@@ -74,9 +74,11 @@ $ docker run -d \
|
||||
| 特性 | --mount | -v |
|
||||
|------|---------|-----|
|
||||
| 语法 | 键值对,更清晰 | 冒号分隔,更简洁 |
|
||||
| 路径不存在时 | 报错 | 自动创建目录 |
|
||||
| 路径不存在时 | 直接报错 (Fail Fast) | 静默自动创建 **目录** |
|
||||
| 推荐程度 | ✅ 推荐 | 常用 |
|
||||
|
||||
> **⚠️ 陷阱**:如果不小心挂载了一个不存在的宿主机路径,使用 `-v` 会在宿主机上静默创建一个 **空目录**(即使你本来想挂载的是一个文件),这常常会导致权限错误或应用无法正常读取。这也正是为什么 Docker 官方更推荐使用 `--mount` 的原因:它会遵循“Fail Fast”原则直接报错,避免弄巧成拙。
|
||||
|
||||
---
|
||||
|
||||
### 8.2.4 使用场景
|
||||
|
||||
@@ -10,16 +10,20 @@
|
||||
|
||||
### 8.3.2 基本用法
|
||||
|
||||
```bash
|
||||
$ docker run --tmpfs /run:rw,noexec,nosuid,size=64m nginx
|
||||
```
|
||||
|
||||
也可以使用 `--mount` 语法:
|
||||
使用 `--mount` 语法(推荐):
|
||||
|
||||
```bash
|
||||
$ docker run --mount type=tmpfs,destination=/run,tmpfs-size=67108864 nginx
|
||||
$ docker run --mount type=tmpfs,destination=/run,tmpfs-size=67108864,tmpfs-mode=1770 nginx
|
||||
```
|
||||
|
||||
也可以使用 `--tmpfs` 简写语法:
|
||||
|
||||
```bash
|
||||
$ docker run --tmpfs /run:size=64m nginx
|
||||
```
|
||||
|
||||
> **注意**:`--tmpfs` 支持的选项有限,主要为 `size` 和 `mode`。如果需要更精细的控制(如 `noexec`、`nosuid`),推荐使用 `--mount` 语法并通过 `tmpfs-mode` 参数设置权限。
|
||||
|
||||
### 8.3.3 注意事项
|
||||
|
||||
- 容器停止后,`tmpfs` 数据会丢失。
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
|
||||
图 8-1 Docker 数据挂载类型示意图
|
||||
|
||||
这一章介绍如何在 Docker 内部以及容器之间管理数据,在容器中管理数据主要有两种方式:
|
||||
这一章介绍如何在 Docker 内部以及容器之间管理数据,在容器中管理数据主要有以下几种方式:
|
||||
|
||||
* [数据卷](8.1_volume.md)
|
||||
* [挂载主机目录](8.2_bind-mounts.md)
|
||||
* [tmpfs 挂载](8.3_tmpfs.md)
|
||||
|
||||
@@ -1,18 +1,12 @@
|
||||
## 本章小结
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
| **作用** | 将宿主机目录挂载到容器 |
|
||||
| **语法** | `-v /宿主机:/容器` 或 `--mount type=bind,...` |
|
||||
| **只读** | 添加 `readonly` 或 `:ro` |
|
||||
| **适用场景** | 开发环境、配置文件、日志 |
|
||||
| **vs Volume** | Bind 更灵活,Volume 更适合生产 |
|
||||
本章介绍了 Docker 的三种数据管理方式:数据卷 (Volume)、绑定挂载 (Bind Mount) 和 tmpfs 挂载。
|
||||
|
||||
### 8.4.1 延伸阅读
|
||||
|
||||
- [数据卷](8.1_volume.md):Docker 管理的持久化存储
|
||||
- [tmpfs 挂载](8.3_tmpfs.md):内存临时存储
|
||||
- [Compose 数据管理](../11_compose/11.5_compose_file.md):Compose 中的挂载配置
|
||||
| 方式 | 特点 | 适用场景 |
|
||||
|------|------|---------|
|
||||
| **数据卷 (Volume)** | Docker 管理,生命周期独立于容器 | 数据库、应用数据(推荐生产环境) |
|
||||
| **绑定挂载 (Bind Mount)** | 挂载宿主机目录,更灵活 | 开发环境、配置文件、日志 |
|
||||
| **tmpfs 挂载** | 仅存储在内存中,容器停止即消失 | 临时敏感数据、高速缓存 |
|
||||
|
||||
| 操作 | 命令 |
|
||||
|------|------|
|
||||
@@ -23,8 +17,13 @@
|
||||
| 清理未用 | `docker volume prune` |
|
||||
| 挂载数据卷 | `-v name:/path` 或 `--mount source=name,target=/path` |
|
||||
|
||||
### 8.4.2 延伸阅读
|
||||
### 延伸阅读
|
||||
|
||||
- [数据卷](8.1_volume.md):Docker 管理的持久化存储
|
||||
- [绑定挂载](8.2_bind-mounts.md):挂载宿主机目录
|
||||
- [tmpfs 挂载](8.3_tmpfs.md):内存中的临时存储
|
||||
- [存储驱动](../12_implementation/12.4_ufs.md):Docker 存储的底层原理
|
||||
- [Compose 数据管理](../11_compose/11.5_compose_file.md):Compose 中的挂载配置
|
||||
---
|
||||
|
||||
> 📝 **发现错误或有改进建议?** 欢迎提交 [Issue](https://github.com/yeasy/docker_practice/issues) 或 [PR](https://github.com/yeasy/docker_practice/pulls)。
|
||||
|
||||
@@ -4,16 +4,16 @@ Docker 1.10.0 以后,内建了一个 DNS 服务器,使得容器可以直接
|
||||
|
||||
但是使用 Docker DNS 有个前提条件,就是它只能在 **自定义网络** 中使用。也就是说,如果使用的是默认的 `bridge` 网络,是无法使用 DNS 的,所以我们就需要自定义网络。
|
||||
|
||||
### 9.2.1 容器的 DNS 机制
|
||||
### 9.1.1 容器的 DNS 机制
|
||||
|
||||
Docker 容器的 DNS 配置有两种情况:
|
||||
|
||||
1. **默认 Bridge 网络**:继承宿主机的 DNS 配置 (`/etc/resolv.conf`)。
|
||||
2. **自定义网络** (推荐):使用 Docker 嵌入式 DNS 服务器 (Embedded DNS),支持通过 **容器名** 进行服务发现。
|
||||
2. **自定义网络**(推荐):使用 Docker 嵌入式 DNS 服务器 (Embedded DNS),支持通过 **容器名** 进行服务发现。
|
||||
|
||||
---
|
||||
|
||||
### 9.2.2 嵌入式 DNS
|
||||
### 9.1.2 嵌入式 DNS
|
||||
|
||||
这是 Docker 网络最强大的功能之一。在自定义网络中,容器可以通过 “名字” 找到彼此,而不需要知道对方的 IP (因为 IP 可能会变)。
|
||||
|
||||
@@ -38,7 +38,7 @@ Docker 守护进程在 `127.0.0.11` 运行了一个 DNS 服务器。容器内的
|
||||
|
||||
---
|
||||
|
||||
### 9.2.3 配置 DNS 参数
|
||||
### 9.1.3 配置 DNS 参数
|
||||
|
||||
如果你需要手动配置容器的 DNS (例如使用内网 DNS 服务器),可以在 `docker run` 中使用以下参数:
|
||||
|
||||
@@ -69,7 +69,7 @@ $ docker run -h myweb nginx
|
||||
|
||||
---
|
||||
|
||||
### 9.2.4 全局 DNS 配置
|
||||
### 9.1.4 全局 DNS 配置
|
||||
|
||||
如果希望所有容器都使用特定的 DNS 服务器 (而不是继承宿主机),可以修改 `/etc/docker/daemon.json`:
|
||||
|
||||
@@ -86,7 +86,7 @@ $ docker run -h myweb nginx
|
||||
|
||||
---
|
||||
|
||||
### 9.2.5 常见问题
|
||||
### 9.1.5 常见问题
|
||||
|
||||
以下是使用容器 DNS 时常见的问题及解决方法:
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
在生产环境中,推荐使用用户自定义网络代替默认的 bridge 网络。自定义网络提供了更好的隔离性和服务发现能力。
|
||||
|
||||
### 9.4.1 为什么要用自定义网络
|
||||
### 9.3.1 为什么要用自定义网络
|
||||
|
||||
默认 bridge 网络存在以下局限,而自定义网络可以很好地解决这些问题:
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
| 所有容器在同一网络 | 更好的隔离性 |
|
||||
| 需要 --link (已废弃)| 原生支持服务发现 |
|
||||
|
||||
### 9.4.2 创建自定义网络
|
||||
### 9.3.2 创建自定义网络
|
||||
|
||||
使用 `docker network create` 命令可以创建自定义网络:
|
||||
|
||||
@@ -26,7 +26,7 @@ $ docker network create mynet
|
||||
$ docker network inspect mynet
|
||||
```
|
||||
|
||||
### 9.4.3 使用自定义网络
|
||||
### 9.3.3 使用自定义网络
|
||||
|
||||
启动容器时通过 `--network` 参数指定连接的网络:
|
||||
|
||||
@@ -43,7 +43,7 @@ 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.4.4 容器名 DNS 解析
|
||||
### 9.3.4 容器名 DNS 解析
|
||||
|
||||
自定义网络自动提供 DNS 服务。Docker 守护进程在 `127.0.0.11` 运行了一个嵌入式 DNS 服务器,容器内的 DNS 请求会被转发到这里:
|
||||
|
||||
@@ -58,7 +58,7 @@ flowchart LR
|
||||
end
|
||||
```
|
||||
|
||||
### 9.4.5 常用网络命令
|
||||
### 9.3.5 常用网络命令
|
||||
|
||||
以下是 Docker 网络管理中常用的命令:
|
||||
|
||||
@@ -91,3 +91,9 @@ $ docker network rm mynet
|
||||
|
||||
$ docker network prune
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
> **🔥 踩坑实录**
|
||||
>
|
||||
> 一个新手开发者通过 `docker-compose` 部署了两个容器化服务:服务 A 和服务 B。他在服务 A 的代码中尝试用 `localhost:3000` 访问服务 B,结果始终连接超时。这个错误非常隐蔽——在本地单机开发时看不出问题,因为他可能在同一个进程中测试。排查时他错误地认为是防火墙或网络配置问题。实际原因是:每个容器都有独立的网络命名空间,`localhost` 在容器内部只指向容器自己,不是宿主机也不是其他容器。正确的做法是使用 docker-compose 自动创建的服务名作为主机名:`http://service-b:3000`。`docker-compose` 会自动在网络中注册服务名的 DNS,这样容器间通信才能正确解析。改动仅需一行代码,问题随之消失。
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
容器之间的网络通信是 Docker 网络的核心功能之一。本节介绍容器互联的几种方式。
|
||||
|
||||
### 9.5.1 同一网络内的容器
|
||||
### 9.4.1 同一网络内的容器
|
||||
|
||||
同一自定义网络内的容器可以直接通过容器名通信,这是推荐的容器互联方式:
|
||||
|
||||
@@ -21,7 +21,7 @@ $ docker run -d --name app --network app-net myapp
|
||||
...
|
||||
```
|
||||
|
||||
### 9.5.2 连接到多个网络
|
||||
### 9.4.2 连接到多个网络
|
||||
|
||||
一个容器可以同时连接到多个网络,这对于需要跨网络通信的中间件容器特别有用:
|
||||
|
||||
@@ -39,7 +39,7 @@ $ docker network connect backend multi-net-container
|
||||
$ docker inspect multi-net-container --format '{{json .NetworkSettings.Networks}}'
|
||||
```
|
||||
|
||||
### 9.5.3 ⚠️ --link 已废弃
|
||||
### 9.4.3 ⚠️ --link 已废弃
|
||||
|
||||
`--link` 是 Docker 早期用于容器互联的方式,**已经被废弃**,不建议在新项目中使用。请使用自定义网络替代:
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
容器运行在自己的隔离网络环境中 (通常是 Bridge 模式)。为了让外部网络访问容器内的服务,我们需要将容器的端口映射到宿主机的端口。
|
||||
|
||||
### 9.6.1 为什么要映射端口
|
||||
### 9.5.1 为什么要映射端口
|
||||
|
||||
容器的网络访问规则如下:
|
||||
|
||||
@@ -21,7 +21,7 @@ flowchart TD
|
||||
|
||||
---
|
||||
|
||||
### 9.6.2 端口映射方式
|
||||
### 9.5.2 端口映射方式
|
||||
|
||||
Docker 提供了多种方式来指定端口映射。
|
||||
|
||||
@@ -66,7 +66,7 @@ abc123456 0.0.0.0:49153->80/tcp
|
||||
|
||||
---
|
||||
|
||||
### 9.6.3 查看端口映射
|
||||
### 9.5.3 查看端口映射
|
||||
|
||||
可以使用以下命令查看容器的端口映射:
|
||||
|
||||
@@ -92,7 +92,7 @@ abc123456 nginx 0.0.0.0:8080->80/tcp web
|
||||
|
||||
---
|
||||
|
||||
### 9.6.4 最佳实践与安全
|
||||
### 9.5.4 最佳实践与安全
|
||||
|
||||
在配置端口映射时,需要注意以下安全事项:
|
||||
|
||||
@@ -127,7 +127,7 @@ $ docker run -d -p 53:53/udp dns-server
|
||||
|
||||
---
|
||||
|
||||
### 9.6.5 实现原理
|
||||
### 9.5.5 实现原理
|
||||
|
||||
Docker 使用 `docker-proxy` 进程 (用户态) 或 `iptables` DNAT 规则 (内核态) 来实现端口转发。
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Docker 网络提供了天然的隔离能力,不同网络之间的容器默认无法通信。这是 Docker 网络安全的重要基础。
|
||||
|
||||
### 9.7.1 网络隔离原理
|
||||
### 9.6.1 网络隔离原理
|
||||
|
||||
不同网络之间默认隔离,容器只能与同一网络中的容器直接通信:
|
||||
|
||||
@@ -26,7 +26,7 @@ $ docker exec web ping db
|
||||
ping: db: Name or service not known
|
||||
```
|
||||
|
||||
### 9.7.2 安全优势
|
||||
### 9.6.2 安全优势
|
||||
|
||||
这种隔离机制带来以下安全优势:
|
||||
|
||||
@@ -37,7 +37,7 @@ ping: db: Name or service not known
|
||||
| **多租户** | 不同租户的容器在不同网络中完全隔离 |
|
||||
| **最小权限** | 容器只能访问必要的网络资源 |
|
||||
|
||||
### 9.7.3 跨网络通信
|
||||
### 9.6.3 跨网络通信
|
||||
|
||||
如果确实需要某个容器跨网络通信,可以将其同时连接到多个网络:
|
||||
|
||||
@@ -52,7 +52,7 @@ $ docker network connect backend api
|
||||
|
||||
这种方式让你可以精确控制哪些容器可以跨网络通信,遵循最小权限原则。
|
||||
|
||||
### 9.7.4 典型网络架构
|
||||
### 9.6.4 典型网络架构
|
||||
|
||||
一个典型的多层应用网络架构如下:
|
||||
|
||||
|
||||
709
09_network/9.7_advanced_networking.md
Normal file
709
09_network/9.7_advanced_networking.md
Normal file
@@ -0,0 +1,709 @@
|
||||
## 9.7 容器网络高级特性
|
||||
|
||||
深入探讨容器网络的核心机制、Overlay 网络、CNI 插件生态、容器 DNS 解析、网络策略等高级特性,为生产级别的网络架构打下坚实基础。
|
||||
|
||||
### 9.7.1 Overlay 网络原理与配置
|
||||
|
||||
Overlay 网络在现有网络基础上建立虚拟网络,允许容器跨宿主机通信。它是 Kubernetes 和 Swarm 模式的基础。
|
||||
|
||||
#### Overlay 网络工作原理
|
||||
|
||||
Overlay 网络通过隧道封装技术(通常是 VXLAN)将容器网络流量封装在宿主机物理网络的 UDP 数据包中传输。
|
||||
|
||||
```
|
||||
容器 A (192.168.0.2)
|
||||
↓
|
||||
veth 对
|
||||
↓
|
||||
br-net (网桥)
|
||||
↓
|
||||
Docker 引擎 (VXLAN 封装)
|
||||
↓
|
||||
物理网络 (172.16.0.0/24)
|
||||
↓
|
||||
Docker 引擎 (VXLAN 解封装)
|
||||
↓
|
||||
br-net (网桥)
|
||||
↓
|
||||
veth 对
|
||||
↓
|
||||
容器 B (192.168.0.3,不同宿主机)
|
||||
```
|
||||
|
||||
#### 创建和使用 Overlay 网络
|
||||
|
||||
**Docker Swarm 模式下的 Overlay 网络:**
|
||||
|
||||
```bash
|
||||
# 初始化 Swarm(创建集群)
|
||||
docker swarm init
|
||||
|
||||
# 创建 overlay 网络
|
||||
docker network create --driver overlay \
|
||||
--subnet 192.168.0.0/24 \
|
||||
--opt com.docker.network.driver.mtu=1450 \
|
||||
my-overlay-net
|
||||
|
||||
# 验证网络创建
|
||||
docker network ls
|
||||
docker network inspect my-overlay-net
|
||||
|
||||
# 在 Swarm 服务中使用 overlay 网络
|
||||
docker service create --name web \
|
||||
--network my-overlay-net \
|
||||
--replicas 3 \
|
||||
nginx:latest
|
||||
|
||||
# 验证服务跨节点通信
|
||||
docker service ps web
|
||||
```
|
||||
|
||||
**单机 Overlay 网络模拟(Linux 容器):**
|
||||
|
||||
```bash
|
||||
# 创建自定义 overlay 网络
|
||||
docker network create --driver overlay custom-overlay
|
||||
|
||||
# 创建两个容器
|
||||
docker run -d --name container1 --network custom-overlay nginx:latest
|
||||
docker run -d --name container2 --network custom-overlay nginx:latest
|
||||
|
||||
# 测试跨容器通信
|
||||
docker exec container1 ping container2
|
||||
docker exec container1 curl http://container2
|
||||
|
||||
# 检查网络配置
|
||||
docker network inspect custom-overlay
|
||||
```
|
||||
|
||||
#### Overlay 网络性能优化
|
||||
|
||||
```bash
|
||||
# 调整 MTU(Maximum Transmission Unit)避免分片
|
||||
# VXLAN 开销 50 字节,物理 MTU 1500,建议设置为 1450
|
||||
docker network create --driver overlay \
|
||||
--opt com.docker.network.driver.mtu=1450 \
|
||||
optimized-overlay
|
||||
|
||||
# 启用 IP 地址管理(IPAM)自定义
|
||||
docker network create --driver overlay \
|
||||
--subnet 10.0.9.0/24 \
|
||||
--aux-address "my-router=10.0.9.2" \
|
||||
my-custom-overlay
|
||||
|
||||
# 在 Compose 中使用 overlay 网络
|
||||
version: '3.9'
|
||||
services:
|
||||
web:
|
||||
image: nginx
|
||||
networks:
|
||||
- backend
|
||||
|
||||
db:
|
||||
image: postgres
|
||||
networks:
|
||||
- backend
|
||||
|
||||
networks:
|
||||
backend:
|
||||
driver: overlay
|
||||
driver_opts:
|
||||
com.docker.network.driver.mtu: 1450
|
||||
```
|
||||
|
||||
### 9.7.2 CNI 插件生态概览
|
||||
|
||||
容器网络接口(CNI)是容器编排平台(尤其是 Kubernetes)的标准化网络接口。不同的 CNI 插件提供不同的网络能力。
|
||||
|
||||
#### 主流 CNI 插件对比
|
||||
|
||||
**Calico - 基于 BGP 的网络**
|
||||
|
||||
Calico 使用 BGP 协议进行路由,支持网络策略和 eBPF 加速。
|
||||
|
||||
```yaml
|
||||
# Kubernetes 中安装 Calico
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: calico-config
|
||||
namespace: kube-system
|
||||
data:
|
||||
cni_network_config: |
|
||||
{
|
||||
"name": "k8s-pod-network",
|
||||
"cniVersion": "0.4.0",
|
||||
"plugins": [
|
||||
{
|
||||
"type": "calico",
|
||||
"datastore_type": "kubernetes",
|
||||
"mtu": 1450,
|
||||
"ipam": {
|
||||
"type": "calico-ipam"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "portmap",
|
||||
"snat": true,
|
||||
"capabilities": {"portMappings": true}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Flannel - 简单可靠的 Overlay**
|
||||
|
||||
Flannel 提供简单的 overlay 网络实现,适合小到中等规模的集群。
|
||||
|
||||
```bash
|
||||
# 安装 Flannel
|
||||
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
|
||||
|
||||
# 配置 Flannel 后端(VXLAN、UDP、AWS VPC 等)
|
||||
cat <<EOF | kubectl apply -f -
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: kube-flannel-cfg
|
||||
namespace: kube-flannel
|
||||
data:
|
||||
cni-conf.json: |
|
||||
{
|
||||
"name": "cbr0",
|
||||
"cniVersion": "0.3.1",
|
||||
"plugins": [
|
||||
{
|
||||
"type": "flannel",
|
||||
"delegate": {
|
||||
"hairpinMode": true,
|
||||
"isDefaultGateway": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "portmap",
|
||||
"capabilities": {
|
||||
"portMappings": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
net-conf.json: |
|
||||
{
|
||||
"Network": "10.244.0.0/16",
|
||||
"Backend": {
|
||||
"Type": "vxlan"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
**Cilium - eBPF 驱动的先进网络**
|
||||
|
||||
Cilium 使用 eBPF 在内核级别实现网络策略和可观测性,性能优异。
|
||||
|
||||
```bash
|
||||
# 安装 Cilium
|
||||
helm repo add cilium https://helm.cilium.io
|
||||
helm install cilium cilium/cilium \
|
||||
--namespace kube-system \
|
||||
--set image.tag=v1.14.0 \
|
||||
--set operator.replicas=1
|
||||
|
||||
# 启用 Hubble(可观测性)
|
||||
helm upgrade cilium cilium/cilium \
|
||||
--namespace kube-system \
|
||||
--reuse-values \
|
||||
--set hubble.enabled=true \
|
||||
--set hubble.ui.enabled=true
|
||||
```
|
||||
|
||||
**Weave - 跨主机网络通信**
|
||||
|
||||
Weave 提供简单的跨主机通信,支持加密和多播。
|
||||
|
||||
```bash
|
||||
# Docker 中使用 Weave 网络
|
||||
docker run -d --name weave \
|
||||
--net=host \
|
||||
--cap-add=NET_ADMIN \
|
||||
--cap-add=SYS_PTRACE \
|
||||
ghcr.io/weaveworks/weave:latest
|
||||
|
||||
# 连接到 Weave 网络
|
||||
docker run -d --network weave --name web nginx:latest
|
||||
```
|
||||
|
||||
**CNI 插件对比表:**
|
||||
|
||||
| 特性 | Calico | Flannel | Cilium | Weave |
|
||||
|------|--------|---------|--------|-------|
|
||||
| 路由方式 | BGP | VXLAN/UDP | eBPF | VxLAN |
|
||||
| 网络策略 | ✓ | ✗ | ✓ (L3-L7) | ✗ |
|
||||
| 性能 | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
|
||||
| 可观测性 | 中 | 低 | ⭐⭐⭐⭐⭐ | 中 |
|
||||
| 学习曲线 | 中 | 低 | 高 | 低 |
|
||||
| 生产就绪 | ✓ | ✓ | ✓ | ✓ |
|
||||
|
||||
### 9.7.3 容器 DNS 解析机制
|
||||
|
||||
Docker 内置 DNS 服务器,但 DNS 解析涉及多个层面的配置。
|
||||
|
||||
#### DNS 解析流程
|
||||
|
||||
```
|
||||
容器应用 (dig www.example.com)
|
||||
↓
|
||||
容器内 /etc/resolv.conf (127.0.0.11:53)
|
||||
↓
|
||||
Docker 内嵌 DNS 服务器 (127.0.0.11)
|
||||
↓
|
||||
用户自定义 DNS 或宿主机 /etc/resolv.conf
|
||||
↓
|
||||
外部 DNS 服务器 (8.8.8.8 等)
|
||||
↓
|
||||
DNS 响应 → 容器缓存 → 应用
|
||||
```
|
||||
|
||||
#### 配置容器 DNS
|
||||
|
||||
**在运行时指定 DNS:**
|
||||
|
||||
```bash
|
||||
# 单个容器
|
||||
docker run -d \
|
||||
--dns 8.8.8.8 \
|
||||
--dns 1.1.1.1 \
|
||||
--dns-search example.com \
|
||||
nginx:latest
|
||||
|
||||
# DNS 选项
|
||||
docker run -d \
|
||||
--dns-option ndots:2 \
|
||||
--dns-option timeout:1 \
|
||||
--dns-option attempts:3 \
|
||||
nginx:latest
|
||||
|
||||
# 查看容器 DNS 配置
|
||||
docker exec <container_id> cat /etc/resolv.conf
|
||||
```
|
||||
|
||||
**Docker Compose DNS 配置:**
|
||||
|
||||
```yaml
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx
|
||||
dns:
|
||||
- 8.8.8.8
|
||||
- 1.1.1.1
|
||||
dns_search:
|
||||
- example.com
|
||||
- local
|
||||
|
||||
db:
|
||||
image: postgres
|
||||
networks:
|
||||
- backend
|
||||
hostname: postgres-db
|
||||
|
||||
networks:
|
||||
backend:
|
||||
driver: bridge
|
||||
|
||||
# 容器内 /etc/resolv.conf 将被自动配置
|
||||
# search example.com local
|
||||
# nameserver 8.8.8.8
|
||||
# nameserver 1.1.1.1
|
||||
```
|
||||
|
||||
**Docker 守护进程级别配置:**
|
||||
|
||||
```json
|
||||
{
|
||||
"dns": ["8.8.8.8", "1.1.1.1"],
|
||||
"dns-search": ["example.com"],
|
||||
"insecure-registries": [],
|
||||
"registry-mirrors": ["https://mirror.example.com"]
|
||||
}
|
||||
```
|
||||
|
||||
#### 自定义服务发现(Service Discovery)
|
||||
|
||||
**使用 Docker 内建 DNS 的服务发现:**
|
||||
|
||||
```bash
|
||||
# 创建自定义网络
|
||||
docker network create mynet
|
||||
|
||||
# 运行服务
|
||||
docker run -d --name web --network mynet nginx:latest
|
||||
docker run -d --name db --network mynet postgres:latest
|
||||
|
||||
# 在其他容器中通过服务名访问
|
||||
docker run -it --network mynet busybox sh
|
||||
# ping web # 自动解析到 web 容器 IP
|
||||
# ping db # 自动解析到 db 容器 IP
|
||||
```
|
||||
|
||||
**Compose 服务名自动发现:**
|
||||
|
||||
```yaml
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
frontend:
|
||||
image: nginx
|
||||
depends_on:
|
||||
- backend
|
||||
environment:
|
||||
BACKEND_URL: http://backend:8080
|
||||
|
||||
backend:
|
||||
image: myapp
|
||||
depends_on:
|
||||
- database
|
||||
|
||||
database:
|
||||
image: postgres
|
||||
environment:
|
||||
POSTGRES_DB: mydb
|
||||
|
||||
# frontend 容器可以直接访问 http://backend:8080
|
||||
# backend 容器可以直接访问 postgres://database:5432
|
||||
```
|
||||
|
||||
#### DNS 性能优化
|
||||
|
||||
```bash
|
||||
# 检查 DNS 延迟
|
||||
time docker exec <container> nslookup www.example.com
|
||||
|
||||
# 优化 DNS 解析
|
||||
docker run -d \
|
||||
--dns 127.0.0.1 \ # 使用本地缓存 DNS (Dnsmasq)
|
||||
nginx:latest
|
||||
|
||||
# 在 Kubernetes 中优化
|
||||
kubectl patch deployment -n kube-system coredns --patch '{
|
||||
"spec": {
|
||||
"template": {
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "coredns",
|
||||
"resources": {
|
||||
"limits": {
|
||||
"memory": "512Mi",
|
||||
"cpu": "500m"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
### 9.7.4 网络策略(NetworkPolicy)实践
|
||||
|
||||
网络策略定义了容器间的流量控制规则,是微服务架构中的安全基础。
|
||||
|
||||
#### 基本网络策略
|
||||
|
||||
**默认拒绝所有入站流量的策略:**
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: default-deny-ingress
|
||||
namespace: default
|
||||
spec:
|
||||
podSelector: {}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
# 不指定 ingress 规则,表示拒绝所有入站流量
|
||||
```
|
||||
|
||||
**允许特定来源的入站流量:**
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-from-frontend
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
tier: backend
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
tier: frontend
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 8080
|
||||
```
|
||||
|
||||
**允许出站流量到数据库:**
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-backend-to-db
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
tier: backend
|
||||
policyTypes:
|
||||
- Egress
|
||||
egress:
|
||||
# 允许到数据库的流量
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
tier: database
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 5432
|
||||
# 允许 DNS 查询
|
||||
- to:
|
||||
- namespaceSelector: {}
|
||||
ports:
|
||||
- protocol: UDP
|
||||
port: 53
|
||||
# 允许到外部 API 的流量
|
||||
- to:
|
||||
- ipBlock:
|
||||
cidr: 0.0.0.0/0
|
||||
except:
|
||||
- 169.254.169.254/32 # 阻止元数据服务
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 443
|
||||
```
|
||||
|
||||
#### 微服务网络策略示例
|
||||
|
||||
```yaml
|
||||
---
|
||||
# 拒绝所有默认
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: default-deny-all
|
||||
spec:
|
||||
podSelector: {}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
|
||||
---
|
||||
# Frontend 容器策略
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-frontend
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app: frontend
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
ingress:
|
||||
# 允许来自 Ingress Controller 的流量
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
name: ingress-nginx
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app: ingress-controller
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 3000
|
||||
egress:
|
||||
# 允许到 API 的流量
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app: api
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 8080
|
||||
# 允许 DNS
|
||||
- to:
|
||||
- namespaceSelector: {}
|
||||
podSelector:
|
||||
matchLabels:
|
||||
k8s-app: kube-dns
|
||||
ports:
|
||||
- protocol: UDP
|
||||
port: 53
|
||||
|
||||
---
|
||||
# API 容器策略
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-api
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app: api
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
ingress:
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app: frontend
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 8080
|
||||
egress:
|
||||
# 允许到数据库的流量
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app: postgres
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 5432
|
||||
# 允许 DNS
|
||||
- to:
|
||||
- namespaceSelector: {}
|
||||
podSelector:
|
||||
matchLabels:
|
||||
k8s-app: kube-dns
|
||||
ports:
|
||||
- protocol: UDP
|
||||
port: 53
|
||||
|
||||
---
|
||||
# 数据库容器策略
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-postgres
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app: postgres
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app: api
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 5432
|
||||
```
|
||||
|
||||
#### 使用 Calico/Cilium 的高级网络策略
|
||||
|
||||
**L7 应用层策略(仅 Cilium 支持):**
|
||||
|
||||
```yaml
|
||||
apiVersion: "cilium.io/v2"
|
||||
kind: CiliumNetworkPolicy
|
||||
metadata:
|
||||
name: "api-gateway-policy"
|
||||
spec:
|
||||
description: "L7 policy for API gateway"
|
||||
endpointSelector:
|
||||
matchLabels:
|
||||
app: api
|
||||
ingress:
|
||||
- fromEndpoints:
|
||||
- matchLabels:
|
||||
app: frontend
|
||||
toPorts:
|
||||
- ports:
|
||||
- port: "8080"
|
||||
protocol: TCP
|
||||
rules:
|
||||
http:
|
||||
# 允许 GET /api/users
|
||||
- method: "GET"
|
||||
path: "/api/users/.*"
|
||||
# 允许 POST /api/users 仅从管理员来源
|
||||
- method: "POST"
|
||||
path: "/api/users"
|
||||
sourceIPs:
|
||||
- "10.0.0.0/8"
|
||||
```
|
||||
|
||||
### 9.7.5 跨主机容器通信方案对比
|
||||
|
||||
#### 方案对比表
|
||||
|
||||
| 方案 | 隔离性 | 性能 | 复杂度 | 适用场景 |
|
||||
|------|--------|------|--------|---------|
|
||||
| 主机网络 | ✗ | ⭐⭐⭐⭐⭐ | 低 | 高性能,单主机 |
|
||||
| Bridge + Host Port | 中 | ⭐⭐⭐⭐ | 低 | 小规模集群 |
|
||||
| Overlay (VXLAN) | ✓ | ⭐⭐⭐ | 中 | 跨域通信 |
|
||||
| BGP (Calico) | ✓ | ⭐⭐⭐⭐ | 中 | 大规模集群 |
|
||||
| eBPF (Cilium) | ✓ | ⭐⭐⭐⭐⭐ | 高 | 高性能大集群 |
|
||||
|
||||
#### 选择建议
|
||||
|
||||
```bash
|
||||
# 1. 开发环境:使用 Bridge 网络
|
||||
docker network create my-app
|
||||
docker-compose up # 默认使用 bridge
|
||||
|
||||
# 2. 小规模生产(< 50 节点):使用 Flannel
|
||||
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
|
||||
|
||||
# 3. 中等规模(50-500 节点):使用 Calico
|
||||
kubeadm init --pod-network-cidr=192.168.0.0/16
|
||||
kubectl apply -f https://docs.projectcalico.org/v3.24/manifests/tigera-operator.yaml
|
||||
|
||||
# 4. 大规模(> 500 节点)或需要 L7 策略:使用 Cilium
|
||||
helm install cilium cilium/cilium --namespace kube-system
|
||||
|
||||
# 5. 需要多云/跨域:使用 Weave
|
||||
```
|
||||
|
||||
### 9.7.6 网络故障排查
|
||||
|
||||
**常见网络问题诊断:**
|
||||
|
||||
```bash
|
||||
# 1. 容器无法访问外部网络
|
||||
docker exec <container> ping 8.8.8.8
|
||||
docker exec <container> cat /etc/resolv.conf
|
||||
docker logs <container> | grep -i network
|
||||
|
||||
# 2. 容器间无法通信
|
||||
docker network inspect <network>
|
||||
docker exec <container1> ping <container2>
|
||||
|
||||
# 3. 端口映射失效
|
||||
docker port <container>
|
||||
netstat -tlnp | grep <port>
|
||||
|
||||
# 4. DNS 解析失败
|
||||
docker exec <container> nslookup example.com
|
||||
docker exec <container> cat /etc/hosts
|
||||
|
||||
# 5. 网络延迟
|
||||
docker run --rm --network host iperf3:latest -c <target>
|
||||
docker exec <container> mtr -r example.com
|
||||
|
||||
# 使用 tcpdump 抓包分析
|
||||
docker run --rm --cap-add NET_ADMIN --network host \
|
||||
corfr/tcpdump -i eth0 -n "port 80"
|
||||
```
|
||||
@@ -34,8 +34,9 @@ graph TD
|
||||
## 本章内容
|
||||
|
||||
* [配置 DNS](9.1_dns.md)
|
||||
* [外部访问容器](9.5_port_mapping.md)
|
||||
* [网络类型](9.2_network_types.md)
|
||||
* [自定义网络](9.3_custom_network.md)
|
||||
* [容器互联](9.4_container_linking.md)
|
||||
* [外部访问容器](9.5_port_mapping.md)
|
||||
* [网络隔离](9.6_network_isolation.md)
|
||||
* [高级网络配置](9.7_advanced_networking.md)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
| **网络隔离** | 不同网络默认隔离,增强安全性 |
|
||||
| **--link** | 已废弃,使用自定义网络替代 |
|
||||
|
||||
### 9.8.1 延伸阅读
|
||||
### 延伸阅读
|
||||
|
||||
- [配置 DNS](9.1_dns.md):自定义 DNS 设置
|
||||
- [网络类型](9.2_network_types.md):Bridge、Host、None 等网络模式
|
||||
@@ -22,3 +22,6 @@
|
||||
- [网络隔离](9.6_network_isolation.md):网络安全与隔离策略
|
||||
- [EXPOSE 指令](../07_dockerfile/7.9_expose.md):在 Dockerfile 中声明端口
|
||||
- [Compose 网络](../11_compose/11.5_compose_file.md):Compose 中的网络配置
|
||||
---
|
||||
|
||||
> 📝 **发现错误或有改进建议?** 欢迎提交 [Issue](https://github.com/yeasy/docker_practice/issues) 或 [PR](https://github.com/yeasy/docker_practice/pulls)。
|
||||
|
||||
@@ -38,6 +38,15 @@ $ docker buildx build --sbom=true -t myimage .
|
||||
|
||||
该命令会在构建结果中包含 SPDX 或 CycloneDX 格式的 SBOM 数据。
|
||||
|
||||
> **⚠️ 注意与失败模式**:
|
||||
> 要使 SBOM (或其它 attestation 元数据) 成功附着并可见,对底层的存储格式有前置要求:默认的 classic image store 不支持 manifest list/index 这种存放 attestation 的结构。
|
||||
>
|
||||
> 如果只简单运行上述命令,你可能会面临 **“命令成功执行,但本地镜像中看不到 SBOM”** 的体会落差。
|
||||
>
|
||||
> **正确的解决路径有两条**:
|
||||
> 1. 在 Docker 守护进程中启用 `containerd image store` 特性(现代 Docker Desktop 默认推荐)。
|
||||
> 2. 或者使用 `docker-container` driver 的构建器,并直接 **加上 `--push` 参数** 将产物推送到远端支持 OCI 的镜像仓库,仓库会正确保存这些元数据。
|
||||
|
||||
### 10.2.2 官方文档
|
||||
|
||||
* https://docs.docker.com/engine/reference/commandline/buildx/
|
||||
|
||||
@@ -11,3 +11,6 @@ Docker Buildx 是一个 docker CLI 插件,其扩展了 docker 命令,支持
|
||||
* [使用 BuildKit 构建镜像](10.1_buildkit.md)
|
||||
* [使用 Buildx 构建镜像](10.2_buildx.md)
|
||||
* [构建多种系统架构支持的 Docker 镜像](10.3_multi-arch-images.md)
|
||||
|
||||
> **供应链安全与存储后端前瞻**:现代软件供应链中,镜像来源证明(Provenance,在 BuildKit 中默认以 `mode=min` 添加)和软件物料清单(SBOM,可通过 `--sbom=true` 显式开启)已经成为极其重要的构建产出。这些 Attestations 数据会作为 manifest 附着在 **镜像索引 (Image Index)** 上。
|
||||
> 正是基于此诉求,自 Docker Engine v29 开始默认启用的 `containerd image store` 提供对 Image Index 的完美本地支持能力,解决了传统经典存储后端(Classic Store)无法有效处理带 Attestations 镜像索引的瓶颈。这使得你可以利用 `docker buildx imagetools inspect` 等手段,甚至做到无需拉取完整镜像内容即可在 Registry 或本地高效校验镜像的安全元数据。
|
||||
|
||||
@@ -17,3 +17,6 @@ Docker Buildx 是 Docker 构建系统的重要进化,提供了高效、安全
|
||||
- [Dockerfile 指令详解](../07_dockerfile/README.md):Dockerfile 编写基础
|
||||
- [多阶段构建](../07_dockerfile/7.17_multistage_builds.md):优化镜像体积
|
||||
- [Dockerfile 最佳实践](../appendix/best_practices.md):编写高效 Dockerfile
|
||||
---
|
||||
|
||||
> 📝 **发现错误或有改进建议?** 欢迎提交 [Issue](https://github.com/yeasy/docker_practice/issues) 或 [PR](https://github.com/yeasy/docker_practice/pulls)。
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
|
||||
### 11.1.1 概述
|
||||
|
||||
Docker Compose 让用户能够以声明式方式定义和管理多容器应用。它的核心价值在于:用一个 YAML 文件取代一连串手动的 `docker run` 命令,使得复杂应用的启动、停止和重建变得一键可达。
|
||||
|
||||
对于开发团队而言,Compose 解决了三个关键问题:环境一致性("在我机器上能跑"的问题)、服务依赖管理(确保数据库在应用之前启动)、以及开发-测试-生产的配置差异管理(通过 `compose.override.yaml` 实现多环境适配)。
|
||||
|
||||
### 11.1.2 模板文件规范
|
||||
|
||||
Compose 模板文件采用 YAML 格式,扩展名为 `.yml` 或 `.yaml`。
|
||||
|
||||
@@ -18,12 +18,12 @@ Linux 系统请使用以下介绍的方法安装。
|
||||
|
||||
> **提示**:版本更新较快,请访问上述链接获取最新版本号,替换下方命令中的版本号。
|
||||
|
||||
例如,在 Linux 64 位系统上直接下载对应的二进制包 (以 v5.0.2 为例)。
|
||||
例如,在 Linux 64 位系统上直接下载对应的二进制包 (以 v5.1.0 为例)。
|
||||
|
||||
```bash
|
||||
$ DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
|
||||
$ mkdir -p $DOCKER_CONFIG/cli-plugins
|
||||
$ curl -SL https://github.com/docker/compose/releases/download/v5.0.2/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose
|
||||
$ curl -SL https://github.com/docker/compose/releases/download/v5.1.0/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose
|
||||
```
|
||||
|
||||
之后,执行
|
||||
@@ -36,13 +36,13 @@ $ chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
|
||||
|
||||
```bash
|
||||
$ docker compose version
|
||||
Docker Compose version v5.0.2
|
||||
Docker Compose version v5.1.0
|
||||
```
|
||||
|
||||
### 11.2.3 bash 补全命令
|
||||
|
||||
```bash
|
||||
$ curl -L https://raw.githubusercontent.com/docker/compose/v5.0.2/contrib/completion/bash/docker-compose | sudo tee /etc/bash_completion.d/docker-compose > /dev/null
|
||||
$ 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 卸载
|
||||
|
||||
@@ -399,8 +399,8 @@ mysql:
|
||||
- my_other_secret
|
||||
|
||||
secrets:
|
||||
my_secret:
|
||||
file: ./my_secret.txt
|
||||
db_root_password:
|
||||
file: ./db_root_password.txt
|
||||
my_other_secret:
|
||||
external: true
|
||||
```
|
||||
|
||||
@@ -1,3 +1,38 @@
|
||||
## 11.9 实战 LNMP
|
||||
|
||||
本项目的维护者 [khs1994](https://github.com/khs1994) 的开源项目 [khs1994-docker/lnmp](https://github.com/khs1994-docker/lnmp) 使用 Docker Compose 搭建了一套 LNMP 环境,各位开发者可以参考该项目在 Docker 或 Kubernetes 中运行 LNMP。
|
||||
### 什么是 LNMP
|
||||
|
||||
LNMP 是一个经典的 Web 应用栈,由以下四个开源软件组合而成:
|
||||
|
||||
- **L**:Linux(操作系统)
|
||||
- **N**:Nginx(Web 服务器)
|
||||
- **M**:MySQL(数据库服务器)
|
||||
- **P**:PHP(脚本语言)
|
||||
|
||||
这个组合被广泛用于构建高性能的 Web 应用。
|
||||
|
||||
### 使用 Docker Compose 部署 LNMP
|
||||
|
||||
本项目的维护者 [khs1994](https://github.com/khs1994) 的开源项目 [khs1994-docker/lnmp](https://github.com/khs1994-docker/lnmp) 使用 Docker Compose 搭建了一套完整的 LNMP 环境。
|
||||
|
||||
### 参考项目
|
||||
|
||||
该项目中包含的服务:
|
||||
|
||||
- **Nginx**:Web 服务器,用于处理 HTTP 请求
|
||||
- **MySQL/MariaDB**:关系型数据库服务
|
||||
- **PHP-FPM**:PHP 处理器,与 Nginx 通过 Fast CGI 协议通信
|
||||
- **Redis**:可选的内存缓存服务(用于会话或缓存)
|
||||
|
||||
### 学习资源
|
||||
|
||||
各位开发者可以参考该项目在以下场景中运行 LNMP:
|
||||
|
||||
- Docker 容器化部署
|
||||
- Kubernetes 集群编排
|
||||
- 开发环境快速搭建
|
||||
- 生产环境配置参考
|
||||
|
||||
项目地址:https://github.com/khs1994-docker/lnmp
|
||||
|
||||
通过该项目,你可以学习到如何使用 Docker Compose 定义多个相互关联的服务,以及如何在容器化环境中管理应用的生命周期。
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
`Docker Compose` 是 Docker 官方编排 (Orchestration) 项目之一,负责快速的部署分布式应用。
|
||||
|
||||
> ⚠️ **重要提示:Compose V1 已停止支持**
|
||||
>
|
||||
> 早期基于 Python 编写的 Compose V1(命令为 `docker-compose`)已于 2023 年中正式停止支持。现已全面升级为基于 Go 编写的 Compose V2,作为 Docker CLI 的官方插件提供(命令为 `docker compose`,中间为空格)。本书强烈推荐且后续章节均以 V2 为核心标准进行讲解。
|
||||
|
||||
本章将介绍 `Compose` 项目情况以及安装和使用。
|
||||
|
||||
* [简介](11.1_introduction.md)
|
||||
|
||||
@@ -13,9 +13,12 @@ Docker Compose 是管理多容器应用的利器,通过 YAML 文件声明式
|
||||
| **查看日志** | `docker compose logs` 查看服务日志 |
|
||||
| **模板文件** | 支持 `services`、`networks`、`volumes` 等顶级配置 |
|
||||
|
||||
### 11.10.1 延伸阅读
|
||||
### 延伸阅读
|
||||
|
||||
- [Compose 模板文件](11.5_compose_file.md):详细模板语法参考
|
||||
- [Compose 命令说明](11.4_commands.md):完整命令列表
|
||||
- [网络配置](../09_network/README.md):Docker 网络基础
|
||||
- [数据管理](../08_data/README.md):数据卷管理
|
||||
---
|
||||
|
||||
> 📝 **发现错误或有改进建议?** 欢迎提交 [Issue](https://github.com/yeasy/docker_practice/issues) 或 [PR](https://github.com/yeasy/docker_practice/pulls)。
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
命名空间是 Linux 内核一个强大的特性。每个容器都有自己单独的命名空间,运行在其中的应用都像是在独立的操作系统中运行一样。命名空间保证了容器之间彼此互不影响。
|
||||
|
||||
## 12.2 什么是 Namespace
|
||||
### 12.2.1 什么是 Namespace
|
||||
|
||||
> **Namespace 是 Linux 内核提供的资源隔离机制,它让容器内的进程仿佛运行在独立的操作系统中。** Namespace 是容器技术的核心基础之一。它回答了一个关键问题:**如何让一个进程 “以为” 自己独占整个系统?**
|
||||
> **Namespace 是 Linux 内核提供的资源隔离机制,它让容器内的进程仿佛运行在独立的操作系统中。**Namespace 是容器技术的核心基础之一。它回答了一个关键问题:**如何让一个进程 “以为” 自己独占整个系统?**
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
@@ -26,7 +26,7 @@ flowchart LR
|
||||
H4 -. "(实际是宿主机的 1234)" .- C1
|
||||
```
|
||||
|
||||
### 12.2.1 Namespace 的类型
|
||||
### 12.2.2 Namespace 的类型
|
||||
|
||||
Linux 内核提供了以下几种 Namespace,Docker 容器使用了全部:
|
||||
|
||||
@@ -42,7 +42,7 @@ Linux 内核提供了以下几种 Namespace,Docker 容器使用了全部:
|
||||
|
||||
---
|
||||
|
||||
### 12.2.2 PID Namespace
|
||||
### 12.2.3 PID Namespace
|
||||
|
||||
PID Namespace 负责进程 ID 的隔离,使得容器内的进程彼此不可见。
|
||||
|
||||
@@ -75,7 +75,7 @@ PID USER COMMAND
|
||||
|
||||
---
|
||||
|
||||
### 12.2.3 NET Namespace
|
||||
### 12.2.4 NET Namespace
|
||||
|
||||
NET Namespace 负责网络栈的隔离,包括网卡、路由表和 iptables 规则等。
|
||||
|
||||
@@ -110,7 +110,7 @@ flowchart LR
|
||||
|
||||
---
|
||||
|
||||
### 12.2.4 MNT Namespace
|
||||
### 12.2.5 MNT Namespace
|
||||
|
||||
MNT Namespace 负责文件系统挂载点的隔离,确保容器看到独立的文件系统视图。
|
||||
|
||||
@@ -143,7 +143,7 @@ MNT Namespace 负责文件系统挂载点的隔离,确保容器看到独立的
|
||||
|
||||
---
|
||||
|
||||
### 12.2.5 UTS Namespace
|
||||
### 12.2.6 UTS Namespace
|
||||
|
||||
UTS Namespace 主要用于隔离主机名和域名。
|
||||
|
||||
@@ -169,7 +169,7 @@ UTS = “UNIX Time-sharing System”,是历史遗留的名称。
|
||||
|
||||
---
|
||||
|
||||
### 12.2.6 IPC Namespace
|
||||
### 12.2.7 IPC Namespace
|
||||
|
||||
IPC Namespace 用于隔离进程间通信资源,如 System V IPC 和 POSIX 消息队列。
|
||||
|
||||
@@ -190,7 +190,7 @@ IPC Namespace 用于隔离进程间通信资源,如 System V IPC 和 POSIX 消
|
||||
|
||||
---
|
||||
|
||||
### 12.2.7 USER Namespace
|
||||
### 12.2.8 USER Namespace
|
||||
|
||||
USER Namespace 允许将容器内的用户 ID 映射到宿主机的不同用户 ID。
|
||||
|
||||
@@ -226,7 +226,7 @@ flowchart LR
|
||||
|
||||
---
|
||||
|
||||
### 12.2.8 动手实验:体验 Namespace
|
||||
### 12.2.9 动手实验:体验 Namespace
|
||||
|
||||
使用 `unshare` 命令可以在不使用 Docker 的情况下体验 Namespace:
|
||||
|
||||
@@ -285,7 +285,7 @@ $ ip addr
|
||||
|
||||
---
|
||||
|
||||
### 12.2.9 Namespace 的局限性
|
||||
### 12.2.10 Namespace 的局限性
|
||||
|
||||
Namespace 提供了隔离但不是安全边界:
|
||||
|
||||
|
||||
@@ -35,10 +35,11 @@ flowchart LR
|
||||
|
||||
| 时间 | 事件 |
|
||||
|------|------|
|
||||
| 2006 | Google 工程师提出 cgroups 概念 |
|
||||
| 2008 | Linux 2.6.24 正式支持 cgroups v1 |
|
||||
| 2006 | Google 工程师提出 "process containers" 概念 |
|
||||
| 2007 | 为避免与 Linux 容器概念混淆,更名为 "control groups" (cgroups) |
|
||||
| 2008 | Linux 2.6.24(2008年1月)正式合并 cgroups v1 |
|
||||
| 2016 | Linux 4.5 引入 cgroups v2 |
|
||||
| 现在 | Docker 默认使用 cgroups v2 (如系统支持)|
|
||||
| 现在 | Docker 在宿主机支持 cgroups v2 时会自动使用 v2,否则回退到 v1 |
|
||||
|
||||
---
|
||||
|
||||
@@ -265,7 +266,7 @@ $ docker run -d --name cadvisor \
|
||||
-v /var/run:/var/run:ro \
|
||||
-v /sys:/sys:ro \
|
||||
-v /var/lib/docker:/var/lib/docker:ro \
|
||||
gcr.io/cadvisor/cadvisor
|
||||
ghcr.io/google/cadvisor
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -92,32 +92,33 @@ flowchart LR
|
||||
|
||||
### 12.4.4 Docker 支持的存储驱动
|
||||
|
||||
Docker 可使用多种联合文件系统实现:
|
||||
Docker 的存储驱动经历了从早期各式各样的机制(如 aufs, devicemapper),到被广泛使用的现代经典 graph driver (`overlay2`),再到当下(Engine v29 及以后)**默认启用的 containerd 镜像存储引擎(containerd image store)** 的演进。
|
||||
|
||||
| 存储驱动 | 说明 | 推荐程度 |
|
||||
| 存储后端 / 驱动 | 核心特性说明 | 推荐程度 |
|
||||
|---------|------|---------|
|
||||
| **overlay2**| 现代 Linux 默认驱动,性能优秀 | ✅**推荐** |
|
||||
| **containerd image store**| (v29+ 新一代默认引擎) 基于 containerd 的 snapshotters,原生支持 OCI image index、多架构镜像与 Attestations 构建溯源元数据存储。 | ✅**强烈推荐 (现代默认)** |
|
||||
| **overlay2**| (经典 Graph Driver) 传统架构下的现代 Linux 默认驱动,性能优秀,但在处理复杂溯源元数据(索引)时受限。 | ✅**推荐 (主要后备)** |
|
||||
| **aufs** | 早期默认,兼容性好 | 遗留系统 |
|
||||
| **btrfs** | 使用 Btrfs 子卷 | 特定场景 |
|
||||
| **zfs** | 使用 ZFS 数据集 | 特定场景 |
|
||||
| **devicemapper** | 块设备级存储 | 遗留系统 |
|
||||
| **btrfs**/**zfs** | 使用原生稳定文件系统快照能力 | 特定场景 |
|
||||
| **devicemapper** | 块设备级存储 | 遗留系统 (已被逐步弃用) |
|
||||
| **vfs** | 不使用 CoW,每层完整复制 | 仅测试 |
|
||||
|
||||
#### 各发行版推荐
|
||||
#### Classic Graph Drivers 与 Snapshotters 的核心差异
|
||||
|
||||
| Linux 发行版 | 推荐存储驱动 |
|
||||
|-------------|-------------|
|
||||
| Ubuntu 16.04+ | overlay2 |
|
||||
| Debian Stretch+ | overlay2 |
|
||||
| CentOS 7+ | overlay2 |
|
||||
| RHEL 8+ | overlay2 |
|
||||
| Fedora | overlay2 |
|
||||
传统模型(如 `overlay2`)将镜像拉取解包的过程由 Docker 的 graph drivers 处理。而新的 `containerd image store` 则将这一职责彻底下放给了 `containerd` 自身的 `snapshotters`(底层在 Linux 发行版通常依然利用操作系统的 overlayfs)。这种架构改变带来了:
|
||||
1. 本地免拉取查看多平台镜像 index manifest 与 attestations (SBOM、Provenance)。
|
||||
2. 避免了以前绕过 CRI 获取本地镜像的问题,带来更好的原生 Kubernetes 生态兼容性。
|
||||
|
||||
#### 查看当前存储驱动
|
||||
#### 查看当前存储驱动与后端
|
||||
|
||||
```bash
|
||||
## 查看默认存储驱动 (Storage Driver)
|
||||
$ docker info | grep "Storage Driver"
|
||||
Storage Driver: overlay2
|
||||
|
||||
## 在 Engine v29+ 中,可以通过如下输出验证是否开启了 containerd 镜像后端:
|
||||
$ docker info | grep "containerd image store"
|
||||
containerd image store: true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -1,3 +1,50 @@
|
||||
## 12.5 容器格式
|
||||
|
||||
最初,Docker 采用了 `LXC` 中的容器格式。从 0.7 版本以后开始去除 LXC,转而使用自行开发的 [libcontainer](https://github.com/docker/libcontainer),从 1.11 开始,则进一步演进为使用 [runC](https://github.com/opencontainers/runc) 和 [containerd](https://github.com/containerd/containerd)。
|
||||
### Docker 容器格式的演进
|
||||
|
||||
最初,Docker 采用了 `LXC` 中的容器格式。从 0.7 版本以后开始去除 LXC 的依赖,转而使用自行开发的 [libcontainer](https://github.com/docker/libcontainer)。从 1.11 开始,则进一步演进为使用 [runC](https://github.com/opencontainers/runc) 和 [containerd](https://github.com/containerd/containerd)。
|
||||
|
||||
### 关键组件说明
|
||||
|
||||
#### LXC(Linux 容器)
|
||||
|
||||
Docker 早期版本(0.1-0.7)直接使用 LXC 作为容器运行时,利用 Linux Namespaces 和 Cgroups 实现容器隔离。
|
||||
|
||||
#### libcontainer
|
||||
|
||||
- Docker 自行开发的容器库
|
||||
- 提供了容器的通用接口
|
||||
- 不依赖于特定的 Linux 容器实现
|
||||
- 更灵活和可控
|
||||
|
||||
#### runC
|
||||
|
||||
- OCI(Open Container Initiative)标准实现
|
||||
- 轻量级的容器运行时
|
||||
- 独立的二进制文件,可单独使用
|
||||
- 基于 libcontainer 发展而来
|
||||
|
||||
#### containerd
|
||||
|
||||
- Docker 开源的容器运行时
|
||||
- 提供了容器的完整生命周期管理
|
||||
- 支持 runC 和其他 OCI 兼容的运行时
|
||||
- 在 Kubernetes 等编排系统中广泛使用
|
||||
|
||||
### 容器规范标准
|
||||
|
||||
Docker 积极参与 Open Container Initiative (OCI) 的制定,推动了以下规范的发展:
|
||||
|
||||
- **Image Spec**:容器镜像格式规范
|
||||
- **Runtime Spec**:容器运行时接口规范
|
||||
- **Distribution Spec**:容器镜像分发规范
|
||||
|
||||
### 架构演变的优势
|
||||
|
||||
从 LXC → libcontainer → runC/containerd 的演变提供了以下优势:
|
||||
|
||||
1. 减少外部依赖
|
||||
2. 提高运行效率
|
||||
3. 遵循行业标准(OCI)
|
||||
4. 增强可移植性和互操作性
|
||||
5. 支持多种容器运行时选择
|
||||
|
||||
@@ -12,6 +12,8 @@ Docker 底层的核心技术包括 Linux 上的命名空间 (Namespaces)、控
|
||||
|
||||
随着 Linux 系统对于命名空间功能的完善实现,程序员已经可以实现上面的所有需求,让某些进程在彼此隔离的命名空间中运行。大家虽然都共用一个内核和某些运行时环境 (例如一些系统命令和系统库),但是彼此却看不到,都以为系统中只有自己的存在。这种机制就是容器 (Container),利用命名空间来做权限的隔离控制,利用 cgroups 来做资源分配。
|
||||
|
||||
## 本章内容
|
||||
|
||||
* [基本架构](12.1_arch.md)
|
||||
* [命名空间](12.2_namespace.md)
|
||||
* [控制组](12.3_cgroups.md)
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
## 本章小结
|
||||
|
||||
本章深入介绍了 Docker 的底层实现,包括命名空间、控制组和联合文件系统三大核心技术。
|
||||
|
||||
| 技术 | 作用 | 要点 |
|
||||
|------|------|------|
|
||||
| **Namespace** | 资源隔离 | PID、NET、MNT、UTS、IPC、USER 六种命名空间 |
|
||||
| **Cgroups** | 资源限制 | 限制 CPU、内存、磁盘 I/O、进程数 |
|
||||
| **Union FS** | 分层存储 | overlay2 为推荐驱动,支持 Copy-on-Write |
|
||||
|
||||
| Namespace | 隔离内容 | 一句话说明 |
|
||||
|-----------|---------|-----------|
|
||||
| PID | 进程 ID | 容器有自己的进程树 |
|
||||
@@ -9,13 +17,6 @@
|
||||
| IPC | 进程间通信 | 容器间 IPC 隔离 |
|
||||
| USER | 用户 ID | 容器 root ≠ 宿主机 root |
|
||||
|
||||
### 12.7.1 延伸阅读
|
||||
|
||||
- [控制组 (Cgroups)](12.3_cgroups.md):资源限制机制
|
||||
- [联合文件系统](12.4_ufs.md):分层存储的实现
|
||||
- [安全](../18_security/README.md):容器安全实践
|
||||
- [Linux Namespace 官方文档](https://man7.org/linux/man-pages/man7/namespaces.7.html)
|
||||
|
||||
| 资源 | 限制参数 | 示例 |
|
||||
|------|---------|------|
|
||||
| **内存** | `-m` | `-m 512m` |
|
||||
@@ -24,21 +25,15 @@
|
||||
| **磁盘 I/O** | `--device-write-bps` | `--device-write-bps /dev/sda:10mb` |
|
||||
| **进程数** | `--pids-limit` | `--pids-limit=100` |
|
||||
|
||||
### 12.7.2 延伸阅读
|
||||
|
||||
- [命名空间](12.2_namespace.md):资源隔离
|
||||
- [安全](../18_security/README.md):容器安全概述
|
||||
- [Docker Stats](../05_container/README.md):监控容器资源
|
||||
|
||||
| 概念 | 说明 |
|
||||
|------|------|
|
||||
| **UnionFS** | 将多层目录联合挂载为一个文件系统 |
|
||||
| **Copy-on-Write** | 写时复制,修改时才复制到可写层 |
|
||||
| **overlay2** | Docker 默认推荐的存储驱动 |
|
||||
| **分层好处** | 镜像复用、快速构建、快速启动 |
|
||||
|
||||
### 12.7.3 延伸阅读
|
||||
### 延伸阅读
|
||||
|
||||
- [命名空间](12.2_namespace.md):资源隔离机制详解
|
||||
- [控制组 (Cgroups)](12.3_cgroups.md):资源限制机制
|
||||
- [联合文件系统](12.4_ufs.md):分层存储的实现
|
||||
- [安全](../18_security/README.md):容器安全实践
|
||||
- [镜像](../02_basic_concept/2.1_image.md):理解镜像分层
|
||||
- [容器](../02_basic_concept/2.2_container.md):容器存储层
|
||||
- [构建镜像](../04_image/4.5_build.md):Dockerfile 层的创建
|
||||
---
|
||||
|
||||
> 📝 **发现错误或有改进建议?** 欢迎提交 [Issue](https://github.com/yeasy/docker_practice/issues) 或 [PR](https://github.com/yeasy/docker_practice/pulls)。
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
## 13.2 基本概念
|
||||
|
||||
如图 12-2 所示,Kubernetes 由控制平面与工作节点构成。
|
||||
如图 13-2 所示,Kubernetes 由控制平面与工作节点构成。
|
||||
|
||||

|
||||
|
||||
图 12-2 Kubernetes 基本概念示意图
|
||||
图 13-2 Kubernetes 基本概念示意图
|
||||
|
||||
* 节点 (`Node`):一个节点是一个运行 Kubernetes 中的主机。
|
||||
* 容器组 (`Pod`):一个 Pod 对应于由若干容器组成的一个容器组,同个组内的容器共享一个存储卷 (volume)。
|
||||
@@ -39,41 +39,56 @@
|
||||
|
||||
#### 节点管理
|
||||
|
||||
节点并非 Kubernetes 创建,而是由云平台创建,或者就是物理机器、虚拟机。在 Kubernetes 中,节点仅仅是一条记录,节点创建之后,Kubernetes 会检查其是否可用。在 Kubernetes 中,节点用如下结构保存:
|
||||
节点并非 Kubernetes 创建,而是由云平台创建,或者就是物理机器、虚拟机。在 Kubernetes 中,节点仅仅是一条记录,节点创建之后,Kubernetes 会检查其是否可用。可以通过 `kubectl` 查看节点信息:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "10.1.2.3",
|
||||
"kind": "Minion",
|
||||
"apiVersion": "v1beta1",
|
||||
"resources": {
|
||||
"capacity": {
|
||||
"cpu": 1000,
|
||||
"memory": 1073741824
|
||||
},
|
||||
},
|
||||
"labels": {
|
||||
"name": "my-first-k8s-node",
|
||||
},
|
||||
}
|
||||
```bash
|
||||
$ kubectl get nodes
|
||||
NAME STATUS ROLES AGE VERSION
|
||||
control-plane Ready control-plane 10d v1.30.2
|
||||
worker-1 Ready <none> 10d v1.30.2
|
||||
worker-2 Ready <none> 10d v1.30.2
|
||||
```
|
||||
|
||||
Kubernetes 校验节点可用依赖于 ID。在当前的版本中,有两个接口可以用来管理节点:节点控制和 Kube 管理。
|
||||
每个节点的详细信息以如下结构保存:
|
||||
|
||||
#### 节点控制
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Node
|
||||
metadata:
|
||||
name: worker-1
|
||||
labels:
|
||||
kubernetes.io/os: linux
|
||||
status:
|
||||
capacity:
|
||||
cpu: "4"
|
||||
memory: 8Gi
|
||||
conditions:
|
||||
- type: Ready
|
||||
status: "True"
|
||||
```
|
||||
|
||||
在 Kubernetes 主节点中,节点控制器是用来管理节点的组件。主要包含:
|
||||
#### 节点控制器
|
||||
|
||||
* 集群范围内节点同步
|
||||
在 Kubernetes 控制平面中,节点控制器 (Node Controller) 负责管理节点的生命周期,主要包含:
|
||||
|
||||
* 集群范围内节点状态同步
|
||||
* 单节点生命周期管理
|
||||
|
||||
节点控制有一个同步轮询,主要监听所有云平台的虚拟实例,会根据节点状态创建和删除。可以通过 `--node_sync_period` 标志来控制该轮询。如果一个实例已经创建,节点控制将会为其创建一个结构。同样的,如果一个节点被删除,节点控制也会删除该结构。在 Kubernetes 启动时可用通过 `--machines` 标记来显示指定节点。同样可以使用 `kubectl` 来一条一条的添加节点,两者是相同的。通过设置 `--sync_nodes=false` 标记来禁止集群之间的节点同步,你也可以使用 api/kubectl 命令行来增删节点。
|
||||
节点控制器会持续监控节点的健康状态。当节点变为不可达时,控制器会等待一个超时期限,然后将该节点上的 Pod 标记为失败,并触发重新调度。可以使用 `kubectl` 来管理节点,例如标记节点为不可调度或排空节点上的工作负载:
|
||||
|
||||
```bash
|
||||
## 标记节点为不可调度
|
||||
$ kubectl cordon worker-1
|
||||
|
||||
## 排空节点上的 Pod
|
||||
$ kubectl drain worker-1 --ignore-daemonsets
|
||||
```
|
||||
|
||||
### 13.2.2 容器组
|
||||
|
||||
在 Kubernetes 中,使用的最小单位是容器组,容器组是创建,调度,管理的最小单位。一个容器组使用相同的 Docker 容器并共享卷 (挂载点)。一个容器组是一个特定应用的打包集合,包含一个或多个容器。
|
||||
在 Kubernetes 中,使用的最小调度单位是容器组 (Pod),它是创建、调度、管理的最小单位。一个 Pod 包含一个或多个紧密协作的容器,它们共享网络命名空间和存储卷。
|
||||
|
||||
和运行的容器类似,一个容器组被认为只有很短的运行周期。容器组被调度到一组节点运行,直到容器的生命周期结束或者其被删除。如果节点死掉,运行在其上的容器组将会被删除而不是重新调度。(也许在将来的版本中会添加容器组的移动)。
|
||||
Pod 通常不会被直接创建,而是通过 Deployment 等控制器来管理。当节点发生故障时,控制器会在其他可用节点上重新创建 Pod。
|
||||
|
||||
#### 容器组设计的初衷
|
||||
|
||||
@@ -93,7 +108,7 @@ Kubernetes 校验节点可用依赖于 ID。在当前的版本中,有两个接
|
||||
|
||||
#### 容器组的使用
|
||||
|
||||
容器组可以通过组合来构建复杂的应用,其本来的意义包含:
|
||||
容器组可以通过组合来构建复杂的应用,典型的使用模式包含:
|
||||
|
||||
* 内容管理,文件和数据加载以及本地缓存管理等。
|
||||
* 日志和检查点备份,压缩,快照等。
|
||||
@@ -101,108 +116,154 @@ Kubernetes 校验节点可用依赖于 ID。在当前的版本中,有两个接
|
||||
* 代理,网桥
|
||||
* 控制器,管理,配置以及更新
|
||||
|
||||
#### 替代方案
|
||||
#### 为什么不在一个容器里运行多个程序
|
||||
|
||||
为什么不在一个单一的容器里运行多个程序?
|
||||
|
||||
* 1. 透明化。为了使容器组中的容器保持一致的基础设施和服务,比如进程管理和资源监控。这样设计是为了用户的便利性。
|
||||
* 2. 解耦软件之间的依赖。每个容器都可能重新构建和发布,Kubernetes 必须支持热发布和热更新 (将来)。
|
||||
* 3. 方便使用。用户不必运行独立的程序管理,也不用担心每个应用程序的退出状态。
|
||||
* 4. 高效。考虑到基础设施有更多的职责,容器必须要轻量化。
|
||||
1. **透明化**:为了使容器组中的容器保持一致的基础设施和服务,比如进程管理和资源监控。
|
||||
2. **解耦依赖**:每个容器都可能独立地重新构建和发布。
|
||||
3. **方便使用**:用户不必运行独立的程序管理,也不用担心每个应用程序的退出状态。
|
||||
4. **高效**:考虑到基础设施有更多的职责,容器必须要轻量化。
|
||||
|
||||
#### 容器组的生命状态
|
||||
|
||||
包括若干状态值:`pending`、`running`、`succeeded`、`failed`。
|
||||
包括若干状态值:`Pending`、`Running`、`Succeeded`、`Failed`。
|
||||
|
||||
##### pending
|
||||
| 状态 | 说明 |
|
||||
|------|------|
|
||||
| **Pending** | Pod 已被集群接受,但有一个或多个容器还没有运行起来(可能在拉取镜像)。|
|
||||
| **Running** | Pod 已被调度到节点,并且所有容器都已启动。至少有一个容器处于运行状态。|
|
||||
| **Succeeded** | Pod 中的所有容器都正常退出,且不会被重启。|
|
||||
| **Failed** | Pod 中的所有容器都已终止,且至少有一个容器以失败状态退出。|
|
||||
|
||||
容器组已经被节点接受,但有一个或多个容器还没有运行起来。这将包含某些节点正在下载镜像的时间,这种情形会依赖于网络情况。
|
||||
#### 容器组生命周期与重启策略
|
||||
|
||||
##### running
|
||||
Pod 的重启策略 (`restartPolicy`) 决定了容器退出后的行为:
|
||||
|
||||
容器组已经被调度到节点,并且所有的容器都已经启动。至少有一个容器处于运行状态 (或者处于重启状态)。
|
||||
| 重启策略 | 容器正常退出 | 容器异常退出 |
|
||||
|---------|------------|------------|
|
||||
| **Always** (默认) | 重启容器 | 重启容器 |
|
||||
| **OnFailure** | 不重启 | 重启容器 |
|
||||
| **Never** | 不重启 | 不重启 |
|
||||
|
||||
##### succeeded
|
||||
当节点故障或不可达时,节点控制器会将该节点上所有 Pod 的状态标记为 `Failed`。如果这些 Pod 由 Deployment 等控制器管理,控制器会自动在其他节点上重新创建。
|
||||
|
||||
所有的容器都正常退出。
|
||||
### 13.2.3 Deployment 与 ReplicaSet
|
||||
|
||||
##### failed
|
||||
Deployment 是管理无状态应用的推荐方式,它通过 ReplicaSet 来确保指定数量的 Pod 副本始终在运行。
|
||||
|
||||
容器组中所有容器都意外中断了。
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx-deployment
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.27
|
||||
ports:
|
||||
- containerPort: 80
|
||||
```
|
||||
|
||||
#### 容器组生命周期
|
||||
Deployment 的核心能力包括:
|
||||
|
||||
通常来说,如果容器组被创建了就不会自动销毁,除非被某种行为触发,而触发此种情况可能是人为,或者复制控制器所为。唯一例外的是容器组由 succeeded 状态成功退出,或者在一定时间内重试多次依然失败。
|
||||
* **副本管理**:确保始终有指定数量的 Pod 在运行
|
||||
* **滚动更新**:逐步替换旧版本 Pod,实现零停机部署
|
||||
* **回滚**:如果新版本出现问题,可以快速回滚到之前的版本
|
||||
|
||||
如果某个节点死掉或者不能连接,那么节点控制器将会标记其上的容器组的状态为 `failed`。
|
||||
|
||||
举例如下。
|
||||
|
||||
* 容器组状态 `running`,有 1 容器,容器正常退出
|
||||
* 记录完成事件
|
||||
* 如果重启策略为:
|
||||
* 始终:重启容器,容器组保持 `running`
|
||||
* 失败时:容器组变为 `succeeded`
|
||||
* 从不:容器组变为 `succeeded`
|
||||
* 容器组状态 `running`,有 1 容器,容器异常退出
|
||||
* 记录失败事件
|
||||
* 如果重启策略为:
|
||||
* 始终:重启容器,容器组保持 `running`
|
||||
* 失败时:重启容器,容器组保持 `running`
|
||||
* 从不:容器组变为 `failed`
|
||||
* 容器组状态 `running`,有 2 容器,有 1 容器异常退出
|
||||
* 记录失败事件
|
||||
* 如果重启策略为:
|
||||
* 始终:重启容器,容器组保持 `running`
|
||||
* 失败时:重启容器,容器组保持 `running`
|
||||
* 从不:容器组保持 `running`
|
||||
* 当有 2 容器退出
|
||||
* 记录失败事件
|
||||
* 如果重启策略为:
|
||||
* 始终:重启容器,容器组保持 `running`
|
||||
* 失败时:重启容器,容器组保持 `running`
|
||||
* 从不:容器组变为 `failed`
|
||||
* 容器组状态 `running`,容器内存不足
|
||||
* 标记容器错误中断
|
||||
* 记录内存不足事件
|
||||
* 如果重启策略为:
|
||||
* 始终:重启容器,容器组保持 `running`
|
||||
* 失败时:重启容器,容器组保持 `running`
|
||||
* 从不:记录错误事件,容器组变为 `failed`
|
||||
* 容器组状态 `running`,一块磁盘死掉
|
||||
* 杀死所有容器
|
||||
* 记录事件
|
||||
* 容器组变为 `failed`
|
||||
* 如果容器组运行在一个控制器下,容器组将会在其他地方重新创建
|
||||
* 容器组状态 `running`,对应的节点段溢出
|
||||
* 节点控制器等到超时
|
||||
* 节点控制器标记容器组 `failed`
|
||||
* 如果容器组运行在一个控制器下,容器组将会在其他地方重新创建
|
||||
|
||||
### 13.2.3 Replication Controllers
|
||||
|
||||
> 注:Replication Controller (RC) 是早期的控制器类型,现代 Kubernetes 更推荐使用 ReplicaSet/Deployment。
|
||||
> 早期 Kubernetes 使用 Replication Controller (RC) 来管理副本,现已被 ReplicaSet/Deployment 取代。
|
||||
|
||||
### 13.2.4 服务
|
||||
|
||||
> 注:服务 (Service) 定义一组 Pod 的逻辑集合和访问它们的策略。
|
||||
服务 (Service) 定义了一组 Pod 的逻辑集合和访问策略。由于 Pod 的 IP 地址是动态分配的,Service 提供了一个稳定的访问入口。
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: nginx-service
|
||||
spec:
|
||||
selector:
|
||||
app: nginx
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 80
|
||||
type: ClusterIP
|
||||
```
|
||||
|
||||
常见的 Service 类型:
|
||||
|
||||
| 类型 | 说明 |
|
||||
|------|------|
|
||||
| **ClusterIP** | 默认类型,仅集群内部可访问 |
|
||||
| **NodePort** | 在每个节点上开放固定端口,集群外部可通过 `节点IP:端口` 访问 |
|
||||
| **LoadBalancer** | 通过云平台的负载均衡器暴露服务 |
|
||||
|
||||
### 13.2.5 卷
|
||||
|
||||
> 注:卷 (Volume) 包含可被 Pod 中容器访问的数据的目录。
|
||||
卷 (Volume) 为 Pod 中的容器提供持久化存储。Kubernetes 支持多种卷类型:
|
||||
|
||||
| 卷类型 | 说明 |
|
||||
|-------|------|
|
||||
| **emptyDir** | 临时存储,Pod 删除后数据丢失 |
|
||||
| **hostPath** | 挂载节点上的文件或目录 |
|
||||
| **PersistentVolumeClaim** | 使用持久卷声明,与底层存储解耦 |
|
||||
| **configMap / secret** | 将配置或敏感数据挂载为文件 |
|
||||
|
||||
生产环境中,推荐使用 PersistentVolume (PV) 和 PersistentVolumeClaim (PVC) 来管理存储,实现存储资源与使用者的解耦。
|
||||
|
||||
### 13.2.6 标签
|
||||
|
||||
> 注:标签 (Label) 是附加到对象 (如 Pods) 上的键值对,用于组织和选择对象子集。
|
||||
标签 (Label) 是附加到 Kubernetes 对象上的键值对,用于组织和选择对象子集。标签是 Kubernetes 中实现松耦合的关键机制。
|
||||
|
||||
### 13.2.7 接口权限
|
||||
```bash
|
||||
## 为 Pod 添加标签
|
||||
$ kubectl label pod my-pod env=production
|
||||
|
||||
> 注:接口权限通过认证、授权和准入控制来保护 Kubernetes API 的访问。
|
||||
## 通过标签选择器查询
|
||||
$ kubectl get pods -l env=production
|
||||
```
|
||||
|
||||
### 13.2.8 web 界面
|
||||
Service、Deployment 等资源都通过标签选择器 (`selector`) 来关联目标 Pod。
|
||||
|
||||
> 注:Kubernetes Dashboard 是一个基于 Web 的用户界面,用于管理集群。
|
||||
### 13.2.7 API 访问控制
|
||||
|
||||
### 13.2.9 命令行操作
|
||||
Kubernetes API 的访问通过三个阶段进行控制:
|
||||
|
||||
> 注:kubectl 是 Kubernetes 的命令行工具,用于与集群进行交互。
|
||||
1. **认证 (Authentication)**:验证请求者的身份(如证书、Token、OIDC)
|
||||
2. **授权 (Authorization)**:判断请求者是否有权限执行操作(通常使用 RBAC)
|
||||
3. **准入控制 (Admission Control)**:在请求被持久化之前对其进行校验或修改
|
||||
|
||||
### 13.2.8 Dashboard
|
||||
|
||||
Kubernetes Dashboard 是一个基于 Web 的用户界面,用于部署容器化应用、监控集群资源和排查问题。Dashboard 的部署方法详见[部署 Dashboard](../14_kubernetes_setup/14.7_dashboard.md) 章节。
|
||||
|
||||
### 13.2.9 命令行工具 kubectl
|
||||
|
||||
`kubectl` 是 Kubernetes 的命令行工具,用于与集群进行交互。常用命令如下:
|
||||
|
||||
```bash
|
||||
## 查看集群中的资源
|
||||
$ kubectl get pods,deployments,services,nodes
|
||||
|
||||
## 创建资源
|
||||
$ kubectl apply -f deployment.yaml
|
||||
|
||||
## 查看 Pod 日志
|
||||
$ kubectl logs my-pod
|
||||
|
||||
## 进入 Pod 执行命令
|
||||
$ kubectl exec -it my-pod -- /bin/sh
|
||||
|
||||
## 查看资源详情
|
||||
$ kubectl describe pod my-pod
|
||||
```
|
||||
|
||||
更多 kubectl 操作详见[kubectl 命令行](../14_kubernetes_setup/14.8_kubectl.md)章节。
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
|
||||
### 13.3.2 运行原理
|
||||
|
||||
如图 12-3 所示,该图完整展示了 Kubernetes 的运行原理。
|
||||
如图 13-3 所示,该图完整展示了 Kubernetes 的运行原理。
|
||||
|
||||

|
||||
|
||||
图 12-3 Kubernetes 运行原理图
|
||||
图 13-3 Kubernetes 运行原理图
|
||||
|
||||
可见,Kubernetes 首先是一套分布式系统,由多个节点组成,节点分为两类:一类是属于管理平面的主节点/控制节点 (Master Node);一类是属于运行平面的工作节点 (Worker Node)。
|
||||
|
||||
@@ -52,4 +52,4 @@
|
||||
|
||||

|
||||
|
||||
图 12-4 kube-proxy 请求转发示意图
|
||||
图 13-4 kube-proxy 请求转发示意图
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
|
||||
Kubernetes 的最小调度单位是 `Pod`。一个 `Pod` 由一组紧密协作的容器构成,它们共享网络命名空间、IP 以及部分存储资源,也可以根据需要对 Pod 进行端口映射。
|
||||
|
||||
本章将分为 5 节介绍 `Kubernetes`,包括
|
||||
本章将分为 5 节介绍 `Kubernetes`:
|
||||
|
||||
* 项目简介
|
||||
* 快速入门
|
||||
* 基本概念
|
||||
* 实践例子
|
||||
* 架构分析等高级话题
|
||||
* [简介](13.1_intro.md)
|
||||
* [基本概念](13.2_concepts.md)
|
||||
* [架构设计](13.3_design.md)
|
||||
* [高级特性](13.4_advanced.md)
|
||||
* [实战练习](13.5_practice.md)
|
||||
|
||||
@@ -17,3 +17,6 @@ Kubernetes 是当前最主流的容器编排平台,其声明式管理模型和
|
||||
- [部署 Kubernetes](../14_kubernetes_setup/README.md):搭建 Kubernetes 集群
|
||||
- [Etcd](../15_etcd/README.md):Kubernetes 使用的分布式存储
|
||||
- [底层实现](../12_implementation/README.md):容器技术原理
|
||||
---
|
||||
|
||||
> 📝 **发现错误或有改进建议?** 欢迎提交 [Issue](https://github.com/yeasy/docker_practice/issues) 或 [PR](https://github.com/yeasy/docker_practice/pulls)。
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## 14.1 使用 kubeadm 部署 Kubernetes (CRI 使用 containerd)
|
||||
## 14.1 使用 kubeadm 部署 Kubernetes
|
||||
|
||||
`kubeadm` 提供了 `kubeadm init` 以及 `kubeadm join` 这两个命令,作为快速创建 `Kubernetes` 集群的最佳实践。
|
||||
|
||||
@@ -292,7 +292,6 @@ kubelet 默认要求禁用 swap,否则可能导致初始化失败或节点无
|
||||
$ sudo swapoff -a
|
||||
|
||||
## 如需永久禁用,可在 /etc/fstab 中注释 swap 对应行
|
||||
|
||||
```
|
||||
|
||||
```bash
|
||||
@@ -446,7 +445,7 @@ $ kubectl get node -o yaml | grep CIDR
|
||||
```
|
||||
|
||||
```bash
|
||||
$ kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/v0.26.1/Documentation/kube-flannel.yml
|
||||
$ kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/v0.28.1/Documentation/kube-flannel.yml
|
||||
```
|
||||
|
||||
### 14.1.10 master 节点默认不能运行 pod
|
||||
|
||||
@@ -2,9 +2,13 @@
|
||||
|
||||
`kubeadm` 提供了 `kubeadm init` 以及 `kubeadm join` 这两个命令,作为快速创建 `Kubernetes` 集群的最佳实践。
|
||||
|
||||
> ⚠️ **重要说明**:自 Kubernetes 1.24 起,内置 `dockershim` 已被移除,Kubernetes 默认不再直接使用 Docker Engine 作为容器运行时 (CRI)。因此,**更推荐参考** 同目录下的《[使用 kubeadm 部署 Kubernetes (CRI 使用 containerd)](14.1_kubeadm.md)》。
|
||||
> ⚠️ **强烈提示:Docker 与 Kubernetes 环境的时代分界**
|
||||
>
|
||||
> 本文档主要用于历史环境/学习目的:如果你确实需要在较新版本中继续使用 Docker Engine,通常需要额外部署 `cri-dockerd` 并在 `kubeadm init/join` 中指定 `--cri-socket`。
|
||||
> 自 Kubernetes v1.24 起,内置的 `dockershim` 组件已被正式移除。这意味着 **Kubernetes 不再将 Docker Engine 作为默认内置的容器运行时**。虽然 Docker 仍然是你本地构建、管理镜像的绝佳工具,但它已不再是 kubelet 的默认运行时选项。
|
||||
>
|
||||
> 因此,**强烈推荐** 读者直接参考同目录下的《[使用 kubeadm 部署 Kubernetes (CRI 使用 containerd)](14.1_kubeadm.md)》作为主要的部署路线。
|
||||
>
|
||||
> 本文档保留,主要用于历史环境维护或特殊需求场景:如果你必须在较新的 Kubernetes 集群中继续使用 Docker Engine 作为底层运行时,你必须理解 CRI 层机制,额外部署并配置第三方兼容层 `cri-dockerd`,同时在部署时手动补充 `--cri-socket` 等参数约束。
|
||||
|
||||
### 14.2.1 安装 Docker
|
||||
|
||||
@@ -74,7 +78,6 @@ kubelet 默认要求禁用 swap,否则可能导致初始化失败或节点无
|
||||
$ sudo swapoff -a
|
||||
|
||||
## 如需永久禁用,可在 /etc/fstab 中注释 swap 对应行
|
||||
|
||||
```
|
||||
|
||||
```bash
|
||||
@@ -212,7 +215,7 @@ $ kubectl get node -o yaml | grep CIDR
|
||||
```
|
||||
|
||||
```bash
|
||||
$ kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/v0.26.1/Documentation/kube-flannel.yml
|
||||
$ kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/v0.28.1/Documentation/kube-flannel.yml
|
||||
```
|
||||
|
||||
### 14.2.9 master 节点默认不能运行 pod
|
||||
|
||||
@@ -1,3 +1,67 @@
|
||||
## 14.6 一步步部署 Kubernetes 集群
|
||||
|
||||
可以参考 [opsnull/follow-me-install-kubernetes-cluster](https://github.com/opsnull/follow-me-install-kubernetes-cluster) 项目一步步部署 Kubernetes 集群。
|
||||
### 概述
|
||||
|
||||
部署 Kubernetes 集群涉及多个组件的安装和配置,包括 Master 节点和 Worker 节点。本章介绍如何使用 systemd 管理这些服务的生命周期。
|
||||
|
||||
### Kubernetes 主要组件
|
||||
|
||||
#### Master 节点组件
|
||||
|
||||
- **kube-apiserver**:API 服务器,Kubernetes 集群的中心
|
||||
- **kube-controller-manager**:控制器管理器
|
||||
- **kube-scheduler**:调度器,负责 Pod 调度
|
||||
- **etcd**:分布式键值存储,存储集群数据
|
||||
|
||||
#### Worker 节点组件
|
||||
|
||||
- **kubelet**:节点代理,管理容器生命周期
|
||||
- **kube-proxy**:网络代理,处理服务网络
|
||||
- **Container Runtime**:容器运行时(Docker、containerd 等)
|
||||
|
||||
### 使用 systemd 管理 Kubernetes 服务
|
||||
|
||||
#### 服务单元文件
|
||||
|
||||
为了让 systemd 管理 Kubernetes 服务,需要创建相应的 `.service` 文件,例如:
|
||||
|
||||
```
|
||||
/etc/systemd/system/kubelet.service
|
||||
/etc/systemd/system/kube-proxy.service
|
||||
/etc/systemd/system/kube-apiserver.service
|
||||
```
|
||||
|
||||
#### 常用命令
|
||||
|
||||
```bash
|
||||
# 启动服务
|
||||
sudo systemctl start kubelet
|
||||
|
||||
# 停止服务
|
||||
sudo systemctl stop kubelet
|
||||
|
||||
# 重启服务
|
||||
sudo systemctl restart kubelet
|
||||
|
||||
# 查看服务状态
|
||||
sudo systemctl status kubelet
|
||||
|
||||
# 设置开机自启
|
||||
sudo systemctl enable kubelet
|
||||
```
|
||||
|
||||
### 参考资源
|
||||
|
||||
详细的部署步骤和配置说明,可以参考以下项目:
|
||||
|
||||
- [opsnull/follow-me-install-kubernetes-cluster](https://github.com/opsnull/follow-me-install-kubernetes-cluster):一个完整的 Kubernetes 集群部署指南项目
|
||||
|
||||
该项目提供了详细的步骤说明,涵盖 Master 节点、Worker 节点的安装配置,以及如何使用 systemd 管理这些组件的生命周期。
|
||||
|
||||
### 推荐学习路径
|
||||
|
||||
1. 理解 Kubernetes 架构和各组件的作用
|
||||
2. 准备所需的系统环境(Linux 主机、网络配置等)
|
||||
3. 按步骤安装各个 Kubernetes 组件
|
||||
4. 配置 systemd 服务单元文件
|
||||
5. 验证集群健康状态
|
||||
|
||||
@@ -8,74 +8,74 @@ kubectl [flags]
|
||||
kubectl [command]
|
||||
```
|
||||
|
||||
## 14.8 get
|
||||
### 14.8.1 get
|
||||
|
||||
显示一个或多个资源
|
||||
|
||||
## 14.8 describe
|
||||
### 14.8.2 describe
|
||||
|
||||
显示资源详情
|
||||
|
||||
## 14.8 create
|
||||
### 14.8.3 create
|
||||
|
||||
从文件或标准输入创建资源
|
||||
|
||||
## 14.8 update
|
||||
### 14.8.4 update
|
||||
|
||||
从文件或标准输入更新资源
|
||||
|
||||
## 14.8 delete
|
||||
### 14.8.5 delete
|
||||
|
||||
通过文件名、标准输入、资源名或者 label selector 删除资源
|
||||
|
||||
## 14.8 logs
|
||||
### 14.8.6 logs
|
||||
|
||||
输出 pod 中一个容器的日志
|
||||
|
||||
## 14.8 rollout
|
||||
### 14.8.7 rollout
|
||||
|
||||
对 Deployment 等资源执行滚动更新/回滚
|
||||
|
||||
## 14.8 exec
|
||||
### 14.8.8 exec
|
||||
|
||||
在容器内部执行命令
|
||||
|
||||
## 14.8 port-forward
|
||||
### 14.8.9 port-forward
|
||||
|
||||
将本地端口转发到 Pod
|
||||
|
||||
## 14.8 proxy
|
||||
### 14.8.10 proxy
|
||||
|
||||
为 Kubernetes API server 启动代理服务器
|
||||
|
||||
## 14.8 run
|
||||
### 14.8.11 run
|
||||
|
||||
在集群中使用指定镜像启动容器
|
||||
|
||||
## 14.8 expose
|
||||
### 14.8.12 expose
|
||||
|
||||
将 replication controller service 或 pod 暴露为新的 Kubernetes service
|
||||
|
||||
## 14.8 label
|
||||
### 14.8.13 label
|
||||
|
||||
更新资源的 label
|
||||
|
||||
## 14.8 config
|
||||
### 14.8.14 config
|
||||
|
||||
修改 Kubernetes 配置文件
|
||||
|
||||
## 14.8 cluster-info
|
||||
### 14.8.15 cluster-info
|
||||
|
||||
显示集群信息
|
||||
|
||||
## 14.8 api-versions
|
||||
### 14.8.16 api-versions
|
||||
|
||||
以 “组/版本” 的格式输出服务端支持的 API 版本
|
||||
|
||||
## 14.8 version
|
||||
### 14.8.17 version
|
||||
|
||||
输出服务端和客户端的版本信息
|
||||
|
||||
## 14.8 help
|
||||
### 14.8.18 help
|
||||
|
||||
显示各个命令的帮助信息
|
||||
|
||||
@@ -2,10 +2,13 @@
|
||||
|
||||
目前,Kubernetes 支持在多种环境下使用,包括本地主机 (Ubuntu、Debian、CentOS、Fedora 等)、云服务 ([腾讯云](https://cloud.tencent.com/act/cps/redirect?redirect=10058&cps_key=3a5255852d5db99dcd5da4c72f05df61)、[阿里云](https://www.aliyun.com/product/kubernetes?source=5176.11533457&userCode=8lx5zmtu&type=copy)、[百度云](https://cloud.baidu.com/product/cce.html)等)。
|
||||
|
||||
你可以使用以下几种方式部署 Kubernetes:
|
||||
你可以使用以下几种方式部署 Kubernetes,接下来的小节会对各种方式进行详细介绍。
|
||||
|
||||
* kubeadm
|
||||
* docker-desktop
|
||||
* k3s
|
||||
|
||||
接下来的小节会对以上几种方式进行详细介绍。
|
||||
* [使用 kubeadm 部署 (CRI 使用 containerd)](14.1_kubeadm.md)
|
||||
* [使用 kubeadm 部署 (使用 Docker)](14.2_kubeadm-docker.md)
|
||||
* [在 Docker Desktop 使用](14.3_docker-desktop.md)
|
||||
* [Kind - Kubernetes IN Docker](14.4_kind.md)
|
||||
* [K3s - 轻量级 Kubernetes](14.5_k3s.md)
|
||||
* [一步步部署 Kubernetes 集群](14.6_systemd.md)
|
||||
* [部署 Dashboard](14.7_dashboard.md)
|
||||
* [Kubernetes 命令行 kubectl](14.8_kubectl.md)
|
||||
|
||||
@@ -15,3 +15,6 @@
|
||||
- [容器编排基础](../13_kubernetes_concepts/README.md):Kubernetes 核心概念
|
||||
- [Dashboard](14.7_dashboard.md):部署可视化管理界面
|
||||
- [kubectl](14.8_kubectl.md):命令行工具使用指南
|
||||
---
|
||||
|
||||
> 📝 **发现错误或有改进建议?** 欢迎提交 [Issue](https://github.com/yeasy/docker_practice/issues) 或 [PR](https://github.com/yeasy/docker_practice/pulls)。
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
`etcd` 基于 `Go` 语言实现,因此,用户可以从[项目主页](https://github.com/etcd-io/etcd)下载源代码自行编译,也可以下载编译好的二进制文件,甚至直接使用制作好的 `Docker` 镜像文件来体验。
|
||||
|
||||
>注意:本章节内容基于 etcd `3.4.x` 版本
|
||||
>注意:本章节内容基于 etcd `3.4.x` 版本编写。etcd 3.4 的官方支持将于 **2026 年 5 月 15 日结束**,新部署建议使用 etcd `3.5` 或 `3.6` 版本。请访问 [etcd 官方发布页](https://github.com/etcd-io/etcd/releases) 获取最新版本。
|
||||
|
||||
### 15.2.1 二进制文件方式下载
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
# 第十五章 Etcd 项目
|
||||
|
||||
`etcd` 是 `CoreOS` 团队发起的一个管理配置信息和服务发现 (`Service Discovery`) 的项目,在这一章里面,我们将基于 `etcd 3.x` 版本介绍该项目的目标,安装和使用,以及实现的技术。
|
||||
|
||||
## 本章内容
|
||||
|
||||
* [简介](15.1_intro.md)
|
||||
* [安装](15.2_install.md)
|
||||
* [集群](15.3_cluster.md)
|
||||
* [使用 etcdctl](15.4_etcdctl.md)
|
||||
|
||||
@@ -15,3 +15,6 @@ etcd 是 Kubernetes 的核心存储组件,为分布式系统提供可靠的键
|
||||
|
||||
- [容器编排基础](../13_kubernetes_concepts/README.md):Kubernetes 如何使用 etcd
|
||||
- [部署 Kubernetes](../14_kubernetes_setup/README.md):在集群中部署 etcd
|
||||
---
|
||||
|
||||
> 📝 **发现错误或有改进建议?** 欢迎提交 [Issue](https://github.com/yeasy/docker_practice/issues) 或 [PR](https://github.com/yeasy/docker_practice/pulls)。
|
||||
|
||||
@@ -15,3 +15,199 @@
|
||||

|
||||
|
||||
图 13-6 腾讯云容器服务示意图
|
||||
|
||||
### 腾讯云容器服务 (TKE) 简介
|
||||
|
||||
腾讯云容器服务 (TKE, Tencent Kubernetes Engine) 是一款容器编排平台,基于原生 Kubernetes 提供,支持自动扩展、负载均衡、多可用区高可用等企业级功能。TKE 帮助开发者快速部署和管理容器化应用,消除集群运维的复杂度。
|
||||
|
||||
### 基本使用步骤
|
||||
|
||||
#### 1. 创建集群
|
||||
|
||||
登录腾讯云控制台,进入容器服务模块:
|
||||
- 选择 "创建集群",配置集群名称、地域和网络
|
||||
- 选择节点配置(云服务器规格和数量)
|
||||
- 设置 Kubernetes 版本和安全组
|
||||
- 完成创建后获得集群 kubeconfig 文件
|
||||
|
||||
```bash
|
||||
# 下载 kubeconfig 文件后,配置本地环境
|
||||
export KUBECONFIG=/path/to/kubeconfig.yaml
|
||||
kubectl cluster-info
|
||||
```
|
||||
|
||||
#### 2. 部署容器应用
|
||||
|
||||
创建 Deployment 部署应用:
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx-app
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:latest
|
||||
ports:
|
||||
- containerPort: 80
|
||||
```
|
||||
|
||||
应用配置文件:
|
||||
|
||||
```bash
|
||||
kubectl apply -f deployment.yaml
|
||||
kubectl get pods
|
||||
kubectl get svc
|
||||
```
|
||||
|
||||
#### 3. 管理镜像
|
||||
|
||||
通过腾讯云容器镜像服务 (TCR) 存储和管理私有镜像:
|
||||
|
||||
```bash
|
||||
# 登录腾讯云镜像仓库
|
||||
docker login ccr.ccs.tencentyun.com -u <username>
|
||||
|
||||
# 标记本地镜像
|
||||
docker tag my-app:latest ccr.ccs.tencentyun.com/namespace/my-app:latest
|
||||
|
||||
# 推送镜像到腾讯云
|
||||
docker push ccr.ccs.tencentyun.com/namespace/my-app:latest
|
||||
```
|
||||
|
||||
### 腾讯云 Docker 镜像加速器配置
|
||||
|
||||
为了加快镜像拉取速度,腾讯云提供了镜像加速服务。配置方法如下:
|
||||
|
||||
#### Linux 系统配置
|
||||
|
||||
编辑 `/etc/docker/daemon.json` 文件(如果不存在则创建):
|
||||
|
||||
```bash
|
||||
# 创建或编辑配置文件
|
||||
sudo mkdir -p /etc/docker
|
||||
sudo nano /etc/docker/daemon.json
|
||||
```
|
||||
|
||||
添加以下内容:
|
||||
|
||||
```json
|
||||
{
|
||||
"registry-mirrors": [
|
||||
"https://mirror.ccs.tencentyun.com"
|
||||
],
|
||||
"insecure-registries": []
|
||||
}
|
||||
```
|
||||
|
||||
重启 Docker 服务:
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl restart docker
|
||||
```
|
||||
|
||||
验证配置:
|
||||
|
||||
```bash
|
||||
# 查看镜像源是否生效
|
||||
docker info | grep -A 5 "Registry Mirrors"
|
||||
```
|
||||
|
||||
#### Windows/Mac 配置
|
||||
|
||||
对于 Docker Desktop,在设置界面中:
|
||||
1. 打开 Docker Desktop 设置
|
||||
2. 导航到 "Docker Engine"
|
||||
3. 在 JSON 配置中添加上述 `registry-mirrors` 字段
|
||||
4. 点击 "Apply & Restart"
|
||||
|
||||
### 腾讯云容器镜像服务 (TCR)
|
||||
|
||||
腾讯云容器镜像服务 (TCR) 提供企业级容器镜像存储和分发能力:
|
||||
|
||||
- **私有镜像仓库**:支持命名空间隔离,完整的访问权限控制
|
||||
- **镜像扫描**:自动扫描镜像漏洞,提供安全建议
|
||||
- **镜像加速**:支持跨地域镜像分发和加速
|
||||
- **Webhook 通知**:镜像推送时自动触发 CI/CD 流程
|
||||
- **镜像版本管理**:标签管理、镜像清理策略、生命周期管理
|
||||
|
||||
#### 快速开始
|
||||
|
||||
1. 在腾讯云控制台创建个人版或企业版 TCR 实例
|
||||
2. 创建命名空间和镜像仓库
|
||||
3. 配置 Docker 登录凭证
|
||||
4. 本地构建镜像并推送到 TCR
|
||||
5. 在 TKE 集群部署时引用 TCR 镜像地址
|
||||
|
||||
#### 完整推送/拉取示例
|
||||
|
||||
```bash
|
||||
# 登录到腾讯云 TCR(使用 API 密钥)
|
||||
docker login ccr.ccs.tencentyun.com \
|
||||
--username <腾讯云账号ID> \
|
||||
--password <API_KEY>
|
||||
|
||||
# 拉取公开镜像
|
||||
docker pull ccr.ccs.tencentyun.com/library/nginx:latest
|
||||
|
||||
# 构建本地镜像
|
||||
docker build -t my-app:v1.0 .
|
||||
|
||||
# 标记镜像为 TCR 地址
|
||||
docker tag my-app:v1.0 \
|
||||
ccr.ccs.tencentyun.com/my-namespace/my-app:v1.0
|
||||
|
||||
# 推送镜像到 TCR
|
||||
docker push ccr.ccs.tencentyun.com/my-namespace/my-app:v1.0
|
||||
|
||||
# 在 Dockerfile 中使用 TCR 镜像
|
||||
FROM ccr.ccs.tencentyun.com/my-namespace/my-app:v1.0
|
||||
RUN echo "使用腾讯云镜像作为基础镜像"
|
||||
```
|
||||
|
||||
#### TKE 集群中使用 TCR 镜像
|
||||
|
||||
配置镜像拉取凭证后,在 Deployment 中直接引用 TCR 镜像:
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: my-app-deployment
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: my-app
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: my-app
|
||||
spec:
|
||||
imagePullSecrets:
|
||||
- name: tcr-secret # 需提前创建该 Secret
|
||||
containers:
|
||||
- name: my-app
|
||||
image: ccr.ccs.tencentyun.com/my-namespace/my-app:v1.0
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
resources:
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "100m"
|
||||
limits:
|
||||
memory: "512Mi"
|
||||
cpu: "500m"
|
||||
```
|
||||
|
||||
@@ -12,6 +12,260 @@
|
||||
|
||||
[阿里云容器服务 Kubernetes 版 ACK](https://www.aliyun.com/product/kubernetes?source=5176.11533457\&userCode=8lx5zmtu\&type=copy) 提供了高性能、可伸缩的容器应用管理服务,支持在一组云服务器上通过 Docker 容器来进行应用生命周期管理。容器服务极大简化了用户对容器管理集群的搭建工作,无缝整合了阿里云虚拟化、存储、网络和安全能力。容器服务提供了多种应用发布方式和流水线般的持续交付能力,原生支持微服务架构,助力用户无缝上云和跨云管理。
|
||||
|
||||

|
||||
<!-- 注意:原阿里云容器服务截图链接已失效,请参考阿里云官方文档获取最新界面截图 -->
|
||||
<!-- 原链接: https://img.alicdn.com/tps/TB10yjtPpXXXXacXXXXXXXXXXXX-1531-1140.png -->
|
||||
|
||||
图 13-4 阿里云容器服务示意图
|
||||
图 13-4 阿里云容器服务示意图(请访问 [阿里云容器服务 ACK 官方文档](https://help.aliyun.com/product/85222.html) 查看最新界面)
|
||||
|
||||
### 阿里云容器服务 ACK 简介
|
||||
|
||||
阿里云容器服务 Kubernetes 版 (ACK, Container Service for Kubernetes) 是一款托管式 Kubernetes 服务,基于开源 Kubernetes 构建,提供企业级的容器编排和管理能力。ACK 集成了阿里云存储、网络和安全能力,支持多种应用部署模式和持续交付流程。
|
||||
|
||||
### 基本使用步骤
|
||||
|
||||
#### 1. 创建集群
|
||||
|
||||
登录阿里云控制台,进入容器服务 > Kubernetes 集群:
|
||||
- 点击 "创建集群",选择集群配置
|
||||
- 配置集群名称、地域、可用区和节点类型
|
||||
- 选择节点规格和数量(支持弹性伸缩)
|
||||
- 配置网络参数和安全设置
|
||||
- 完成创建,下载 kubeconfig 文件
|
||||
|
||||
```bash
|
||||
# 配置本地 kubectl
|
||||
export KUBECONFIG=/path/to/kubeconfig.yaml
|
||||
kubectl get nodes
|
||||
```
|
||||
|
||||
#### 2. 部署容器应用
|
||||
|
||||
通过 Deployment 部署应用示例:
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: web-server
|
||||
spec:
|
||||
replicas: 2
|
||||
selector:
|
||||
matchLabels:
|
||||
app: web
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: web
|
||||
spec:
|
||||
containers:
|
||||
- name: web
|
||||
image: registry.cn-hangzhou.aliyuncs.com/myapp/web:v1
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
resources:
|
||||
limits:
|
||||
memory: "512Mi"
|
||||
cpu: "500m"
|
||||
```
|
||||
|
||||
部署应用:
|
||||
|
||||
```bash
|
||||
kubectl apply -f deployment.yaml
|
||||
kubectl get pods -o wide
|
||||
kubectl logs <pod-name>
|
||||
```
|
||||
|
||||
#### 3. 暴露服务
|
||||
|
||||
创建 Service 暴露应用:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: web-service
|
||||
spec:
|
||||
type: LoadBalancer
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: web
|
||||
```
|
||||
|
||||
应用:
|
||||
|
||||
```bash
|
||||
kubectl apply -f service.yaml
|
||||
kubectl get svc web-service
|
||||
```
|
||||
|
||||
### 阿里云 Docker 镜像加速器配置
|
||||
|
||||
为了加快从阿里云镜像源拉取官方镜像的速度,可以配置镜像加速器。阿里云为容器服务 ACK 用户提供了免费的镜像加速服务。
|
||||
|
||||
#### 获取加速器地址
|
||||
|
||||
登录阿里云容器镜像服务控制台,在 "镜像工具" > "镜像加速器" 中可获取个人的加速器地址(类似于 `https://xxxxxx.mirror.aliyuncs.com`)。
|
||||
|
||||
#### Linux 系统配置
|
||||
|
||||
编辑或创建 `/etc/docker/daemon.json` 文件:
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /etc/docker
|
||||
sudo nano /etc/docker/daemon.json
|
||||
```
|
||||
|
||||
添加或修改以下内容(替换为你的加速器地址):
|
||||
|
||||
```json
|
||||
{
|
||||
"registry-mirrors": [
|
||||
"https://xxxxxx.mirror.aliyuncs.com"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
重新加载并重启 Docker:
|
||||
|
||||
```bash
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl restart docker
|
||||
```
|
||||
|
||||
验证配置生效:
|
||||
|
||||
```bash
|
||||
docker info | grep -A 5 "Registry Mirrors"
|
||||
```
|
||||
|
||||
#### Windows/Mac 配置
|
||||
|
||||
在 Docker Desktop 的 Settings 中:
|
||||
1. 进入 "Docker Engine" 标签
|
||||
2. 编辑 JSON 配置,添加 `registry-mirrors` 字段
|
||||
3. 点击 "Apply & Restart"
|
||||
|
||||
#### 测试加速效果
|
||||
|
||||
```bash
|
||||
# 从加速器拉取镜像(速度应该明显提升)
|
||||
docker pull nginx:latest
|
||||
time docker pull alpine:latest
|
||||
```
|
||||
|
||||
### 阿里云容器镜像服务 (ACR)
|
||||
|
||||
阿里云容器镜像服务 (ACR, Container Registry) 是企业级的容器镜像存储和分发平台:
|
||||
|
||||
- **私有镜像仓库**:支持多个命名空间,细粒度权限控制
|
||||
- **镜像构建**:云端编译和构建,支持自动化 CI/CD
|
||||
- **镜像扫描**:自动检测镜像中的漏洞和恶意代码
|
||||
- **跨地域复制**:支持镜像在多个地域的同步和加速
|
||||
- **集成 ACK**:与 ACK 无缝集成,自动身份认证
|
||||
- **镜像版本管理**:标签管理、镜像过期清理、保留策略
|
||||
|
||||
#### 完整推送/拉取示例
|
||||
|
||||
```bash
|
||||
# 登录阿里云镜像仓库(使用 Docker 登录)
|
||||
# 使用阿里云账户 ID 和 RAM 访问密钥或密码
|
||||
docker login registry.cn-hangzhou.aliyuncs.com \
|
||||
--username=<阿里云账户ID>
|
||||
|
||||
# 拉取阿里云公开镜像
|
||||
docker pull registry.cn-hangzhou.aliyuncs.com/library/nginx:latest
|
||||
|
||||
# 构建本地镜像
|
||||
docker build -t my-app:v1.0 .
|
||||
|
||||
# 标记镜像为阿里云仓库地址
|
||||
docker tag my-app:v1.0 \
|
||||
registry.cn-hangzhou.aliyuncs.com/myapp/my-app:v1.0
|
||||
|
||||
# 推送镜像到阿里云 ACR
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/myapp/my-app:v1.0
|
||||
|
||||
# 在 Dockerfile 中使用 ACR 镜像
|
||||
FROM registry.cn-hangzhou.aliyuncs.com/myapp/my-app:v1.0
|
||||
COPY . /app
|
||||
RUN echo "已成功使用阿里云镜像"
|
||||
```
|
||||
|
||||
#### ACK 集群中使用 ACR 镜像
|
||||
|
||||
在 ACK 集群中,需要先配置镜像拉取凭证(Secret),然后在 Deployment 中引用:
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: web-server
|
||||
namespace: default
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: web
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: web
|
||||
spec:
|
||||
# 如果是私有镜像,需配置镜像拉取凭证
|
||||
imagePullSecrets:
|
||||
- name: acr-secret
|
||||
containers:
|
||||
- name: web
|
||||
image: registry.cn-hangzhou.aliyuncs.com/myapp/web:v2.0
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
resources:
|
||||
requests:
|
||||
memory: "256Mi"
|
||||
cpu: "100m"
|
||||
limits:
|
||||
memory: "512Mi"
|
||||
cpu: "500m"
|
||||
affinity:
|
||||
# 配置 Pod 反亲和性,分散到不同节点
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 100
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchExpressions:
|
||||
- key: app
|
||||
operator: In
|
||||
values:
|
||||
- web
|
||||
topologyKey: kubernetes.io/hostname
|
||||
```
|
||||
|
||||
#### 创建镜像拉取凭证
|
||||
|
||||
在 ACK 集群中创建 Secret,用于拉取私有镜像:
|
||||
|
||||
```bash
|
||||
# 创建镜像拉取 Secret
|
||||
kubectl create secret docker-registry acr-secret \
|
||||
--docker-server=registry.cn-hangzhou.aliyuncs.com \
|
||||
--docker-username=<阿里云账户ID> \
|
||||
--docker-password=<RAM访问密钥或密码> \
|
||||
--docker-email=<邮箱地址>
|
||||
|
||||
# 查看创建的 Secret
|
||||
kubectl get secret acr-secret
|
||||
kubectl describe secret acr-secret
|
||||
```
|
||||
|
||||
#### ACR 优势
|
||||
|
||||
- 在 ACK 集群中与镜像仓库无缝集成,简化身份认证
|
||||
- 支持 Helm Chart 存储和版本管理,方便应用交付
|
||||
- 提供完整的图形化镜像仓库管理界面
|
||||
- 完整的审计日志和操作追踪功能
|
||||
- 支持镜像自动扫描和漏洞报告
|
||||
|
||||
@@ -3,3 +3,11 @@
|
||||
Docker 目前已经得到了众多公有云平台的支持,并成为除虚拟机之外的核心云业务。
|
||||
|
||||
除了 AWS、Google、Azure 等,国内的各大公有云厂商,基本上都同时支持了虚拟机服务和基于 Kubernetes 的容器云业务。有的还推出了其他服务,例如[容器镜像服务](https://cloud.tencent.com/act/cps/redirect?redirect=11588&cps_key=3a5255852d5db99dcd5da4c72f05df61)让用户在云上享有安全高效的镜像托管、分发等服务。
|
||||
|
||||
## 本章内容
|
||||
|
||||
* [简介](16.1_intro.md)
|
||||
* [腾讯云](16.2_tencentCloud.md)
|
||||
* [阿里云](16.3_alicloud.md)
|
||||
* [亚马逊云](16.4_aws.md)
|
||||
* [多云部署策略](16.5_multicloud.md)
|
||||
|
||||
@@ -11,3 +11,6 @@
|
||||
* 利用公有云和 Docker 的特性更加方便的迁移和扩展应用。
|
||||
|
||||
同时,容器将作为与虚拟机类似的业务直接提供给用户使用,极大的丰富了应用开发和部署的场景。
|
||||
---
|
||||
|
||||
> 📝 **发现错误或有改进建议?** 欢迎提交 [Issue](https://github.com/yeasy/docker_practice/issues) 或 [PR](https://github.com/yeasy/docker_practice/pulls)。
|
||||
|
||||
@@ -21,8 +21,3 @@ FCOS 使用 rpm-ostree 系统进行事务性升级。无需像 yum 升级那样
|
||||
#### 容器工具
|
||||
|
||||
对于诸如构建,复制和其他管理容器的任务,FCOS 用一组容器工具代替了 **Docker CLI**。**podman CLI** 工具支持许多容器运行时功能,例如运行,启动,停止,列出和删除容器和镜像。**skopeo CLI** 工具可以复制,认证和签名镜像。您还可以使用 **crictl CLI** 工具来处理 CRI-O 容器引擎中的容器和镜像。
|
||||
|
||||
### 17.1.2 参考文档
|
||||
|
||||
* [官方文档](https://docs.fedoraproject.org/en-US/fedora-coreos/)
|
||||
* [openshift 官方文档](https://docs.openshift.com/container-platform/4.3/architecture/architecture-rhcos.html)
|
||||
|
||||
@@ -47,7 +47,3 @@ $ ssh core@虚拟机IP
|
||||
|
||||
$ docker --version
|
||||
```
|
||||
|
||||
### 17.2.6 参考链接
|
||||
|
||||
* [官方文档](https://docs.fedoraproject.org/en-US/fedora-coreos/bare-metal/)
|
||||
|
||||
Binary file not shown.
@@ -2,10 +2,28 @@
|
||||
|
||||
本章将介绍 Docker 和 Kubernetes 之外的容器生态技术。
|
||||
|
||||
- **Fedora CoreOS**:专为容器化工作负载设计的操作系统。
|
||||
- **Podman**:兼容 Docker CLI 的下一代无守护进程容器引擎。
|
||||
- **Buildah**:无需守护进程的 OCI 容器镜像构建工具。
|
||||
- **Skopeo**:远程检查和管理容器镜像的利器。
|
||||
- **containerd**:作为现代容器生态基石的核心容器运行时。
|
||||
- **安全容器运行时**:通过提供更强隔离性来保证安全的技术方案(如 Kata Containers、gVisor)。
|
||||
- **WebAssembly**:一种极具潜力的轻量级跨平台二进制指令格式。
|
||||
## 本章内容
|
||||
|
||||
* [Fedora CoreOS 简介](17.1_coreos_intro.md)
|
||||
* 专为容器化工作负载设计的操作系统。
|
||||
|
||||
* [Fedora CoreOS 安装与配置](17.2_coreos_install.md)
|
||||
* CoreOS 的安装方式与基本配置。
|
||||
|
||||
* [Podman](17.3_podman.md)
|
||||
* 兼容 Docker CLI 的下一代无守护进程容器引擎。
|
||||
|
||||
* [Buildah](17.4_buildah.md)
|
||||
* 无需守护进程的 OCI 容器镜像构建工具。
|
||||
|
||||
* [Skopeo](17.5_skopeo.md)
|
||||
* 远程检查和管理容器镜像的利器。
|
||||
|
||||
* [containerd](17.6_containerd.md)
|
||||
* 作为现代容器生态基石的核心容器运行时。
|
||||
|
||||
* [安全容器运行时](17.7_secure_runtime.md)
|
||||
* 通过提供更强隔离性来保证安全的技术方案(如 Kata Containers、gVisor)。
|
||||
|
||||
* [WebAssembly](17.8_wasm.md)
|
||||
* 一种极具潜力的轻量级跨平台二进制指令格式。
|
||||
|
||||
@@ -28,3 +28,6 @@ Docker 并非容器生态的唯一选择,了解其他工具有助于根据场
|
||||
|
||||
- [底层实现](../12_implementation/README.md):容器技术的内核基础
|
||||
- [安全](../18_security/README.md):容器安全实践
|
||||
---
|
||||
|
||||
> 📝 **发现错误或有改进建议?** 欢迎提交 [Issue](https://github.com/yeasy/docker_practice/issues) 或 [PR](https://github.com/yeasy/docker_practice/pulls)。
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## 18.1 内核命名空间
|
||||
|
||||
命名空间 (Namespace) 是 Linux 容器隔离的基础,它确保了容器内的进程无法直接干扰主机或其他容器。虽然在本书第 12 章中我们已经从底层实现的角度介绍了 Namespace,但在本节中,我们将重点探讨其**安全意义**及相关配置。
|
||||
命名空间 (Namespace) 是 Linux 容器隔离的基础,它确保了容器内的进程无法直接干扰主机或其他容器。虽然在本书第 12 章中我们已经从底层实现的角度介绍了 Namespace,但在本节中,我们将重点探讨其 **安全意义** 及相关配置。
|
||||
|
||||
### 18.1.1 隔离的安全本质
|
||||
|
||||
@@ -22,7 +22,7 @@ Docker 守护进程在启动容器时,会在后台为容器创建一套独立
|
||||
通过命名空间,Docker 也能限制进程从外部环境获取信息。
|
||||
例如,由于进程环境被隔离,进程在内部其实是无法感知到外部宿主机的存在的。它既不能获取其他容器的进程列表,也无法通过网络与其他系统进行交互(除非经过配置)。
|
||||
|
||||
### 18.1.1 用户命名空间 与提权防护
|
||||
### 18.1.3 用户命名空间与提权防护
|
||||
|
||||
在所有的 Namespace 中,**User Namespace** 对安全的影响尤为关键。
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## 18.2 控制组
|
||||
|
||||
控制组 (Cgroups) 是 Linux 容器机制的另外一个关键组件。如果说命名空间 (Namespace) 决定了容器能**看到**什么,那么控制组就决定了容器能**使用**多少资源。
|
||||
控制组 (Cgroups) 是 Linux 容器机制的另外一个关键组件。如果说命名空间 (Namespace) 决定了容器能 **看到** 什么,那么控制组就决定了容器能 **使用** 多少资源。
|
||||
|
||||
在安全领域中,资源的不可用性本身就是一种安全威胁。控制组负责实现资源的审计和限制,这对于抵御资源耗尽型攻击(如拒绝服务攻击 DoS)至关重要。
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
### 18.2.2 核心资源限制实战
|
||||
|
||||
为了确保多租户平台(如公有或私有的 PaaS 平台)的稳定性,或者在生产环境防止服务级联故障,我们要养成在启动容器时**显式声明资源上限**的习惯。
|
||||
为了确保多租户平台(如公有或私有的 PaaS 平台)的稳定性,或者在生产环境防止服务级联故障,我们要养成在启动容器时 **显式声明资源上限** 的习惯。
|
||||
|
||||
#### 1. 内存限制
|
||||
|
||||
|
||||
@@ -83,4 +83,4 @@ $ docker version
|
||||
|
||||
### 18.3.4 结语
|
||||
|
||||
保障 Docker 服务端的安全主要是做减法:关闭不必要的网络监听点,严管 Socket 访问权限。而一旦基础系统条件允许,**毫不犹豫地在生产环境启用 Rootless 模式**将是一项划算的安全加固选择。
|
||||
保障 Docker 服务端的安全主要是做减法:关闭不必要的网络监听点,严管 Socket 访问权限。而一旦基础系统条件允许,**毫不犹豫地在生产环境启用 Rootless 模式** 将是一项划算的安全加固选择。
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
### 18.4.1 容器内置的 Capability 白名单
|
||||
|
||||
在默认情况下,即便一个容器是在以 `root` 用户运行,Docker 也只为其内核授予了所有可用能力中的**一小部分“白名单”能力**。
|
||||
在默认情况下,即便一个容器是在以 `root` 用户运行,Docker 也只为其内核授予了所有可用能力中的 **一小部分“白名单”能力**。
|
||||
|
||||
常见的 Linux Capabilities 包含:
|
||||
- `CAP_CHOWN`: 修改文件所有者。
|
||||
@@ -14,7 +14,7 @@
|
||||
- `CAP_NET_ADMIN`: 网络管理的最高权限(例如调整路由配置,设置防火墙规则等)。
|
||||
- `CAP_SYS_ADMIN`: 被誉为“Linux 内核的特权网管”,允许各种高危操作(挂载磁盘、访问敏感设备等)。
|
||||
|
||||
为了在**“最小特权原则”**的指导下加强安全,Docker 默认**移除了**大量可能导致容器大范围破坏宿主机的能力,例如:
|
||||
为了在 **“最小特权原则”** 的指导下加强安全,Docker 默认 **移除了** 大量可能导致容器大范围破坏宿主机的能力,例如:
|
||||
* 完全禁止了任何通过 `CAP_SYS_ADMIN` 进行的核心挂载或设备操作。
|
||||
* 禁止修改内核模块。
|
||||
* 禁止直接访问硬件套接字。
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
#### 实战场景一:构建极限安全的 Web 靶机
|
||||
|
||||
假设你正在提供一个公共的 Web 容器。你不希望里面的任何恶意脚本修改进程权限或者创建设备节点,你可以通过命令先移除**所有**默认能力,然后再按需授权该守护进程一个仅仅能绑端口的能力。
|
||||
假设你正在提供一个公共的 Web 容器。你不希望里面的任何恶意脚本修改进程权限或者创建设备节点,你可以通过命令先移除 **所有** 默认能力,然后再按需授权该守护进程一个仅仅能绑端口的能力。
|
||||
|
||||
```bash
|
||||
$ docker run -d \
|
||||
@@ -56,7 +56,7 @@ $ docker run -it --rm \
|
||||
我们只授予了所需的网络管理控制(NET_ADMIN)和侦听底层套接字的权限(NET_RAW),而免去了赋予整个容器终极杀器 `--privileged` 参数。
|
||||
|
||||
> [!WARNING]
|
||||
> 大量开发人员遇到了“权限遭到拒绝”的错误时,往往习惯性图省事添加 `--privileged` 这个核选项。但这将把**宿主机上一切特权和所有访问设备完全投射给容器内的根用户**,其危险性等价于根本没有做隔离!请务必查明进程出错的实际原因,精准施加必要的隔离 `CAP_*` 能力。
|
||||
> 大量开发人员遇到了“权限遭到拒绝”的错误时,往往习惯性图省事添加 `--privileged` 这个核选项。但这将把 **宿主机上一切特权和所有访问设备完全投射给容器内的根用户**,其危险性等价于根本没有做隔离!请务必查明进程出错的实际原因,精准施加必要的隔离 `CAP_*` 能力。
|
||||
|
||||
### 18.4.3 总结
|
||||
|
||||
|
||||
@@ -85,4 +85,4 @@ Total: 2 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 1, CRITICAL: 0)
|
||||
|
||||
### 18.5.4 容器核心层基石结语
|
||||
|
||||
到这里,Docker 为保障宿主和容器界限安全的几个护城河:从**资源剥离限制** (`Cgroups`) 到**进程/网络/身份蒙蔽** (`Namespace`)、到**特权能力回收** (`Capabilities`) 再到**内核强制策略拦截管制** (`Seccomp`/`AppArmor`) 已悉数交代完毕。虽然绝没有“100% 免疫网络穿刺的防线”,只要开发者牢记 **权限最小化原则** ,容器的堡垒就可以做到令攻击者望洋兴叹。
|
||||
到这里,Docker 为保障宿主和容器界限安全的几个护城河:从 **资源剥离限制**(`Cgroups`) 到 **进程/网络/身份蒙蔽**(`Namespace`)、到 **特权能力回收**(`Capabilities`) 再到 **内核强制策略拦截管制**(`Seccomp`/`AppArmor`) 已悉数交代完毕。虽然绝没有“100% 免疫网络穿刺的防线”,只要开发者牢记 **权限最小化原则** ,容器的堡垒就可以做到令攻击者望洋兴叹。
|
||||
|
||||
556
18_security/18.6_image_security.md
Normal file
556
18_security/18.6_image_security.md
Normal file
@@ -0,0 +1,556 @@
|
||||
## 18.6 容器镜像安全扫描与供应链安全
|
||||
|
||||
在 DevOps 流程中,容器镜像安全已经成为不容忽视的关键环节。从开发、构建、存储到部署,镜像的整个生命周期都需要安全防护。本节深入讨论镜像漏洞扫描、软件物料清单(SBOM)、镜像签名验证等供应链安全实践。
|
||||
|
||||
### 18.6.1 容器镜像漏洞扫描工具对比
|
||||
|
||||
#### Trivy - 轻量级通用扫描器
|
||||
|
||||
Trivy 是由 Aqua Security 开发的开源漏洞扫描器,以其轻量级、快速、准确而闻名,已成为业界标准。
|
||||
|
||||
**优点:**
|
||||
- 零依赖,单个二进制文件
|
||||
- 扫描速度快(秒级)
|
||||
- 支持镜像、文件系统、Git 仓库多种扫描源
|
||||
- 数据库每日自动更新
|
||||
- 支持多种输出格式(JSON、表格、SBOM 等)
|
||||
|
||||
**安装与基本使用:**
|
||||
|
||||
```bash
|
||||
# 安装 Trivy
|
||||
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
|
||||
|
||||
# 扫描本地镜像
|
||||
trivy image nginx:latest
|
||||
|
||||
# 生成 JSON 格式报告
|
||||
trivy image -f json -o report.json nginx:latest
|
||||
|
||||
# 扫描文件系统
|
||||
trivy fs /path/to/project
|
||||
|
||||
# 扫描 Git 仓库
|
||||
trivy repo https://github.com/aquasecurity/trivy
|
||||
```
|
||||
|
||||
**在 CI/CD 中集成:**
|
||||
|
||||
```bash
|
||||
# 设置严重程度过滤
|
||||
trivy image --severity HIGH,CRITICAL \
|
||||
--exit-code 1 \
|
||||
myregistry.com/myapp:v1.0.0
|
||||
```
|
||||
|
||||
#### Grype - 支持多种软件包的扫描器
|
||||
|
||||
Grype 由 Anchore 开发,支持更广泛的软件包管理器和语言。
|
||||
|
||||
**优点:**
|
||||
- 支持 Java、Python、Go、Ruby、JavaScript 等多种语言的依赖检测
|
||||
- 与 Syft(SBOM 生成器)配合效果好
|
||||
- 可自定义漏洞数据库源
|
||||
- 支持离线扫描模式
|
||||
|
||||
**安装与使用:**
|
||||
|
||||
```bash
|
||||
# 安装 Grype
|
||||
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
|
||||
|
||||
# 扫描镜像
|
||||
grype docker:nginx:latest
|
||||
|
||||
# 与 Syft 配合生成 SBOM
|
||||
syft docker:nginx:latest -o json > sbom.json
|
||||
grype sbom:sbom.json
|
||||
|
||||
# 扫描特定目录
|
||||
grype dir:/path/to/app
|
||||
```
|
||||
|
||||
#### Snyk - 完整的安全平台
|
||||
|
||||
Snyk 提供了商业级的安全扫描服务,特别适合企业环境。
|
||||
|
||||
**特点:**
|
||||
- 支持开源漏洞和许可证扫描
|
||||
- 与多个 Git 平台深度集成(GitHub、GitLab、Bitbucket)
|
||||
- 提供修复建议和自动化修复 PR
|
||||
- 支持 Kubernetes 部署后安全监控
|
||||
|
||||
**基本使用:**
|
||||
|
||||
```bash
|
||||
# 安装 Snyk CLI
|
||||
npm install -g snyk
|
||||
|
||||
# 认证
|
||||
snyk auth
|
||||
|
||||
# 扫描镜像
|
||||
snyk container test docker-archive://image.tar
|
||||
|
||||
# 监控仓库
|
||||
snyk monitor --docker
|
||||
```
|
||||
|
||||
**工具对比表:**
|
||||
|
||||
| 特性 | Trivy | Grype | Snyk |
|
||||
|------|-------|-------|------|
|
||||
| 零依赖 | ✓ | ✗ | ✗ |
|
||||
| 离线模式 | ✓ | ✓ | ✗ |
|
||||
| 许可证扫描 | ✗ | ✓ | ✓ |
|
||||
| 自动修复 | ✗ | ✗ | ✓ |
|
||||
| 开源免费 | ✓ | ✓ | 部分 |
|
||||
| IDE 集成 | ✓ | ✓ | ✓ |
|
||||
|
||||
### 18.6.2 SBOM(软件物料清单)生成与管理
|
||||
|
||||
SBOM(Software Bill of Materials)是一份详细列表,记录了软件中使用的所有组件、依赖库及其版本信息。SBOM 在供应链安全中至关重要,特别是在发现新的安全漏洞时,能快速定位受影响的应用。
|
||||
|
||||
#### Syft - SBOM 生成工具
|
||||
|
||||
Syft 是 Anchore 推出的专业 SBOM 生成工具。
|
||||
|
||||
**安装:**
|
||||
|
||||
```bash
|
||||
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
|
||||
```
|
||||
|
||||
**生成 SBOM:**
|
||||
|
||||
```bash
|
||||
# 从镜像生成 SBOM(多种格式)
|
||||
syft docker:nginx:latest -o json > sbom.json
|
||||
syft docker:nginx:latest -o spdx > sbom.spdx
|
||||
syft docker:nginx:latest -o cyclonedx > sbom.xml
|
||||
|
||||
# 从本地文件系统生成
|
||||
syft dir:/path/to/app -o json > sbom.json
|
||||
|
||||
# 从 OCI 镜像档案生成
|
||||
syft oci-archive:image.tar -o json > sbom.json
|
||||
```
|
||||
|
||||
#### CycloneDX 与 SPDX 格式
|
||||
|
||||
两种主流的 SBOM 格式:
|
||||
|
||||
**CycloneDX 格式示例:**
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bom xmlns="http://cyclonedx.org/schema/bom/1.4" version="1">
|
||||
<components>
|
||||
<component type="library">
|
||||
<name>openssl</name>
|
||||
<version>1.1.1k</version>
|
||||
<purl>pkg:deb/debian/openssl@1.1.1k-1+deb11u5</purl>
|
||||
</component>
|
||||
<component type="library">
|
||||
<name>curl</name>
|
||||
<version>7.74.0-1.3+deb11u1</version>
|
||||
<purl>pkg:deb/debian/curl@7.74.0-1.3+deb11u1</purl>
|
||||
</component>
|
||||
</components>
|
||||
</bom>
|
||||
```
|
||||
|
||||
**SPDX 格式示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"SPDXID": "SPDXRef-DOCUMENT",
|
||||
"spdxVersion": "SPDX-2.2",
|
||||
"creationInfo": {
|
||||
"created": "2024-03-01T12:00:00Z",
|
||||
"creators": ["Tool: syft"]
|
||||
},
|
||||
"packages": [
|
||||
{
|
||||
"SPDXID": "SPDXRef-Package-openssl",
|
||||
"name": "openssl",
|
||||
"versionInfo": "1.1.1k",
|
||||
"downloadLocation": "NOASSERTION"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### SBOM 的应用场景
|
||||
|
||||
**漏洞关联:**
|
||||
|
||||
当新的 CVE 被发现时,可快速查询受影响的应用:
|
||||
|
||||
```bash
|
||||
# 使用 Grype 针对 SBOM 进行漏洞扫描
|
||||
grype sbom:sbom.json --add-cpes-if-none
|
||||
```
|
||||
|
||||
**合规性报告:**
|
||||
|
||||
将 SBOM 保存为构建产物,用于审计和合规性检查。
|
||||
|
||||
**依赖升级决策:**
|
||||
|
||||
通过分析 SBOM 中的依赖版本,制定安全升级计划。
|
||||
|
||||
### 18.6.3 镜像签名与验证(Cosign/Notary)
|
||||
|
||||
镜像签名确保镜像的来源可信且未被篡改。两种主流方案是 Cosign 和 Notary。
|
||||
|
||||
#### Cosign - 现代签名解决方案
|
||||
|
||||
Cosign 是 Sigstore 项目的核心工具,支持无密钥签名,适合现代 CI/CD 流程。
|
||||
|
||||
**安装:**
|
||||
|
||||
```bash
|
||||
wget https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64
|
||||
chmod +x cosign-linux-amd64
|
||||
sudo mv cosign-linux-amd64 /usr/local/bin/cosign
|
||||
```
|
||||
|
||||
**生成密钥对(传统方式):**
|
||||
|
||||
```bash
|
||||
cosign generate-key-pair
|
||||
# 生成 cosign.key 和 cosign.pub
|
||||
```
|
||||
|
||||
**签名镜像:**
|
||||
|
||||
```bash
|
||||
# 使用私钥签名(推送到仓库前)
|
||||
cosign sign --key cosign.key myregistry.com/myapp:v1.0.0
|
||||
|
||||
# 系统会提示输入私钥密码
|
||||
```
|
||||
|
||||
**验证签名:**
|
||||
|
||||
```bash
|
||||
# 使用公钥验证
|
||||
cosign verify --key cosign.pub myregistry.com/myapp:v1.0.0
|
||||
|
||||
# 输出结果示例
|
||||
# Verification successful!
|
||||
# {
|
||||
# "critical": {
|
||||
# "identity": {...},
|
||||
# "image": {...},
|
||||
# "type": "cosign container image signature"
|
||||
# },
|
||||
# "optional": {...}
|
||||
# }
|
||||
```
|
||||
|
||||
**Keyless 签名(推荐用于 CI/CD):**
|
||||
|
||||
```bash
|
||||
# 在 GitHub Actions 等 CI 中无需存储密钥
|
||||
cosign sign --yes myregistry.com/myapp:v1.0.0
|
||||
|
||||
# 验证时自动使用 OIDC 令牌验证身份
|
||||
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(DCT)与 Notary
|
||||
|
||||
Docker Content Trust 使用 Notary 实现镜像签名,是 Docker 官方的签名解决方案。
|
||||
|
||||
**启用 DCT:**
|
||||
|
||||
```bash
|
||||
# 在环境中启用 DCT
|
||||
export DOCKER_CONTENT_TRUST=1
|
||||
|
||||
# 此后所有 docker push/pull 都需要签名
|
||||
docker push myregistry.com/myapp:v1.0.0
|
||||
# 如果镜像未签名,操作会被拒绝
|
||||
|
||||
# 禁用 DCT(仅用于特定操作)
|
||||
docker push --disable-content-trust myregistry.com/myapp:v1.0.0
|
||||
```
|
||||
|
||||
**签名密钥管理:**
|
||||
|
||||
```bash
|
||||
# 首次推送时会提示创建 Delegation Key
|
||||
# 密钥存储在 ~/.docker/trust/private/root_keys/ 和 ~/.docker/trust/private/tuf_keys/
|
||||
|
||||
# 查看签名信息
|
||||
docker inspect --format='{{.RepoDigests}}' myregistry.com/myapp:v1.0.0
|
||||
```
|
||||
|
||||
### 18.6.4 供应链安全最佳实践
|
||||
|
||||
#### 1. 基础镜像安全
|
||||
|
||||
```dockerfile
|
||||
# ❌ 不推荐:使用 latest 标签
|
||||
FROM ubuntu:latest
|
||||
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 中集成安全扫描:
|
||||
|
||||
```dockerfile
|
||||
FROM golang:1.20-alpine AS builder
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
|
||||
# 使用 Trivy 扫描源代码
|
||||
RUN apk add --no-cache curl && \
|
||||
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin && \
|
||||
trivy fs . --exit-code 1 --severity HIGH,CRITICAL
|
||||
|
||||
RUN go build -o app .
|
||||
|
||||
FROM alpine:3.17@sha256:abcd1234...(请替换为实际完整的 64 位摘要哈希)
|
||||
COPY --from=builder /app/app /app
|
||||
```
|
||||
|
||||
#### 3. 运行时镜像扫描策略
|
||||
|
||||
```bash
|
||||
# 镜像构建完成后立即扫描
|
||||
trivy image --severity HIGH,CRITICAL \
|
||||
--exit-code 1 \
|
||||
--timeout 30m \
|
||||
$IMAGE_NAME:$IMAGE_TAG
|
||||
|
||||
# 定期扫描已部署的镜像
|
||||
trivy image --scanners vuln,misconfig registry:5000/myapp:latest
|
||||
```
|
||||
|
||||
#### 4. 镜像仓库安全配置
|
||||
|
||||
**Harbor(私有镜像仓库)的安全扫描:**
|
||||
|
||||
```yaml
|
||||
# harbor.yml 配置示例
|
||||
trivy:
|
||||
enabled: true
|
||||
# 启用镜像扫描
|
||||
image_source: "Official"
|
||||
|
||||
# 默认扫描配置
|
||||
scan_on_push: true # 推送时自动扫描
|
||||
scan_all: true # 扫描仓库中的所有镜像
|
||||
```
|
||||
|
||||
#### 5. 政策执行(Admission Controller)
|
||||
|
||||
在 Kubernetes 环境中使用 Admission Webhook 强制镜像签名和扫描:
|
||||
|
||||
```yaml
|
||||
apiVersion: admissionregistration.k8s.io/v1
|
||||
kind: ValidatingWebhookConfiguration
|
||||
metadata:
|
||||
name: image-security-policy
|
||||
webhooks:
|
||||
- name: image-security.example.com
|
||||
clientConfig:
|
||||
service:
|
||||
name: image-security-webhook
|
||||
namespace: security
|
||||
path: "/validate"
|
||||
rules:
|
||||
- operations: ["CREATE", "UPDATE"]
|
||||
apiGroups: [""]
|
||||
apiVersions: ["v1"]
|
||||
resources: ["pods"]
|
||||
admissionReviewVersions: ["v1"]
|
||||
sideEffects: None
|
||||
```
|
||||
|
||||
### 18.6.5 CI/CD 中集成安全扫描
|
||||
|
||||
#### GitHub Actions 工作流示例
|
||||
|
||||
```yaml
|
||||
name: Build and Scan Image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, develop]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
build-scan:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
security-events: write
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: false
|
||||
load: true
|
||||
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
||||
|
||||
- name: Run Trivy vulnerability scan
|
||||
uses: aquasecurity/trivy-action@master
|
||||
with:
|
||||
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
||||
format: 'sarif'
|
||||
output: 'trivy-results.sarif'
|
||||
severity: 'HIGH,CRITICAL'
|
||||
|
||||
- name: Upload Trivy results to GitHub Security tab
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: 'trivy-results.sarif'
|
||||
|
||||
- name: Generate SBOM
|
||||
uses: anchore/sbom-action@v0
|
||||
with:
|
||||
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
||||
format: cyclonedx-json
|
||||
output-file: sbom-cyclonedx.json
|
||||
|
||||
- name: Upload SBOM
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sbom
|
||||
path: sbom-cyclonedx.json
|
||||
|
||||
- name: Sign image with Cosign
|
||||
if: github.event_name == 'push'
|
||||
run: |
|
||||
cosign sign --yes ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
||||
|
||||
- name: Login to Registry and Push
|
||||
if: github.event_name == 'push'
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Push image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
||||
```
|
||||
|
||||
#### GitLab CI 工作流示例
|
||||
|
||||
```yaml
|
||||
stages:
|
||||
- build
|
||||
- scan
|
||||
- sign
|
||||
- push
|
||||
|
||||
variables:
|
||||
REGISTRY: registry.gitlab.com
|
||||
IMAGE_NAME: $REGISTRY/$CI_PROJECT_PATH
|
||||
|
||||
build:
|
||||
stage: build
|
||||
image: docker:latest
|
||||
services:
|
||||
- docker:dind
|
||||
script:
|
||||
- docker build -t $IMAGE_NAME:$CI_COMMIT_SHA .
|
||||
- docker save $IMAGE_NAME:$CI_COMMIT_SHA > image.tar
|
||||
|
||||
scan:trivy:
|
||||
stage: scan
|
||||
image: aquasec/trivy:latest
|
||||
script:
|
||||
- trivy image --severity HIGH,CRITICAL --exit-code 1 docker-archive://image.tar
|
||||
allow_failure: false
|
||||
|
||||
scan:grype:
|
||||
stage: scan
|
||||
image: anchore/grype:latest
|
||||
script:
|
||||
- grype docker-archive://image.tar
|
||||
|
||||
generate:sbom:
|
||||
stage: scan
|
||||
image: anchore/syft:latest
|
||||
script:
|
||||
- syft docker-archive://image.tar -o cyclonedx > sbom.xml
|
||||
artifacts:
|
||||
reports:
|
||||
sbom: sbom.xml
|
||||
|
||||
sign:
|
||||
stage: sign
|
||||
image: gcr.io/projectsigstore/cosign:latest
|
||||
script:
|
||||
- cosign sign --key $COSIGN_KEY $IMAGE_NAME:$CI_COMMIT_SHA
|
||||
only:
|
||||
- main
|
||||
|
||||
push:
|
||||
stage: push
|
||||
image: docker:latest
|
||||
services:
|
||||
- docker:dind
|
||||
script:
|
||||
- docker load < image.tar
|
||||
- docker login -u $REGISTRY_USER -p $REGISTRY_PASSWORD $REGISTRY
|
||||
- docker push $IMAGE_NAME:$CI_COMMIT_SHA
|
||||
only:
|
||||
- main
|
||||
```
|
||||
|
||||
### 18.6.6 常见问题与最佳实践
|
||||
|
||||
**Q: 扫描报告中有过时的 CVE,如何处理?**
|
||||
|
||||
A: 某些 CVE 可能已经被修复但数据库未更新,可以:
|
||||
- 手动验证安全补丁是否已应用
|
||||
- 使用工具的忽略列表功能(如 Trivy 的 `.trivyignore`)
|
||||
- 定期更新扫描工具和漏洞数据库
|
||||
|
||||
**Q: 如何平衡镜像大小和安全性?**
|
||||
|
||||
A:
|
||||
- 使用多阶段构建减少最终镜像大小
|
||||
- 使用精简基础镜像(Alpine、Distroless)
|
||||
- 定期更新依赖而不是一味求小
|
||||
- 优先安全性,体积次之
|
||||
|
||||
**Q: 如何管理和轮换签名密钥?**
|
||||
|
||||
A:
|
||||
- 在密钥管理系统(如 HashiCorp Vault)中存储密钥
|
||||
- 定期轮换密钥(建议每 90 天)
|
||||
- 使用 Keyless 签名消除密钥管理复杂性
|
||||
- 保留密钥轮换的审计日志
|
||||
@@ -24,273 +24,27 @@ flowchart LR
|
||||
end
|
||||
```
|
||||
|
||||
---
|
||||
## 本章内容
|
||||
|
||||
## 核心安全机制
|
||||
本章涵盖 Docker 安全的多个层面,从内核隔离机制到运行时防护和供应链安全。
|
||||
|
||||
### 1. 命名空间
|
||||
* [内核命名空间](18.1_kernel_ns.md)
|
||||
* 命名空间的安全意义、User Namespace 与提权防护。
|
||||
|
||||
提供进程、网络、文件系统等资源的隔离:
|
||||
* [控制组](18.2_control_group.md)
|
||||
* 通过 Cgroups 限制容器资源使用,防止资源耗尽攻击。
|
||||
|
||||
| Namespace | 隔离内容 | 安全作用 |
|
||||
|-----------|---------|---------|
|
||||
| PID | 进程 | 容器看不到其他进程 |
|
||||
| NET | 网络 | 独立网络栈 |
|
||||
| MNT | 文件系统 | 独立的根目录 |
|
||||
| USER | 用户 | 容器 root ≠ 宿主机 root |
|
||||
| IPC | 进程通信 | 隔离共享内存 |
|
||||
| UTS | 主机名 | 独立主机名 |
|
||||
* [服务端防护](18.3_daemon_sec.md)
|
||||
* Docker 守护进程的安全配置与网络访问控制。
|
||||
|
||||
详见[命名空间](../12_implementation/12.2_namespace.md)章节。
|
||||
* [内核能力机制](18.4_kernel_capability.md)
|
||||
* Linux Capabilities 的细粒度权限控制。
|
||||
|
||||
### 2. 控制组
|
||||
* [其它安全特性](18.5_other_feature.md)
|
||||
* 镜像安全(漏洞扫描、签名验证)、运行时安全(非 root 运行、只读文件系统、Seccomp、AppArmor)、Dockerfile 安全实践、软件供应链安全(SBOM、SLSA)。
|
||||
|
||||
限制容器的资源使用,防止资源耗尽攻击:
|
||||
|
||||
```bash
|
||||
## 限制内存(超出会被 OOM Kill)
|
||||
|
||||
$ docker run -m 512m myapp
|
||||
|
||||
## 限制 CPU
|
||||
|
||||
$ docker run --cpus=1.5 myapp
|
||||
|
||||
## 限制磁盘 I/O
|
||||
|
||||
$ docker run --device-write-bps /dev/sda:10mb myapp
|
||||
```
|
||||
|
||||
### 3. 能力机制
|
||||
|
||||
Linux 将 root 权限拆分为多个细粒度的能力。Docker 默认禁用危险能力:
|
||||
|
||||
| 能力 | 说明 | 默认状态 |
|
||||
|------|------|---------|
|
||||
| `CAP_NET_ADMIN` | 网络管理 | ❌ 禁用 |
|
||||
| `CAP_SYS_ADMIN` | 系统管理 | ❌ 禁用 |
|
||||
| `CAP_SYS_PTRACE` | 进程追踪 | ❌ 禁用 |
|
||||
| `CAP_CHOWN` | 更改文件所有者 | ✅ 启用 |
|
||||
| `CAP_NET_BIND_SERVICE` | 绑定低端口 | ✅ 启用 |
|
||||
|
||||
```bash
|
||||
## 删除所有能力,只添加需要的
|
||||
|
||||
$ docker run --cap-drop=all --cap-add=NET_BIND_SERVICE myapp
|
||||
|
||||
## 查看容器的能力
|
||||
|
||||
$ docker exec myapp cat /proc/1/status | grep Cap
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 镜像安全
|
||||
|
||||
### 使用可信镜像
|
||||
|
||||
```bash
|
||||
## ✅ 使用官方镜像
|
||||
|
||||
$ docker pull nginx
|
||||
|
||||
## ✅ 使用经过验证的镜像
|
||||
|
||||
$ docker pull bitnami/nginx
|
||||
|
||||
## ⚠️ 谨慎使用未知来源镜像
|
||||
|
||||
$ docker pull randomuser/suspicious-image
|
||||
```
|
||||
|
||||
### 漏洞扫描
|
||||
|
||||
扫描镜像中的已知安全漏洞:
|
||||
|
||||
```bash
|
||||
## Docker Scout(官方工具)
|
||||
|
||||
$ docker scout cves nginx:latest
|
||||
$ docker scout recommendations nginx:latest
|
||||
|
||||
## Trivy(开源工具)
|
||||
|
||||
$ trivy image nginx:latest
|
||||
|
||||
## Snyk(商业工具)
|
||||
|
||||
$ snyk container test nginx:latest
|
||||
```
|
||||
|
||||
### 镜像签名验证
|
||||
|
||||
当前更推荐使用 Sigstore / Notation 体系进行镜像签名。`Docker Content Trust (DCT)` 已进入退场阶段,不建议作为新项目主方案。
|
||||
|
||||
> 注意:Cosign 默认会把签名写回镜像所在仓库,请使用你有推送权限的镜像地址。
|
||||
|
||||
```bash
|
||||
## 准备示例镜像
|
||||
$ export IMAGE=<你的仓库地址>/myimage:latest
|
||||
$ docker pull nginx:1.27
|
||||
$ docker tag nginx:1.27 $IMAGE
|
||||
$ docker push $IMAGE
|
||||
|
||||
## 生成签名密钥(会生成 cosign.key / cosign.pub)
|
||||
$ cosign generate-key-pair
|
||||
|
||||
## Cosign: 签名与验证
|
||||
$ cosign sign --key cosign.key $IMAGE
|
||||
$ cosign verify --key cosign.pub $IMAGE
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 运行时安全
|
||||
|
||||
### 1. 非 root 用户运行
|
||||
|
||||
> 笔者强调:这是最重要的安全实践之一。
|
||||
|
||||
```dockerfile
|
||||
FROM node:22-alpine
|
||||
|
||||
## 创建非 root 用户
|
||||
|
||||
RUN addgroup -g 1001 appgroup && \
|
||||
adduser -u 1001 -G appgroup -D appuser
|
||||
|
||||
## 设置工作目录权限
|
||||
|
||||
WORKDIR /app
|
||||
COPY --chown=appuser:appgroup . .
|
||||
|
||||
## 切换用户
|
||||
|
||||
USER appuser
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
```
|
||||
|
||||
或在运行时指定:
|
||||
|
||||
```bash
|
||||
$ docker run -u 1001:1001 myapp
|
||||
```
|
||||
|
||||
### 2. 只读文件系统
|
||||
|
||||
```bash
|
||||
## 根文件系统只读
|
||||
|
||||
$ docker run --read-only myapp
|
||||
|
||||
## 需要写入的目录使用 tmpfs
|
||||
|
||||
$ docker run --read-only --tmpfs /tmp --tmpfs /var/run myapp
|
||||
```
|
||||
|
||||
### 3. 禁用特权模式
|
||||
|
||||
```bash
|
||||
## ❌ 绝对不要在生产环境使用
|
||||
|
||||
$ docker run --privileged myapp
|
||||
|
||||
## ✅ 只添加必要的能力
|
||||
|
||||
$ docker run --cap-add=SYS_TIME myapp
|
||||
```
|
||||
|
||||
### 4. 限制资源
|
||||
|
||||
```bash
|
||||
$ docker run \
|
||||
-m 512m \ # 内存限制
|
||||
--cpus=1 \ # CPU 限制
|
||||
--pids-limit=100 \ # 进程数限制
|
||||
--ulimit nofile=1024:1024 \ # 文件描述符限制
|
||||
myapp
|
||||
```
|
||||
|
||||
### 5. 网络隔离
|
||||
|
||||
```bash
|
||||
## 禁用网络(适用于不需要网络的任务)
|
||||
|
||||
$ docker run --network=none myapp
|
||||
|
||||
## 使用自定义网络隔离
|
||||
|
||||
$ docker network create --internal isolated_net
|
||||
$ docker run --network=isolated_net myapp
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dockerfile 安全实践
|
||||
|
||||
### 1. 使用精简基础镜像
|
||||
|
||||
```dockerfile
|
||||
## ✅ 好:使用精简镜像
|
||||
|
||||
FROM node:22-alpine # ~50MB
|
||||
FROM gcr.io/distroless/nodejs # ~20MB
|
||||
|
||||
## ❌ 差:使用完整镜像
|
||||
|
||||
FROM node:22 # ~1GB
|
||||
FROM ubuntu:24.04 # ~78MB
|
||||
```
|
||||
|
||||
### 2. 多阶段构建
|
||||
|
||||
```dockerfile
|
||||
## 构建阶段
|
||||
|
||||
FROM node:22 AS builder
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN npm install && npm run build
|
||||
|
||||
## 生产阶段(不包含开发依赖和源码)
|
||||
|
||||
FROM node:22-alpine
|
||||
COPY --from=builder /app/dist /app
|
||||
USER node
|
||||
CMD ["node", "/app/server.js"]
|
||||
```
|
||||
|
||||
### 3. 不存储敏感信息
|
||||
|
||||
```dockerfile
|
||||
## ❌ 错误:敏感信息写入镜像
|
||||
|
||||
ENV DB_PASSWORD=secret123
|
||||
COPY .env /app/
|
||||
|
||||
## ✅ 正确:运行时传入
|
||||
|
||||
## docker run -e DB_PASSWORD=xxx 或使用 Docker Secrets
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
### 4. 固定依赖版本
|
||||
|
||||
```dockerfile
|
||||
## ✅ 固定版本
|
||||
|
||||
FROM node:22.12.0-alpine3.21
|
||||
RUN apk add --no-cache curl=8.5.0-r0
|
||||
|
||||
## ❌ 使用 latest
|
||||
|
||||
FROM node:latest
|
||||
RUN apk add curl
|
||||
```
|
||||
|
||||
---
|
||||
* [镜像安全](18.6_image_security.md)
|
||||
* 容器镜像的安全扫描、漏洞检测与签名验证。
|
||||
|
||||
## 安全扫描清单
|
||||
|
||||
@@ -306,89 +60,3 @@ RUN apk add curl
|
||||
| 最小能力 | 检查 `--cap-drop=all` |
|
||||
| 网络隔离 | 检查网络配置 |
|
||||
| 敏感信息 | 确认无硬编码密码 |
|
||||
|
||||
---
|
||||
|
||||
## 高级安全方案
|
||||
|
||||
### Seccomp 系统调用过滤
|
||||
|
||||
限制容器可以使用的系统调用:
|
||||
|
||||
```bash
|
||||
$ docker run --security-opt seccomp=/path/to/profile.json myapp
|
||||
```
|
||||
|
||||
### AppArmor / SELinux
|
||||
|
||||
使用强制访问控制:
|
||||
|
||||
```bash
|
||||
$ docker run --security-opt apparmor=docker-default myapp
|
||||
```
|
||||
|
||||
### 安全容器 (gVisor / Kata)
|
||||
|
||||
需要更强隔离时:
|
||||
|
||||
```bash
|
||||
## 使用 gVisor 运行时
|
||||
|
||||
$ docker run --runtime=runsc myapp
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 软件供应链安全
|
||||
|
||||
随着软件供应链攻击日益频繁,仅保障运行时安全已不足够。
|
||||
|
||||
### 1. SBOM (软件物料清单)
|
||||
|
||||
SBOM 类似于食品的配料表,列出了容器镜像中包含的所有软件包及其版本。
|
||||
|
||||
- **生成 SBOM**:使用 `docker buildx build --sbom` 或 `docker scout sbom`。
|
||||
- **管理 SBOM**:确保持续监控 SBOM 中的组件是否存在新披露的漏洞。
|
||||
|
||||
### 2. 镜像签名 (Sigstore / Notary v2)
|
||||
|
||||
确保镜像在构建后未被篡改,且确实来自可信的发布者。
|
||||
|
||||
- **Cosign**:Sigstore 项目的一部分,用于签署和验证容器镜像。
|
||||
```bash
|
||||
## 使用有写权限的仓库地址
|
||||
$ export IMAGE=<你的仓库地址>/myimage:tag
|
||||
$ docker pull nginx:1.27
|
||||
$ docker tag nginx:1.27 $IMAGE
|
||||
$ docker push $IMAGE
|
||||
|
||||
## 生成签名密钥(会生成 cosign.key / cosign.pub)
|
||||
$ cosign generate-key-pair
|
||||
|
||||
## 签署与验证镜像
|
||||
$ cosign sign --key cosign.key $IMAGE
|
||||
$ cosign verify --key cosign.pub $IMAGE
|
||||
```
|
||||
|
||||
### 3. SLSA (Supply-chain Levels for Software Artifacts)
|
||||
|
||||
遵循 SLSA 框架,确保构建过程的完整性,例如使用 GitHub Actions 等受控环境进行构建,而非在开发者本地机器上构建发布。
|
||||
|
||||
---
|
||||
|
||||
## 本章小结
|
||||
|
||||
| 安全措施 | 重要程度 | 实现方式 |
|
||||
|---------|---------|---------|
|
||||
| 非 root 运行 | ⭐⭐⭐ | `USER` 指令 |
|
||||
| 漏洞扫描 | ⭐⭐⭐ | `docker scout`, `trivy` |
|
||||
| 资源限制 | ⭐⭐⭐ | `-m`, `--cpus` |
|
||||
| 只读文件系统 | ⭐⭐ | `--read-only` |
|
||||
| 最小能力 | ⭐⭐ | `--cap-drop=all` |
|
||||
| 镜像签名 | ⭐⭐ | `cosign` / Notation |
|
||||
|
||||
## 延伸阅读
|
||||
|
||||
- [命名空间](../12_implementation/12.2_namespace.md):隔离机制详解
|
||||
- [控制组](../12_implementation/12.3_cgroups.md):资源限制详解
|
||||
- [最佳实践](../appendix/best_practices.md):Dockerfile 安全配置
|
||||
|
||||
@@ -5,3 +5,6 @@ Docker 的安全性依赖于多层隔离机制的协同工作,同时需要用
|
||||
总体来看,Docker 容器还是十分安全的,特别是在容器内不使用 root 权限来运行进程的话。
|
||||
|
||||
另外,用户可以使用现有工具,比如 [Apparmor](https://docs.docker.com/engine/security/apparmor/),[Seccomp](https://docs.docker.com/engine/security/seccomp/),SELinux,GRSEC 来增强安全性;甚至自己在内核中实现更复杂的安全机制。
|
||||
---
|
||||
|
||||
> 📝 **发现错误或有改进建议?** 欢迎提交 [Issue](https://github.com/yeasy/docker_practice/issues) 或 [PR](https://github.com/yeasy/docker_practice/pulls)。
|
||||
|
||||
@@ -89,7 +89,7 @@ services:
|
||||
- monitoring
|
||||
|
||||
cadvisor:
|
||||
image: gcr.io/cadvisor/cadvisor:latest
|
||||
image: ghcr.io/google/cadvisor:latest
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
|
||||
@@ -22,10 +22,11 @@ ELK (Elasticsearch,Logstash,Kibana) 是目前业界最流行的开源日志
|
||||
```yaml
|
||||
services:
|
||||
elasticsearch:
|
||||
image: docker.elastic.co/elasticsearch/elasticsearch:7.17.0
|
||||
image: docker.elastic.co/elasticsearch/elasticsearch:8.17.0
|
||||
container_name: elasticsearch
|
||||
environment:
|
||||
- "discovery.type=single-node"
|
||||
- "xpack.security.enabled=false"
|
||||
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
|
||||
ports:
|
||||
- "9200:9200"
|
||||
@@ -35,7 +36,7 @@ services:
|
||||
- logging
|
||||
|
||||
kibana:
|
||||
image: docker.elastic.co/kibana/kibana:7.17.0
|
||||
image: docker.elastic.co/kibana/kibana:8.17.0
|
||||
container_name: kibana
|
||||
environment:
|
||||
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
|
||||
@@ -47,7 +48,7 @@ services:
|
||||
- logging
|
||||
|
||||
fluentd:
|
||||
image: fluent/fluentd-kubernetes-daemonset:v1.14.3-debian-elasticsearch7-1.0
|
||||
image: fluent/fluentd-kubernetes-daemonset:v1.17-debian-elasticsearch8-1
|
||||
container_name: fluentd
|
||||
environment:
|
||||
- "FLUENT_ELASTICSEARCH_HOST=elasticsearch"
|
||||
|
||||
632
19_observability/19.3_performance_optimization.md
Normal file
632
19_observability/19.3_performance_optimization.md
Normal file
@@ -0,0 +1,632 @@
|
||||
## 19.3 容器性能优化与故障诊断
|
||||
|
||||
容器的轻量级特性不代表性能问题会自动消失。在实际运维中,性能瓶颈可能来自 CPU 限制、内存溢出、磁盘 I/O、网络拥塞等多个层面。本节深入讨论容器性能监控、诊断方法和优化策略。
|
||||
|
||||
### 19.3.1 容器性能监控指标
|
||||
|
||||
#### 核心性能指标体系
|
||||
|
||||
容器性能监控涉及以下关键指标:
|
||||
|
||||
**CPU 相关指标:**
|
||||
- `cpu.usage_usec`:容器 CPU 使用时间(微秒)
|
||||
- `cpu.stat.nr_throttled`:CPU 限流发生次数
|
||||
- `cpu.stat.throttled_usec`:CPU 限流总时间
|
||||
- `cpu_percent`:CPU 使用百分比
|
||||
- `cpu_quota`:CPU 配额设置(微秒)
|
||||
|
||||
**内存相关指标:**
|
||||
- `memory.usage_bytes`:当前内存使用量
|
||||
- `memory.max_usage_bytes`:内存使用峰值
|
||||
- `memory.limit_in_bytes`:内存限制
|
||||
- `memory.fail_cnt`:OOM(Out of Memory)失败次数
|
||||
- `memory.stat.cache`:页面缓存占用
|
||||
- `memory.stat.rss`:实际内存占用(RSS)
|
||||
- `memory.stat.swap`:SWAP 使用量
|
||||
|
||||
**网络相关指标:**
|
||||
- `rx_bytes`:接收字节数
|
||||
- `tx_bytes`:发送字节数
|
||||
- `rx_packets`:接收包数
|
||||
- `tx_packets`:发送包数
|
||||
- `rx_errors`:接收错误数
|
||||
- `tx_errors`:发送错误数
|
||||
- `rx_dropped`:接收丢包数
|
||||
- `tx_dropped`:发送丢包数
|
||||
|
||||
**I/O 相关指标:**
|
||||
- `io_service_bytes`:I/O 操作字节数
|
||||
- `io_service_time`:I/O 操作耗时
|
||||
- `io_queued`:I/O 队列长度
|
||||
- `fs_limit_bytes`:文件系统限制
|
||||
- `fs_usage_bytes`:文件系统使用量
|
||||
|
||||
### 19.3.2 使用 docker stats 实时监控
|
||||
|
||||
`docker stats` 是最基础但强大的监控工具,提供实时的容器资源使用情况。
|
||||
|
||||
**基本使用:**
|
||||
|
||||
```bash
|
||||
# 实时监控所有运行中的容器
|
||||
docker stats
|
||||
|
||||
# 输出示例:
|
||||
# CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O
|
||||
# abc123def456 nginx 0.45% 24.3 MiB / 256 MiB 9.49% 1.2kB / 3.4kB 0 B / 0 B
|
||||
# def789ghi012 redis 0.23% 12.5 MiB / 512 MiB 2.44% 2.1kB / 1.5kB 0 B / 0 B
|
||||
|
||||
# 只监控特定容器
|
||||
docker stats nginx redis
|
||||
|
||||
# 一次性输出不进入交互模式
|
||||
docker stats --no-stream
|
||||
|
||||
# 指定刷新间隔(单位:秒,默认 1 秒)
|
||||
docker stats --no-stream --interval 2
|
||||
|
||||
# 格式化输出(使用 Go 模板)
|
||||
docker stats --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}" --no-stream
|
||||
|
||||
# 导出为 JSON 格式用于日志记录
|
||||
docker stats --format json --no-stream > stats.json
|
||||
```
|
||||
|
||||
**在脚本中使用:**
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# 持续监控并记录到文件
|
||||
while true; do
|
||||
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
docker stats --no-stream --format "{{.Container}},{{.CPUPerc}},{{.MemUsage}}" | \
|
||||
awk -v ts="$timestamp" '{print ts","$0}' >> container_stats.log
|
||||
sleep 10
|
||||
done
|
||||
```
|
||||
|
||||
**性能指标解读:**
|
||||
|
||||
```bash
|
||||
# CPU % 超过 80%:需要增加 CPU 限制或优化应用
|
||||
# MEM % 接近 100%:容器即将 OOM,需要增加内存或排查内存泄漏
|
||||
# 如果 NET I/O 中 dropped 为非零:网络拥塞或丢包
|
||||
```
|
||||
|
||||
### 19.3.3 cAdvisor 容器监控系统
|
||||
|
||||
cAdvisor 是 Google 开发的容器监控工具,提供比 `docker stats` 更详细的性能数据。
|
||||
|
||||
**Docker Compose 部署 cAdvisor:**
|
||||
|
||||
```yaml
|
||||
services:
|
||||
cadvisor:
|
||||
image: ghcr.io/google/cadvisor:v0.51.0
|
||||
container_name: cadvisor
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- /:/rootfs:ro
|
||||
- /var/run:/var/run:ro
|
||||
- /sys:/sys:ro
|
||||
- /var/lib/docker/:/var/lib/docker:ro
|
||||
- /dev/disk/:/dev/disk:ro
|
||||
privileged: true
|
||||
devices:
|
||||
- /dev/kmsg
|
||||
networks:
|
||||
- monitoring
|
||||
|
||||
networks:
|
||||
monitoring:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
启动后访问 `http://localhost:8080` 查看:
|
||||
- 容器性能统计
|
||||
- 系统资源使用情况
|
||||
- 历史性能数据
|
||||
|
||||
**从 cAdvisor 提取指标:**
|
||||
|
||||
```bash
|
||||
# 获取所有容器的 JSON 格式性能数据
|
||||
curl http://localhost:8080/api/v1.3/machine | jq .
|
||||
|
||||
# 获取特定容器信息
|
||||
curl http://localhost:8080/api/v1.3/docker | jq '.docker | keys' | head -5
|
||||
|
||||
# 获取容器统计信息
|
||||
curl http://localhost:8080/api/v1.3/docker/abc123/ | jq '.stats[-1]'
|
||||
```
|
||||
|
||||
**与 Prometheus 集成:**
|
||||
|
||||
```yaml
|
||||
# prometheus.yml 配置
|
||||
global:
|
||||
scrape_interval: 15s
|
||||
|
||||
scrape_configs:
|
||||
- job_name: 'cadvisor'
|
||||
static_configs:
|
||||
- targets: ['localhost:8080']
|
||||
metrics_path: '/metrics'
|
||||
```
|
||||
|
||||
### 19.3.4 Prometheus 容器监控配置
|
||||
|
||||
使用 Prometheus 和 node-exporter 进行长期的容器性能监控。
|
||||
|
||||
**完整监控栈部署:**
|
||||
|
||||
```yaml
|
||||
services:
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
container_name: prometheus
|
||||
ports:
|
||||
- "9090:9090"
|
||||
volumes:
|
||||
- ./prometheus.yml:/etc/prometheus/prometheus.yml
|
||||
- prometheus_data:/prometheus
|
||||
command:
|
||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||
- '--storage.tsdb.path=/prometheus'
|
||||
- '--storage.tsdb.retention.time=30d'
|
||||
networks:
|
||||
- monitoring
|
||||
|
||||
node-exporter:
|
||||
image: prom/node-exporter:latest
|
||||
container_name: node-exporter
|
||||
ports:
|
||||
- "9100:9100"
|
||||
volumes:
|
||||
- /proc:/host/proc:ro
|
||||
- /sys:/host/sys:ro
|
||||
- /:/rootfs:ro
|
||||
command:
|
||||
- '--path.procfs=/host/proc'
|
||||
- '--path.sysfs=/host/sys'
|
||||
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
|
||||
networks:
|
||||
- monitoring
|
||||
|
||||
cadvisor:
|
||||
image: ghcr.io/google/cadvisor:v0.51.0
|
||||
container_name: cadvisor
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- /:/rootfs:ro
|
||||
- /var/run:/var/run:ro
|
||||
- /sys:/sys:ro
|
||||
- /var/lib/docker/:/var/lib/docker:ro
|
||||
privileged: true
|
||||
networks:
|
||||
- monitoring
|
||||
|
||||
grafana:
|
||||
image: grafana/grafana:latest
|
||||
container_name: grafana
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- GF_SECURITY_ADMIN_PASSWORD=admin
|
||||
- GF_INSTALL_PLUGINS=grafana-piechart-panel
|
||||
volumes:
|
||||
- grafana_data:/var/lib/grafana
|
||||
networks:
|
||||
- monitoring
|
||||
|
||||
volumes:
|
||||
prometheus_data:
|
||||
grafana_data:
|
||||
|
||||
networks:
|
||||
monitoring:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
**Prometheus 配置文件(prometheus.yml):**
|
||||
|
||||
```yaml
|
||||
global:
|
||||
scrape_interval: 15s
|
||||
evaluation_interval: 15s
|
||||
|
||||
scrape_configs:
|
||||
- job_name: 'prometheus'
|
||||
static_configs:
|
||||
- targets: ['localhost:9090']
|
||||
|
||||
- job_name: 'node-exporter'
|
||||
static_configs:
|
||||
- targets: ['node-exporter:9100']
|
||||
|
||||
- job_name: 'cadvisor'
|
||||
static_configs:
|
||||
- targets: ['cadvisor:8080']
|
||||
|
||||
- job_name: 'docker'
|
||||
static_configs:
|
||||
- targets: ['localhost:9323']
|
||||
```
|
||||
|
||||
**常用的 Prometheus 查询(PromQL):**
|
||||
|
||||
```promql
|
||||
# 容器 CPU 使用百分比
|
||||
rate(container_cpu_usage_seconds_total[5m]) * 100
|
||||
|
||||
# 容器内存使用百分比
|
||||
(container_memory_usage_bytes / container_spec_memory_limit_bytes) * 100
|
||||
|
||||
# 容器网络入站流量(MB/s)
|
||||
rate(container_network_receive_bytes_total[5m]) / 1024 / 1024
|
||||
|
||||
# 容器网络出站流量(MB/s)
|
||||
rate(container_network_transmit_bytes_total[5m]) / 1024 / 1024
|
||||
|
||||
# 容器磁盘读取速率(MB/s)
|
||||
rate(container_fs_io_current[5m]) / 1024 / 1024
|
||||
|
||||
# CPU 限流情况
|
||||
rate(container_cpu_cfs_throttled_seconds_total[5m])
|
||||
|
||||
# 内存缓存占比
|
||||
container_memory_cache_bytes / container_memory_usage_bytes
|
||||
|
||||
# 按镜像统计容器数
|
||||
count(container_memory_usage_bytes) by (image)
|
||||
```
|
||||
|
||||
### 19.3.5 容器 OOM 排查与内存限制调优
|
||||
|
||||
#### OOM 问题诊断
|
||||
|
||||
```bash
|
||||
# 检查容器是否因 OOM 被杀死
|
||||
docker inspect <container_id> | grep OOMKilled
|
||||
|
||||
# 查看容器退出码:137 表示被 OOM 杀死
|
||||
docker ps -a --format "{{.ID}}\t{{.Status}}" | grep "137"
|
||||
|
||||
# 查看容器日志中的 OOM 信息
|
||||
docker logs <container_id> 2>&1 | grep -i "out of memory\|oom"
|
||||
|
||||
# 从宿主机日志查看 OOM 事件
|
||||
dmesg | grep -i "oom\|kill"
|
||||
journalctl -u docker -n 100 | grep -i "oom"
|
||||
```
|
||||
|
||||
#### 内存泄漏检测
|
||||
|
||||
使用专项工具分析应用内存使用:
|
||||
|
||||
**Python 应用内存泄漏检测:**
|
||||
|
||||
```python
|
||||
# Dockerfile
|
||||
FROM python:3.11-slim
|
||||
WORKDIR /app
|
||||
COPY requirements.txt .
|
||||
RUN pip install -r requirements.txt memory_profiler tracemalloc
|
||||
|
||||
COPY app.py .
|
||||
CMD ["python", "-m", "memory_profiler", "app.py"]
|
||||
```
|
||||
|
||||
```python
|
||||
# app.py - 内存泄漏示例
|
||||
from memory_profiler import profile
|
||||
import tracemalloc
|
||||
|
||||
@profile
|
||||
def memory_leak():
|
||||
# 不断创建未释放的列表
|
||||
data = []
|
||||
while True:
|
||||
data.append([0] * 1000000)
|
||||
print(f"List size: {len(data)}")
|
||||
|
||||
# 使用 tracemalloc 跟踪内存分配
|
||||
tracemalloc.start()
|
||||
|
||||
# 执行可能泄漏的代码
|
||||
# ...
|
||||
|
||||
current, peak = tracemalloc.get_traced_memory()
|
||||
print(f"Current: {current / 1024 / 1024:.2f} MB")
|
||||
print(f"Peak: {peak / 1024 / 1024:.2f} MB")
|
||||
```
|
||||
|
||||
**Java 应用内存分析:**
|
||||
|
||||
```bash
|
||||
# 在容器中启用 JVM 远程调试
|
||||
docker run -e JAVA_OPTS="-Xmx512m -Xms256m -XX:+UseG1GC" \
|
||||
-p 5005:5005 \
|
||||
myapp:latest
|
||||
|
||||
# 使用 jstat 检查垃圾回收情况
|
||||
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
|
||||
# 为容器设置内存限制
|
||||
docker run -m 512m --memory-swap 1g myapp:latest
|
||||
|
||||
# 参数说明:
|
||||
# -m / --memory:内存限制(这里是 512MB)
|
||||
# --memory-swap:内存+SWAP 总额(这里是 1GB,意味着 SWAP 为 512MB)
|
||||
# 如果不设置 --memory-swap,则等于 --memory 值
|
||||
|
||||
# Docker Compose 配置
|
||||
services:
|
||||
app:
|
||||
image: myapp:latest
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 512M
|
||||
reservations:
|
||||
memory: 256M
|
||||
```
|
||||
|
||||
**内存超额提交(Memory Overcommit):**
|
||||
|
||||
```bash
|
||||
# 在 Docker Compose 中区分限制和预留
|
||||
# limits:绝不能超过的最大值
|
||||
# reservations:Compose 排期时的参考值
|
||||
|
||||
services:
|
||||
web:
|
||||
memory: 512M # 限制
|
||||
memswap_limit: 1G # SWAP 限制
|
||||
|
||||
db:
|
||||
memory: 2G
|
||||
memory_reservation: 1G # 预留 1GB,允许突发到 2GB
|
||||
```
|
||||
|
||||
### 19.3.6 镜像体积优化与多阶段构建
|
||||
|
||||
#### 镜像体积分析工具
|
||||
|
||||
**使用 dive 分析镜像层:**
|
||||
|
||||
```bash
|
||||
# 安装 dive
|
||||
wget https://github.com/wagoodman/dive/releases/download/v0.11.0/dive_0.11.0_linux_amd64.deb
|
||||
sudo apt install ./dive_0.11.0_linux_amd64.deb
|
||||
|
||||
# 分析镜像
|
||||
dive myapp:latest
|
||||
|
||||
# 输出详细的分层信息,显示每一层的大小和内容
|
||||
```
|
||||
|
||||
**使用 Dockerfile 分析工具:**
|
||||
|
||||
```bash
|
||||
# 安装 hadolint
|
||||
curl https://github.com/hadolint/hadolint/releases/download/v2.12.0/hadolint-Linux-x86_64 -L -o hadolint
|
||||
chmod +x hadolint
|
||||
|
||||
# 检查 Dockerfile 最佳实践
|
||||
./hadolint Dockerfile
|
||||
```
|
||||
|
||||
#### 多阶段构建最佳实践
|
||||
|
||||
**Go 应用的最小化镜像构建:**
|
||||
|
||||
```dockerfile
|
||||
# Stage 1: 构建阶段
|
||||
FROM golang:1.20-alpine AS builder
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# 安装依赖
|
||||
RUN apk add --no-cache git ca-certificates tzdata
|
||||
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
COPY . .
|
||||
|
||||
# 构建静态二进制(支持 scratch 基础镜像)
|
||||
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
|
||||
-a -installsuffix cgo \
|
||||
-ldflags="-w -s" \
|
||||
-o app .
|
||||
|
||||
# Stage 2: 运行阶段
|
||||
FROM scratch
|
||||
|
||||
# 从 builder 复制必要的文件
|
||||
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
|
||||
COPY --from=builder /build/app /app
|
||||
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["/app"]
|
||||
|
||||
# 最终镜像大小通常 < 15MB(相比 golang:1.20-alpine 的 ~1GB)
|
||||
```
|
||||
|
||||
**Node.js 应用的多阶段构建:**
|
||||
|
||||
```dockerfile
|
||||
# Stage 1: 依赖安装
|
||||
FROM node:18-alpine AS dependencies
|
||||
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm ci --only=production && \
|
||||
npm cache clean --force
|
||||
|
||||
# Stage 2: 构建阶段
|
||||
FROM node:18-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
# Stage 3: 运行阶段
|
||||
FROM node:18-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# 从依赖阶段复制 node_modules
|
||||
COPY --from=dependencies /app/node_modules ./node_modules
|
||||
# 从构建阶段复制构建产物
|
||||
COPY --from=builder /app/dist ./dist
|
||||
COPY --from=builder /app/package*.json ./
|
||||
|
||||
# 删除开发依赖和不必要的文件
|
||||
RUN rm -rf src tests *.config.js
|
||||
|
||||
USER node
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["node", "dist/index.js"]
|
||||
|
||||
# 镜像大小对比:
|
||||
# 不优化:~500MB
|
||||
# 多阶段构建后:~120MB(减少 76%)
|
||||
```
|
||||
|
||||
**Python 应用的多阶段构建:**
|
||||
|
||||
```dockerfile
|
||||
# Stage 1: 构建阶段
|
||||
FROM python:3.11-slim AS builder
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
&& rm -rf /var/apt/lists/*
|
||||
|
||||
COPY requirements.txt .
|
||||
RUN pip install --user --no-cache-dir -r requirements.txt
|
||||
|
||||
# Stage 2: 运行阶段
|
||||
FROM python:3.11-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# 从 builder 复制虚拟环境
|
||||
COPY --from=builder /root/.local /root/.local
|
||||
|
||||
# 设置 PATH
|
||||
ENV PATH=/root/.local/bin:$PATH \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
PYTHONDONTWRITEBYTECODE=1
|
||||
|
||||
COPY . .
|
||||
|
||||
USER nobody
|
||||
EXPOSE 5000
|
||||
|
||||
CMD ["python", "app.py"]
|
||||
```
|
||||
|
||||
#### 镜像体积优化检查清单
|
||||
|
||||
```bash
|
||||
# 检查清单
|
||||
□ 使用精简基础镜像(Alpine、Distroless)
|
||||
□ 清理包管理器缓存(apt-get clean、rm -rf /var/cache/*)
|
||||
□ 在同一 RUN 指令中安装和清理依赖
|
||||
□ 使用 .dockerignore 排除不必要的文件
|
||||
□ 多阶段构建避免构建依赖污染最终镜像
|
||||
□ 去除调试符号:-ldflags="-w -s"(Go)、strip 命令(C/C++)
|
||||
□ 压缩静态资源和应用文件
|
||||
□ 使用 BuildKit 缓存优化加速构建
|
||||
|
||||
# 优化示例:
|
||||
FROM ubuntu:22.04
|
||||
|
||||
# ❌ 不推荐
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y curl wget git
|
||||
RUN apt-get clean
|
||||
|
||||
# ✓ 推荐
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
curl \
|
||||
wget \
|
||||
git && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
```
|
||||
|
||||
### 19.3.7 常见性能问题及解决方案
|
||||
|
||||
**问题 1: 容器频繁被 OOM 杀死**
|
||||
|
||||
症状:容器进程被无故杀死,exit code 137
|
||||
解决方案:
|
||||
```bash
|
||||
# 增加内存限制
|
||||
docker update -m 1g <container_id>
|
||||
|
||||
# 排查内存泄漏
|
||||
docker exec <container_id> ps aux | grep -E "VSZ|RSS"
|
||||
|
||||
# 使用 docker stats 实时监控
|
||||
docker stats <container_id>
|
||||
|
||||
# 启用内存交换(作为最后手段)
|
||||
docker run -m 512m --memory-swap 1g myapp:latest
|
||||
```
|
||||
|
||||
**问题 2: CPU 被限流(CPU Throttling)**
|
||||
|
||||
症状:应用性能突然下降,但 CPU 使用率不高
|
||||
诊断:
|
||||
```bash
|
||||
# 查看 CPU 限流统计
|
||||
docker exec <container_id> cat /sys/fs/cgroup/cpu/cpu.stat
|
||||
|
||||
# 如果 throttled_time > 0,说明发生了 CPU 限流
|
||||
# 解决方案:增加 CPU 限制
|
||||
docker update --cpus 2 <container_id>
|
||||
```
|
||||
|
||||
**问题 3: 网络丢包或延迟高**
|
||||
|
||||
诊断:
|
||||
```bash
|
||||
# 进入容器检查网络状态
|
||||
docker exec <container_id> ip -s link show
|
||||
|
||||
# 检查路由和 DNS
|
||||
docker exec <container_id> cat /etc/resolv.conf
|
||||
|
||||
# 测试网络延迟
|
||||
docker exec <container_id> ping 8.8.8.8
|
||||
|
||||
# 检查容器网络驱动
|
||||
docker inspect <container_id> | grep -A 10 NetworkSettings
|
||||
|
||||
# 解决方案:更换网络驱动或调整 MTU
|
||||
docker run --net=host myapp:latest # 使用宿主机网络(性能最佳)
|
||||
```
|
||||
@@ -9,9 +9,20 @@
|
||||
- **容器监控**:以 Prometheus 为主,讲解如何采集和展示容器性能指标。
|
||||
- **日志管理**:以 ELK (Elasticsearch, Logstash, Kibana) 套件为例,介绍集中式日志收集平台。
|
||||
|
||||
为了让读者能够在生产环境中真正用起来,本章会补齐以下“最小闭环”:
|
||||
为了让读者能够在生产环境中真正用起来,本章会补齐以下”最小闭环”:
|
||||
|
||||
* 关键指标与日志的验证方法
|
||||
* 常见故障排查路径
|
||||
* 最小告警闭环 (Prometheus -> Alertmanager -> 接收端)
|
||||
* 日志容量治理的最小实践
|
||||
|
||||
## 本章内容
|
||||
|
||||
* [Prometheus 监控](19.1_prometheus.md)
|
||||
* 容器监控基础、指标采集与告警配置。
|
||||
|
||||
* [ELK 日志管理](19.2_elk.md)
|
||||
* 集中式日志收集、存储与检索。
|
||||
|
||||
* [性能优化](19.3_performance_optimization.md)
|
||||
* 容器和应用性能优化实践。
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
* **指标监控**:以 Prometheus + Grafana 为主,完成指标采集、存储与可视化。
|
||||
* **日志管理**:以 EFK/ELK 为例,完成容器日志的集中采集、检索与分析。
|
||||
|
||||
生产环境中,建议将“可观测性”当成一个完整闭环:**采集 -> 存储 -> 展示 -> 告警 -> 排错 -> 容量治理**。
|
||||
生产环境中,建议将”可观测性”当成一个完整闭环:**采集 -> 存储 -> 展示 -> 告警 -> 排错 -> 容量治理**。
|
||||
|
||||
## 19.3 Docker 日志驱动
|
||||
## 扩展阅读:Docker 日志驱动
|
||||
|
||||
Docker 提供了多种日志驱动 (Log Driver),用于将容器标准输出的日志转发到不同后端。
|
||||
|
||||
@@ -47,3 +47,6 @@ Docker 提供了多种日志驱动 (Log Driver),用于将容器标准输出的
|
||||
* Elasticsearch 数据目录已持久化,并有明确的日志保留周期与容量上限策略。
|
||||
* Kibana 能查询到最新日志;当 UI 异常时能用 Elasticsearch API 验证入库。
|
||||
* 可观测性组件未直接暴露到公网,访问已加鉴权或置于内网。
|
||||
---
|
||||
|
||||
> 📝 **发现错误或有改进建议?** 欢迎提交 [Issue](https://github.com/yeasy/docker_practice/issues) 或 [PR](https://github.com/yeasy/docker_practice/pulls)。
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user