Docker 容器架构:从原理到实战全攻略
Docker 容器架构:从原理到实战全攻略
一、概述
本文覆盖Docker容器架构从基础概念、云服务模型到进阶实操的全维度知识点,包含容器与虚拟机对比、Docker环境搭建、镜像/容器核心管理、端口映射、数据卷挂载、Dockerfile自动化构建、Docker Compose容器编排、企业级镜像仓库(registry/Harbor)、容器互联等核心模块,同时衔接Shell编程基础运维能力,是Linux运维实现容器化部署与自动化运维的核心技能。
二、核心知识点
2.1 云服务模型(IaaS/PaaS/SaaS/CaaS)
云服务模型从左到右用户需管理的内容逐渐减少,核心聚焦业务应用,容器即服务(CaaS)介于IaaS和PaaS之间,是Docker容器化的核心服务形态:
| 服务模型 | 全称 | 核心定位 | 代表产品/场景 | 运维管理重点 |
|---|---|---|---|---|
| IaaS | 基础设施即服务 | 提供底层硬件/虚拟化资源 | 阿里云ECS、腾讯云CVM、KVM | 服务器、网络、存储等基础设施 |
| PaaS | 平台即服务 | 提供应用运行/开发平台 | 各类云原生平台、SLB负载均衡 | 应用部署、平台配置,无需管理基础设施 |
| SaaS | 软件即服务 | 提供开箱即用的软件服务 | WPS、ProcessOn、亿图 | 仅使用服务,无管理操作 |
| CaaS | 容器即服务 | 提供容器化部署/管理平台 | Docker Swarm、K8s | 容器、镜像、服务编排,无需管理底层系统 |
2.2 容器核心定义
容器是在隔离环境中运行的单个进程,进程结束则容器停止;其隔离环境拥有独立IP、系统文件、主机名、进程管理,等价于一个轻量的mini系统,共享宿主机Linux内核,无需独立操作系统。
2.3 容器vs虚拟机核心对比
容器是轻量级虚拟化技术,与传统虚拟机相比核心差异在资源占用、启动速度和隔离性,是目前云原生部署的主流选择:
| 特性 | 容器 | 虚拟机 |
|---|---|---|
| 启动速度 | 秒级启动 | 分钟级启动,需完整系统启动流程 |
| 资源占用 | 轻量,共享宿主机内核,占用资源极少 | 较重,包含独立操作系统,资源利用率低 |
| 隔离性 | 内核级隔离,隔离性较弱 | 硬件级隔离,隔离性强 |
| 部署效率 | 快速扩容/弹性伸缩,现成镜像丰富 | 扩容慢,回滚/部署繁琐 |
| 硬件依赖 | 无需硬件虚拟化技术(VT-X) | 依赖硬件虚拟化技术支持 |
| 核心优势 | 聚焦应用配置/优化,无需关注基础设施 | 可随意定制,有成熟管理工具(VMware、Openstack) |
| 核心劣势 | 共享宿主机内核,推荐较新Linux内核 | 同一主机多服务易冲突,不满足快速部署需求 |
2.4 Docker基础要求与架构
- 系统要求:Linux内核版本3.10以上,低内核需升级后使用,推荐安装
docker-ce(开源社区版),版本采用年-月命名(如20.10); - C/S架构:Docker采用客户端-服务端架构,客户端为
docker命令,服务端为dockerd守护进程,二者通过DOCKER_HOST通信; - 核心组件:
- 镜像(Images):存放应用运行的环境/服务,是容器的基础模板;
- 容器(Containers):运行起来的镜像,本质是隔离的进程;
- 仓库(Registry):存储镜像的位置,分为远程仓库(Docker Hub)和本地仓库。
2.5 Docker镜像系统类型
Docker镜像基于不同Linux发行版构建,不同系统镜像的核心差异在体积和精简度,alpine是运维首选的轻量镜像:
| 镜像系统 | 核心特点 | 体积 | 运维建议 |
|---|---|---|---|
| Ubuntu | 功能完善,生态丰富 | 中等 | 开发/测试场景使用 |
| Debian | 稳定,Docker官方镜像默认系统 | 中等 | 生产环境通用 |
| CentOS | 国内运维最熟悉,命令体系友好 | 较大 | 新手入门使用 |
| Alpine | 基于Linux内核+Busybox,命令/依赖精简 | 极小(MB级) | 生产环境首选,节省资源 |
2.6 容器运行核心逻辑
容器的生命周期与前台进程强绑定,必须有一个前台进程阻塞容器,否则容器会启动后立即退出;常见的前台进程方式:nginx -g 'daemon off;'、php-fpm --nodaemonize、sshd -D、java -jar xxx.jar等。
2.7 数据卷挂载核心目的与分类
解决容器数据持久化问题,容器默认的数据存储在自身文件系统中,容器删除后数据会丢失;通过数据卷将宿主机目录/文件与容器内目录/文件绑定,数据会持久化到宿主机,容器删除后数据不丢失。
| 数据卷类型 | 核心特点 | 适用场景 |
|---|---|---|
| 绑定挂载(-v 宿主机路径:容器路径) | 手动指定宿主机路径,双向同步 | 需明确数据存储位置(如配置文件、日志) |
| 自定义数据卷(docker volume create) | Docker自动管理存储路径,路径统一 | 无需关注数据存储位置,仅需持久化数据 |
| 随机数据卷(-v :容器路径) | Docker自动创建临时路径,容器删除后失效 | 临时数据存储,无需长期保留 |
2.8 Dockerfile核心概念
Dockerfile是自动化构建自定义镜像的文本文件,包含一系列按顺序执行的指令,通过docker build命令构建镜像,核心价值是“一次编写,多次构建”,解决手动构建镜像的繁琐与不可重复问题。
- 核心指令分类:
- 基础配置指令:
FROM(指定基础镜像)、LABEL(添加镜像属性)、ENV(设置环境变量)、WORKDIR(指定工作目录); - 构建操作指令:
RUN(执行构建命令)、COPY(复制文件/目录)、ADD(复制+自动解压)、USER(指定运行用户); - 容器启动指令:
EXPOSE(声明端口)、CMD(默认启动命令,可被覆盖)、ENTRYPOINT(入口命令,参数可追加);
- 基础配置指令:
- CMD与ENTRYPOINT核心区别:
| 指令 | 共同点 | 核心区别 | 适用场景 |
|---|---|---|---|
| CMD | 容器启动时默认执行的命令 | 可被docker run后续命令覆盖 |
简单服务启动,允许灵活替换命令 |
| ENTRYPOINT | 容器启动时默认执行的命令 | 不可被覆盖,docker run后续命令作为参数追加 |
固定服务入口,需强制执行核心命令 |
- 多阶段构建:在一个Dockerfile中使用多个
FROM指令,中间镜像用于编译/构建,最终镜像仅保留运行时依赖,核心目的是减小最终镜像体积。
2.9 Docker Compose核心概念
Docker Compose是单机容器编排工具,通过YAML文件定义多容器应用的服务、网络、数据卷等配置,一键实现多容器的启动、停止、重启等管理,解决多容器手动编排的繁琐问题。
- 核心作用:统一管理多容器依赖(如nginx+php+mysql)、简化部署命令、保证服务启动顺序;
- 核心组件:
docker-compose.yml:配置文件,定义服务、端口、数据卷、依赖关系;docker-compose命令:客户端工具,解析配置文件并操作容器;
- 核心指令:
version(配置文件版本)、services(服务定义)、links(容器互联)、volumes(数据卷挂载)、depends_on(服务依赖顺序)。
2.10 镜像仓库分类与核心作用
镜像仓库是存储Docker镜像的集中式服务,用于镜像的上传、下载、版本管理,解决镜像跨主机共享问题,分为以下类型:
| 仓库类型 | 核心特点 | 代表产品 | 适用场景 |
|---|---|---|---|
| 公有仓库 | 公开镜像,无需搭建,免费使用 | Docker Hub、阿里云镜像仓库 | 下载官方镜像、开源镜像 |
| 私有仓库(registry) | 轻量,无图形化界面,命令行操作 | Docker Registry | 小型团队,镜像数量少 |
| 企业级仓库(Harbor) | 图形化界面,支持权限管理、镜像同步 | Harbor | 中大型企业,镜像数量多,需权限控制 |
2.11 容器互联核心原理
容器互联是实现多容器间网络通信的机制,通过--link选项或自定义网络,让容器之间可通过容器名/别名访问,无需依赖宿主机IP,核心原理是Docker DNS服务的内部解析。
- 核心方式:
--link选项:单向关联运行中的容器,自动配置/etc/hosts解析;- 自定义网络:创建桥接网络,容器加入网络后可通过容器名互通,支持双向通信;
- 通信条件:互联的容器需在同一网络中,且目标容器处于运行状态。
三、步骤/命令
3.1 ⭐️ Docker环境搭建(CentOS系统)
操作场景:搭建标准Docker-ce环境,配置国内镜像加速、命令自动补全,满足生产环境使用要求。
3.1.1 安装Docker-ce
# 1. 安装依赖包
yum install -y yum-utils device-mapper-persistent-data lvm2
# 2. 添加Docker官方YUM源
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 3. 替换为清华源,提升下载速度
sed -i 's+download.docker.com+mirrors.tuna.tsinghua.edu.cn/docker-ce+' /etc/yum.repos.d/docker-ce.repo
# 4. 安装Docker-ce(默认安装最新版,指定版本加docker-ce-20.10.xx)
yum install -y docker-ce
# 5. 开机自启并启动Docker服务
systemctl enable --now docker
# 6. 验证安装
docker version
效果验证:执行docker version,输出Client和Server版本信息,无报错即安装成功。
3.1.2 配置镜像加速(阿里云)
# 1. 创建docker配置目录
mkdir -p /etc/docker
# 2. 写入加速配置
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": [
"https://bjjtv7cs.mirror.aliyuncs.com",
"https://docker.1ms.run"
]
}
EOF
# 3. 重载配置并重启Docker
systemctl daemon-reload
systemctl restart docker
效果验证:执行docker info,查看Registry Mirrors字段,显示配置的加速地址即生效。
3.1.3 配置Docker命令自动补全
# 安装补全依赖
yum install -y bash-completion bash-completion-extras
# 生效补全配置
source /etc/profile
效果验证:输入docker im后按Tab键,自动补全为docker images,即配置成功。
3.2 ⭐️ Docker镜像核心管理操作
操作场景:实现镜像的搜索、下载、导出、导入、删除、打标、信息查看等日常管理,核心命令标⭐️。
3.2.1 搜索镜像docker search
# 搜索PHP镜像,关注OFFICIAL(官方)、STARS(星级)
docker search php
效果验证:输出镜像列表,包含仓库名、描述、星级、是否官方等信息,优先选择官方/高星级镜像。
3.2.2 下载镜像docker pull⭐️
# 下载最新版nginx镜像(默认tag:latest)
docker pull nginx
# 下载指定版本nginx镜像
docker pull nginx:1.22-alpine
# 下载第三方仓库镜像(用户名/镜像名:版本)
docker pull bitnami/nginx:1.22
效果验证:执行docker images,能看到下载的镜像信息,即下载成功。
3.2.3 查看镜像docker images⭐️
# 查看本地所有镜像
docker images
# 查看所有镜像(包含隐藏的中间镜像)
docker images -a
# 只显示镜像ID
docker images -q
效果验证:输出镜像列表,包含仓库名、标签、镜像ID、创建时间、大小等信息。
3.2.4 导出/导入镜像docker save/docker load⭐️
# 1. 导出镜像(-o 指定输出文件)
docker save nginx:1.22-alpine -o nginx_1.22_alpine.tar
# 2. 批量导出所有镜像(结合awk生成命令并执行)
docker images | awk 'NR>1{print "docker save",$1":"$2,"-o",$1"_"$2".tar"}' | bash
# 3. 导入镜像(-i 指定导入文件)
docker load -i nginx_1.22_alpine.tar
效果验证:导入后执行docker images,能看到导入的镜像,即导入成功。
3.2.5 删除镜像docker rmi⭐️
# 通过镜像名删除
docker rmi nginx:latest
# 通过镜像ID删除(推荐,避免重名)
docker rmi 605c77e624dd
# 强制删除镜像(慎用)
docker rmi -f nginx:1.22-alpine
# 清理无效镜像(名字/标签为none的镜像)
docker image prune -f
注意:镜像被容器使用时无法直接删除,需先删除容器。
3.2.6 镜像打标docker tag⭐️
# 给镜像设置新标签(原镜像:原标签 新镜像:新标签)
docker tag nginx:1.22-alpine nginx:1.22-alpine-oldboy
# 打标用于私有仓库上传(仓库地址/镜像名:标签)
docker tag nginx:1.22-alpine 10.0.0.81/nginx:1.22-alpine
效果验证:执行docker images,能看到同一镜像ID对应两个标签,即打标成功。
3.2.7 查看镜像详情docker inspect
# 查看nginx:1.22-alpine镜像详情(JSON格式)
docker inspect nginx:1.22-alpine
# 结合jq过滤镜像IP/大小等信息(需安装jq:yum install -y jq)
docker inspect nginx:1.22-alpine | jq '.[].Size'
效果验证:输出镜像的详细配置信息,包含系统、架构、层信息等。
3.3 ⭐️ Docker容器核心管理操作
操作场景:实现容器的创建、运行、查看、启停、删除、进入、数据传输等日常管理,核心命令标⭐️。
3.3.1 运行容器docker run⭐️
# 基础运行:后台运行,端口映射80:80,指定容器名
docker run -d -p 80:80 --name nginx_oldboy nginx:1.22-alpine
# 交互式运行:进入容器终端,前台运行(退出后容器停止)
docker run -it --name centos7_oldboy centos:centos7.9.2009
# 后台交互式运行:后台运行并分配终端,适合无服务的系统镜像
docker run -itd --name centos7_daemon centos:centos7.9.2009
# 运行带前台进程的CentOS容器(避免启动后退出)
docker run -d --name centos7_sleep centos:centos7.9.2009 sleep 3600
参数说明:-d后台运行,-p端口映射,--name指定容器名,-i交互模式,-t分配终端。
效果验证:执行docker ps,能看到容器状态为Up,即运行成功。
3.3.2 查看容器docker ps⭐️
# 查看运行中的容器
docker ps
# 查看所有容器(运行中+已停止)
docker ps -a
# 只显示容器ID
docker ps -q
# 显示容器完整信息(不省略命令)
docker ps --no-trunc
# 过滤已停止的容器
docker ps -a | grep Exited
效果验证:输出容器列表,包含容器ID、镜像、命令、创建时间、状态、端口、名字等信息。
3.3.3 容器启停/重启docker start/stop/restart⭐️
# 启动已停止的容器(通过容器名/ID)
docker start nginx_oldboy
# 停止运行中的容器
docker stop nginx_oldboy
# 重启容器
docker restart nginx_oldboy
# 强制停止容器(类似kill -9)
docker kill nginx_oldboy
效果验证:执行docker ps,容器状态随命令变化为Up/Exited,即操作成功。
3.3.4 删除容器docker rm⭐️
# 删除已停止的容器
docker rm nginx_oldboy
# 强制删除运行中的容器(慎用)
docker rm -f nginx_oldboy
# 批量删除所有容器(高危操作,生产环境禁用)
docker rm -f $(docker ps -aq)
# 批量删除已停止的容器
docker rm $(docker ps -a | grep Exited | awk '{print $1}')
效果验证:执行docker ps -a,无对应容器信息,即删除成功。
3.3.5 进入运行中的容器docker exec⭐️
# 进入容器并分配bash终端(推荐,创建新终端,不影响容器进程)
docker exec -it nginx_oldboy /bin/bash
# 若bash不可用,使用sh终端
docker exec -it nginx_oldboy /bin/sh
# 直接在容器中执行命令(无需进入)
docker exec -it nginx_oldboy ls /usr/share/nginx/html
效果验证:进入容器后命令行提示符变化,可执行容器内命令,即进入成功。
3.3.6 宿主机与容器数据传输docker cp⭐️
# 宿主机→容器:将宿主机/etc/hosts复制到容器/tmp目录
docker cp /etc/hosts nginx_oldboy:/tmp/
# 容器→宿主机:将容器/usr/share/nginx/html/index.html复制到宿主机/tmp
docker cp nginx_oldboy:/usr/share/nginx/html/index.html /tmp/
效果验证:进入容器/宿主机对应目录,能看到复制的文件,即传输成功。
3.3.7 查看容器资源占用docker stats
# 实时查看容器CPU、内存、网络、磁盘等资源占用
docker stats
# 查看指定容器的资源占用
docker stats nginx_oldboy
效果验证:实时输出容器资源占用数据,按Ctrl+C退出。
3.3.8 容器制作为镜像docker commit
# 1. 手动创建tengine镜像(基础步骤)
# 启动ubuntu容器
docker run -it --name ubt_tengine_2.3.3 ubuntu:20.04 /bin/bash
# 容器内配置apt源、安装依赖、编译安装tengine(省略详细步骤)
# 容器内清理缓存、创建软连接、启动测试
# 2. 将运行中的容器制作为新镜像(容器名/ID 新镜像:新标签)
docker commit ubt_tengine_2.3.3 tengine:2.3.3-v1
效果验证:执行docker images,能看到新创建的镜像,即制作成功。
3.3.9 CMD与ENTRYPOINT实操
# 1. CMD示例:创建镜像,默认执行top命令
cat > Dockerfile <<EOF
FROM ubuntu:20.04
CMD ["top", "-b", "-c"]
EOF
docker build -t test:cmd .
# 启动容器,默认执行top
docker run -d --name test_cmd test:cmd
# 覆盖CMD命令,执行sleep 999
docker run -d --name test_cmd_sleep test:cmd sleep 999
# 2. ENTRYPOINT示例:创建镜像,固定执行top命令
cat > Dockerfile <<EOF
FROM ubuntu:20.04
ENTRYPOINT ["top", "-b", "-c"]
EOF
docker build -t test:entrypoint .
# 启动容器,默认执行top -b -c
docker run -d --name test_entrypoint test:entrypoint
# 追加参数,执行top -b -c -H
docker run -d --name test_entrypoint_h test:entrypoint -H
效果验证:通过docker ps查看容器命令,验证CMD被覆盖、ENTRYPOINT追加参数的效果。
3.4 ⭐️ Docker端口映射实操
操作场景:实现宿主机与容器的端口映射,让外部能访问容器内的服务,核心通过-p选项实现。
# 1. 一对一映射:宿主机80→容器80
docker run -d -p 80:80 --name nginx_80 nginx:1.22-alpine
# 2. 多端口映射:宿主机8080/8081→容器8080/8081
docker run -d -p 8080:8080 -p 8081:8081 --name nginx_multi nginx:1.22-alpine
# 3. 端口范围映射:宿主机80-82→容器80-82
docker run -d -p 80-82:80-82 --name nginx_range nginx:1.22-alpine
# 4. 绑定IP映射:仅允许通过宿主机172.16.1.81的12306端口访问容器80
docker run -d -p 172.16.1.81:12306:80 --name nginx_bind_ip nginx:1.22-alpine
# 5. 查看容器端口映射关系
docker port nginx_oldboy
效果验证:通过curl 宿主机IP:映射端口,能访问到容器内的服务,即映射成功。
3.5 ⭐️ Docker数据卷挂载实操
操作场景:实现容器数据持久化,分为目录/文件挂载、自定义数据卷挂载、随机数据卷挂载,核心通过-v选项实现。
3.5.1 目录/文件挂载(指定宿主机路径)⭐️
# 1. 准备宿主机目录
mkdir -p /app/docker/nginx/{conf,code,log}
echo "Docker数据卷挂载测试" > /app/docker/nginx/code/index.html
# 2. 挂载目录+文件:配置目录、代码目录、日志目录
docker run -d -p 80:80 --name nginx_volume \
-v /app/docker/nginx/conf/:/etc/nginx/conf.d/ \
-v /app/docker/nginx/code/:/usr/share/nginx/html/ \
-v /app/docker/nginx/log/:/var/log/nginx/ \
nginx:1.22-alpine
# 3. 挂载单个文件:宿主机index.html→容器index.html
docker run -d -p 9958:80 --name nginx_file \
-v /app/docker/nginx/code/index.html:/usr/share/nginx/html/index.html \
nginx:1.22-alpine
效果验证:访问宿主机IP:80,显示宿主机index.html的内容;容器删除后,宿主机目录数据仍存在,即挂载成功。
3.5.2 自定义数据卷挂载(Docker自动管理路径)
# 1. 创建自定义数据卷
docker volume create nginx_log_data
# 2. 查看数据卷
docker volume ls
# 3. 挂载自定义数据卷到容器/var/log/nginx
docker run -d -p 80:80 --name nginx_vol_custom \
-v nginx_log_data:/var/log/nginx/ \
nginx:1.22-alpine
# 4. 查看数据卷实际路径
docker inspect nginx_log_data | jq '.[].Mountpoint'
效果验证:数据卷实际路径为/var/lib/docker/volumes/nginx_log_data/_data,容器日志会写入该路径,即挂载成功。
3.5.3 随机数据卷挂载(临时数据存储)
# 挂载随机数据卷到容器/var/tmp,Docker自动创建临时路径
docker run -d -p 80:80 --name nginx_vol_random \
-v :/var/tmp/ \
nginx:1.22-alpine
效果验证:容器删除后,随机数据卷自动清理,临时数据不保留,即挂载成功。
3.6 ⭐️ Dockerfile实操(自定义镜像构建)
操作场景:通过Dockerfile自动化构建自定义镜像,包含tengine、nginx+php、多阶段构建等实战案例,核心命令标⭐️。
3.6.1 Dockerfile基础格式与构建命令
# 1. 准备Dockerfile目录
mkdir -p /server/dockerfile/nginx-tengine && cd /server/dockerfile/nginx-tengine
# 2. 编写基础Dockerfile(构建tengine镜像)
cat > Dockerfile <<EOF
# 基础镜像
FROM ubuntu:20.04
# 镜像属性
LABEL maintainer="oldboylidao996" author="oldboyedu"
# 环境变量
ENV Web_Server="tengine" Web_Version="2.3.3" Server_Dir="/app/tools/tengine"
# 安装依赖、编译安装tengine
RUN sed -ri 's#archive.ubuntu.com|security.ubuntu.com#mirrors.aliyun.com#g' /etc/apt/sources.list \
&& apt update \
&& apt install -y wget libssl-dev make gcc pcre2-utils libpcre3-dev zlib1g-dev \
&& wget -P /tmp/ http://tengine.taobao.org/download/${Web_Server}-${Web_Version}.tar.gz \
&& cd /tmp && tar xf ${Web_Server}-${Web_Version}.tar.gz \
&& cd ${Web_Server}-${Web_Version} \
&& ./configure --prefix=${Server_Dir} \
--user=nginx --group=nginx \
--with-http_ssl_module --with-http_v2_module \
&& make -j 1 && make install \
&& groupadd nginx && useradd -g nginx nginx \
&& ln -s ${Server_Dir}/sbin/nginx /sbin/ \
# 清理缓存
&& rm -fr /tmp/* /var/cache/*
# 复制首页文件
COPY index.html ${Server_Dir}/html/index.html
# 声明端口
EXPOSE 80
# 启动命令(前台运行)
CMD ["nginx", "-g", "daemon off;"]
EOF
# 3. 准备首页文件
echo "Tengine Dockerfile Build" > index.html
# 4. 构建镜像(-t 镜像名:标签,. 表示当前目录)
docker build -t tengine:2.3.3-dockerfile .
# 5. 运行镜像
docker run -d -p 80:80 --name tengine_dockerfile tengine:2.3.3-dockerfile
效果验证:访问宿主机IP:80,显示“Tengine Dockerfile Build”,即构建并运行成功。
3.6.2 多阶段构建案例(减小镜像体积)
# 1. 编写多阶段构建Dockerfile
cat > Dockerfile <<EOF
# 第一阶段:编译构建(中间镜像)
FROM ubuntu:20.04 AS build
ENV Web_Server="tengine" Web_Version="2.3.3"
RUN sed -ri 's#archive.ubuntu.com|security.ubuntu.com#mirrors.aliyun.com#g' /etc/apt/sources.list \
&& apt update \
&& apt install -y wget libssl-dev make gcc pcre2-utils libpcre3-dev zlib1g-dev \
&& wget -P /tmp/ http://tengine.taobao.org/download/${Web_Server}-${Web_Version}.tar.gz \
&& cd /tmp && tar xf ${Web_Server}-${Web_Version}.tar.gz \
&& cd ${Web_Server}-${Web_Version} \
&& ./configure --prefix=/app/tools/tengine \
--user=nginx --group=nginx \
&& make -j 1 && make install
# 第二阶段:最终镜像(仅保留运行依赖)
FROM ubuntu:20.04
COPY --from=build /app/ /app/
COPY --from=build /etc/passwd /etc/passwd
COPY --from=build /etc/group /etc/group
# 安装运行依赖
RUN apt update && apt install -y libssl-dev pcre2-utils zlib1g-dev \
&& ln -s /app/tools/tengine/sbin/nginx /sbin/ \
&& rm -fr /var/cache/*
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
EOF
# 2. 构建镜像
docker build -t tengine:2.3.3-multi-stage .
效果验证:执行docker images,对比单阶段与多阶段镜像大小,多阶段镜像体积显著减小。
3.6.3 nginx+php多服务镜像案例
# 1. 准备目录与文件
mkdir -p /server/dockerfile/nginx-php && cd /server/dockerfile/nginx-php
# 2. 编写entrypoint.sh(启动脚本,保证多服务前台运行)
cat > entrypoint.sh <<EOF
#!/bin/bash
# 启动php-fpm
php-fpm
# 启动nginx前台运行
nginx -g "daemon off;"
EOF
# 3. 编写nginx配置文件(kod.oldboylinux.cn.conf)
cat > kod.oldboylinux.cn.conf <<EOF
server {
listen 80;
server_name kod.oldboylinux.cn;
root /app/code/kod;
location / {
index index.php;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;
include fastcgi_params;
}
}
EOF
# 4. 编写Dockerfile
cat > Dockerfile <<EOF
FROM centos:7
LABEL author="oldboylidao996" nginx_version="1.20.2" php_version="7.2.34"
# 配置yum源
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo \
&& curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo \
# 安装nginx和php
&& yum install -y nginx php72w php72w-fpm php72w-common \
# 配置php-fpm用户
&& sed -i 's#apache#nginx#g' /etc/php-fpm.d/www.conf \
# 复制配置文件和启动脚本
&& mkdir -p /app/code/kod \
&& COPY kod.oldboylinux.cn.conf /etc/nginx/conf.d/ \
&& COPY entrypoint.sh / \
&& chmod +x /entrypoint.sh \
# 清理缓存
&& rm -fr /tmp/* /var/cache/*
# 声明端口
EXPOSE 80 9000
# 启动入口
CMD ["/entrypoint.sh"]
EOF
# 5. 构建镜像
docker build -t web:nginx-php-v1 .
# 6. 运行镜像
docker run -d -p 80:80 --name nginx-php-service web:nginx-php-v1
效果验证:进入容器执行ps aux,能看到nginx和php-fpm进程,访问宿主机IP显示nginx默认页面,即构建成功。
3.7 ⭐️ Docker Compose实操(多容器编排)
操作场景:安装Docker Compose,通过YAML文件编排多容器服务(nginx+php),实现一键部署,核心命令标⭐️。
3.7.1 安装Docker Compose
# 1. 安装Docker Compose(CentOS系统)
yum install -y docker-compose
# 2. 验证安装
docker-compose --version
效果验证:输出docker-compose version 1.29.2, build 5becea4c(版本号可能不同),即安装成功。
3.7.2 编写docker-compose.yml配置文件
# 1. 准备目录
mkdir -p /server/compose/nginx-php && cd /server/compose/nginx-php
# 2. 编写docker-compose.yml
cat > docker-compose.yml <<EOF
version: "3.3"
services:
# nginx服务
web_nginx:
image: nginx:1.22-alpine
ports:
- "80:80"
volumes:
- ./conf/nginx.conf:/etc/nginx/nginx.conf
- ./conf/kod.oldboylinux.cn.conf:/etc/nginx/conf.d/kod.oldboylinux.cn.conf
- ./code:/app/code/kod
links:
- web_php:php
depends_on:
- web_php # 依赖php服务,优先启动php
# php服务
web_php:
image: php:7-fpm
volumes:
- ./conf/www.conf:/usr/local/etc/php-fpm.d/www.conf
- ./code:/app/code/kod
expose:
- "9000"
EOF
# 3. 准备配置文件和代码目录
mkdir -p conf code
# 复制之前的nginx配置和php-fpm配置到conf目录
cp /server/dockerfile/nginx-php/kod.oldboylinux.cn.conf conf/
# 4. 启动多容器服务
docker-compose up -d
# 5. 查看服务状态
docker-compose ps
# 6. 查看日志
docker-compose logs -f
# 7. 停止服务
# docker-compose stop
# 8. 删除服务(容器)
# docker-compose rm -f
效果验证:执行docker-compose ps,显示web_nginx和web_php服务状态为Up,访问宿主机IP正常,即编排成功。
3.8 ⭐️ 镜像仓库实操(registry/Harbor)
操作场景:搭建私有镜像仓库(registry和Harbor),实现镜像的私有上传、下载,核心命令标⭐️。
3.8.1 搭建Docker Registry私有仓库
# 1. 所有节点配置insecure-registries(包括仓库服务器和客户端)
cat > /etc/docker/daemon.json <<EOF
{
"registry-mirrors": ["https://bjjtv7cs.mirror.aliyuncs.com"],
"insecure-registries": ["reg.oldboylinux.cn:5000"]
}
EOF
systemctl daemon-reload && systemctl restart docker
# 2. 启动registry仓库(仓库服务器:10.0.0.82)
docker volume create registry_data
docker run -d --name oldboy_registry \
-p 5000:5000 \
-v registry_data:/var/lib/registry \
--restart=always \
registry:latest
# 3. 镜像打标(客户端:10.0.0.81)
docker tag nginx:1.22-alpine reg.oldboylinux.cn:5000/oldboyedu/nginx:1.22-alpine
# 4. 推送镜像到私有仓库
docker push reg.oldboylinux.cn:5000/oldboyedu/nginx:1.22-alpine
# 5. 从私有仓库拉取镜像(其他客户端)
docker pull reg.oldboylinux.cn:5000/oldboyedu/nginx:1.22-alpine
# 6. 查看仓库镜像列表
curl http://reg.oldboylinux.cn:5000/v2/_catalog
效果验证:执行curl命令输出{"repositories":["oldboyedu/nginx"]},即镜像推送成功。
3.8.2 搭建Harbor企业级镜像仓库
# 1. 环境准备(2C4G以上,关闭防火墙/selinux)
systemctl stop firewalld && systemctl disable firewalld
setenforce 0 && sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
# 2. 安装Docker和Docker Compose(已安装可跳过)
yum install -y docker-ce docker-compose
systemctl enable --now docker
# 3. 下载并解压Harbor安装包
wget https://github.com/goharbor/harbor/releases/download/v2.3.1/harbor-offline-installer-v2.3.1.tgz
tar xf harbor-offline-installer-v2.3.1.tgz -C /app/tools/
cd /app/tools/harbor
# 4. 配置Harbor
cp harbor.yml.tmpl harbor.yml
# 修改配置文件
sed -i 's/hostname: reg.mydomain.com/hostname: harbor.oldboylinux.cn/' harbor.yml
sed -i '/https:/,/private_key:/d' harbor.yml # 禁用HTTPS
sed -i 's/harbor_admin_password: Harbor12345/harbor_admin_password: Lidao996/' harbor.yml
# 5. 安装Harbor
./install.sh
# 6. 访问Harbor(浏览器)
# 地址:http://harbor.oldboylinux.cn,用户名:admin,密码:Lidao996
# 7. 客户端配置并登录Harbor
cat > /etc/docker/daemon.json <<EOF
{
"registry-mirrors": ["https://bjjtv7cs.mirror.aliyuncs.com"],
"insecure-registries": ["harbor.oldboylinux.cn"]
}
EOF
systemctl daemon-reload && systemctl restart docker
# 登录Harbor
docker login -u admin -p Lidao996 harbor.oldboylinux.cn
# 8. 镜像推送与拉取
docker tag tengine:2.3.3-dockerfile harbor.oldboylinux.cn/library/tengine:2.3.3
docker push harbor.oldboylinux.cn/library/tengine:2.3.3
docker pull harbor.oldboylinux.cn/library/tengine:2.3.3
效果验证:浏览器登录Harbor后,在library项目中能看到推送的tengine镜像,即搭建成功。
3.9 ⭐️ 容器互联实操(--link选项)
操作场景:通过--link选项实现nginx与php容器互联,让nginx能通过容器名访问php服务。
# 1. 启动php容器(先启动被关联容器)
docker run -d --name php_service \
-v /app/code:/app/code \
php:7-fpm
# 2. 启动nginx容器,链接php容器
docker run -d --name nginx_service \
-p 80:80 \
--link php_service:php \
-v /app/nginx/conf:/etc/nginx/conf.d \
-v /app/code:/app/code \
nginx:1.22-alpine
# 3. 验证互联(进入nginx容器测试php连接)
docker exec -it nginx_service /bin/sh
# 容器内执行ping测试
ping php # 能ping通php_service容器的IP
# 容器内执行curl测试(需安装curl)
apk add curl
curl http://php:9000 # 能连接到php-fpm服务
效果验证:nginx容器内能ping通php(别名),curl能访问php-fpm端口,即互联成功。
四、原理说明
4.1 Docker C/S架构通信原理
Docker客户端(docker命令)与服务端(dockerd守护进程)通过Unix套接字(默认/var/run/docker.sock)或TCP/IP通信;客户端发送命令请求后,由dockerd统一处理并执行,返回结果给客户端;所有镜像/容器的操作均由服务端完成,客户端仅负责发起请求。
4.2 docker run的底层执行流程
执行docker run命令时,Docker会按以下步骤执行,缺省步骤会自动补全:
- 检查本地镜像:判断本地是否存在指定镜像,若不存在则执行
docker pull从远程仓库下载; - 创建容器:基于镜像创建容器,生成容器的隔离文件系统和配置;
- 启动容器:启动容器内的指定进程,若指定
-d则后台运行,-it则分配交互式终端; - 网络配置:若指定端口映射,自动配置iptables规则和内核转发,实现宿主机与容器的网络通信。
4.3 Docker镜像的分层存储原理
Docker镜像采用分层只读文件系统设计,每个镜像由多个只读层组成,层与层之间基于UnionFS(联合文件系统)叠加:
- 基础层:为Linux发行版的核心系统层(如alpine、debian);
- 中间层:为安装软件、配置环境的操作层(如安装nginx、配置php);
- 顶层:为镜像的最终运行层,只读;
- 容器启动时,会在镜像顶层添加一个可写层,容器内的所有操作均在可写层完成,镜像本身保持只读,实现多容器共享一个镜像。
4.4 端口映射的底层实现原理
Docker端口映射(-p选项)的本质是iptables NAT规则+Linux内核IP转发:
- 内核转发:Docker要求开启
net.ipv4.ip_forward = 1,否则宿主机无法转发请求到容器; - iptables规则:Docker会在
nat表中创建DOCKER自定义链,添加DNAT规则,将宿主机映射端口的请求转发到容器的对应端口; - docker-proxy:Docker会启动
docker-proxy进程,监听宿主机映射端口,实现请求的转发和负载均衡。
4.5 数据卷挂载的底层原理
Docker数据卷挂载基于Linux绑定挂载(Bind Mount) 实现,将宿主机的目录/文件与容器内的目录/文件进行硬绑定:
- 挂载后,宿主机和容器对该目录/文件的操作双向同步;
- 容器内的挂载路径会屏蔽原有的文件系统,仅显示宿主机挂载的内容;
- 自定义数据卷由Docker统一管理,实际路径为
/var/lib/docker/volumes/卷名/_data,Docker会自动维护该路径的权限和目录结构。
4.6 Dockerfile构建原理
Dockerfile构建镜像的核心是分层构建,每个指令对应一个镜像层,按顺序执行并缓存:
- 指令执行顺序:从
FROM开始,依次执行后续指令,每个指令生成一个新的只读层; - 缓存机制:若指令未修改,构建时会复用缓存层,加速构建;若某指令修改,后续所有指令的缓存失效,需重新执行;
- 多阶段构建原理:第一阶段(构建阶段)生成中间镜像,包含编译工具、源码等;第二阶段(运行阶段)从中间镜像复制仅运行所需的文件和依赖,丢弃构建工具,减小最终镜像体积。
4.7 Docker Compose编排原理
Docker Compose的核心是解析YAML配置文件,批量调用Docker API操作容器:
- 配置解析:读取
docker-compose.yml,解析服务、网络、数据卷等配置; - 服务依赖:根据
depends_on定义的顺序启动服务,确保依赖服务先启动; - 网络管理:自动创建默认桥接网络,将所有服务容器加入该网络,实现容器间通过容器名通信;
- 生命周期管理:通过
docker-compose up/stop/restart等命令,统一管理所有服务的生命周期。
4.8 镜像仓库存储原理
- Registry仓库存储原理:
- Registry采用文件系统存储,镜像数据默认存储在
/var/lib/registry/docker/registry/v2/repositories目录; - 镜像按“仓库名/镜像名/标签”分层存储,每层数据以哈希值命名的文件形式保存,支持断点续传和增量上传;
- 无内置权限控制,需通过
insecure-registries配置允许HTTP访问,或配置HTTPS实现安全访问。
- Registry采用文件系统存储,镜像数据默认存储在
- Harbor仓库存储原理:
- 基于Registry二次开发,核心存储依赖Registry的文件系统,同时新增数据库(PostgreSQL) 存储用户、项目、权限等元数据;
- 镜像数据默认存储在
/data/registry目录,支持镜像复制、同步功能,可通过配置实现多Harbor节点的高可用; - 内置Nginx反向代理,提供HTTPS加密、负载均衡和身份认证功能,保障镜像传输安全。
4.9 容器互联的底层原理
容器互联的核心是网络名称解析,实现容器间无需依赖宿主机IP即可通信:
- --link选项原理:
- 启动被链接容器后,启动链接容器时,Docker会自动在链接容器的
/etc/hosts文件中添加被链接容器的“容器名→IP”映射; - 仅支持单向通信(链接容器→被链接容器),且被链接容器重启后,IP可能变化,
/etc/hosts映射不会自动更新,需重启链接容器。
- 启动被链接容器后,启动链接容器时,Docker会自动在链接容器的
- 自定义网络原理:
- 创建自定义桥接网络(
docker network create)后,容器加入该网络时,Docker会启动内置DNS服务; - 容器间可通过容器名或别名相互解析,DNS服务自动维护IP映射,容器重启后IP更新时,DNS解析同步生效,支持双向通信。
- 创建自定义桥接网络(
4.10 CMD与ENTRYPOINT执行原理
- CMD执行原理:
- 容器启动时,若
docker run后未指定命令,执行CMD定义的命令;若指定了命令,CMD命令会被覆盖; - 格式支持“exec格式”(
["命令", "参数1", "参数2"])和“shell格式”(命令 参数1 参数2),exec格式直接执行命令,shell格式会通过/bin/sh -c执行。
- 容器启动时,若
- ENTRYPOINT执行原理:
- 无论
docker run后是否指定命令,ENTRYPOINT定义的命令都会执行,后续指定的命令会作为参数追加到ENTRYPOINT命令后; - 仅支持exec格式,若需使用shell特性,需显式指定
["/bin/sh", "-c", "命令 参数"]; - 可与CMD配合使用:ENTRYPOINT定义核心命令,CMD定义默认参数,
docker run后续命令可覆盖CMD的默认参数。
- 无论
五、注意事项
- Dockerfile构建注意事项:
- 基础镜像尽量指定具体版本(如
ubuntu:20.04),避免使用latest导致版本不一致; - 合并RUN指令(用
&&连接),减少镜像层数,同时清理缓存(rm -fr /var/cache/*),减小镜像体积; - COPY与ADD区分使用:仅复制文件用COPY,复制并自动解压用ADD(仅支持tar包);
- 避免在Dockerfile中运行后台服务,容器启动命令需前台运行(如
nginx -g 'daemon off;'),否则容器启动后立即退出。
- 基础镜像尽量指定具体版本(如
- Docker Compose注意事项:
- 配置文件版本(
version)需与Docker Compose版本兼容(如3.3版本适配Docker Compose 1.29+); depends_on仅保证启动顺序,不保证服务就绪(如数据库启动后需初始化,应用服务可能连接失败),需在应用中添加重试逻辑;- 修改配置文件后,执行
docker-compose up -d会自动重启变化的服务,若服务名修改,需添加--remove-orphans删除旧服务,避免端口冲突。
- 配置文件版本(
- 镜像仓库注意事项:
- Registry仓库无权限控制,仅适用于内网环境,公网环境需配置HTTPS和身份认证;
- Harbor仓库默认禁用HTTPS,生产环境需配置SSL证书,避免镜像传输过程中被窃听;
- 推送镜像到私有仓库前,必须给镜像打标(格式:
仓库地址/项目名/镜像名:标签),否则推送失败。
- 容器互联注意事项:
- 避免使用
--link选项,推荐使用自定义网络实现容器互联,支持双向通信和IP自动更新; - 容器加入自定义网络后,若需对外提供服务,需配置端口映射(
-p),否则外部无法访问。
- 避免使用
- 数据卷挂载注意事项:
- 挂载宿主机目录时,确保宿主机目录权限正确(如容器运行用户为nginx,宿主机目录需授权
chown -R nginx:nginx); - 自定义数据卷删除前,需先删除使用该数据卷的容器,否则无法删除;
- 避免挂载容器内的核心系统目录(如
/etc),可能导致容器运行异常。
- 挂载宿主机目录时,确保宿主机目录权限正确(如容器运行用户为nginx,宿主机目录需授权
- 其他补充注意事项:
- 多阶段构建时,中间镜像仅用于编译构建,最终镜像需仅保留运行依赖,避免携带编译工具和源码;
- Harbor仓库管理员密码需定期修改,创建项目时按业务划分,配置最小权限(如开发人员仅授予“拉取”权限);
- 容器运行时若需修改内核参数,需通过
--sysctl选项(docker run --sysctl net.ipv4.ip_forward=1),避免直接修改宿主机内核参数。
六、结尾
6.1 总结
各模块核心要点如下:
- 基础操作:Docker环境搭建、镜像/容器日常管理、端口映射、数据卷挂载,是容器化部署的基础;
- 自动化构建:通过Dockerfile实现自定义镜像的自动化、可重复构建,掌握多阶段构建减小镜像体积,适配生产环境镜像标准化;
- 多容器编排:Docker Compose通过YAML文件统一管理多容器依赖,一键实现启动、停止、重启,解决手动编排的繁琐问题;
- 镜像仓库:Registry适用于小型团队内网私有镜像存储,Harbor提供图形化界面、权限管理、镜像同步,满足中大型企业镜像管理需求;
- 容器互联:自定义网络替代
--link选项,实现容器间安全、可靠的通信,适配多服务协作场景; - 高级用法:CMD与ENTRYPOINT的配合使用,实现容器启动命令的灵活配置,满足不同业务场景的启动需求。
6.2 避坑指南
| 坑点 | 解决方案 |
|---|---|
| Dockerfile构建镜像体积过大 | 1. 采用多阶段构建,仅保留运行依赖;2. 合并RUN指令,清理缓存和临时文件;3. 使用alpine基础镜像 |
| 容器互联后无法通信 | 1. 优先使用自定义网络(docker network create),避免--link;2. 检查容器是否在同一网络,通过docker network inspect验证;3. 容器内安装ping/curl工具测试连通性 |
| Docker Compose服务启动顺序异常 | 1. 使用depends_on定义启动顺序;2. 应用服务中添加依赖服务就绪检查(如数据库连接重试);3. 避免依赖服务未初始化完成时应用服务启动 |
| 私有仓库推送镜像失败 | 1. 镜像打标格式正确(仓库地址/项目名/镜像名:标签);2. 客户端配置insecure-registries(非HTTPS仓库);3. 登录私有仓库(docker login)后再推送 |
CMD命令被docker run覆盖导致服务启动失败 |
1. 核心服务启动命令用ENTRYPOINT定义;2. CMD仅定义默认参数,避免核心命令被覆盖;3. 检查docker run后续是否误写命令 |
| Harbor仓库无法访问 | 1. 关闭防火墙或开放80/443端口;2. 客户端配置insecure-registries(非HTTPS);3. 检查宿主机/etc/hosts是否配置Harbor域名解析 |
| 数据卷挂载后容器无权限读写 | 1. 宿主机目录授权(chown -R 容器运行用户:组 目录);2. 启动容器时通过--user指定运行用户;3. 避免挂载容器核心系统目录 |
| 容器重启后互联解析失败 | 1. 替换--link为自定义网络;2. 自定义网络中容器通过容器名解析,自动同步IP变化;3. 重启被链接容器后,重启链接容器更新/etc/hosts |
| 多阶段构建复制文件失败 | 1. 中间镜像编译后的文件路径正确;2. 使用COPY --from=中间镜像别名 源路径 目标路径;3. 确保中间镜像中文件存在且权限可读取 |
| Docker Compose修改配置后服务未更新 | 1. 执行docker-compose up -d --force-recreate强制重建容器;2. 服务名修改时添加--remove-orphans删除旧服务;3. 检查配置文件缩进是否正确(YAML对缩进敏感) |

浙公网安备 33010602011771号