《UNIX/Linux系统管理技术手册-读书笔记-第二十五章
容器
1. 容器概述
1.1 什么是容器
| 概念 |
说明 |
能做什么 |
| 容器 |
一组独立的进程,被限制在私有根文件系统和进程名称空间中 |
将应用及其依赖打包成标准可移植单元,在任何兼容环境中运行 |
| 容器镜像 |
容器的模板,包含应用代码、库、运行时、配置文件 |
一次构建,到处运行(Build Once, Run Anywhere) |
| 容器运行时引擎 |
管理容器生命周期的软件(如Docker) |
创建、启动、停止、删除容器,管理镜像和卷 |
1.2 容器 vs 虚拟机
| 对比维度 |
容器 |
虚拟机 |
| 启动时间 |
<1秒 |
1~2分钟 |
| 资源开销 |
轻量(MB级镜像) |
重量(GB级镜像) |
| 隔离级别 |
进程级(共享宿主机内核) |
系统级(独立内核) |
| 密度 |
每主机数百个 |
每主机数十个 |
| OS兼容性 |
必须与宿主机内核一致 |
可运行不同OS |
1.3 容器背后的内核技术
| 技术 |
功能 |
| 名称空间(Namespace) |
隔离进程视图(PID、挂载点、网络、用户、UTS、IPC) |
| 控制组(Cgroup) |
限制资源使用(CPU、内存、磁盘I/O) |
| 能力(Capability) |
细粒度root权限划分(约40种) |
| Seccomp |
限制系统调用访问 |
💡 容器本质上就是利用这些内核特性隔离进程,没有任何魔法——这也是Docker之前LXC等工具已存在多年的原因。
2. Docker核心架构
2.1 组件
| 组件 |
说明 |
| dockerd |
持续运行的守护进程,负责所有容器和镜像操作 |
| docker客户端 |
命令行工具,通过UNIX套接字或TCP与dockerd通信 |
| 镜像(Image) |
只读模板,包含文件系统+应用+配置 |
| 容器(Container) |
镜像的运行实例,拥有独立的可写层 |
| Registry |
镜像仓库(默认Docker Hub) |
| 联合文件系统(UnionFS) |
多层叠加,写时复制(CoW)机制 |
架构图:docker客户端 ↔ docker守护进程 ↔ 镜像/容器存储 ↔ Registry
2.2 镜像分层(写时复制)
容器运行层(可写)
─────────────
Layer 3(只读)
Layer 2(只读)
Layer 1(只读) ← 基础镜像(如debian:jessie)
- 多个容器共享相同的基础层 → 节省存储、快速启动
- 容器修改写入可写层,不影响基础镜像
2.3 安装与配置
| 系统 |
安装方式 |
| Linux |
Docker官网提供针对各发行版的仓库 |
| FreeBSD |
实验性支持 |
| macOS/Windows |
Docker Desktop |
守护进程配置覆盖(systemd):
1
2
3
4
5
6
|
systemctl edit docker
# 写入覆盖配置
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd --storage-driver overlay --dns 8.8.8.8 --bip 172.18.0.0/19
systemctl restart docker
|
安全警告:docker组用户相当于拥有root权限!建议通过sudo控制访问,而非将用户加入docker组。
3. Docker核心命令速查
| 命令 |
功能 |
示例 |
docker pull image |
从registry下载镜像 |
docker pull debian:jessie |
docker images |
列出本地镜像 |
|
docker run |
创建并启动容器 |
docker run -it --rm debian bash |
docker ps |
列出运行中容器 |
docker ps -a(含停止的) |
docker stop/start |
停止/启动容器 |
|
docker rm |
删除容器 |
docker rm container_name |
docker rmi |
删除镜像 |
docker rmi image_name |
docker exec |
在运行容器中执行命令 |
docker exec -it nginx bash |
docker logs |
查看容器日志 |
docker logs -f nginx |
docker inspect |
查看容器/镜像详细配置(JSON) |
|
docker build -t tag . |
从Dockerfile构建镜像 |
|
docker push/pull |
上传/下载镜像到registry |
|
docker volume ls |
列出卷 |
|
docker system prune |
清理未使用的资源 |
|
快速体验:
1
2
3
4
5
6
7
8
|
# 运行交互式Debian容器
docker run --hostname debian -it debian /bin/bash
# 后台运行Nginx,映射端口80
docker run -p 80:80 --name nginx -d nginx
# 查看Nginx访问日志
docker logs nginx
|
4. Dockerfile(镜像构建)
4.1 常用指令
| 指令 |
功能 |
FROM |
第一条,指定基础镜像 |
RUN |
构建时执行命令(如安装软件包) |
COPY / ADD |
将文件复制到镜像中(ADD支持URL和自动解压) |
ENV |
设置环境变量 |
EXPOSE |
声明容器监听端口(文档性) |
CMD |
容器启动时执行的默认命令(可被覆盖) |
ENTRYPOINT |
容器启动时执行的固定命令(不易被覆盖) |
WORKDIR |
设置后续指令的工作目录 |
USER |
切换运行用户(安全实践) |
VOLUME |
声明持久化存储卷 |
ARG |
构建时变量(非敏感) |
4.2 Dockerfile示例(Nginx官方镜像简化版)
1
2
3
4
5
6
7
8
|
FROM debian:jessie
ENV NGINX_VERSION 1.10.3-1-jessie
RUN apt-get update && apt-get install -y nginx=${NGINX_VERSION} \
&& rm -rf /var/lib/apt/lists/*
RUN ln -sf /dev/stdout /var/log/nginx/access.log \
&& ln -sf /dev/stderr /var/log/nginx/error.log
EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]
|
关键实践:
- 日志重定向到
/dev/stdout和/dev/stderr → 由Docker日志驱动收集
- 前台运行(
daemon off;)→ 容器不会因进程退出而终止
- 一条RUN安装+清理 → 减少层数,减小镜像大小
4.3 构建自定义镜像
1
2
3
4
5
6
7
8
9
|
# Dockerfile
FROM nginx
ADD index.html /usr/share/nginx/html/
# 构建
docker build -t nginx:ulshar .
# 运行
docker run -p 80:80 --name nginx-ulshar -d nginx:ulshar
|
5. 卷(数据持久化)
5.1 卷类型
| 类型 |
创建方式 |
特点 |
适用场景 |
| 匿名卷 |
docker run -v /data |
自动命名,保存在/var/lib/docker/volumes/ |
临时数据 |
| 命名卷 |
docker volume create mydata |
可管理,持久化 |
生产数据 |
| 绑定挂载 |
docker run -v /host/path:/container/path |
主机目录直接挂载 |
开发、配置共享 |
| 数据卷容器 |
docker create -v /data --name data-container ... |
专用于持有卷配置 |
容器间共享卷 |
5.2 绑定挂载示例
1
2
3
|
# 主机目录挂载到容器
docker run -v /mnt/data:/data --name web -d nginx
# 容器写入/data → 主机/mnt/data可见
|
5.3 数据卷容器模式
1
2
3
4
5
|
# 创建纯数据容器
docker create -v /data --name nginx-data nginx
# 其他容器使用该卷
docker run --volumes-from nginx-data -p 80:80 --name web -d nginx
|
注意:数据卷容器使容器与特定主机绑定,违背容器“短暂性”理念。需要持久状态的应用,认真评估此模式是否适合。
6. Docker网络
6.1 网络模式
| 模式 |
说明 |
适用场景 |
| bridge(默认) |
容器在私有网段,主机通过NAT暴露端口 |
大多数场景 |
| host |
容器共享主机网络栈(无隔离) |
需要高性能网络的应用 |
| none |
无网络配置 |
高级自定义 |
1
2
3
|
docker run -p 80:80 --net host nginx # host模式
docker network ls # 查看网络
docker inspect -f '{{json .NetworkSettings.Networks.bridge}}' container
|
6.2 端口映射
1
2
3
|
docker run -p 80:80 nginx # 主机80→容器80
docker run -p 8080:80 nginx # 主机8080→容器80
docker run -P nginx # 随机映射EXPOSE的端口
|
6.3 自定义网络
1
2
3
4
|
docker network create --driver bridge mynet
docker run --net mynet --name web1 -d nginx
docker run --net mynet --name web2 -d nginx
# web1可通过容器名直接访问web2(内置DNS)
|
7. 存储驱动程序(Storage Driver)
| 驱动 |
特点 |
默认平台 |
| overlay |
OverlayFS,稳定的现代UnionFS |
CentOS 7+ |
| overlay2 |
overlay改进版,更高效 |
推荐生产使用 |
| aufs |
原始Docker驱动,非内核主线 |
Debian/Ubuntu(历史) |
| devicemapper |
需直接LVM模式配置,否则性能差 |
RHEL/CentOS 6 |
| zfs / btrfs |
原生CoW文件系统驱动 |
对应系统 |
| vfs |
无联合文件系统(完整复制),稳定但慢 |
测试环境 |
💡 推荐:Linux优先选择overlay2,性能与稳定性最佳。
8. 日志管理
8.1 容器日志惯例
- 应用将日志写入STDOUT(正常输出)和STDERR(错误)
- Docker收集并转发到可配置的日志驱动
8.2 日志驱动
| 驱动 |
说明 |
json-file |
默认,JSON格式保存到/var/lib/docker/containers/ |
syslog |
转发到系统syslog |
journald |
转发到systemd日志 |
awslogs |
直接写入AWS CloudWatch |
gelf |
Graylog扩展日志格式 |
none |
禁用日志收集 |
1
2
3
4
5
|
# 运行时指定日志驱动
docker run --log-driver syslog --log-opt syslog-address=udp://logs.example.com:514 nginx
# 配置json-file轮替
docker run --log-driver json-file --log-opt max-size=10m --log-opt max-file=3 nginx
|
9. 安全最佳实践
| 实践 |
说明 |
| 限制守护进程访问 |
使用sudo而非加入docker组(docker组=root) |
| 使用TLS远程通信 |
dockerd -H tcp://0.0.0.0:2376 --tlsverify |
| 非root用户运行 |
Dockerfile中使用USER nobody |
| 只读根文件系统 |
docker run --read-only |
| 最小能力集 |
docker run --cap-drop ALL --cap-add NET_RAW |
| 内容信任 |
export DOCKER_CONTENT_TRUST=1(验证镜像签名) |
| 镜像漏洞扫描 |
使用docker scan或Clair等工具扫描基础镜像 |
1
2
3
|
# 安全运行示例
docker run --read-only --cap-drop ALL --cap-add NET_BIND_SERVICE \
-v /tmp:/tmp -p 80:80 -d nginx
|
10. Registry(镜像仓库)
10.1 Docker Hub
- 公共镜像仓库,大量官方镜像(debian、ubuntu、nginx、mysql等)
- 付费账户支持私有仓库
- 内容信任验证部分官方镜像
10.2 私有Registry
1
2
3
4
5
6
|
# 运行简单registry容器
docker run -d -p 5000:5000 --name registry registry:2
# 推送镜像到私有registry
docker tag nginx localhost:5000/nginx
docker push localhost:5000/nginx
|
生产registry注意事项:
- 必须启用TLS加密通信
- 配置认证(token或htpasswd)
- 考虑存储后端(S3/GCS)和清理策略
- 云托管registry(AWS ECR、GCR)是更省心的选择
11. 容器集群管理(编排)
11.1 为什么需要编排
| 问题 |
编排的解决方案 |
| 容器部署在哪台服务器? |
调度算法自动选择合适节点 |
| 节点故障怎么办? |
自动重新调度容器到健康节点 |
| 如何发现服务? |
内置服务发现 + DNS |
| 如何负载均衡? |
集成负载均衡器 |
| 如何滚动更新? |
零停机部署策略 |
11.2 主流编排系统对比
| 系统 |
来源 |
特点 |
学习曲线 |
适用场景 |
| Kubernetes(k8s) |
Google |
功能最全,社区最大,生产级 |
陡峭 |
复杂微服务架构 |
| Docker Swarm |
Docker, Inc. |
最简单,与Docker原生集成 |
低 |
中小规模,已有Docker环境 |
| Mesos + Marathon |
Apache |
通用集群管理,支持多种framework |
中 |
大数据+容器混合环境 |
| AWS ECS |
Amazon |
托管服务,与AWS深度集成 |
低 |
AWS云环境,不想自建管理面 |
11.3 Kubernetes核心概念
| 概念 |
说明 |
| Pod |
一个或多个容器的组合,共享网络和存储(最小调度单元) |
| Service |
一组Pod的稳定网络入口(地址不变) |
| Deployment |
声明式管理Pod副本数、滚动更新、回滚 |
| Node |
集群中的一个工作节点 |
| Kubelet |
每个节点上的代理,管理Pod生命周期 |
| kubectl |
Kubernetes命令行工具 |
1
2
3
4
5
6
7
8
|
# 部署应用
kubectl create deployment nginx --image=nginx
# 暴露服务
kubectl expose deployment nginx --port=80 --type=LoadBalancer
# 滚动更新
kubectl set image deployment/nginx nginx=nginx:1.17
# 回滚
kubectl rollout undo deployment/nginx
|
11.4 Docker Swarm
1
2
3
4
5
|
docker swarm init # 初始化集群
docker node ls # 查看节点
docker service create --replicas 3 -p 80:80 --name web nginx # 部署服务
docker service scale web=5 # 扩展副本数
docker service update --image nginx:1.17 web # 更新
|
Swarm优势:学习成本最低,命令与单机Docker几乎一致,TLS加密开箱即用。
12. 容器实践建议(运维视角)
| 场景 |
建议 |
| 调度任务(cron) |
在主机上运行cron,调度一次性容器 |
| 远程登录调试 |
不要sshd进容器!登录主机后用docker exec -it |
| 配置管理 |
用环境变量传入配置 |
| 容器升级 |
替换容器,而非原地更新 |
| 日志收集 |
容器日志通过Docker日志驱动收集 |
| 容器维护 |
避免手动访问容器“修复”问题 |
| 数据持久化 |
状态化应用使用卷(Volume) |
| 资源限制 |
使用--memory和--cpus限制容器资源 |
| 清理 |
定期清理停止的容器、悬空镜像和卷 |
13. 本章核心命令速查表
| 命令 |
功能 |
docker pull ubuntu:22.04 |
下载镜像 |
docker run -it --rm ubuntu bash |
运行临时交互式容器 |
docker run -d -p 80:80 --name web nginx |
后台运行Nginx |
docker exec -it web bash |
进入运行中容器 |
docker logs -f web |
查看实时日志 |
docker stop web && docker rm web |
停止并删除 |
docker build -t myapp:v1 . |
从Dockerfile构建镜像 |
docker tag myapp:v1 myregistry/myapp:v1 |
标记镜像 |
docker push myregistry/myapp:v1 |
推送到私有registry |
docker volume create mydata |
创建命名卷 |
docker run -v mydata:/data -d nginx |
使用命名卷 |
docker system prune -f |
清理未使用资源 |
kubectl get pods |
查看Kubernetes Pod |
docker service ls |
查看Swarm服务 |
DBA视角补充:
- 数据库容器化需谨慎:数据库是状态化应用,容器化意味着管理数据卷、备份、恢复、网络等复杂性。生产环境建议将数据库部署在虚拟机/裸机上,将无状态应用层容器化。开发/测试环境可容器化数据库以快速拉起环境。
- 如果必须容器化数据库:
- 使用命名卷或绑定挂载持久化数据(绝不能用容器可写层存数据)
- 配置资源限制(
--memory、--cpus)防止数据库容器耗尽宿主机资源
- 使用
--restart=always确保崩溃后自动重启
- 数据库配置通过环境变量或配置文件挂载传入
- 备份通过主机侧卷数据备份,而非
docker exec执行备份(避免额外负载)
- 官方数据库镜像:Docker Hub有官方MySQL/PostgreSQL镜像,适合快速测试,使用前仔细阅读镜像文档,理解初始化机制(如
/docker-entrypoint-initdb.d/)。
- 网络性能:容器网络(bridge模式)有NAT开销,数据库高吞吐场景可考虑
--net=host模式,但需权衡安全与端口冲突。
- 编排与数据库:Kubernetes StatefulSet + PersistentVolume可实现有状态数据库容器编排,但复杂度高。建议优先使用云托管数据库服务(AWS RDS、GCP Cloud SQL)替代自建容器化数据库。