📚前言
👀回顾,系统学习docker系列已发布内容:
【docker基础】第三课:镜像管理与Dockerfile基础
【docker基础】第五课:Docker网络详解-CSDN博客
【docker基础】第六课:Web应用与数据库容器部署-CSDN博客
【docker基础】 第七课:Docker Compose 多容器实战-CSDN博客
【docker基础】 第八周:容器监控与应用更新策略-CSDN博客
🔗相关文档:
【docker基础】Ubuntu 安装 Docker 超详细小白教程
📒本课学习目标:
- Docker 安全 :非特权用户、官方镜像、资源限制、网络隔离
- 镜像扫描 :使用 Docker scan 和 Trivy 检查漏洞
- 镜像优化 :多阶段构建、使用 alpine、合并命令、清理文件
- 安全加固 :只读模式、能力限制、隔离网络
🌍Docker第九周:Docker安全与镜像优化
欢迎来到 Docker 第九周的学习!本周我们将深入学习 Docker 的高级特性,包括容器安全最佳实践和镜像优化技巧。
第一章:Docker 安全基础
1.1 为什么容器安全很重要
容器虽然提供了隔离性,但并非绝对安全。以下是常见的安全风险:
- 容器逃逸:攻击者从容器内部突破到宿主机
- 恶意镜像:使用了包含恶意代码的镜像
- 权限过大:容器以 root 用户运行
- 网络攻击:容器之间或外部网络的攻击
1.2 容器安全最佳实践
1.2.1 避免使用 root 用户
问题:默认情况下,容器以 root 用户运行,这很危险。
解决方案:在 Dockerfile 中创建非特权用户
FROM nginx:latest
# 创建非特权用户
RUN useradd -m appuser
# 切换到非特权用户
USER appuser
# 后续命令将以 appuser 身份执行
CMD ["nginx", "-g", "daemon off;"]
验证:
docker exec -it mycontainer whoami
# 输出: appuser
1.2.2 使用官方镜像
问题:第三方镜像可能包含恶意代码或漏洞。
解决方案:
-
使用 Docker Hub 官方认证的镜像
-
优先选择带有
OFFICIAL标签的镜像正确:使用官方镜像
docker pull nginx:latest
避免:使用不明来源的镜像
docker pull randomuser/nginx:latest
1.2.3 限制容器资源
问题:容器可能占用过多资源,影响其他容器或宿主机。
解决方案:使用资源限制参数
docker run -d \
--name myapp \
--memory=512m \
--cpus=1 \
--memory-swap=1g \
nginx
参数说明:
| 参数 | 说明 |
|---|---|
--memory |
限制内存使用(如 512m) |
--cpus |
限制 CPU 使用(如 1 表示1个核心) |
--memory-swap |
限制交换内存 |
--pids-limit |
限制进程数量 |
1.2.4 限制容器网络
问题:容器可能被允许访问不必要的网络资源。
解决方案:
-
使用自定义网络隔离容器
-
限制容器的网络访问
创建隔离网络
docker network create --internal secure-network
运行容器在隔离网络中
docker run -d --network secure-network --name isolated-app nginx
1.2.5 定期更新镜像
问题:镜像中可能包含已知的安全漏洞。
解决方案:定期更新基础镜像
# 更新镜像
docker pull nginx:latest
# 重新构建应用镜像
docker build -t myapp:latest .
第二章:镜像安全扫描
2.1 什么是镜像扫描
镜像扫描是检查 Docker 镜像中安全漏洞的过程。
2.2 使用 Docker 内置扫描工具
# 扫描镜像
docker scan myapp:latest
输出示例:
Testing myapp:latest...
✗ HIGH CVE-2021-3156: sudo vulnerability
Package: sudo
Version: 1.8.31-1ubuntu1.2
Severity: HIGH
URL: https://security.snyk.io/vuln/SNYK-UBUNTU2004-SUDO-1583796
✗ MEDIUM CVE-2021-23214: systemd vulnerability
Package: systemd
Version: 245.4-4ubuntu3.1
Severity: MEDIUM
URL: https://security.snyk.io/vuln/SNYK-UBUNTU2004-SYSTEMD-1583795
✓ No critical issues found
2.3 使用第三方扫描工具
Trivy(推荐):
# 安装 Trivy
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy:0.19.0 image myapp:latest
输出示例:
2021-06-01T12:00:00.000+0000 INFO Detected OS: ubuntu
2021-06-01T12:00:00.000+0000 INFO Detecting Ubuntu vulnerabilities...
2021-06-01T12:00:00.000+0000 INFO Number of PLUGINS: 0
2021-06-01T12:00:00.000+0000 INFO Number of vulnerabilities: 5
+------------------+------------------+----------+-------------------+---------------+---------------------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
+------------------+------------------+----------+-------------------+---------------+---------------------------------------+
| sudo | CVE-2021-3156 | HIGH | 1.8.31-1ubuntu1.2 | 1.8.31-1ubuntu1.3 | sudo heap-based buffer overflow |
| systemd | CVE-2021-23214 | MEDIUM | 245.4-4ubuntu3.1 | 245.4-4ubuntu3.2 | systemd out-of-bounds write |
+------------------+------------------+----------+-------------------+---------------+---------------------------------------+
第三章:Docker 镜像优化
3.1 为什么需要优化镜像
- 减少存储空间:更小的镜像占用更少的磁盘空间
- 加快传输速度:更小的镜像下载更快
- 提高安全性:更小的镜像意味着更少的攻击面
3.2 镜像优化技巧
3.2.1 使用多阶段构建
原理 :在一个 Dockerfile 中使用多个 FROM 指令,只保留最终需要的文件。
示例:
# 第一阶段:构建阶段
FROM node:14 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
# 第二阶段:运行阶段
FROM nginx:alpine
# 从构建阶段复制产物
COPY --from=builder /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
效果:
- 构建阶段包含 Node.js 环境(约 1GB)
- 运行阶段只包含 Nginx(约 20MB)
- 最终镜像大小约 20MB
3.2.2 使用更小的基础镜像
对比:
| 镜像 | 大小 | 说明 |
|---|---|---|
ubuntu:latest |
~72MB | 完整的 Ubuntu 系统 |
alpine:latest |
~5MB | 最小的 Linux 发行版 |
debian:latest |
~114MB | 完整的 Debian 系统 |
node:14 |
~900MB | 包含 Node.js 的完整系统 |
node:14-alpine |
~100MB | 基于 Alpine 的 Node.js |
建议 :优先使用 alpine 版本的镜像
# 不好:使用完整镜像
FROM node:14
# 好:使用 alpine 版本
FROM node:14-alpine
3.2.3 合并 RUN 命令
问题 :每个 RUN 命令都会创建一个新的镜像层。
解决方案 :使用 && 合并多个命令
# 不好:多个 RUN 命令
RUN apt-get update
RUN apt-get install -y nginx
RUN apt-get clean
# 好:合并为一个 RUN 命令
RUN apt-get update && \
apt-get install -y nginx && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
3.2.4 使用 .dockerignore 文件
问题:构建上下文可能包含不必要的文件。
解决方案 :创建 .dockerignore 文件
# .dockerignore 文件内容
node_modules/
.git/
.vscode/
*.log
.env
build/
dist/
3.2.5 使用 COPY 代替 ADD
问题 :ADD 会自动解压文件,可能导致意外行为。
解决方案 :优先使用 COPY
# 不好:使用 ADD
ADD app.tar.gz /app
# 好:使用 COPY
COPY app.tar.gz /app
RUN tar -xzf /app/app.tar.gz -C /app
3.2.6 清理不必要的文件
FROM ubuntu:20.04
RUN apt-get update && \
apt-get install -y nginx && \
# 清理 apt 缓存
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
# 删除不必要的文件
rm -rf /usr/share/doc && \
rm -rf /usr/share/man
第四章:Docker 安全加固实战
4.1 创建安全的 Dockerfile
# 使用最小基础镜像
FROM alpine:3.14
# 创建非特权用户
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# 安装必要的依赖
RUN apk update && \
apk add --no-cache nginx && \
rm -rf /var/cache/apk/*
# 配置 Nginx
COPY nginx.conf /etc/nginx/nginx.conf
COPY index.html /usr/share/nginx/html/
# 设置文件权限
RUN chown -R appuser:appgroup /usr/share/nginx/html
# 切换到非特权用户
USER appuser
# 暴露端口
EXPOSE 8080
# 健康检查
HEALTHCHECK --interval=5s --timeout=3s \
CMD wget -qO- http://localhost:8080 || exit 1
# 启动命令
CMD ["nginx", "-g", "daemon off;"]
4.2 运行安全的容器
docker run -d \
--name secure-app \
--user appuser \
--memory=256m \
--cpus=0.5 \
--read-only \
--tmpfs /run \
--tmpfs /tmp \
--cap-drop=ALL \
--network=secure-network \
secure-app:latest
参数说明:
| 参数 | 说明 |
|---|---|
--user |
指定运行用户 |
--read-only |
以只读模式运行容器 |
--tmpfs |
创建临时文件系统 |
--cap-drop=ALL |
移除所有 Linux 能力 |
--network |
指定隔离网络 |
第五章:镜像优化实战
5.1 优化前后对比
优化前的 Dockerfile:
FROM node:14
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]
优化后的 Dockerfile:
# 构建阶段
FROM node:14-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
# 运行阶段
FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
5.2 构建并验证
# 构建优化前的镜像
docker build -t myapp-before .
# 构建优化后的镜像
docker build -t myapp-after -f Dockerfile.optimized .
# 查看镜像大小
docker images | grep myapp
预期结果:
REPOSITORY TAG IMAGE ID SIZE
myapp-before latest abc123def456 900MB
myapp-after latest ghi789jkl012 25MB
第六章:Docker Security 命令汇总
6.1 安全相关命令
| 命令 | 说明 |
|---|---|
docker scan |
扫描镜像中的安全漏洞 |
docker run --user |
指定容器运行用户 |
docker run --read-only |
以只读模式运行容器 |
docker run --cap-drop |
移除 Linux 能力 |
docker network create --internal |
创建隔离网络 |
6.2 镜像优化命令
| 命令 | 说明 |
|---|---|
docker build --no-cache |
不使用缓存构建镜像 |
docker images |
查看镜像大小 |
docker history |
查看镜像历史 |
docker save |
保存镜像到文件 |
docker import |
从文件导入镜像 |
第七章:常见问题与解决方案
7.1 问题:容器需要 root 权限
解决方案:
-
尽可能使用非特权用户
-
如果必须使用 root,限制容器的能力
docker run -d
--cap-drop=ALL
--cap-add=NET_BIND_SERVICE
nginx
7.2 问题:镜像扫描发现漏洞
解决方案:
- 更新基础镜像
- 更新依赖包
- 使用更小的基础镜像
7.3 问题:镜像太大
解决方案:
- 使用多阶段构建
- 使用 alpine 镜像
- 清理不必要的文件
本周总结
本周我们学习了:
- Docker 安全:非特权用户、官方镜像、资源限制、网络隔离
- 镜像扫描:使用 Docker scan 和 Trivy 检查漏洞
- 镜像优化:多阶段构建、使用 alpine、合并命令、清理文件
- 安全加固:只读模式、能力限制、隔离网络
练习作业:
- 创建一个安全的 Dockerfile,包含非特权用户和健康检查
- 使用多阶段构建优化一个 Node.js 应用
- 使用 Trivy 扫描镜像并修复发现的漏洞