Docker 学习笔记:从生态系统到镜像构建
本笔记系统梳理了容器生态、Docker 架构、镜像原理与 Dockerfile 最佳实践。保留了全部关键实验代码,文末提供知识速查表,适合快速复习与查阅。
1. 容器生态系统鸟瞰
容器技术绝非只有 Docker,而是一整套分层、协作的技术栈。理解整体生态,才能分清主次、有的放矢。
1.1 核心技术
让容器在 Host OS 上跑起来的最基础组件。
- 容器规范 :OCI (Open Container Initiative) 制定
runtime spec和image format spec,保证不同容器间的可移植性。 - 容器 runtime :
lxc,runc,rkt。runc 是 Docker 默认 runtime。 - 容器管理工具 :对内与 runtime 交互,对外提供 CLI。Docker Engine (
dockerd+dockerCLI)、lxd、rkt CLI。 - 容器定义工具:Docker image(模板)、Dockerfile(构建镜像的文本文件)。
- Registry :存放镜像的仓库。公共的有 Docker Hub、Quay.io;企业可自建私有 Registry。
- 容器 OS:裁剪过的操作系统,专用于运行容器,如 CoreOS、Atomic、Ubuntu Core。
1.2 平台技术
使容器作为集群在分布式环境中运行。
- 容器编排引擎:管理集群中的容器,实现调度、服务发现、动态伸缩。主流:Docker Swarm、Kubernetes、Mesos+Marathon。
- 容器管理平台:在编排引擎之上的通用平台,如 Rancher、ContainerShip。
- 基于容器的 PaaS:开发者无需关心基础设施,如 Deis、Flynn、Dokku。
1.3 支持技术
为容器基础设施提供周边能力。
- 容器网络:Docker network、Flannel、Calico、Weave 等。
- 服务发现:动态跟踪容器服务位置。常用 etcd、Consul、Zookeeper。
- 监控:Docker stats、cAdvisor、Weave Scope、Sysdig。
- 数据管理:跨主机迁移持久化数据,如 Flocker。
- 日志管理:Docker logs、Logspout。
- 安全性:扫描镜像漏洞,如 OpenSCAP。
2. Docker 安装与加速
2.1 安装 Docker CE (CentOS Stream 8)
bash
bash
# 卸载旧版本
yum remove docker docker-client docker-client-latest docker-common docker-latest ...
# 安装必要工具
yum install -y yum-utils device-mapper-persistent-data lvm2 vim
# 添加阿里云镜像仓库
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 生成缓存并安装
yum makecache
yum install -y docker-ce
# 启动并设置开机自启
systemctl enable docker.service --now
docker --version
2.2 配置镜像加速器(阿里云/华为云)
bash
bash
mkdir -p /etc/docker
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://spcqvmfn.mirror.aliyuncs.com"]
}
EOF
systemctl daemon-reload
systemctl restart docker
docker info | grep "Registry Mirrors"
3. Docker C/S 分离部署
Docker 采用 Client/Server 架构。可在独立管理机上仅安装客户端,远程连接 Docker 服务端。
3.1 服务端配置(docker_server: 192.168.108.30)
bash
bash
# 安装 Docker 并启动
# 编辑服务文件,添加监听端口
vim /usr/lib/systemd/system/docker.service
# ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2375
systemctl daemon-reload
systemctl restart docker
systemctl stop firewalld
3.2 客户端配置(docker_client: 192.168.108.31)
bash
bash
# 仅安装 Docker CLI
yum install -y docker-ce-cli
# 远程连接服务端执行命令
docker -H 192.168.108.30 run hello-world
docker -H 192.168.108.30 images
4. 容器 What, Why, How
4.1 什么是容器?
容器是一种轻量级、可移植、自包含的软件打包技术,应用+依赖被打包成容器,可在几乎任何地方以相同方式运行。
4.2 容器 vs 虚拟机
| 特性 | 容器 | 虚拟机 |
|---|---|---|
| 启动速度 | 秒级/毫秒级 | 分钟级 |
| 内核 | 共享 Host OS 内核 | 各自独立 Guest OS |
| 性能 | 接近原生 | 有额外虚拟化开销 |
| 镜像大小 | MB 级 | GB 级 |
| 运行密度 | 上千个 | 几十个 |
| 隔离性 | 进程级 | 系统级 |
| 迁移性 | 优秀 | 一般 |
4.3 为什么需要容器?------集装箱思想
Docker 借鉴了集装箱运输的理念。任何软件及其依赖被打包进标准化的"集装箱"(容器),开发、测试、运维环境无缝衔接,消除了"在我机器上能跑"的终极痛点。
Docker 特性与集装箱类比:
- 打包对象:任何货物 → 任何软件及依赖
- 标准接口:标准集装箱接口 → 各种平台无修改运行
- 隔离性:货物不会相互压坏 → 资源、库完全隔离
- 自动化:易于机械装卸 → run, start, stop 标准化
- 职责分工:货主关心装什么,承运方关心怎么运 → 开发关心代码,运维关心基础环境
5. Docker 核心概念与架构
5.1 三大核心概念
- 镜像(Image):只读模板,例如一个包含 Apache 的 Ubuntu 系统。
- 容器(Container):镜像的运行实例,轻量级沙盒。
- 仓库(Registry):存放镜像的场所,分为公有(Docker Hub)和私有。
5.2 Docker 架构
Docker 采用 Client/Server 模型:
- Docker Client :命令行工具
docker,通过 REST API 与 daemon 通信。 - Docker Daemon:后台服务,管理镜像、容器、网络、存储等。
- Registry:镜像仓库,默认 Docker Hub。
一次 docker run 的简单流程:
- Client 向 Daemon 发起请求。
- Daemon 检查本地有无镜像,若无则从 Registry 下载。
- Daemon 创建并启动容器,输出返回给 Client。
6. Docker 镜像深度解析
6.1 最小的镜像:hello-world
镜像仅 13.3 kB,Dockerfile 如下:
dockerfile
bash
FROM scratch
COPY hello /
CMD ["hello"]
镜像内只有一个可执行文件 /hello,无 Shell、无 Lib,体现了镜像的极简理念。
6.2 base 镜像与 rootfs
-
base 镜像 :不依赖其他镜像,从
scratch构建,提供最小化的 Linux 发行版 rootfs。 -
Linux 操作系统 = 内核空间 (kernel) + 用户空间 (rootfs)。
-
容器直接使用 Host 的 kernel,自身只提供 rootfs,因此 CentOS 镜像可以只有约 200 MB。
-
不同 Linux 发行版的容器可以共用同一个 Host Kernel,例如在 CentOS Stream 8 的 Host 上运行 Ubuntu 容器:
bash
bashdocker run -it ubuntu uname -r # 输出 Host 的 kernel 版本
6.3 镜像的分层结构与 Copy-on-Write
- 镜像由多个只读层堆叠而成,每层对应 Dockerfile 的一条指令。
- 容器启动时,在最顶层添加一个可写容器层。
- 修改文件时,先将文件从镜像层拷贝到容器层,再进行修改(Copy-on-Write)。
- 删除文件时,在容器层创建
whiteout文件遮挡下层文件。 - 优势:多个镜像可共享相同的底层,节省磁盘和内存。
6.4 构建镜像:两种方式
方式1:docker commit(不推荐)
bash
bash
docker run -it ubuntu
# 在容器内安装 vim
docker commit <容器ID> ubuntu-with-vim
缺点:手工操作,不可重复,无法审计,容易产生安全隐患。
方式2:Dockerfile(推荐)
dockerfile
dockerfile
FROM ubuntu
RUN apt-get update && apt-get install -y vim
bash
dockerfile
docker build -t ubuntu-with-vim-dockerfile .
构建过程:每执行一条指令,就会启动临时容器、执行命令、commit 为新层,然后删除临时容器。
6.5 镜像缓存特性
- Docker 会缓存已有的镜像层,下次构建如层未变则直接复用。
- 如果某层发生变化,其后的所有层缓存都失效。
- 可用
--no-cache强制不使用缓存。
6.6 调试 Dockerfile
如果某条指令失败,Docker 会保留前一条指令成功构建的镜像。可基于该镜像启动临时容器,手工执行失败命令来定位问题。
bash
bash
docker run -it <最后成功镜像ID> sh
6.7 Dockerfile 常用指令详解
| 指令 | 说明 |
|---|---|
FROM |
指定 base 镜像,第一条必须为 FROM |
MAINTAINER |
镜像作者信息(已弃用,建议用 LABEL) |
COPY |
从 build context 复制文件到镜像 |
ADD |
类似 COPY,但能自动解压归档文件 |
ENV |
设置环境变量,后续指令可用 |
EXPOSE |
声明容器监听端口 |
VOLUME |
声明挂载点 |
WORKDIR |
为后续指令设置工作目录 |
RUN |
在容器内执行命令,通常用于安装软件 |
CMD |
容器启动时的默认命令,可被 docker run 后的命令覆盖 |
ENTRYPOINT |
容器启动时运行,一般不会被覆盖 |
6.8 RUN vs CMD vs ENTRYPOINT
- RUN:在构建镜像时执行,生成新的镜像层,常用于安装软件。
- CMD :设置容器默认启动命令,若
docker run指定了其他命令则被忽略。 - ENTRYPOINT :设定容器启动时的主命令,
docker run的额外参数会作为该命令的参数。
Shell 格式 vs Exec 格式
- Shell 格式:
CMD echo "Hello"→ 调用/bin/sh -c。 - Exec 格式:
CMD ["executable","param1"]→ 直接调用executable,推荐使用。
示例:
dockerfile
dockerfile
FROM busybox
ENV name world
ENTRYPOINT ["/bin/echo", "Hello,"]
CMD ["${name}"]
如果 docker run 不加参数,输出 Hello, ${name}(因为 Exec 格式不会解析变量)。若改为 Shell 格式 ENTRYPOINT echo "Hello, $name",则会正确替换变量。
6.9 典型 Dockerfile 案例
带 SSH 的 CentOS 镜像
dockerfile
dockerfile
FROM centos:8.4.2105
RUN minorver=8.4.2105 && \
sed -e "s|^mirrorlist=|#mirrorlist=|g" \
-e "s|^#baseurl=http://mirror.centos.org/\$contentdir/\$releasever|baseurl=https://mirrors.aliyun.com/centos-vault/\$minorver|g" \
-i.bak /etc/yum.repos.d/CentOS-*.repo
RUN yum install -y openssh-server
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
RUN ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key
RUN echo "root:huawei" | chpasswd
EXPOSE 22
CMD ["/usr/sbin/sshd","-D"]
自定义 httpd 镜像
dockerfile
dockerfile
FROM centos:8.4.2105
# ... 替换 yum 源
RUN yum install -y httpd && yum clean all
COPY index.html /var/www/html/
EXPOSE 80
CMD ["/usr/sbin/httpd", "-DFOREGROUND"]
CentOS + Java 8 开发环境
dockerfile
dockerfile
FROM centos:8.4.2105
ENV MYPATH /usr/local
WORKDIR $MYPATH
# 安装 vim、net-tools、glibc
RUN yum -y install vim net-tools glibc.i686
RUN mkdir /usr/local/java
ADD jdk-8u461-linux-x64.tar.gz /usr/local/java/
ENV JAVA_HOME /usr/local/java/jdk1.8.0_461
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
ENV PATH $JAVA_HOME/bin:$PATH
CMD /bin/bash
7. 知识点速查表
7.1 Docker 生态核心组件
| 层次 | 组件 | 常见实例 |
|---|---|---|
| 核心技术 | 容器规范 | OCI |
| 容器 runtime | runc, lxc, rkt | |
| 管理工具 | Docker Engine, lxd | |
| 定义工具 | Dockerfile, Docker Image | |
| Registry | Docker Hub, Harbor | |
| 容器 OS | CoreOS, Atomic | |
| 平台技术 | 编排引擎 | Kubernetes, Swarm, Mesos |
| 管理平台 | Rancher, ContainerShip | |
| 容器 PaaS | Deis, Flynn, Dokku | |
| 支持技术 | 网络 | flannel, calico, weave |
| 服务发现 | etcd, consul, zookeeper | |
| 监控 | cAdvisor, Weave Scope |
7.2 容器与虚拟机快速对比
| 指标 | 容器 | 虚拟机 |
|---|---|---|
| 启动速度 | 秒/毫秒级 | 分钟级 |
| 镜像大小 | MB 级 | GB 级 |
| 系统内核 | 共享 Host 内核 | 各自完整 OS |
| 性能 | 近原生 | 有虚拟化损耗 |
| 部署密度 | 数千个 | 数十个 |
| 隔离级别 | 进程级 | 系统级 |
7.3 Dockerfile 指令速查
| 指令 | 用途 | 重要备注 |
|---|---|---|
FROM |
指定基础镜像 | 必须为第一条指令 |
RUN |
执行命令并提交新层 | 用于安装软件,常结合 &&\ 减少层数 |
COPY |
复制本地文件到镜像 | 优于 ADD(除非需要解压) |
ADD |
复制并自动解压归档文件 | 使用需谨慎 |
ENV |
设置环境变量 | 后续指令及容器运行时均可用 |
WORKDIR |
设置工作目录 | 不存在则自动创建 |
CMD |
容器启动默认命令 | 可被 docker run 后命令覆盖 |
ENTRYPOINT |
容器入口点命令 | 不会被覆盖,推荐 Exec 格式 |
EXPOSE |
声明端口 | 仅声明,不实际映射 |
VOLUME |
定义匿名卷 | 用于持久化或共享数据 |
7.4 docker run 常用参数
| 参数 | 作用 | 示例 |
|---|---|---|
-d |
后台运行 | docker run -d nginx |
-p |
端口映射 | -p 8080:80 |
-v |
挂载 volume | -v /host/path:/container/path |
-e |
设置环境变量 | -e MYSQL_ROOT_PASSWORD=123 |
--name |
指定容器名 | --name web |
--restart |
重启策略 | --restart always |
--network |
指定网络模式 | --network host |
7.5 镜像构建与分发命令
| 命令 | 用途 |
|---|---|
docker build -t name:tag . |
基于当前目录 Dockerfile 构建镜像 |
docker tag src dest |
给镜像打新标签 |
docker push repository/image:tag |
推送镜像到仓库 |
docker pull image:tag |
从仓库拉取镜像 |
docker images |
列出本地镜像 |
docker rmi image |
删除镜像 |
docker history image |
查看镜像构建历史(各层) |
docker save -o file.tar image |
导出镜像为 tar 文件 |
docker load -i file.tar |
从 tar 文件导入镜像 |
本笔记覆盖 Docker 学习技术文档第1章至第3章017节,后续内容将涉及容器运行、网络、存储等,敬请期待。