精读整理自 RHCE9 随堂讲义(原文字版 100 页)|同名视频(第02套,约 100 节大章) 关联知识文件:分章笔记/01-Linux/02-08-自动化运维、分章笔记/01-Linux/02-07-Shell编程
- 容器是“沙盒技术”:把应用连同运行环境装进集装箱,应用之间有边界互不干扰,整体可搬运。容器的本质是进程,容器镜像=系统里的“.exe”安装包。
- Docker:Docker.Inc 开源的轻量级虚拟化容器引擎,Go 语言开发、Apache 2.0 协议;通过分层镜像标准化 + 内核虚拟化实现跨平台统一发布;秒级启停、占用资源少、体积小(MB 级 vs VM 的 GB 级)、对基础环境几乎无依赖。
- 有容器前后对比:无容器时开发/测试/运维各自装 LAMP 环境;有容器后开发在容器里配好环境 → 打成镜像 → 运维直接跑。
- 传统部署“安装→配置→运行” vs Docker 部署“复制→运行”;核心理念 Build once, Run anywhere(一次构建到处运行)。
- 优势:交付物标准化(镜像);应用隔离(比虚拟机开销小);一次构建多次交付;快速部署/升级(VM 分钟级 vs 容器秒级);利于微服务松耦合。
- 度量四方面:隔离性(内核命名空间隔离进程/网络/消息/文件系统/主机名)、可度量性(cgroups 控制资源)、可移植性(AUFS/overlay2 分层快速更新)、安全性(namespace+cgroups 管容器间,内核能力机制防入侵宿主机)。
- 容器 vs VM:体积小/启动秒级/基于进程隔离/共享宿主内核/只用 64 位 OS;VM 独立内核、完全隔离、分钟级启动。
- CentOS7 自带源:
yum install -y epel-release、yum install docker -y(老版本);启动 CentOS6 service docker start; chkconfig docker on,CentOS7 systemctl start/enable docker.service;docker version 若只显示 Client 说明服务未启动。 - 官方安装(新版 docker-ce):下载
https://download.docker.com/linux/centos/docker-ce.repo 到 /etc/yum.repos.d/,yum install -y docker-ce;或下载 rpm 后 yum localinstall。国内用阿里源:yum install -y yum-utils device-mapper-persistent-data lvm2 git + yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo。 - 版本家族:moby(社区开源母项目)→ docker-ce(公司维护免费)与 docker-ee(公司商业闭源);装指定版本
yum list docker-ce --showduplicates、yum install -y docker-ce-18.03.0.ce(老版本加 --setopt=obsoletes=0)。 - 验证:
docker -v、docker version(20.10.21 示例含 containerd 1.6.9/runc 1.1.4)、docker info(Containers/Images 计数、Root Dir)。 - 排错:
bridge-nf-call-iptables is disabled → /etc/sysctl.conf 加 net.bridge.bridge-nf-call-iptables=1 等 3 行重启;DNS 慢/拉镜像超时 → /etc/resolv.conf 改 nameserver 8.8.8.8。 - 镜像源/加速:官方 Docker Hub docker.io;国内 daocloud/aliyun/网易蜂巢;加速器配置
/etc/docker/daemon.json:{"registry-mirrors":["https://...mirror.aliyuncs.com"]} 后 systemctl daemon-reload && systemctl restart docker;Docker 加速器要求 1.8+。 - 阿里云/腾讯云私有镜像服务流程(通用):
docker login --username=xxx registry.cn-hangzhou.aliyuncs.com(或腾讯 ccr.ccs.tencentyun.com)→ docker tag 源镜像 域名/命名空间/镜像:tag → docker push;公开仓库拉取免登录、推送要登录;私有仓库拉/推都要登录。
- Docker 系统=服务端(docker engine,管理所有容器)+ 客户端(远程控制器)。
- 三大组件:仓库 registry、镜像 image、容器 container。
- 容器三大组成要素:namespace(隔离 pid/net/mnt/user/hostname…)、cgroups(资源限制)、overlay2/UnionFS(文件系统)。
- 仓库体系:registry 存镜像 → 内按 repository 组织 → 每个 repository 有多个 tag 镜像;公有库 Docker Hub(docker.io),私有库公司自建(daocloud/aliyun 为国内加速镜像站)。
- 镜像命名解析:完整名
docker.io/library/nginx:v1=registry/repository:tag;省略 registry 默认 docker.io;tag 表版本,省略默认 latest;镜像 ID 为 64 位十六进制,可用前 12 位短 ID。 - 镜像分层:只读模板、一系列层(layers)、UnionFS 联合;改动镜像=加新层,基础镜像(无父镜像)→ 子/父镜像关系;镜像不可写、无状态。
- 镜像 vs 容器:run 时在镜像层之上加可写层(运行态 Running / 退出态 Exited);对容器的一切变更写入容器文件系统而非镜像;同镜像可启动多个互相隔离的容器;改底层镜像不影响已运行容器。
- 6 种 namespace:pid(进程隔离,可嵌套实现 Docker in Docker)、net(网络接口/IP/路由表隔离)、ipc(信号量/共享内存/socket/管道)、mnt(挂载点隔离)、uts(主机名)、user(用户)。
| 操作 | 命令 |
|---|
| 搜索 | docker search centos、docker search ubuntu -f stars=100(仅官方库) |
| 拉取 | docker pull centos(默认 docker.io)、docker pull daocloud.io/library/tomcat:7 |
| 查看 | docker images / docker image list |
| 详情 | docker inspect 镜像id/名、docker image inspect |
| 删除 | docker rmi 名称或id(多个空格分隔)、--force 强删 |
| 只看 ID / 删全部 | docker images -q、docker rmi $(docker images -q) |
| 看构建过程 | docker history 镜像名/id(相当于看 Dockerfile 步骤) |
- 注意:
rm 删容器、rmi 删镜像;容器运行中不能删镜像——先停容器、删容器再删镜像。
| 操作 | 命令 | 说明 |
|---|
| 创建不启动 | docker create -it 镜像 /bin/bash | |
| 创建并运行 | docker run -it --restart=always 镜像 /bin/bash | -i 标准输入、-t 终端;--restart=always 随 engine 自启;-d 后台 |
| 起名 | --name 名字 | 不指定则随机 UUID |
| 断开不关 | ctrl+p+q | 容器内快捷键 |
| 断开并关闭 | exit | |
| 查看 | docker ps(运行中)/ docker ps -a(全部)/ -q(仅 id)/ -f status=exited | |
| 详情 | docker inspect 名称/id | 配置/网络/卷/状态,可用 id 前缀 |
| 启停删 | docker start、docker stop、docker restart、docker rm、docker kill | |
| 批量 | docker kill $(docker ps -q)、docker rm $(docker ps -qf status=exited) | |
| 暂停 | docker pause / docker unpause | 暂停容器内所有进程 |
| 改名 | docker rename 旧名 新名 | |
| 资源监控 | docker stats | CPU/内存/网络 IO 实时流 |
| 进容器 | docker attach id(须创建时有交互 shell);docker exec -it id /bin/bash(交互)、docker exec id touch /f(后台型) | exec 优先 |
| 日志/进程/退出码 | docker logs -f 容器名(--tail N)、docker top、docker wait | wait 挂起直到容器停,打印退出码 |
| 文件互拷 | docker cp 容器:路径 本机路径、docker cp 本机路径 容器:路径、-a 拷目录 | |
- stop 发 SIGTERM(可被程序捕获处理),kill 发 SIGKILL(必退出);运行中删除加
-f(慎用,先 stop)。 --rm:容器退出即自动清理文件系统,适合临时容器;老版本后台模式(-d)不能用 --rm,且 --rm 与 --restart=always 冲突。- 退出码:0 正常;非 0 异常(chroot 标准);125 dockerd 本身错误;126 默认命令无法调用;127 默认命令不存在。
- 容器内启服务示例:
docker run -it --name nginx1 镜像 /bin/bash → 容器内 /usr/sbin/nginx → ctrl+p+q → 宿主机 curl -I http://172.17.0.3 可通 → 另开终端 docker logs -f nginx1 跟踪访问日志。
| 场景 | 命令 | 说明 |
|---|
| 容器导出 tar | docker export -o centos7-1.tar 容器id 或 docker export 名称 > 1.tar | 容器文件系统打包(丢元数据) |
| tar 导入 | docker import 1.tar 新镜像:v1 | 生成镜像再 run |
| 容器转镜像 | docker commit -m "注释" -a "作者" 容器id soso/test:v2 | 保留操作结果 |
| 镜像存 tar | docker save -o nginx.tar 镜像:tag | 含分层元数据 |
| tar 载入 | docker load < nginx.tar | 迁移到其他宿主机 |
- 口诀:容器↔tar 用 export/import;容器→镜像用 commit;镜像↔tar 用 save/load。
docker build [选项] 路径 按 Dockerfile 构建;常用选项:-t name:tag、-f 指定文件、--no-cache 不用缓存、--build-arg 构建变量、--network 等。- 基础指令:
FROM 基础镜像(第一条必有)、MAINTAINER 作者、RUN 在镜像内执行命令、WORKDIR=cd、ADD 本地文件/自动解压 tar 进容器、COPY 拷贝、ENV 环境变量、EXPOSE 暴露端口(声明)、CMD 默认启动命令、ENTRYPOINT 入口命令、VOLUME 卷、USER 用户。指令大写、# 注释。 - 每个原语执行后生成一个镜像层(即使 ENV 等没改文件也会产生“空层”)。
- Flask 实例(Python Web 容器化):
FROM python:2.7-slim
WORKDIR /app
ADD . /app
RUN pip install --trusted-host pypi.python.org -r requirements.txt
EXPOSE 80
ENV NAME World
CMD ["python", "app.py"]
docker build -t testpython . → docker run -it -p 4000:80 testpython /bin/bash → 容器内 python app.py & → 宿主 curl localhost:4000。
- Jenkins 实例:FROM centos:7 + ENV JAVA_HOME/TOMCAT_HOME/PATH + ADD 两个 tar.gz(自动解压到 /usr/local)+ 清 webapps + ADD jenkins.war + EXPOSE 8080 +
ENTRYPOINT [".../catalina.sh","run"];docker build -t jenkins:v1 .,docker run -itd --name jenkins1 -p 8081:8080 jenkins:v1。 - Nginx 实例:一条大 RUN(&& 串联)装编译依赖→建 nginx 用户/目录→下载编译安装→清缓存删源码→设时区;ENV PATH、COPY nginx.conf、WORKDIR、EXPOSE 80、
CMD ["nginx","-g","daemon off;"]。 - CMD vs ENTRYPOINT:二者都只能有一个(多个只执行最后一个);CMD 会被
docker run 镜像 参数 覆盖;ENTRYPOINT 是“开机启动”内容,run 追加的参数会拼接在其后,常把“必须执行”的入口放 ENTRYPOINT。 - 优化:① RUN 尽量合并成一条(每多一条 RUN 镜像就增一层);② 装完依赖
yum clean all 清缓存;③ 选小基础镜像(如 alpine);④ 用 .dockerignore。 - systemd 容器:CentOS7 默认 fakesystemd,可 Dockerfile 里
yum -y swap -- remove fakesystemd -- install systemd systemd-libs,删多余 .wants 链接,VOLUME ["/sys/fs/cgroup"],CMD ["/usr/sbin/init"];运行须 --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro(--privileged 让容器内 root 有真 root 权限);示例可把 httpd/sshd 做成 systemd 容器。
- 部署:
docker pull registry;docker run -itd -v /home/dockerdata/registry:/var/lib/registry --name pri_registry --restart=always -p 5000:5000 registry(-v 把数据目录挂出防容器删除丢镜像;-p 端口映射)。 - 上传:先
docker tag 镜像 192.168.x.x:5000/镜像名(打上仓库地址)再 docker push;默认 https 报 “http: server gave HTTP response to HTTPS client”→ /etc/docker/daemon.json 加 {"insecure-registries":["192.168.x.x:5000"]} 后重启 docker。 - 查看/拉取:
curl http://ip:5000/v2/_catalog 列全部;curl .../v2/镜像/tags/list 看 tag;客户端 docker pull 192.168.x.x:5000/busybox。 - Web UI:
docker run -it -d --name docker-web -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock uifd/ui-for-docker,浏览器 ip:9000。
- 背景:多容器共享 CPU/内存/磁盘,不限制会互相影响甚至拖垮主机;网络暂无法用 docker 原生限制(走插件)。
- 压测工具 stress:
docker run --rm -it progrium/stress --cpu 4 --vm 1 --vm-bytes 64M --vm-hang 0(--cpu 起计算进程、--vm 起内存进程、--vm-bytes 内存量、--vm-hang 卡住时间);监控用 htop。 - CPU 限制三招: | 参数 | 作用 | 说明 | | --- | --- | --- | |
-c/--cpu-shares | 相对权重 | 默认 1024;两容器 1024:512≈2:1 分配;只能定比例不能定核数;删掉一个剩余容器可用满 | | --cpus 1.5 | 限定最多核数 | 1.13+ 可用,浮点精确到 0.01;超主机核数直接报错;多容器超卖时按 share 竞争 | | --cpuset-cpus=0,1 | CPU 绑定 | 只跑在指定核心上(生产中一般不推荐) | - 内存限制:默认不限(危险,恶意程序/内存泄漏可耗尽主机)。
-m/--memory 64m 上限(最小 4m,单位 b/k/m/g);超限容器被杀(signal 9 / OOM),不会拖垮主机;过小会让正常服务被 OOM 误杀,先压测再设值;尽量不用 swap(对调度器不友好)。 - IO 限制(了解):docker 可限制磁盘读写速度与频率,但无法限制容器磁盘容量(mount 后能用整块盘)。
-p 宿主机端口:容器端口 让外部访问容器应用,可用多个 -p 映射多个端口;-P(大 P)随机映射 32768~49900 到容器开放端口。- MySQL 示例:
docker run -d --name mysql1 -p 3307:3306 -e MYSQL_ROOT_PASSWORD=Qf@123! mysql:5.7(-e 传环境变量);客户端 mysql -uroot -p'密码' -h 宿主机IP -P 3307。 - Redis 示例:
docker run -d --name myredis -P redis → docker ps 见 0.0.0.0:32768->6379/tcp → 其他机器 redis-cli -h ip -p 32768。
- 挂载宿主机目录/文件进容器:
docker run -it -v /test:/test2 nginx /bin/bash(宿主机目录:容器目录,两边目录不必提前存在、自动创建;新卷只能在创建容器时挂载);双向共享即时生效。 - 共享单文件:
-v /dir/a.txt:/dir1/a.txt;共享其他容器的卷:docker run -it --volumes-from 容器A 镜像(继承 A 挂的卷);多个卷多个 -v 叠加。
- 默认存储
/var/lib/docker(docker info | grep Root);改位置:编辑 /usr/lib/systemd/system/docker.service 的 ExecStart 追加 --data-root=/data → systemctl daemon-reload && systemctl restart docker。 - 默认 3 种网络:
bridge(默认,容器启动按序获取 IP)、host(与主机共用 IP,--net host 启动后 netstat 可见 80 在监听)、none(不分配局域网 IP)。 - 自定义网段固定 IP:
docker network create --subnet=192.168.0.0/16 staticnet → docker run -itd --name server --net staticnet --ip 192.168.0.2 镜像(重启 IP 不变);docker network rm 前须先删使用该网络的容器。 - 异主容器互联(方式一·路由):不同宿主机 Docker 默认内网都是 172.17.0.0/16 会冲突,先改其中一台
/etc/sysconfig/docker-network 为 DOCKER_NETWORK_OPTIONS=--bip=172.18.0.1/16;两台都开 net.ipv4.ip_forward=1(sysctl.conf + sysctl -p)并重启;再互加路由:server1 route add -net 172.18.0.0/16 gw 192.168.246.143、server2 route add -net 172.17.0.0/16 gw 192.168.246.141;容器间即可 ping 通。 - 方式二:open vswitch 实现大规模跨物理机容器互联(了解:openvswitch 建虚拟交换机打通不同宿主机的容器网段)。
| 场景 | 写法 |
|---|
| 拉/看/删镜像 | docker pull、docker images、docker rmi |
| 运行容器 | docker run -itd --name x -p 8080:80 --restart=always 镜像 |
| 进容器 | docker exec -it 容器 /bin/bash |
| 启停删 | docker start/stop/restart/rm 容器 |
| 日志 | docker logs -f --tail N 容器 |
| 互拷 | docker cp 容器:路径 路径 |
| 容器→镜像 | docker commit -a -m 容器 新镜像:tag |
| 镜像迁移 | docker save -o x.tar 镜像 / docker load < x.tar |
| 容器迁移 | docker export -o x.tar 容器 / docker import x.tar 镜像:tag |
| 构建 | docker build -t 名:tag . |
| 资源限制 | -c 512、--cpus 1.5、--cpuset-cpus=0,1、-m 64m |
| 端口 | -p 3307:3306 指定、-P 随机 |
| 卷 | -v /宿主机:/容器、--volumes-from 容器 |
| 网络 | docker network create --subnet=x staticnet、--net host |
- 容器是进程不是虚拟机:共用宿主内核;容器内变更写可写层,不写镜像。
rm 删容器、rmi 删镜像;镜像被运行中容器占用时先停/删容器。- run 的 -it 用于交互、-d 后台;后台型老版本不能配 --rm;--rm 与 --restart=always 冲突。
- CMD 会被 run 后参数覆盖,ENTRYPOINT 不覆盖只拼接;两者各只能一个。
- export/import 与 save/load 别混:容器用 export/import,镜像用 save/load。
-P 随机端口(32768~49900),-p 才是指定映射。- 私有仓库推送默认走 https,必须配 daemon.json 的 insecure-registries 且与仓库 IP:端口一致。
--cpus 超主机核数直接报错;多容器超卖不会失败,而是按 share 竞争。- 内存限制太小会把正常服务 OOM kill;容器默认不限内存非常危险。
- -v 卷目录“宿主机:容器”方向别写反;卷只能在创建容器时挂载。
- systemd 容器运行要
--privileged 并挂 /sys/fs/cgroup,否则 systemd 起不来。 - 多宿主机容器互联先解决内网网段冲突(--bip)+ ip_forward + 路由表。
装 docker-ce + 配加速器 → pull nginx/mysql 并 run(-itd/-p/-e)→ 镜像管理全家桶(search/pull/images/inspect/rmi/history)→ 容器管理全家桶(create/run/ps/exec/attach/start/stop/restart/kill/rm/pause/rename/stats/logs/top/wait/cp)→ export/import、commit、save/load 三组迁移演练 → Dockerfile 三例(centos 基础/flask/Jenkins+nginx)并看 build 分层 → CMD/ENTRYPOINT 对比 → Dockerfile 优化 → 部署私有 registry(-v + -p + insecure-registries)+ push/pull → stress 做 CPU/mem 限制对比(htop 观察)→ -p/-P 映射 mysql/redis 外部访问 → -v/--volumes-from 共享 → systemd httpd/sshd 容器 → --data-root 迁移存储 → 自定义网络固定 IP → 两台宿主机路由互联 ping 通。
- 容器的本质是什么?容器与 VM 的核心区别?
- Docker 三组件、容器三要素(namespace/cgroup/overlay2)分别解决什么问题?
- 镜像名
daocloud.io/library/nginx:v1 各部分含义?短 ID 规则? - run/start/exec/attach 区别?stop 与 kill 信号区别?退出码 125/126/127 含义?
- export/import、commit、save/load 各用于什么场景?
- Dockerfile 常用指令及顺序要求?CMD 与 ENTRYPOINT 区别?
- CPU 的 -c/--cpus/--cpuset-cpus 与内存 -m 各自效果与限制?
- -p 与 -P 的区别?如何让外部访问 mysql/redis 容器?
- -v 与 --volumes-from 怎么用?为什么私有仓库要挂数据目录?
- 修改 docker 数据目录与网络存储(--data-root、--bip、ip_forward、路由)怎么做?
- 多宿主机容器互联有哪些方式?如何避免网段冲突?