mirror of
https://github.com/yeasy/docker_practice.git
synced 2026-03-11 12:21:17 +00:00
103 lines
4.0 KiB
Go
103 lines
4.0 KiB
Go
## 18.2 控制组
|
||
|
||
控制组 (Cgroups) 是 Linux 容器机制的另外一个关键组件。如果说命名空间 (Namespace) 决定了容器能 **看到** 什么,那么控制组就决定了容器能 **使用** 多少资源。
|
||
|
||
在安全领域中,资源的不可用性本身就是一种安全威胁。控制组负责实现资源的审计和限制,这对于抵御资源耗尽型攻击(如拒绝服务攻击 DoS)至关重要。
|
||
|
||
### 18.2.1 为什么资源限制关乎安全?
|
||
|
||
默认情况下,Docker 容器对系统资源的使用是没有限制的:一个容器理论上可以使用宿主机所有的 CPU 计算能力、吃光所有的内存、耗尽所有的系统 PID。
|
||
|
||
想象一下以下场景:
|
||
- 一个恶意用户向你暴露在公网的应用发起海量并发请求。
|
||
- 应用程序逻辑中存在内存泄漏漏洞。
|
||
- 黑客在入侵容器后,在里面运行了挖矿木马程序。
|
||
|
||
如果没有 Cgroups 的限制,某个容器内的异常行为(或恶意攻击)将会榨干宿主机的资源,导致宿主机上其他健康的容器甚至 Docker 守护进程自身因为 OOM(Out Of Memory)崩溃或 CPU 饥饿而停止响应。
|
||
|
||
### 18.2.2 核心资源限制实战
|
||
|
||
为了确保多租户平台(如公有或私有的 PaaS 平台)的稳定性,或者在生产环境防止服务级联故障,我们要养成在启动容器时 **显式声明资源上限** 的习惯。
|
||
|
||
#### 1. 内存限制
|
||
|
||
限制内存可以防止应用程序因内存泄漏或恶意载荷导致宿主机 OOM。
|
||
|
||
**关键参数:**
|
||
- `-m, --memory=""`:硬限制,容器可使用的最大内存量。
|
||
- `--memory-swap=""`:限制容器可使用的内存与 Swap 总量。
|
||
|
||
**实战示例:**
|
||
|
||
限制容器最多只能使用 512MB 内存,并且禁用 Swap(将 memory 和 memory-swap 设置成一样的值即可):
|
||
|
||
```bash
|
||
$ docker run -d \
|
||
--name web_app \
|
||
--memory="512m" \
|
||
--memory-swap="512m" \
|
||
nginx:alpine
|
||
```
|
||
|
||
如果该容器内的应用尝试分配超过 512MB 的内存,该进程将会被内核的 OOM Killer 杀掉,但绝不会波及到宿主机的其他部分。
|
||
|
||
#### 2. CPU 限制
|
||
|
||
限制 CPU 可以防止个别计算密集型的容器垄断 CPU 时间片,保证系统的调度公平性。
|
||
|
||
**关键参数:**
|
||
- `--cpus=<value>`:指定容器可以使用的 CPU 核心数量(可以是小数)。
|
||
- `-c, --cpu-shares=0`:软限制,设置容器使用 CPU 的相对权重(默认是 1024)。
|
||
|
||
**实战示例:**
|
||
|
||
限制容器最多使用 1.5 个 CPU 核心的算力:
|
||
|
||
```bash
|
||
$ docker run -d \
|
||
--name worker_app \
|
||
--cpus="1.5" \
|
||
busybox \
|
||
md5sum /dev/urandom
|
||
```
|
||
|
||
即使上面的命令是一个死循环的哈希计算进程,容器也永远无法吃满双核 CPU 系统的全部算力。
|
||
|
||
#### 3. 进程数限制
|
||
|
||
进程炸弹(Fork Bomb)是一种典型的拒绝服务攻击方式,它通过不断 `fork()` 新进程来耗尽系统的进程表条目,导致系统无法创建任何新任务。
|
||
|
||
**关键参数:**
|
||
- `--pids-limit=<number>`:限制容器内允许创建的最大进程数。
|
||
|
||
**实战示例:**
|
||
|
||
一个常规的 Web 服务进程数通常在几十到上百之间。我们可以设定一个合理的上限来防范 Fork 炸弹:
|
||
|
||
```bash
|
||
$ docker run -d \
|
||
--name app_service \
|
||
--pids-limit=100 \
|
||
python:alpine python app.py
|
||
```
|
||
|
||
当容器内的进程总数达到 100 时,任何尝试派生新进程的操作都会失败并返回 `Resource temporarily unavailable`,从而挫败相关的攻击行为。
|
||
|
||
### 18.2.3 最佳实践建议
|
||
|
||
在生产环境中,不仅要在单机使用 Docker 命令时设置这些参数,更应当在集群编排工具中将资源配额制度化。
|
||
|
||
例如,在 Kubernetes 中,强烈建议为每个 Pod 设置 `requests` 和 `limits`:
|
||
|
||
```yaml
|
||
resources:
|
||
requests:
|
||
memory: "256Mi"
|
||
cpu: "250m"
|
||
limits:
|
||
memory: "512Mi"
|
||
cpu: "500m"
|
||
```
|
||
|
||
通过 Cgroups 的资源边界控制,你可以从根本上切断一条导致整个系统雪崩的脆弱链路。这也进一步使得 Docker 以及容器技术成为了现代高可用服务的基础设施首选。
|