我在学习一个知识点或者一个技术主要弄得这三个问题,是什么为什么,这么用,搞懂这三个问题。咱们也就弄懂这三个问题,也就初步理解这个技术了。

一、什么是 Docker?

Docker 本质上是一套应用打包、分发、运行的标准化解决方案

  • 它让开发者可以将应用程序及其所有依赖(代码、运行时、库、环境变量、配置文件等)打包到一个可移植的容器
  • 这个容器可以被分发到任何支持 Docker 的环境(开发机、测试服务器、云服务器等)
  • 无论运行环境如何变化,容器内的应用都能以完全相同的方式运行,实现了 "一次构建,到处运行"(Build once, run anywhere)

核心组件

1. 镜像(Image)

  • 本质:一个只读的二进制模板,包含运行应用所需的完整文件系统(代码、库、工具、依赖、配置等)
  • 特性
    • 只读性:一旦构建完成就无法修改,确保一致性
    • 分层存储:采用 Union File System(联合文件系统),将镜像分为多个只读层,不同镜像可共享相同层,节省存储空间
    • 可版本化:每个镜像可以有多个版本(通过标签 Tag 区分,如 nginx:1.23ubuntu: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.0app: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 采用了多阶段构建,将构建过程和运行环境分离,具有以下优势:

  1. 构建阶段(第一阶段)

    • 使用 maven:3.8.5-openjdk-17 作为基础镜像,包含完整的 Maven 和 JDK 环境
    • 先复制 pom.xml 并下载依赖,利用 Docker 缓存机制加速后续构建
    • 复制源代码并打包成 JAR 文件(跳过测试以提高构建速度)
  2. 运行阶段(第二阶段)

    • 使用轻量级的 openjdk:17-jdk-slim 镜像,减小最终镜像体积
    • 创建并切换到非 root 用户运行应用,提高安全性
    • 仅复制构建好的 JAR 文件,避免包含源代码和构建工具
    • 暴露应用端口并设置启动命令

使用创建的这个Dockerfile方法:

  1. 将此 Dockerfile 放在 Java 项目根目录(与 pom.xml 同级)
  2. 构建镜像:
    docker build -t my-java-app:1.0 .
    
  3. 运行容器:
    docker run -d -p 8080:8080 --name java-app my-java-app:1.0

自定义调整建议

  1. JVM 参数优化:如果需要添加 JVM 参数,可以修改 ENTRYPOINT:

    ENTRYPOINT ["java", "-Xmx512m", "-jar", "app.jar"]
    
  2. 指定具体 JAR 文件名:如果 target 目录下有多个 JAR 文件,可以指定具体名称:

    COPY --from=builder /app/target/myapp-1.0.0.jar app.jar
    
  3. 环境变量配置:可以添加环境变量用于配置应用:

    ENV SPRING_PROFILES_ACTIVE=prod
    ENV SERVER_PORT=8080
    
  4. 健康检查:添加健康检查确保应用正常运行

    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

验证部署

  1. 访问 Nacos 控制台http://localhost:8848/nacos检查服务列表,确认所有服务已注册

  2. 访问 Sentinel 控制台http://localhost:8080查看服务监控和流量控制规则

  3. 测试 API 网关

  4. 验证服务间调用

    • 检查用户服务是否能通过 OpenFeign 调用订单服务
    • 验证 RabbitMQ 消息传递是否正常
    • 检查 ElasticSearch 数据索引是否正确
  5. 查看 Kibanahttp://localhost:5601验证 ElasticSearch 数据可视化

扩展与伸缩

# 扩展订单服务实例(测试负载均衡)
docker-compose up -d --scale order-service=2

# 查看服务实例
docker-compose ps order-service

4. 关键技术点说明

  1. 服务注册与发现

    • 所有服务通过 Nacos 注册,实现服务发现
    • 服务间调用通过服务名进行,无需硬编码 IP 地址
  2. 配置管理

    • 使用 Nacos 作为配置中心,集中管理各服务配置
    • 支持动态配置更新,无需重启服务
  3. API 网关

    • Gateway 实现请求路由、负载均衡
    • 集成 Sentinel 实现网关层流量控制
  4. 服务间通信

    • OpenFeign 实现声明式服务调用
    • 集成 Sentinel 实现服务熔断与降级
  5. 数据存储

    • MySQL 存储业务数据
    • ElasticSearch 用于全文检索
    • RabbitMQ 实现异步通信和解耦
  6. 容器编排

    • 定义服务依赖关系,确保启动顺序
    • 配置健康检查,实现故障自动恢复
    • 使用数据卷持久化关键数据

五、linux-docker关系图解

linux,docker,docker容器的关系:

容器的端口映射:

用Linux的80端口映射到容器中的80端口(容器没有公网ip只能用回环地址)

docker run -d -p 3306:3306 这里面的 -p就是进行端口映射 格式:Linux端口:容器端口

目录的挂载:

Docker的自定义网络

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐