一、容器生态系统 (001‑003)
容器技术是云计算之后热门的 IT 技术,Docker 的普及让容器走入广大开发者和运维的视野。学习容器不要一上来就敲命令,先建立整体认知,就像旅游先看城市地图,理清分层、各组件职责,避免学习迷路。
容器生态分为三大板块:容器核心技术、容器平台技术、容器支持技术。
1. 容器核心技术
负责让容器能够在单机主机上运行起来。
- 容器规范 OCI:由 Docker、Google、CoreOS 等厂商联合制定,包含 runtime spec 运行时规范、image format spec 镜像格式规范,保证不同容器实现之间可移植、互相兼容。代表项目 rkt、podman、containerd。
- 容器 runtime:容器真正运行环境,和操作系统内核深度交互。类比 Java 里 JVM,容器程序就像 Java 应用。主流实现:lxc(Docker 早期底层)、runc(Docker 现在默认 runtime,符合 OCI)、rkt。
- 容器管理工具:对外提供 CLI 交互,对内调用 runtime。Docker Engine 就是 Docker 的管理工具,包含后台守护进程 daemon 和命令行 cli。
- 容器定义工具:定义容器内容属性,用来保存、共享、重建容器。Dockerfile 用来构建镜像,镜像就是容器模板。
- Registries 镜像仓库:存放镜像。Docker Hub 是公共仓库;Docker Registry 可搭建私有仓库;Quay.io 是第三方公共镜像仓库。
- 容器 OS:专门运行容器的操作系统,体积小启动快。典型:CoreOS、Atomic、Ubuntu Core。
2. 容器平台技术
解决集群分布式环境下容器运行的问题,单机容器靠核心技术,多机器集群靠平台技术。
- 容器编排引擎:微服务场景,大量容器需要动态创建、调度、迁移、销毁。主流:Docker Swarm、Kubernetes、Mesos+Marathon。负责调度、集群管理、服务发现。
- 容器管理平台:封装编排引擎,提供 UI、应用一键部署,如 Rancher、ContainerShip。
- 基于容器的 PaaS:面向开发人员,不用关心底层基础设施,专注业务开发,Deis、Flynn、Dokku 属于这类。
3. 容器支持技术
配套支撑容器基础设施运行。
- 容器网络:docker network、flannel、weave、calico,解决容器之间、容器外部网络连通隔离。
- 服务发现:容器 IP 会动态变化,etcd、consul、zookeeper 保存服务地址信息,供客户端查询访问。
- 监控:docker 自带 ps/top/stats,还有 sysdig、cAdvisor、Weave Scope。
- 数据管理、日志管理、容器安全扫描,都是生产环境必不可少的组成部分。
二、Docker 安装与第一个容器 (004‑005)
实验环境采用 CentOS Stream8,克隆虚拟机,配置静态 IP。 Docker 由两部分:Docker Engine 服务端 dockerd,Docker‑cli 客户端。
安装步骤简述
- 配置阿里云 Docker 软件源
- 安装 docker‑ce 服务端,设置开机自启并启动服务
- 配置镜像加速器(阿里云 / 华为云 SWR),修改
/etc/docker/daemon.json配置registry‑mirrors,重载 systemd,重启 docker,使用docker info校验加速器是否生效。
运行第一个容器
docker run hello-world
执行逻辑:本地找不到镜像 → 去镜像仓库拉取镜像 → 基于镜像启动容器,输出提示信息。
再运行 httpd 网页容器做端口映射:
docker run -d -p 80:80 httpd
把容器 80 端口映射宿主机 80,浏览器访问服务器 IP,看到It works!说明 web 容器正常。
Docker C/S 分离部署
Docker 是典型 C/S 架构,客户端 cli 和服务端 daemon 可以分开部署。
-
docker_server 节点:修改 docker.service,dockerd 监听
‑H tcp://0.0.0.0:2375,开放远程 API。 -
docker_client 节点:只安装 docker‑ce‑cli 客户端,不安装完整 docker‑ce。
-
客户端远程调用服务端执行命令:
docker -H 192.168.108.30 run hello-world
镜像、容器全部存储在 server 服务端机器,client 只发送指令。
三、什么是容器?容器与虚拟机对比 (006)
容器发展简史
容器思想很早就存在:chroot、FreeBSD Jail,后续 Linux VServer,Solaris Zone,Google cgroups,LXC,直到 2013 年 Docker 诞生,把容器普及开来。
What 什么是容器
容器是轻量级、可移植、自包含的软件打包技术。把应用连同依赖库一起打包,开发环境打包好,测试、生产环境直接运行,无需修改。
容器 = 应用程序 + 全部依赖库。 容器运行在宿主机用户空间,共享宿主机 Linux 内核。
容器 vs 虚拟机
表格
| 项目 | 虚拟机 | 容器 |
|---|---|---|
| 内核 | 拥有独立完整内核 | 共享宿主机内核 |
| 启动速度 | 分钟级 | 秒级甚至毫秒级 |
| 隔离 | 硬件级完全隔离 | 进程级别隔离 (namespace/cgroup) |
| 资源开销 | 大,每个虚拟机完整 OS | 很小,只是宿主机进程 |
| 单机实例数量 | 几十台 | 上千个容器 |
| 镜像 | 完整操作系统镜像,GB 级别 | 分层镜像,MB 级别 |
虚拟机通过 Hypervisor 虚拟化硬件;容器直接复用宿主机内核,利用 namespace 做隔离,cgroups 做资源限制。
Why 为什么用容器
传统开发会遇到环境矩阵难题:多个业务服务,需要部署到开发、测试、多套生产环境,每个环境配置非常麻烦。
现实世界的集装箱 解决了货运的 N×M 匹配难题:不管什么货物统一装进标准集装箱,卡车、火车、轮船通用搬运。Docker 借鉴这个思想,把软件打包成 "软件集装箱",实现一次构建,到处运行。
开发:Build Once, Run Anywhere 运维:Configure Once, Run Anything 消除开发、测试、生产环境不一致问题。
四、Docker 架构详解 (007‑008)
Docker 采用C/S 客户端‑服务端架构。
- Docker Client 客户端:就是 docker 命令行,用户输入 docker 指令。
- Docker Daemon 服务端 (dockerd):后台守护进程,真正干活,管理镜像、容器、网络、卷。客户端通过 REST API 和 daemon 通信,可以本地 socket,也可以远程 tcp。
- Image 镜像:只读模板,创建容器的模板。
- Container 容器:镜像的运行实例,可读写。
- Registry 镜像仓库:存放镜像,Docker Hub 是默认公共仓库。
组件协同流程,以docker run -d -p 80:80 httpd为例
- 用户在客户端执行 docker run;
- 请求发送给 dockerd 守护进程;
- daemon 本地查找 httpd 镜像,本地不存在;
- daemon 向 Registry 拉取 httpd 镜像;
- 镜像下载保存本地;
- daemon 基于镜像创建容器,设置端口映射,启动容器。
五、镜像内部结构 (009‑012)
最小镜像 hello‑world
hello‑world 镜像体积只有十几 KB。Dockerfile:
FROM scratch
COPY hello /
CMD ["/hello"]
FROM scratch代表从零开始构建,镜像里面只有一个 hello 可执行程序,没有 /bin、/usr 这些系统目录,只用来验证 docker 环境。
base 基础镜像
base 镜像含义:①scratch 从零构建;②其他镜像可以以此为基础扩展。 常见 centos、ubuntu、alpine 都属于 base 镜像。
重点:容器镜像只有 rootfs,没有内核! bootfs 是内核文件系统,宿主机 Linux 内核;rootfs 是用户态文件系统,包含 /bin/etc /dev 目录。容器复用宿主机 kernel。 无论容器镜像是 centos7 还是 ubuntu,执行 uname‑r 看到的内核版本永远是宿主机的内核,容器内部不能修改升级内核。如果业务对内核版本强依赖,应该选择虚拟机。
镜像分层与写时复制 Copy‑on‑Write
Docker 镜像是多层只读堆叠,每一条 Dockerfile 指令生成一层镜像。 多个镜像如果共用 base 基础层,磁盘和内存只存一份,实现资源共享。
镜像层全部只读;容器启动,会在最顶层增加一层可读写容器层。 所有新增、修改、删除文件全部发生在最上层读写层;下层镜像层永远不变。修改底层文件会触发写时复制:把对应文件复制到上层容器层再修改,底层原始数据保持原样。
两种创建镜像方式
docker commit:启动容器,手动修改容器环境,把容器提交保存成镜像。 缺点:手工操作,构建过程不可审计,不推荐生产使用,但可以帮助理解底层原理。- Dockerfile 构建镜像(官方推荐):用文本文件记录每一步构建指令,可复用、可审计。
六、Dockerfile 构建镜像 (013‑017)
Dockerfile 是描述镜像构建步骤的文本文件。 规则:
- 指令大写,参数跟随;
- 从上往下顺序执行;
#是注释;- 每一条指令生成一个镜像层。
构建命令:
docker build -t 镜像名:tag -f Dockerfile路径 上下文路径
.代表当前目录作为构建上下文,docker 会把上下文全部文件传给 daemon,不要把 / 根目录当做上下文,避免文件过多拖慢构建。
Docker 镜像缓存
构建镜像时,如果指令和上一次构建完全一致,直接复用缓存镜像层,提升构建速度。 只要某一层发生改动,该层上面所有层缓存全部失效 。 构建禁用缓存:docker build --no-cache。
调试 Dockerfile
build 中途某条指令报错,已经构建成功的镜像层会保留。直接运行上一步成功的镜像,复现操作排查错误。
Dockerfile 常用指令
FROM:指定基础镜像,必须是 Dockerfile 第一条有效指令;scratch 代表空白镜像。MAINTAINER:设置镜像作者信息。COPY src dest:把构建上下文文件复制到镜像内部,只做复制,不解压。ADD src dest:复制文件,如果源是压缩包会自动解压到目标路径。ENV key value设置环境变量,后续指令、容器运行时都可以读取。WORKDIR /xxx设置后续 RUN/CMD/ENTRYPOINT 等指令的工作目录,目录不存在自动创建。EXPOSE 80:声明容器打算监听的端口,只是文档声明,不会自动做端口映射。VOLUME:声明数据卷,实现容器数据持久化。
RUN / CMD / ENTRYPOINT 重点区分
- RUN :构建镜像阶段执行命令,执行结束生成新镜像层。常用于安装软件包。 两种写法:shell 格式
RUN apt install vim;exec 数组格式RUN ["apt","install","vim"]。 - CMD :容器启动阶段执行默认命令。
- docker run 后面追加命令参数,会直接覆盖替换 CMD;
- 多个 CMD 只有最后一条生效。 格式:exec 数组格式(推荐)
CMD ["echo","hello"];shell 格式。
-
ENTRYPOINT:容器启动运行程序,不会被 docker run 参数覆盖;run 后面传入的参数会当做参数传给 ENTRYPOINT。 可以配合 CMD 设置默认参数。
ENTRYPOINT ["/bin/echo","Hello"]
CMD ["world"]
直接运行容器输出Hello world;docker run 镜像 gqd输出Hello gqd。
shell 格式的 ENTRYPOINT 会忽略 CMD 和 run 传入参数,写服务镜像优先选择 exec 数组格式。
几个实操案例要点
- 制作带 ssh 的 centos 镜像:安装 openssh‑server,生成 ssh 密钥,设置 root 密码,
CMD ["/usr/sbin/sshd","‑D"]前台运行 sshd 服务。 - 自定义 httpd 镜像:把本地 index.html 复制进镜像,httpd 前台启动。
- 制作 jdk8 镜像:ADD 把 jdk 压缩包导入镜像,配置 JAVA_HOME 系列环境变量。
Dockerfile 不要把多个独立软件安装拆分成多个 RUN,尽量合并 && 减少镜像层数,同时要注意 apt/yum 更新和安装写在同一个 RUN,避免缓存带来版本老旧问题。