尧图精选

Docker微服务实战:从安装到编排的完整指南

🕒 发布时间:2026/10/2 19:45:59 📁 来源:尧图网络
简介围绕Docker与微服务技术演进脉络的DOCX资料面向软件开发者、架构师及运维人员系统梳理从SOA、单体架构到微服务架构、容器化与Kubernetes的发展进程帮助理解技术变革背后的驱动因素和落地方案。压缩包共1个docx文件整体112KB轻量易读可直接用于个人笔记整理或团队培训辅助。文档从SOA简史与企业服务总线ESB讲起分析单体应用在更新、扩展方面的痛点再引出微服务模块化与独立部署的价值同时结合Docker容器解决环境一致性、隔离性和可移植性的实际优势以及Kubernetes在编排管理上的作用内容配有架构示意图和关键点小结方便按章节快速检索也适合技术选型讨论、培训备课或实际项目演示时参考。已有120人浏览学习对希望建立容器化知识框架的技术人员是不错的入门参考。1. Docker 和微服务技术的崛起先把两个概念绑在一起看Docker 和微服务技术的崛起是我这几年做部署侧感受最明显的一件事以前上线是装环境、改配置、换目录现在上线是构建镜像、编排容器、注册服务。这两样东西解决的是同一个问题——让应用不再依赖某台特定机器让团队能独立交付自己的服务。这篇文章不聊概念史只讲你上手要用的那条路从 Linux 和 Windows 上把 Docker 装对跑起 MySQL、Redis到用 Compose 把一个订单服务编排成可启动的微服务再讲到网络不通、镜像拉不下来、注册中心地址错这类让人想砸键盘的问题。适合正要引入容器化、准备自己搭一套微服务环境的人。2. 先把 Docker 环境装对Linux 和 Windows 下的选型与启动验证2.1 装哪种 DockerEngine、Desktop 和发行版自带包的区别Docker 是 C/S 架构。你平时敲的docker命令只是客户端真正执行容器生命周期的是后台的dockerd守护进程。服务器上装的是 Docker EngineWindows 和 Mac 上日常用的是 Docker Desktop它自带一台轻量虚拟机Windows 下默认走 WSL 2 后端。这个区别直接决定了你后面遇到的很多问题比如“Docker Desktop 启动失败”“docker 服务启动失败”是两种完全不同性质的故障。Ubuntu 上有两条路直接apt install docker.io用发行版打包或者从 Docker 官方仓库装docker-ce。docker.io胜在一条命令缺点是版本落后Compose v2 插件、新网络特性经常要自己补。我一般建议服务器上用官方docker-ce源装完自带docker compose子命令省去后续升级折腾。CentOS 7 上老版本 Docker 存量很大升级前先把 compose 文件里的 volumes 和 network 定义备份好因为新版本对 down 和 rm 的清理策略更激进容易把还在跑的容器一起带走。2.2 Ubuntu 上从零安装 Docker Engine# 卸载可能存在的旧版本避免 systemd 残留旧 unit sudo apt-get remove docker docker-engine docker.io containerd runc # 安装基础依赖和 GPG 密钥管理工具 sudo apt-get update sudo apt-get install -y ca-certificates curl gnupg sudo install -m 0755 -d /etc/apt/keyrings # 导入官方 GPG 密钥用于软件包签名校验 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod ar /etc/apt/keyrings/docker.gpg # 写入官方软件源架构和系统版本号自动代入 echo deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release echo $VERSION_CODENAME) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null sudo apt-get update sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin第一段卸载是为了清理可能残留的旧版二进制和 systemd 服务定义避免装完新包后systemctl start docker时报“unit not found”。GPG 密钥的作用是让 apt 校验下载包的签名跳过这步虽然能装但后续apt update会一直报“NO_PUBKEY”。最后一步里的docker-compose-plugin是 Compose v2 插件装完直接用docker compose不用再单独 pip 装一个老旧的docker-compose。2.3 启动 Docker 服务并验证链路# 开机自启并立即启动 sudo systemctl enable --now docker # 查守护进程运行状态 sudo systemctl status docker --no-pager # 验证客户端与守护进程能正常通信 docker version # 跑第一个测试容器验证镜像拉取链路 docker run --rm hello-worlddocker run --rm hello-world会先从 Docker Hub 拉取 hello-world 镜像再运行如果这步成功说明 daemon、镜像仓库链路和容器运行时都通。跑完容器自动删除不留垃圾。这里有个高频问题不加 sudo 直接敲docker ps报 permission denied。原因是当前用户不在 docker 组里。解决方式是sudo usermod -aG docker $USER然后退出登录重进。但要注意加入 docker 组等于把 root 权限交给这个用户内网开发机问题不大生产机器最好不要这么干。2.4 daemon.json镜像源、数据目录和日志轮转一次配好{ registry-mirrors: [https://docker.mirrors.example.com], data-root: /data/docker, iptables: true, log-driver: json-file, log-opts: { max-size: 20m, max-file: 5 } }registry-mirrors是 Docker 官方支持的加速配置项地址可以填多个前提是你所在网络能访问。># 查看镜像每一层执行的指令 docker history mysql:8.0 --no-trunc # 查看镜像的分层 ID 列表 docker image inspect mysql:8.0 | grep -A 20 Layers拉镜像失败的几种典型报错manifest unknown是 tag 不存在先检查版本号是不是写全timeout或TLS handshake timeout是网络链路问题优先查镜像源配置而不是反复重试。docker 镜像下载慢这个问题不要靠玄学先docker info看 Registry Mirrors 是否生效。3.2 docker run 参数速查与 MySQL 8.0 落地docker run本质是 create 加 start一条命令完成容器创建和启动。微服务环境里最常用的一组参数是-d后台运行、-p映射端口、-e注入环境变量、-v挂载数据卷、--name指定名字、--restart设置重启策略。这几个参数组合起来就是一个服务最基础的生产形态。docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDRoot123456 \ -e MYSQL_DATABASEorder_db \ -e TZAsia/Shanghai \ -v mysql-data:/var/lib/mysql \ --restart unless-stopped \ mysql:8.0mysql-data是命名的数据卷不指定宿主路径交给 Docker 管理好处是不管容器删多少次数据还在而且可以通过docker volume inspect mysql-data查到真实目录。--restart unless-stopped的意思是除手动 stop 外daemon 重启或容器异常退出都会自动拉起这是单机部署微服务的最低保障。启动后进入容器检查# 进入容器内执行 mysql 客户端 docker exec -it mysql8 mysql -uroot -p # 看容器启动日志排查失败原因 docker logs mysql8 --tail 100docker 安装 mysql 失败九成是三种原因宿主端口被占用、挂载了旧版本的数据目录、容器内存不足被 OOM kill。第一种用ss -lntp | grep 3306查第二种看日志里的 “Initialization of datadir” 报错第三种直接看docker logs里有没有 “Container killed by OOM”。不用瞎猜先看日志。3.3 Redis 主从用 Compose 编排两个容器MySQL 是单容器Redis 主从是两容器组成的集群正好用来演示 Compose 的编排能力。Compose 会在当前项目下自动创建一个默认网络两个容器通过服务名互访这里用的就是 Docker 内置 DNS——这也是后面微服务之间互相调用的基础机制。services: redis-master: image: redis:7-alpine container_name: redis-master command: [redis-server, --appendonly, yes] ports: - 6379:6379 volumes: - redis-master-data:/data networks: - micro-net redis-slave: image: redis:7-alpine container_name: redis-slave command: [redis-server, --replicaof, redis-master, 6379] depends_on: - redis-master ports: - 6380:6379 networks: - micro-net volumes: redis-master-data: networks: micro-net:启动和验证# 后台拉起整套编排 docker compose up -d # 验证主从状态 docker exec redis-slave redis-cli -p 6379 info replicationreplicaof redis-master 6379是让 slave 从 master 同步数据这里写的是服务名而不是 IP因为容器重建后 IP 会变服务名在自定义网络里始终指向对应容器这是微服务环境下最重要的一个习惯。Redis 7 里replicaof是官方推荐写法slaveof虽然还能用但启动日志里会有 deprecation 提示主从状态里的字段也会从master_link_status变成master_link_status看的时候留意一下。3.4 容器不是虚拟机进入、排查与后悔药容器和虚拟机最大的区别是共享内核它不是一个完整操作系统。所以容器里没有 systemd不能在里面systemctl start xxx容器挂掉重启后之前手动改的文件会全部还原成镜像里的原样。这也是为什么依赖管理必须写进 Dockerfile而不是启动后进容器手动装——装完一重建就没了。docker ps -a # 看所有容器包含已退出的 docker logs 容器名 --tail 50 # 看日志尾部 docker exec -it 容器名 bash # 进入容器做排查 docker stop / start / restart 容器名 docker rm -f 容器名 # 强制删除容器 docker system df # 看镜像、容器、卷占用空间 docker system prune -a --volumes # 清理所有闲置资源慎用docker ps -a是排查时第一个要敲的命令很多容器 create 成功但启动秒退只有-a才能看到退出码。docker logs是定位启动失败最直接的入口比进容器慢慢翻配置快得多。docker system prune -a --volumes会把没在运行的容器、没被容器引用的镜像和所有未挂载的数据卷一起删掉执行前看清输出这不是能后悔的操作。4. 把单体拆成微服务Dockerfile、Compose 与配置外置4.1 拆分依据业务边界比技术分层更重要拆微服务最常见的错误是照技术层拆controller 一个服务、service 一个服务、dao 一个服务拆完发现每次需求要跨三四个服务改代码部署顺序还互相依赖。合理的拆分是按业务能力订单一个服务、用户一个服务、库存一个服务每个服务有独立的数据存储独立发布、独立伸缩。Docker 在这里的价值是把“环境依赖”变成“镜像描述”。订单服务依赖 JDK 17、用户服务依赖 Python 3.12各自写进 Dockerfile新环境 pull 下来直接 run不用再手动配环境。很多人喜欢用青龙这类面板跑定时任务依赖管理同样走 Dockerfile而不是启动后进容器手动 pip install——容器一重建就全没了这是容器的特性不是 bug。什么时候别拆也别硬上团队只有三五个人服务之间共享一个数据库且事务强一致要求高启动一套环境要折腾半天。容器解决的是部署问题解决不了架构治理问题团队没准备好就上微服务等于把单体的一台机器模型换成一堆容器模型故障面反而更大。4.2 Dockerfile 多阶段构建Java 服务的标准写法一个 Spring Boot 微服务的镜像最标准的写法是多阶段构建第一阶段放 Maven 和 JDK负责编译打包第二阶段只放 JRE 和编译产物。最终镜像里没有源码、没有 Maven、没有编译器体积能少一大半。# 第一阶段构建环境只负责产出 jar FROM maven:3.9-eclipse-temurin-17 AS builder WORKDIR /build COPY pom.xml . # 先只拷 pom.xml利用 Docker 层缓存依赖没变时不会反复下载 RUN mvn dependency:go-offline COPY src ./src RUN mvn package -DskipTests # 第二阶段运行环境只保留 jar 和运行时 FROM eclipse-temurin:17-jre-alpine WORKDIR /app COPY --frombuilder /build/target/order-service.jar app.jar EXPOSE 8080 ENV JAVA_OPTS-Xms256m -Xmx512m ENTRYPOINT [sh, -c, java $JAVA_OPTS -jar app.jar]这里的关键点有两个。第一COPY pom.xml和RUN mvn dependency:go-offline单独放一层pom.xml 没变动时 Docker 会直接复用这层缓存依赖下载不会每次重复执行第二COPY --frombuilder只从上一阶段拿 jar所以最终镜像里没有/build/src和 Maven 仓库。还需要配套一份 .dockerignoretarget/ .git/ .idea/ *.iml .dockerignore Dockerfile不写这个docker build会把本地的 target 目录、.git 历史全部打进构建上下文镜像构建前先传几百 MB 垃圾每次都慢而且 .git 里的敏感信息有可能被带进镜像。Python 服务的 Dockerfile 同理基础镜像用python:3.12-slim不要用完整版python:3.12完整版里带着一大套编译工具和文档生产镜像体积能差三倍以上。依赖安装加--no-cache-dir避免 pip 缓存残留在镜像层里。4.3 Compose 编排微服务服务名即域名把单体拆成微服务后编排粒度从单容器变成多服务。Compose 在这里承担的是“docker run 的批处理版本”角色一次定义一条命令拉起整套环境。order-service、mysql、redis 三个服务放同一个自定义网络里order-service 访问数据库直接写服务名不用关心 IP。services: order-service: build: ./order-service ports: - 8080:8080 environment: - SPRING_PROFILES_ACTIVEdocker - DB_HOSTmysql - DB_PORT3306 - DB_NAMEorder_db - DB_USERroot - DB_PASSWORDRoot123456 - REDIS_HOSTredis-master depends_on: mysql: condition: service_healthy redis-master: condition: service_started networks: - micro-net mysql: image: mysql:8.0 environment: - MYSQL_ROOT_PASSWORDRoot123456 - MYSQL_DATABASEorder_db healthcheck: test: [CMD, mysqladmin, ping, -h, 127.0.0.1, -uroot, -pRoot123456] interval: 10s timeout: 5s retries: 10 volumes: - mysql-data:/var/lib/mysql networks: - micro-net redis-master: image: redis:7-alpine command: [redis-server, --appendonly, yes] networks: - micro-net volumes: mysql-data: networks: micro-net:关键点是depends_on加condition: service_healthy。默认的depends_on只保证启动顺序不保证服务就绪——mysql 容器起来不代表 mysqld 已经能接受连接order-service 这时候启动照样连不上数据库报错。给 mysql 配置了 healthcheck 之后Compose 会在 mysql 健康检查通过后才启动 order-service。微服务之间的调用也一样。order-service 需要调用 user-service 时直接配置http://user-service:8081这种地址Docker 内置 DNS 会解析到对应容器。这套机制是微服务容器化最省心的一部分前提是大家都挂在同一个自定义网络里。4.4 配置外置为什么密码不能写进镜像镜像要能在开发、测试、生产三套环境里复用环境相关的东西就不能写死在镜像里连构建参数都不应该。数据库地址、密码、Redis 地址这些全部通过environment注入或者通过.env文件在 compose 层替换。# .env 文件内容不进版本库或进加密仓库 DB_PASSWORDRoot123456compose 文件里引用environment: - DB_PASSWORD${DB_PASSWORD}.env文件与 compose 文件放在同一目录时compose 会自动读取并做变量替换。好处是镜像可以在任何环境原样运行配置文件里只有占位符没有明文。这是微服务部署里最该守住的一条底线——镜像可以在内部仓库共享但密码只存在于运行环境的.env里。镜像 tag 规范同样重要。别用latest本地开发无所谓一旦环境一多你根本不知道latest到底指哪个版本。常见做法是打构建时间和 commit 短哈希比如order-service:20250112-a1b2c3d回滚的时候直接切回上一个 tag。5. 微服务容器化的典型故障启动失败、网络不通与地址错位5.1 虚拟化没开导致 Docker Desktop 起不来现象Docker Desktop 启动后闪退系统弹窗提示 virtualization support not detectedDocker Desktop failed to start。原因Windows 上 Docker Desktop 依赖虚拟化技术跑轻量虚拟机BIOS 里 VT-x/AMD-V 没开或者 Windows 功能里的“虚拟机平台”“适用于 Linux 的 Windows 子系统”没启用。解决先去“控制面板-程序-启用或关闭 Windows 功能”勾选“虚拟机平台”和“适用于 Linux 的 Windows 子系统”重启后再启动 Docker Desktop如果还不行进 BIOS 找 Intel Virtualization Technology 或 SVM Mode 打开。启动后在任务管理器-性能页看“虚拟化”是否为已启用这一步能帮你快速判断是系统层还是 BIOS 层的问题。5.2 docker 网络不通容器之间互相访问超时现象order-service 报连接 mysql 超时docker exec进容器 ping 某个服务名不通容器能上外网但主机访问不了容器端口。原因最常见的两种情况——两个容器不在同一个自定义网络默认 bridge 网络下容器之间靠 IP 访问而容器重启后 IP 会变或者 Docker 默认生成的网段与公司局域网 IP 段冲突导致路由错乱表现为部分网络访问时通时不通。解决把需要互相访问的容器放进同一个自定义网络用服务名而不是 IP。如果宿主机本身在 172.17.x.x 网段和 Docker 默认的 172.17.0.0/16 撞了在 daemon.json 里调整分配池{ default-address-pools: [ {base: 172.28.0.0/16, size: 24} ] }改完重启 Docker然后docker network inspect micro-net确认新网络段的 IP 分配。网络不通这类问题先看docker network ls确认容器挂在哪张网上再docker exec进容器 ping 对方服务名定位失效点不要上来就改防火墙。5.3 镜像下载慢、pull 一直 retrying现象docker pull卡很久显示 retrying 最后 timeout换了一个加速地址时好时坏。原因默认走 Docker Hub 官方仓库公网链路不稳定第三方镜像加速地址本质上是别人提供的缓存代理有容量和地域限制失效不是玄学是正常现象。解决在 daemon.json 的registry-mirrors里配两到三个当前网络环境下可用的加速地址配完systemctl restart docker然后docker info看 Registry Mirrors 是否生效。生产服务器不要直连 Docker Hub在 CI 里构建镜像推到内部私有仓库服务器直接 pull 私有仓库速度和稳定性都可控。5.4 容器里连不上宿主机数据库现象微服务跑在容器里数据库装宿主机配置文件里写localhost:3306启动后连接被拒。原因容器有自己的网络栈容器里的localhost是容器自己不是宿主机。从容器访问宿主不能用回环地址。解决Docker Desktop 和 Windows/Mac 环境直接用host.docker.internalLinux 上 compose 里加一段声明extra_hosts: - host.docker.internal:host-gateway然后把微服务的数据库地址改成host.docker.internal。这是容器网络模型最容易忽略的一个点第一次踩坑的人基本都会对着配置看半天怀疑是不是密码错了。5.5 微服务注册中心里出现容器内网地址现象order-service 注册到 Nacos 或 Eureka 里的地址是172.x.x.x容器 IP宿主机上的网关或外部客户端按这个地址访问连不上。原因注册中心拿到的 IP 来自容器网卡这个 IP 只在 Docker 网络内部可路由容器外的客户端看不到这张网自然访问不了。解决如果网关也是容器化并在同一网络里让网关通过服务名调用微服务注册地址保持容器 IP 没问题如果调用方在容器外微服务在注册时就要显式配置对外可达的宿主 IP 和映射端口。Spring Cloud 体系里一般通过注册配置项指定 IP各框架的 key 不一样思路一致注册到中心的地址必须能被真实调用方路由到。这类问题用docker logs 注册中心或直接在注册中心控制台看服务列表就能发现。排查顺序固定成套路能省很多时间先docker ps -a看容器状态再docker logs看应用日志接着docker network inspect看网络和 IP最后docker exec进容器 curl 对端服务名端口确认连通走到这一步还不行才怀疑代码逻辑。6. 镜像瘦身与生产化改造少装东西多留观察口6.1 镜像瘦身清单优化手段做法典型效果多阶段构建builder 只产出 jar/二进制runtime 只放运行产物体积减小一半以上小基础镜像jre-alpine、python:3.12-slim、distroless体积更小、漏洞面更小.dockerignore排除 target、.git、node_modules构建上下文小构建速度快合并 RUN安装依赖与清理缓存写在同一 RUN减少无用镜像层固定版本不用 latest用具体 tag 或 digest构建可复现回滚可预期镜像瘦身不只是省磁盘还直接关系部署速度和安全面。镜像越小从仓库拉取到启动完成的时间越短生产发布窗口就越短。6.2 生产化配置健康检查、资源上限与日志轮转FROM eclipse-temurin:17-jre-alpine WORKDIR /app COPY --frombuilder /build/target/order-service.jar app.jar EXPOSE 8080 ENV JAVA_OPTS-Xms256m -Xmx512m # 每 30 秒探一次连续 3 次失败判为不健康启动期给足 20 秒 HEALTHCHECK --interval30s --timeout5s --start-period20s --retries3 \ CMD wget -q --spider http://localhost:8080/actuator/health || exit 1start-period很关键Java 服务启动慢不给这个缓冲时间容器一启动就在探活很容易误杀。Spring Boot 项目记得引入 actuator 依赖这个端点默认返回 200 时容器就报健康编排系统才能准确判断服务是否就绪。services: order-service: mem_limit: 512m cpus: 0.5 logging: driver: json-file options: max-size: 10m max-file: 3单机 compose 用mem_limit和cpus限制资源防止某个服务内存泄露把整台机器拖死日志限制max-size和max-file让 Docker 自己按大小轮转旧日志不用人工清理。6.3 验证方法docker compose config -q # 校验 compose 文件语法 docker compose up -d # 拉起整套服务 docker compose ps # 看各服务运行状态和健康状态 curl http://127.0.0.1:8080/actuator/health # 直接探活 docker logs order-service --tail 100 # 观察启动日志我现在养成的习惯是每套微服务交付的最低标准必须包含四样Dockerfile 用多阶段构建compose 里有 healthcheck日志限制大小资源给上限。少任何一样上线后都会以某种方式还回来——要么磁盘被日志占满要么某个服务把机器内存吃光要么编排系统判断不了服务死活。这套标准让发布变成一件可预测的事镜像版本明确、健康状态可见、资源边界清楚。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →