学习docker 这一篇就够了
我在学习一个知识点或者一个技术主要弄得这三个问题,是什么,为什么,这么用,搞懂这三个问题。咱们也就弄懂这三个问题,也就初步理解这个技术了。
一、什么是 Docker?
Docker 本质上是一套应用打包、分发、运行的标准化解决方案:
- 它让开发者可以将应用程序及其所有依赖(代码、运行时、库、环境变量、配置文件等)打包到一个可移植的容器中
- 这个容器可以被分发到任何支持 Docker 的环境(开发机、测试服务器、云服务器等)
- 无论运行环境如何变化,容器内的应用都能以完全相同的方式运行,实现了 "一次构建,到处运行"(Build once, run anywhere)
核心组件
1. 镜像(Image)
- 本质:一个只读的二进制模板,包含运行应用所需的完整文件系统(代码、库、工具、依赖、配置等)
- 特性:
- 只读性:一旦构建完成就无法修改,确保一致性
- 分层存储:采用 Union File System(联合文件系统),将镜像分为多个只读层,不同镜像可共享相同层,节省存储空间
- 可版本化:每个镜像可以有多个版本(通过标签 Tag 区分,如
nginx:1.23、ubuntu:20.04)
- 类比:相当于操作系统的 "安装光盘",或程序的 "安装包",但包含了完整运行环境
2. 容器(Container)
- 本质:镜像的可运行实例,是一个被隔离的进程环境
- 特性:
- 可读写:在镜像只读层之上添加了一个可写层,所有运行时修改都发生在这一层
- 轻量级:无需模拟完整操作系统,直接共享主机内核,启动速度快(秒级),资源占用低
- 强隔离:通过 Linux namespace 实现进程、网络、文件系统等资源的隔离,通过 cgroups 实现资源限制(CPU、内存等)
- 生命周期可控:可被创建、启动、停止、暂停、删除
- 类比:相当于用 "安装光盘" 安装好的操作系统,或安装后正在运行的程序
3. 仓库(Repository)
- 本质:用于集中存储和分发镜像的服务
- 分类:
- 公共仓库:最知名的是 Docker Hub(https://hub.docker.com/),包含大量官方和社区镜像
- 私有仓库:企业或个人搭建的内部仓库,用于存储私有镜像(如 Docker Registry、Harbor 等)
- 功能:支持镜像的上传(push)、下载(pull)、版本管理,类似代码仓库(如 GitHub)
4. Docker 引擎(Docker Engine)了解即可
- 本质:Docker 的核心运行时环境,是一个客户端 - 服务器架构的应用
- 组成:
- Docker 守护进程(dockerd):运行在主机上的后台服务,负责管理镜像、容器、网络等
- Docker 客户端(docker):命令行工具,通过 API 与守护进程通信,接收用户指令
- Docker API:供客户端和其他工具调用的接口
- 依赖:在 Linux 上直接基于内核特性运行;在 Windows/Mac 上通过虚拟机(如 WSL2、HyperKit)模拟 Linux 环境
Docker 与传统虚拟化的区别
| 特性 | Docker 容器 | 传统虚拟机(VM) |
|---|---|---|
| 启动速度 | 秒级 | 分钟级 |
| 资源占用 | 轻量(共享主机内核) | 重量级(完整操作系统) |
| 隔离级别 | 进程级隔离(共享内核) | 完全隔离(独立内核) |
| 移植性 | 极高(标准化容器格式) | 较高(依赖虚拟机格式) |
| 镜像大小 | 通常 MB 级 | 通常 GB 级 |
二、为什么要使用 Docker?
Docker 之所以能在软件开发和运维领域迅速普及,源于它从根本上解决了传统部署模式中的诸多痛点。以下从多个维度详细解析其核心价值:
1. 彻底解决环境一致性问题
传统痛点:开发环境、测试环境、生产环境配置不一致,导致 "在我电脑上能运行,到你那里就报错" 的经典问题。开发人员常说 "我本地跑没问题啊",运维人员则苦于环境差异引发的各种部署故障。
Docker 解决方案:
- 将应用程序与所有依赖(操作系统版本、库文件、配置参数、运行时环境)打包成不可变的镜像,确保从开发到生产的全流程使用完全一致的环境
- 镜像一旦构建完成,无论在开发者的笔记本、测试服务器还是云服务器上运行,内部环境完全相同
- 消除了 "环境配置文档写十页,不如镜像打包一次" 的尴尬,新人入职只需拉取镜像即可快速搭建开发环境,大幅降低环境配置成本
2. 极致的资源高效利用
传统虚拟化的局限:虚拟机(VM)需要运行完整的操作系统,每个 VM 都有独立的内核、内存、磁盘空间,资源占用大(通常以 GB 为单位),启动缓慢(分钟级)。
Docker 容器的优势:
- 共享内核:容器直接使用主机操作系统的内核,无需为每个应用分配完整的操作系统资源
- 轻量级:容器仅包含应用及其依赖,镜像大小通常以 MB 为单位(如 Nginx 镜像约 20MB),远小于虚拟机镜像(通常 GB 级)
- 快速启动:容器启动无需加载完整操作系统,通常在秒级甚至毫秒级即可完成
- 高密度部署:相同硬件资源下,可运行的容器数量是虚拟机的 10-100 倍,大幅降低服务器硬件成本
3. 安全可靠的隔离性
传统部署问题:多个应用运行在同一台服务器时,可能出现依赖冲突(如不同应用需要不同版本的 Python 库)、资源抢占(某个应用占用过多内存导致其他应用崩溃)、权限混乱等问题。
Docker 的隔离机制:
- 进程隔离:通过 Linux Namespace 技术,使每个容器拥有独立的进程空间、网络栈、文件系统视图,容器内的进程无法直接访问其他容器
- 资源限制:通过 cgroups 技术,可精确限制每个容器的 CPU 使用率、内存配额、磁盘 I/O 等,防止单个应用耗尽主机资源
- 依赖隔离:每个容器拥有独立的依赖环境,不同应用可使用不同版本的库文件而不冲突(如一个容器用 Python 3.8,另一个用 Python 3.10)
- 安全边界:容器间默认无法相互访问,需通过显式配置的网络规则通信,降低了恶意攻击的扩散风险
4. 超强的可移植性与跨平台能力
传统部署困境:为不同操作系统(Linux、Windows)、不同硬件架构编译和打包应用,需要大量适配工作,且难以保证行为一致。
Docker 的跨平台特性:
- 一次构建,到处运行:同一镜像可在任何安装了 Docker 的环境中运行,无论底层是笔记本电脑、物理服务器还是云平台(AWS、Azure、阿里云等)
- 跨系统兼容:支持 Linux、Windows、macOS 等主流操作系统,通过 Docker Desktop 实现了对非 Linux 系统的无缝支持
- 云原生友好:所有主流云服务提供商都原生支持 Docker 容器,使应用在不同云平台间迁移变得简单,避免厂商锁定
- 硬件无关性:应用运行不依赖特定硬件配置,降低了对基础设施的依赖
5. 大幅简化部署与运维流程
传统部署痛点:手动部署步骤繁琐(上传文件、配置环境、启动服务),易出错;升级和回滚风险高,可能导致服务中断。
Docker 带来的变革:
- 自动化部署:容器镜像可作为部署单元,通过脚本或工具实现全自动化部署,减少人工操作
- 快速迭代:支持蓝绿部署、金丝雀发布等高级部署策略,实现零停机升级
- 一键回滚:若新版本出现问题,只需停止当前容器,启动旧版本镜像的容器即可快速回滚,风险可控
- 标准化流程:将部署流程固化到 Dockerfile 和编排文件中,使部署过程可重复、可审计
- 与 CI/CD 无缝集成:完美融入现代持续集成 / 持续部署流程,代码提交后自动构建镜像、运行测试、部署到对应环境
6. 完善的版本控制与生命周期管理
传统应用管理问题:应用版本混乱,难以追踪每个版本的具体内容;不同版本的应用并行运行困难。
Docker 的版本管理能力:
- 镜像版本化:每个镜像可通过标签(Tag)标识版本(如
app:v1.0、app:v1.1),清晰区分不同版本 - 版本追溯:每个镜像的构建过程可通过 Dockerfile 追溯,明确记录了该版本包含的依赖和配置
- 多版本并行:不同版本的镜像可同时运行在同一主机上(通过不同容器),便于 A/B 测试或兼容旧系统
- 镜像仓库管理:通过仓库(如 Docker Hub、私有仓库)集中管理所有版本的镜像,支持拉取历史版本
7. 促进 DevOps 文化与协作效率
Docker 不仅是技术工具,更推动了开发(Dev)与运维(Ops)的协作模式变革:
- 开发人员可以自己定义应用运行环境(通过 Dockerfile),减少与运维人员的沟通成本
- 运维人员无需关心应用内部细节,只需管理容器的生命周期,职责边界更清晰
- 团队成员使用相同的镜像,避免了 "开发指责运维环境不对,运维指责开发代码有问题" 的推诿
- 加速了 "开发 - 测试 - 部署" 的迭代周期,使团队能够更快地响应业务需求
三、如何使用 Docker?
1. 安装 Docker(linux系统)
-
准备工作
# 查看内核版本 uname -r # 卸载旧版本(如果之前安装过) sudo apt-get remove docker docker-engine docker.io containerd runc -
安装 Docker 引擎
# 方法 1:使用官方脚本自动安装(推荐新手) # 下载并运行官方安装脚本 curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh # 启动 Docker 服务 sudo systemctl start docker # 设置开机自启动 sudo systemctl enable docker# 方法 2:手动安装(更可控) # 安装依赖包 sudo apt-get update sudo apt-get install ca-certificates curl gnupg lsb-release # 添加 Docker 官方 GPG 密钥 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg # 设置稳定版仓库 echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # 安装 Docker 引擎 sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io - 配置非 root 用户使用 Docker
# 默认情况下,只有 root 用户和 docker 组的用户可以运行 Docker 命令,为了避免每次使用 sudo,可以将当前用户添加到 docker 组: # 将当前用户添加到 docker 组 sudo usermod -aG docker $USER # 注销并重新登录,使设置生效 -
验证安装是否成功
# 查看 Docker 版本 docker --version # 运行 hello-world 测试镜像 docker run hello-world
2.使用docker常用命令
-
镜像操作
# 搜索镜像(在 Docker Hub 中) docker search mysql # 可通过 --filter=stars=1000 筛选星数超过1000的镜像 # 拉取指定版本镜像(推荐指定版本,避免自动更新) docker pull mysql:8.0.33 # 为镜像添加标签(重命名或版本标记) docker tag mysql:8.0.33 mycompany/mysql:v1 # 推送镜像到仓库(需先登录) docker login docker push mycompany/mysql:v1 # 查看镜像详细信息 docker inspect mysql:8.0.33 # 清理悬空镜像(无标签的镜像) docker image prune # 清理所有未使用的镜像(谨慎使用) docker image prune -a - 容器操作
# 启动交互式容器(如 Ubuntu) docker run -it --name myubuntu ubuntu:20.04 /bin/bash # -i: 保持标准输入打开 # -t: 分配伪终端 # 退出容器按 Ctrl+D 或输入 exit # 启动带数据卷的容器(数据持久化) docker run -d -p 3306:3306 \ --name mysql \ -v mysql-data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=123456 \ mysql:8.0.33 # -d:后台运行 # -p:端口映射(宿主机:容器) # -v: 挂载数据卷(自动创建名为 mysql-data 的卷) # -e: 设置环境变量 # 查看容器详细信息(IP、配置等) docker inspect mysql # 查看容器资源使用情况 docker stats mysql # 暂停/恢复容器 docker pause mysql docker unpause mysql # 重启容器 docker restart mysql # 强制删除运行中的容器 docker rm -f mysql # 批量操作容器 # 停止所有运行中的容器 docker stop $(docker ps -q) # 删除所有已停止的容器 docker rm $(docker ps -aq) -
容器数据管理命令
# 创建数据卷 docker volume create mydata # 查看所有数据卷 docker volume ls # 查看数据卷详情(包含存储路径) docker volume inspect mydata # 删除未使用的数据卷 docker volume prune # 挂载主机目录到容器(绑定挂载) docker run -d -p 8080:80 \ --name mynginx \ -v /home/user/html:/usr/share/nginx/html \ nginx # 主机目录 /home/user/html 会映射到容器内的 /usr/share/nginx/html -
容器网络管理命令
# 创建自定义网络(桥接模式) docker network create mynetwork # 查看所有网络 docker network ls # 将容器连接到网络(容器间可通过名称通信) docker run -d --name web --network mynetwork nginx docker run -d --name app --network mynetwork python:3.9 # 在 app 容器中可直接通过 web 访问 nginx 服务 # 连接已有容器到网络 docker network connect mynetwork existing-container
3. 构建自定义镜像(Dockerfile)
常用指令详解
| 指令 | 作用 | 示例 |
|---|---|---|
| FROM | 指定基础镜像(必须是第一条指令) | FROM python:3.9-slim |
| WORKDIR | 设置工作目录(后续命令在此目录执行) | WORKDIR /app |
| COPY | 复制本地文件到容器 | COPY requirements.txt . |
| ADD | 类似 COPY,支持 URL 和自动解压 | ADD https://example.com/file.tar.gz /tmp |
| RUN | 执行命令(构建镜像时运行) | RUN pip install -r requirements.txt |
| ENV | 设置环境变量 | ENV PYTHONUNBUFFERED=1 |
| EXPOSE | 声明容器监听的端口(仅文档作用) | EXPOSE 5000 |
| CMD | 容器启动时执行的命令(可被覆盖) | CMD ["python", "app.py"] |
| ENTRYPOINT | 容器入口点(不可被覆盖,常与 CMD 配合) | ENTRYPOINT ["python"] + CMD ["app.py"] |
| VOLUME | 声明数据卷(持久化数据) | VOLUME ["/data"] |
| USER | 指定运行容器的用户 | USER nobody |
Dockerfile 示例:
以下是一个 Java 项目的 Dockerfile 示例,适用于 Spring Boot 应用,包含了多阶段构建优化以减小最终镜像体积:
# 第一阶段:构建阶段
FROM maven:3.8.5-openjdk-17 AS builder
# 设置工作目录
WORKDIR /app
# 复制pom.xml并下载依赖(利用缓存)
COPY pom.xml .
RUN mvn dependency:go-offline
# 复制源代码
COPY src ./src
# 构建项目(跳过测试以加快构建)
RUN mvn package -DskipTests
# 第二阶段:运行阶段
FROM openjdk:17-jdk-slim
# 设置工作目录
WORKDIR /app
# 创建非root用户并切换
RUN addgroup --system --gid 1001 appgroup && \
adduser --system --uid 1001 --gid 1001 appuser
USER appuser
# 从构建阶段复制jar文件
COPY --from=builder --chown=appuser:appgroup /app/target/*.jar app.jar
# 暴露应用端口(Spring Boot默认8080)
EXPOSE 8080
# 启动命令(使用exec形式,确保信号能正确传递)
ENTRYPOINT ["java", "-jar", "app.jar"]
Dockerfile 解析
这个 Dockerfile 采用了多阶段构建,将构建过程和运行环境分离,具有以下优势:
-
构建阶段(第一阶段):
- 使用
maven:3.8.5-openjdk-17作为基础镜像,包含完整的 Maven 和 JDK 环境 - 先复制
pom.xml并下载依赖,利用 Docker 缓存机制加速后续构建 - 复制源代码并打包成 JAR 文件(跳过测试以提高构建速度)
- 使用
-
运行阶段(第二阶段):
- 使用轻量级的
openjdk:17-jdk-slim镜像,减小最终镜像体积 - 创建并切换到非 root 用户运行应用,提高安全性
- 仅复制构建好的 JAR 文件,避免包含源代码和构建工具
- 暴露应用端口并设置启动命令
- 使用轻量级的
使用创建的这个Dockerfile方法:
- 将此 Dockerfile 放在 Java 项目根目录(与 pom.xml 同级)
- 构建镜像:
docker build -t my-java-app:1.0 . - 运行容器:
docker run -d -p 8080:8080 --name java-app my-java-app:1.0
自定义调整建议
-
JVM 参数优化:如果需要添加 JVM 参数,可以修改 ENTRYPOINT:
ENTRYPOINT ["java", "-Xmx512m", "-jar", "app.jar"] -
指定具体 JAR 文件名:如果 target 目录下有多个 JAR 文件,可以指定具体名称:
COPY --from=builder /app/target/myapp-1.0.0.jar app.jar -
环境变量配置:可以添加环境变量用于配置应用:
ENV SPRING_PROFILES_ACTIVE=prod ENV SERVER_PORT=8080 -
健康检查:添加健康检查确保应用正常运行
HEALTHCHECK --interval=30s --timeout=3s \ CMD curl -f http://localhost:8080/actuator/health || exit 1
这个 Dockerfile 适用于大多数 Spring Boot 应用,通过多阶段构建可以显著减小最终镜像大小(通常从几百 MB 减小到 100MB 左右),同时遵循了容器安全最佳实践。
4. 多容器管理(Docker Compose 进阶)
上面示例是部署一个容器,但是在工作中往往会有多个容器一起部署的(mysql,redis,spring项目等),这样一个一个部署太慢了,所以我们就引用了Docker Compose进行多容器管理。
Docker Compose 常用命令
# 启动服务(后台运行)
docker-compose up -d
# 查看服务状态
docker-compose ps
# 查看服务日志(实时)
docker-compose logs -f web
# 进入容器
docker-compose exec web /bin/bash
# 重启服务
docker-compose restart web
# 构建并启动(重新构建镜像)
docker-compose up -d --build
# 停止服务(保留容器)
docker-compose stop
# 停止并删除服务(容器、网络)
docker-compose down
# 停止并删除服务(包括数据卷)
docker-compose down -v
# 查看服务资源使用情况
docker-compose top
完整 docker-compose.yml 示例(Web+DB+Redis)
version: '3.8' # 指定 Compose 版本
services:
# Web 应用服务
web:
build:
context: ./app # Dockerfile 所在目录
dockerfile: Dockerfile # Dockerfile 文件名
restart: always # 总是重启(故障时自动恢复)
ports:
- "8000:8000" # 端口映射
environment:
- DATABASE_URL=mysql://root:password@db:3306/mydb
- REDIS_URL=redis://redis:6379/0
depends_on:
- db
- redis
volumes:
- static_files:/app/static # 挂载数据卷
networks:
- app-network
# 数据库服务
db:
image: mysql:8.0.33
restart: always
environment:
- MYSQL_ROOT_PASSWORD=password
- MYSQL_DATABASE=mydb
volumes:
- mysql_data:/var/lib/mysql # 数据持久化
- ./init.sql:/docker-entrypoint-initdb.d/init.sql # 初始化脚本
networks:
- app-network
healthcheck: # 健康检查
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
# Redis 服务
redis:
image: redis:6.2-alpine
restart: always
volumes:
- redis_data:/data
networks:
- app-network
# 定义数据卷
volumes:
mysql_data:
redis_data:
static_files:
# 定义网络
networks:
app-network:
driver: bridge
四、实战案例:使用 Docker Compose 部署 Spring Cloud 分布式项目
以下是一个完整的 Spring Cloud 分布式项目部署方案,包含 Nacos、Gateway、OpenFeign、Sentinel 等组件,以及 MySQL、RabbitMQ、ElasticSearch 等中间件。
项目架构概览
spring-cloud-project/
├── docker-compose.yml # 主编排配置
├── nacos/ # 服务注册与配置中心
│ ├── Dockerfile
│ └── conf/
│ └── application.properties
├── gateway/ # API网关
│ ├── Dockerfile
│ ├── pom.xml
│ └── src/
├── user-service/ # 用户微服务
│ ├── Dockerfile
│ ├── pom.xml
│ └── src/
├── order-service/ # 订单微服务
│ ├── Dockerfile
│ ├── pom.xml
│ └── src/
├── sentinel/ # 流量控制中心
│ └── Dockerfile
├── mysql/ # 数据库
│ └── init.sql
├── rabbitmq/ # 消息队列
│ └── enabled_plugins
├── elasticsearch/ # 搜索引擎
│ └── elasticsearch.yml
├── kibana/ # ES可视化工具
│ └── kibana.yml
└── nginx/ # 反向代理
├── Dockerfile
└── nginx.conf
1. 核心配置文件
docker-compose.yml
# 版本声明:指定Docker Compose语法版本(3.8是较新且稳定的版本)
version: '3.8'
# 定义所有服务
services:
# 1. 服务注册与配置中心:Nacos
nacos:
build: ./nacos # 从当前目录的nacos文件夹构建镜像
container_name: nacos # 容器名称,方便管理
ports: # 端口映射:宿主机端口:容器内端口
- "8848:8848" # Nacos主端口(服务注册/配置)
- "9848:9848" # Nacos客户端通信端口
- "9849:9849" # Nacos客户端通信端口
environment: # 环境变量配置
- MODE=standalone # 单机模式(非集群)
- SPRING_DATASOURCE_PLATFORM=mysql # 数据源类型为MySQL
- MYSQL_SERVICE_HOST=mysql # MySQL服务地址(容器名,同一网络可直接访问)
- MYSQL_SERVICE_PORT=3306 # MySQL端口
- MYSQL_SERVICE_DB_NAME=nacos_config # Nacos使用的数据库名
- MYSQL_SERVICE_USER=root # MySQL用户名
- MYSQL_SERVICE_PASSWORD=password # MySQL密码
- MYSQL_DATABASE_NUM=1 # 数据库实例数量
volumes: # 数据卷挂载(持久化数据)
- nacos-data:/home/nacos/data # Nacos数据持久化
- nacos-log:/home/nacos/logs # Nacos日志持久化
depends_on: # 依赖关系:启动顺序控制
mysql:
condition: service_healthy # 等待MySQL健康检查通过后再启动
networks: # 加入的网络
- app-network
healthcheck: # 健康检查:确保服务可用
test: ["CMD", "curl", "-f", "http://localhost:8848/nacos/actuator/health"] # 检查健康接口
interval: 30s # 检查间隔
timeout: 10s # 超时时间
retries: 3 # 重试次数
# 2. 流量控制中心:Sentinel
sentinel:
build: ./sentinel # 从sentinel文件夹构建镜像
container_name: sentinel
ports:
- "8080:8080" # Sentinel控制台端口
networks:
- app-network
# 3. API网关:Spring Cloud Gateway
gateway:
build: ./gateway # 从gateway文件夹构建镜像
container_name: gateway
ports:
- "9000:9000" # 网关端口
environment:
- SPRING_PROFILES_ACTIVE=docker # 激活docker环境的配置
- SPRING_CLOUD_NACOS_DISCOVERY_SERVER-ADDR=nacos:8848 # Nacos服务注册地址
- SPRING_CLOUD_NACOS_CONFIG_SERVER-ADDR=nacos:8848 # Nacos配置中心地址
- SPRING_CLOUD_SENTINEL_TRANSPORT_DASHBOARD=sentinel:8080 # Sentinel控制台地址
depends_on: # 依赖Nacos和Sentinel启动后再启动
nacos:
condition: service_healthy
sentinel:
condition: service_started # 只需Sentinel启动即可,无需健康检查
networks:
- app-network
restart: always # 故障时自动重启
# 4. 微服务:用户服务
user-service:
build: ./user-service
container_name: user-service
environment:
- SPRING_PROFILES_ACTIVE=docker # 激活docker环境配置
- SPRING_CLOUD_NACOS_DISCOVERY_SERVER-ADDR=nacos:8848 # 注册到Nacos
- SPRING_CLOUD_NACOS_CONFIG_SERVER-ADDR=nacos:8848 # 从Nacos获取配置
- SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/user_db?useSSL=false&serverTimezone=UTC # MySQL连接地址
- SPRING_DATASOURCE_USERNAME=root # MySQL用户名
- SPRING_DATASOURCE_PASSWORD=password # MySQL密码
- SPRING_RABBITMQ_HOST=rabbitmq # RabbitMQ地址
- SPRING_ELASTICSEARCH_REST_URIS=http://elasticsearch:9200 # ElasticSearch地址
- SPRING_CLOUD_SENTINEL_TRANSPORT_DASHBOARD=sentinel:8080 # 接入Sentinel
depends_on: # 依赖的中间件
nacos:
condition: service_healthy
mysql:
condition: service_healthy
rabbitmq:
condition: service_healthy
elasticsearch:
condition: service_healthy
networks:
- app-network
restart: always
# 5. 微服务:订单服务(与用户服务配置类似)
order-service:
build: ./order-service
container_name: order-service
environment:
- SPRING_PROFILES_ACTIVE=docker
- SPRING_CLOUD_NACOS_DISCOVERY_SERVER-ADDR=nacos:8848
- SPRING_CLOUD_NACOS_CONFIG_SERVER-ADDR=nacos:8848
- SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/order_db?useSSL=false&serverTimezone=UTC # 订单服务专用数据库
- SPRING_DATASOURCE_USERNAME=root
- SPRING_DATASOURCE_PASSWORD=password
- SPRING_RABBITMQ_HOST=rabbitmq
- SPRING_ELASTICSEARCH_REST_URIS=http://elasticsearch:9200
- SPRING_CLOUD_SENTINEL_TRANSPORT_DASHBOARD=sentinel:8080
depends_on:
nacos:
condition: service_healthy
mysql:
condition: service_healthy
rabbitmq:
condition: service_healthy
elasticsearch:
condition: service_healthy
networks:
- app-network
restart: always
# 6. 数据库:MySQL
mysql:
image: mysql:8.0.33 # 使用官方MySQL镜像(8.0.33版本)
container_name: mysql
ports:
- "3306:3306" # MySQL默认端口
environment:
- MYSQL_ROOT_PASSWORD=password # root用户密码
- MYSQL_DATABASE=nacos_config # 初始化nacos_config数据库
- MYSQL_DATABASE=user_db # 初始化用户服务数据库
- MYSQL_DATABASE=order_db # 初始化订单服务数据库
volumes:
- mysql-data:/var/lib/mysql # MySQL数据持久化
- ./mysql/init.sql:/docker-entrypoint-initdb.d/init.sql # 初始化脚本(容器启动时执行)
networks:
- app-network
healthcheck: # 健康检查:通过mysqladmin ping验证
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
restart: always
# 7. 消息队列:RabbitMQ
rabbitmq:
image: rabbitmq:3.12-management # 带管理界面的RabbitMQ镜像
container_name: rabbitmq
ports:
- "5672:5672" # 消息通信端口
- "15672:15672" # 管理界面端口
environment:
- RABBITMQ_DEFAULT_USER=admin # 管理界面用户名
- RABBITMQ_DEFAULT_PASS=password # 管理界面密码
volumes:
- rabbitmq-data:/var/lib/rabbitmq # RabbitMQ数据持久化
- ./rabbitmq/enabled_plugins:/etc/rabbitmq/enabled_plugins # 启用的插件配置
networks:
- app-network
healthcheck: # 健康检查:通过rabbitmqctl status验证
test: ["CMD", "rabbitmqctl", "status"]
interval: 30s
timeout: 10s
retries: 3
restart: always
# 8. 搜索引擎:ElasticSearch
elasticsearch:
image: elasticsearch:7.17.0 # ES镜像(7.17.0版本,与Kibana版本一致)
container_name: elasticsearch
ports:
- "9200:9200" # HTTP访问端口
- "9300:9300" # 节点间通信端口
environment:
- discovery.type=single-node # 单机模式(非集群)
- "ES_JAVA_OPTS=-Xms512m -Xmx512m" # JVM内存限制(根据实际情况调整)
- xpack.security.enabled=false # 关闭安全验证(开发环境)
volumes:
- elasticsearch-data:/usr/share/elasticsearch/data # ES数据持久化
- ./elasticsearch/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml # 自定义配置
networks:
- app-network
healthcheck: # 健康检查:通过集群健康接口验证
test: ["CMD", "curl", "-f", "http://localhost:9200/_cluster/health"]
interval: 30s
timeout: 10s
retries: 3
restart: always
# 9. ES可视化:Kibana
kibana:
image: kibana:7.17.0 # Kibana镜像(与ES版本一致)
container_name: kibana
ports:
- "5601:5601" # Kibana访问端口
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200 # 连接的ES地址
depends_on:
elasticsearch:
condition: service_healthy # 等待ES健康后启动
networks:
- app-network
restart: always
# 10. 反向代理:Nginx
nginx:
build: ./nginx # 从nginx文件夹构建镜像
container_name: nginx
ports:
- "80:80" # 监听80端口(默认HTTP端口)
depends_on:
- gateway # 依赖网关启动
networks:
- app-network
restart: always
# 定义数据卷(所有需要持久化的数据)
volumes:
nacos-data: # Nacos数据
nacos-log: # Nacos日志
mysql-data: # MySQL数据
rabbitmq-data: # RabbitMQ数据
elasticsearch-data: # ElasticSearch数据
# 定义网络(所有服务在同一网络内,可通过服务名通信)
networks:
app-network:
driver: bridge # 桥接模式(默认网络模式)
2. 关键服务配置
Nacos 配置
nacos/Dockerfile
FROM nacos/nacos-server:v2.2.3
# 复制自定义配置
COPY conf/application.properties /home/nacos/conf/
# 暴露端口
EXPOSE 8848 9848 9849
# 启动命令
CMD ["bin/startup.sh", "-m", "standalone"]
nacos/conf/application.properties
# 服务器端口
server.port=8848
# 数据源配置
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://mysql:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=password
# 日志配置
nacos.logs.path=/home/nacos/logs
nacos.core.auth.enabled=false
Sentinel 配置
sentinel/Dockerfile
FROM openjdk:17-jdk-slim
WORKDIR /app
# 下载Sentinel Dashboard
RUN curl -L https://github.com/alibaba/Sentinel/releases/download/1.8.6/sentinel-dashboard-1.8.6.jar -o sentinel-dashboard.jar
# 暴露端口
EXPOSE 8080
# 启动命令,关闭登录验证
ENTRYPOINT ["java", "-jar", "sentinel-dashboard.jar", "--server.port=8080", "--auth.enabled=false"]
Gateway 配置
gateway/Dockerfile
# 构建阶段
FROM maven:3.8.5-openjdk-17 AS builder
WORKDIR /app
# 复制依赖文件
COPY pom.xml .
RUN mvn dependency:go-offline
# 复制源代码并构建
COPY src ./src
RUN mvn package -DskipTests
# 运行阶段
FROM openjdk:17-jdk-slim
WORKDIR /app
# 创建非root用户
RUN addgroup --system --gid 1001 gatewaygroup && \
adduser --system --uid 1001 --gid 1001 gatewayuser
USER gatewayuser
# 复制构建产物
COPY --from=builder --chown=gatewayuser:gatewaygroup /app/target/*.jar gateway.jar
# 暴露端口
EXPOSE 9000
# 启动命令
ENTRYPOINT ["java", "-Xmx256m", "-jar", "gateway.jar"]
gateway/src/main/resources/application-docker.yml
server:
port: 9000
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: nacos:8848
config:
server-addr: nacos:8848
file-extension: yaml
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**filters:
- StripPrefix=1
- name: Sentinel
args:
resourceName: user-service
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**filters:
- StripPrefix=1
- name: Sentinel
args:
resourceName: order-service
sentinel:
transport:
dashboard: sentinel:8080
eager: true
用户服务配置(OpenFeign 示例)
user-service/src/main/java/com/example/userservice/feign/OrderServiceClient.java
package com.example.userservice.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(name = "order-service")
public interface OrderServiceClient {
@GetMapping("/orders/user/{userId}")
List<OrderDTO> getOrdersByUserId(@PathVariable("userId") Long userId);
}
3. 部署与验证步骤
启动服务
# 构建并启动所有服务
docker-compose up -d --build
# 查看服务状态
docker-compose ps
# 查看日志(例如查看网关日志)
docker-compose logs -f gateway
验证部署
-
访问 Nacos 控制台:http://localhost:8848/nacos检查服务列表,确认所有服务已注册
-
访问 Sentinel 控制台:http://localhost:8080查看服务监控和流量控制规则
-
测试 API 网关:
- 用户服务接口:http://localhost/api/users/1
- 订单服务接口:http://localhost/api/orders/1
-
验证服务间调用:
- 检查用户服务是否能通过 OpenFeign 调用订单服务
- 验证 RabbitMQ 消息传递是否正常
- 检查 ElasticSearch 数据索引是否正确
-
查看 Kibana:http://localhost:5601验证 ElasticSearch 数据可视化
扩展与伸缩
# 扩展订单服务实例(测试负载均衡)
docker-compose up -d --scale order-service=2
# 查看服务实例
docker-compose ps order-service
4. 关键技术点说明
-
服务注册与发现:
- 所有服务通过 Nacos 注册,实现服务发现
- 服务间调用通过服务名进行,无需硬编码 IP 地址
-
配置管理:
- 使用 Nacos 作为配置中心,集中管理各服务配置
- 支持动态配置更新,无需重启服务
-
API 网关:
- Gateway 实现请求路由、负载均衡
- 集成 Sentinel 实现网关层流量控制
-
服务间通信:
- OpenFeign 实现声明式服务调用
- 集成 Sentinel 实现服务熔断与降级
-
数据存储:
- MySQL 存储业务数据
- ElasticSearch 用于全文检索
- RabbitMQ 实现异步通信和解耦
-
容器编排:
- 定义服务依赖关系,确保启动顺序
- 配置健康检查,实现故障自动恢复
- 使用数据卷持久化关键数据
五、linux-docker关系图解
linux,docker,docker容器的关系:

容器的端口映射:
用Linux的80端口映射到容器中的80端口(容器没有公网ip只能用回环地址)
docker run -d -p 3306:3306 这里面的 -p就是进行端口映射 格式:Linux端口:容器端口

目录的挂载:

Docker的自定义网络


更多推荐
所有评论(0)