目 录CONTENT

文章目录

基于 Docker Compose 的微服务架构部署实践

Administrator
2025-10-13 / 0 评论 / 0 点赞 / 0 阅读 / 0 字 / 正在检测是否收录...
温馨提示:
部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

基于 Docker Compose 的微服务架构部署实践

在现代软件开发中,微服务架构已成为主流趋势。本文将深入探讨如何使用 Docker Compose 来部署和管理一个复杂的微服务系统,重点分析技术要点和实现方式,以便后续复用。

核心技术要点

1. Docker Compose 编排技术

Docker Compose 是定义和运行多容器 Docker 应用程序的工具。通过 YAML 文件配置应用程序的服务,然后使用单个命令即可创建并启动所有服务。

在该项目中,使用了多个 docker-compose 文件来管理不同层次的服务:

文件用途
docker-compose.middleware.yaml管理基础中间件服务(Redis、MySQL、Elasticsearch等)
docker-compose.app.yaml管理应用服务(网关、认证、业务应用等)

这种方式的优势在于:

  • 服务分层管理,职责清晰
  • 可以独立启动和停止不同层次的服务
  • 便于开发、测试和生产环境的差异化配置

2. 环境变量管理

项目采用 .env 文件统一管理环境变量,这种方式具有以下优点:

  1. 配置集中化:所有配置参数集中在一个文件中,便于维护
  2. 环境隔离:不同环境(开发、测试、生产)可以使用不同的 .env 文件
  3. 安全性:敏感信息(如密码)不会硬编码在配置文件中

例如,在 docker-compose.middleware.yaml 中使用环境变量:

redis:
  env_file:
    - .env  # 通用配置文件
  image: redis:latest
  container_name: ${REDIS_CONTAINER_NAME}
  restart: always
  volumes:
    - ${DATA_DIR}/redis:/data
  command: ["redis-server", "--requirepass", "${REDIS_PASSWORD}"]
  ports:
    - "${REDIS_PORT:-6379}:6379"

3. 微服务注册与发现

项目使用 Nacos 作为服务注册与发现中心。在 bootstrap-nacos.yml 配置文件中可以看到相关配置:

spring:
  cloud:
    nacos:
      discovery:
        server-addr: ${MID_NODE}:${MICRO_SERVICE_PORT}
        namespace: ${MICRO_SERVICE_NAMESPACE}
        group: ${MICRO_SERVICE_GROUP}
        ip: ${APP_NODE}
        port: ${服务端口}

这种配置方式使得服务能够动态注册到注册中心,并通过服务名进行调用,实现了服务间的解耦。

实现方式详解

1. 环境配置文件生成

项目使用 pre-start.sh 脚本从 .env.tmp 模板生成实际的 .env 文件,支持端口偏移和容器名称后缀功能:

# 设置端口偏移量
OFFSET_PORT=500 ./pre-start.sh

# 设置容器名后缀
SUFFIX="-test" ./pre-start.sh

该脚本的主要功能包括:

  1. 端口偏移计算:对以 _PORT 结尾的变量进行数值偏移
  2. 容器名后缀:对以 _CONTAINER_NAME 结尾的变量添加指定后缀
  3. 环境隔离:通过不同后缀区分不同环境的容器

.env.tmp 示例(脱敏后):

#===============================中间件部署环境变量===================================
MID_NODE=中间件节点IP
DATA_DIR=./data
######################redis######################
REDIS_PORT=6379
REDIS_PASSWORD=Redis密码
REDIS_CONTAINER_NAME=redis
######################mysql#####################
MYSQL_PORT=3306
MYSQL_PASSWORD=MySQL密码
MYSQL_CONTAINER_NAME=mysql
######################es#####################
ES_PORT=9200
ES_CONTAINER_NAME=es
######################nacos#####################
NACOS_PORT1=8848
NACOS_PORT2=9848
NACOS_CONTAINER_NAME=nacos
######################minio#####################
MINIO_PORT1=MinIO端口1
MINIO_PORT2=MinIO端口2
MINIO_CONTAINER_NAME=minio
MINIO_USER=MinIO用户名
MINIO_PASSWORD=MinIO密码
######################mongo#####################
MONGO_PORT=27017
MONGO_CONTAINER_NAME=mongo
MONGO_INITDB_ROOT_USERNAME=Mongo用户名
MONGO_INITDB_ROOT_PASSWORD=Mongo密码

#===============================普通应用部署环境变量==================================
# 应用部署在机器的信息
APP_NODE=应用节点IP

# 微服务NACOS信息
MICRO_SERVICE_NODE=Nacos节点IP
MICRO_SERVICE_PORT=Nacos端口
MICRO_SERVICE_NAMESPACE=命名空间
MICRO_SERVICE_GROUP=组名

######################服务1######################
服务1_PORT=服务端口
服务1_CONTAINER_NAME=服务容器名
服务1_IMAGE_TAG=镜像标签
######################服务2######################
服务2_PORT=服务端口
服务2_CONTAINER_NAME=服务容器名
服务2_IMAGE_TAG=镜像标签
#=================================================================================

2. 镜像管理

项目提供了 save-images.sh 和 load-images.sh 脚本用于镜像的批量保存和加载:

  • save-images.sh:将所有需要的 Docker 镜像保存为 .tar 文件,适用于离线环境部署
  • load-images.sh:从 .tar 文件批量加载 Docker 镜像,用于离线环境的镜像恢复

这两个脚本使得在无网络连接的环境中也能完成系统部署,提高了部署的灵活性。

3. 服务编排策略

项目采用分层服务编排策略:

  1. 基础服务层:包括数据库、缓存、消息队列等基础设施
  2. 核心服务层:包括网关、认证、业务服务等核心应用

这种分层策略的优势在于:

  • 启动顺序可控,避免服务依赖问题
  • 便于资源分配和管理
  • 支持按需启动和扩展

4. 网络隔离设计

项目通过自定义网络实现服务间通信:

networks:
  自定义网络名:
    driver: bridge

所有服务都连接到同一个网络,实现服务间的互联互通,同时与宿主机网络隔离,提高安全性。

5. 数据持久化方案

通过 volume 映射实现数据持久化:

volumes:
  - ${DATA_DIR}/服务名:/数据目录

这种方式确保容器重启或删除后数据不会丢失。

6. CI/CD 集成

项目通过 Jenkins 实现持续集成和部署,Jenkinsfile 示例:

pipeline {
    agent { 
        label '构建节点标签'
    }
    
    parameters {
        string(
            name: 'BRANCH_NAME',
            defaultValue: '默认分支',
            description: '分支参数说明'
        )
    }
    
    stages {
        stage("下载代码") {
            steps {
                script {
                    // 设置 Git 代理和 SSL 验证
                    sh 'git config --global http.proxy http://代理地址:端口'
                    sh 'git config --global http.sslVerify false'

                    checkout([
                        $class: 'GitSCM',
                        branches: [[name: "${BRANCH_NAME}"]],
                        extensions: [[
                            $class: 'CloneOption',
                            depth: 1, 
                            noTags: false, 
                            reference: '', 
                            shallow: true
                        ]],
                        userRemoteConfigs: [[
                            credentialsId: "凭证ID",
                            url: "仓库地址"
                        ]]
                    ])
                }
            }
        }
        
        stage("设置相关环境变量") {
            steps {
                script {
                    env.commitId = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
                }
            }
        }
        
        stage('构建代码') {
            steps {
                script {
                    sh "mvn clean package -U"
                }
            }
        }
        
        stage('构建镜像') {
            steps {
                script {
                    // 打包镜像
                    sh "ls -alh ."
                    sh "ls -alh 服务目录"
                    sh "docker rmi -f 镜像仓库/镜像名:${BRANCH_NAME}"
                    sh "cd 服务目录 && docker build -t 镜像仓库/镜像名:${BRANCH_NAME} -f Dockerfile ./"
                }
            }
        }
        
        stage('启动容器') {
            steps {
                script {
                    sh "cd 部署目录 && docker-compose -f docker-compose.app.yaml -p 项目名 up -d --force-recreate --build 服务名"
                }
            }
        }
    }
}

该流水线实现了以下功能:

  1. 代码拉取和环境配置
  2. 应用构建(Maven)
  3. Docker 镜像构建
  4. 服务部署(通过 docker-compose)

相关脚本

pre-start.sh

#!/bin/bash
# ==============================================================================
# 环境变量预处理脚本
# 用于从 .env.tmp 模板生成实际环境变量文件 .env
# 功能:
# 1. 对 _PORT 结尾的变量进行端口偏移计算
# 2. 对 _CONTAINER_NAME 结尾的变量添加后缀
# 3. 支持通过环境变量覆盖默认偏移量和后缀

# ==============================================================================

# 启用严格错误检查模式
# -e: 命令失败时立即退出
# -u: 使用未定义变量时报错
# -o pipefail: 管道中任意命令失败时整个管道失败
set -euo pipefail

# ====================== 配置参数 ======================
# 定义默认端口偏移量(可通过环境变量 OFFSET_PORT 覆盖)
# 示例:OFFSET_PORT=500 ./pre-start.sh
: ${OFFSET_PORT:=0}

# 定义默认容器名后缀(可通过环境变量 SUFFIX 覆盖)
# 注意:变量名疑似应为 SUFFIX,当前保持 SUFFIX 以兼容旧版本
: ${SUFFIX:="-dev"}

# ====================== 文件处理 ======================
# 创建临时文件(原子化操作保障)
# 使用 mktemp 避免文件名冲突,XXXXX 模板生成随机后缀
TMP_FILE=$(mktemp) || { echo "无法创建临时文件"; exit 1; }

# ====================== 核心处理逻辑 ======================
# 使用 awk 进行模板处理,支持以下特性:
# 1. 端口偏移计算(支持直接数值和变量引用)
# 2. 容器名后缀追加(自动处理引号包裹的值)
# 3. 保留原始注释和格式
awk -v offset="$OFFSET_PORT" -v suffix="$SUFFIX" '
# ================= 端口处理模块 =================
# 匹配模式:_PORT 或 _PORT+数字 结尾的变量(如 DB_PORT, REDIS_PORT2)
/^[^=]*_PORT([0-9]+)?=/ {
    # 分割变量名和值
    split($0, a, "=")
    var_name = a[1]
    var_value = a[2]

    # 数值校验逻辑
    if (var_value ~ /^[0-9]+$/ || var_value ~ /^\$\{.*\}$/) {
        # 执行算术运算(支持变量引用如 ${BASE_PORT})
        new_value = var_value + offset
        printf "%s=%s\n", var_name, new_value
    } else {
        # 非数值内容保持原样(如注释行)
        print
    }
    next  # 跳过后续处理
}

# ================= 容器名处理模块 =================
# 匹配模式:_CONTAINER_NAME 结尾的变量
/^[^=]*_CONTAINER_NAME=/ {
    # 分割变量名和值
    split($0, a, "=")
    var_name = a[1]
    var_value = a[2]

    # 引号处理逻辑
    if (var_value ~ /^".*"$/) {         # 双引号包裹的值
        gsub(/"/, "", var_value)        # 去除引号
        printf "%s=\"%s%s\"\n", var_name, var_value, suffix
    } else if (var_value ~ /^'\''/) {   # 单引号包裹的值
        gsub(/'\''/, "", var_value)     # 去除引号
        printf "%s=''%s%s'\''\n", var_name, var_value, suffix
    } else {                            # 无引号包裹的值
        printf "%s=%s%s\n", var_name, var_value, suffix
    }
    next  # 跳过后续处理
}

# ================= 默认处理模块 =================
# 保留所有其他内容(包括注释、空行、未匹配变量等)
{ print }
' .env.tmp > "$TMP_FILE"

# ====================== 后处理操作 ======================
# 原子化文件替换(确保操作完整性)
mv -f "$TMP_FILE" .env || { echo "文件替换失败"; exit 1; }

# ====================== 输出结果信息 ======================
cat << EOF
成功生成环境变量文件 .env
配置信息:
  - 端口偏移量: +${OFFSET_PORT}
  - 容器名后缀: ${SUFFIX}
EOF

# 根据.env中的DATA_DIR变量,创建相关路径:
set -x
# 读取DATA_DIR变量并展开其中的环境变量
data_dir=$(bash -c "source .env && echo \$DATA_DIR")
echo "创建相关路径: $data_dir"
mkdir -p "$data_dir"

# 创建各个服务的数据子目录
mkdir -p "$data_dir"/{redis,mysql,nacos,minio,mongo,elasticsearch}

exit 0

save-images.sh

#!/bin/bash

# 批量保存Docker镜像脚本
# 根据.env文件中的变量和docker-compose文件保存所有需要的镜像

set -euo pipefail

echo "开始保存Docker镜像..."

# 检查Docker是否运行
if ! command -v docker &> /dev/null; then
    echo "错误: 未找到Docker命令,请确保Docker已安装并正在运行"
    exit 1
fi

# 检查.env文件是否存在
if [ ! -f ".env" ]; then
    echo "未找到.env文件,运行pre-start.sh生成..."
    ./pre-start.sh
fi

# 创建保存镜像的目录
IMAGES_DIR="./images"
mkdir -p "$IMAGES_DIR"
echo "镜像将保存到: $IMAGES_DIR"

# 保存镜像的函数
save_image() {
    local image_name=$1
    local image_tag=$2
    local output_name=$3
    
    full_image_name="${image_name}:${image_tag}"
    output_file="${IMAGES_DIR}/${output_name}.tar"
    
    echo "正在保存镜像: $full_image_name -> $output_file"
    
    # 检查镜像是否存在
    if docker images --format "{{.Repository}}:{{.Tag}}" | grep -q "^${full_image_name}$"; then
        if docker save "$full_image_name" -o "$output_file"; then
            echo "成功保存镜像: $full_image_name"
        else
            echo "错误: 无法保存镜像 $full_image_name"
        fi
    else
        echo "警告: 镜像 $full_image_name 不存在于本地,跳过保存"
    fi
}

load-images.sh

#!/bin/bash

# 批量加载Docker镜像脚本
# 用于加载保存在./images目录下的所有Docker镜像

set -euo pipefail

echo "开始加载Docker镜像..."

# 检查Docker是否运行
if ! command -v docker &> /dev/null; then
    echo "错误: 未找到Docker命令,请确保Docker已安装并正在运行"
    exit 1
fi

# 检查images目录是否存在
IMAGES_DIR="./images"
if [ ! -d "$IMAGES_DIR" ]; then
    echo "错误: 镜像目录 $IMAGES_DIR 不存在"
    exit 1
fi

# 检查images目录是否为空
if [ -z "$(ls -A "$IMAGES_DIR")" ]; then
    echo "错误: 镜像目录 $IMAGES_DIR 为空"
    exit 1
fi

# 加载镜像的函数
load_image() {
    local image_file=$1
    
    echo "正在加载镜像: $image_file"
    
    if docker load -i "$image_file"; then
        echo "成功加载镜像: $image_file"
    else
        echo "错误: 无法加载镜像 $image_file"
    fi
}

# 遍历images目录下的所有tar文件并加载
echo "=== 开始加载镜像 ==="
for image_file in "$IMAGES_DIR"/*.tar; do
    # 检查是否有匹配的文件
    if [ -f "$image_file" ]; then
        load_image "$image_file"
    else
        echo "未找到任何.tar镜像文件"
        break
    fi
done

echo "所有镜像加载完成!"
echo "使用 'docker images' 命令查看已加载的镜像"

总结

基于 Docker Compose 的微服务部署方案具有以下优势:

  1. 简化部署:通过声明式配置文件定义服务,一条命令即可部署整个系统
  2. 环境一致性:开发、测试、生产环境使用相同的配置,避免环境差异问题
  3. 可扩展性:支持水平扩展和垂直扩展,满足不同规模的业务需求
  4. 可观测性:统一的日志和监控方案,便于问题排查和性能优化

在实际应用中,需要根据业务特点和资源情况合理设计服务架构,选择合适的技术组件,制定完善的部署和运维策略,才能充分发挥微服务架构的优势。

0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区