从零到一:Docker Compose 轻松部署微服务实战!

发布于:2025-07-28 ⋅ 阅读:(13) ⋅ 点赞:(0)

从零到一:Docker Compose 轻松部署微服务实战

今天实践一下使用Docker Compose部署一个微服务项目。

项目包括docker compose部署的代码都放在了我的github上:https://github.com/cra358/demo

首先简单写一个微服务项目,主要技术栈:Spring Cloud Alibaba、redis、Mysql、Gateway、SaToken

主要就是用户登陆积分记录功能。用户每登陆系统一次,用户登陆积分+1。

服务划分

  • gatway主要实现登陆校验。
  • user实现用户注册、退出、积分查询增长功能。

在这里插入图片描述

容器划分

  • 环境容器:nacos、mysql、redis

  • 服务容器:gateway、user

服务打包package:

先双击clean,清理target目录文件,再双击package文件,点击右上角的>中的带斜线的圈可以跳过test。

在这里插入图片描述

在target目录中可以找到对应的jar包。确定没有问题后就可以开始部署了。

安装Docker(略)

Docker 使用的版本是Docker version 27.5.0,安装完成后在pull一下mysql、redis和nacos的镜像,方便后面创建环境容器。本次使用的是mysql8.0、redis7.2.3、nacos v2.2.0版本。

在这里插入图片描述

Docker Compose安装

在选择安装版本时,需要注意Docker Compose 版本和Docker版本对应。我使用的Docker Compose版本是Docker Compose version v2.30.0

  • https://github.com/docker/compose/releases/tag/v2.30.0。到这里下载Docker Compose文件。

在这里插入图片描述

  • 将文件移动到:/usr/local/bin/docker-compose

sudo cp docker-compose-linux-x86_64 /usr/local/bin/docker-compose

  • 添加可执行权限

chmod +x /usr/local/bin/docker-compose

  • 测试安装成功

docker-compose --version

在这里插入图片描述

安装成功后,正式准备部署。在项目目录的docker目录中:

在这里插入图片描述

docker下的demo目录存放两个服务模块的我们之前打包生成好的jar包和Dockerfile文件:

在这里插入图片描述

现在,我们需要为每个微服务编写 Dockerfile内容,用于构建 Docker 镜像。Dockerfile 定义了镜像的构建过程,包括基础镜像、依赖安装、代码复制、启动命令等。

为微服务编写Dockerfile文件
  • user
# 基础镜像
FROM openjdk:17

# 挂载目录,就是容器中的目录
VOLUME /home/user
# 创建目录,也是容器中的目录
RUN mkdir -p /home/user
# 指定路径
WORKDIR /home/user
# 复制jar文件到容器指定路径,就是把宿主机中的./jar/user.jar文件复制到容器/home/user/user.jar中
COPY ./jar/user.jar /home/user/user.jar
# 启动用户服务
ENTRYPOINT ["java","-jar","user.jar"]
  • gateway
# 基础镜像
FROM openjdk:17

# 挂载目录
VOLUME /home/gateway
# 创建目录
RUN mkdir -p /home/gateway
# 指定路径
WORKDIR /home/gateway
# 复制jar文件到路径
COPY ./jar/gateway.jar /home/gateway/gateway.jar
# 启动用户服务
ENTRYPOINT ["java","-jar","gateway.jar"]

完成上述步骤后,准备环境容器的Docker文件和一些配置:

  • mysql容器准备:

    在这里插入图片描述

在db目录下存放项目所需的初始数据库表。同时由于nacos配置依赖于mysql存放相关数据,也在这里存放一个nacos_config.sql文件,文件内容直接网上照抄即可。

db.sql文件如下:

CREATE DATABASE IF NOT EXISTS `demo_user` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE `demo_user`;

-- 删除已存在的表(谨慎使用)
DROP TABLE IF EXISTS `user`;
-- 创建 user 表
CREATE TABLE `user` (
    `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID,主键',
    `username` varchar(50) NOT NULL COMMENT '用户名',
    `password` varchar(255) NOT NULL COMMENT '密码(存储加密后的密码)',
    `score` int(11) NOT NULL DEFAULT '0' COMMENT '用户积分',
    PRIMARY KEY (`id`),
    UNIQUE KEY `idx_username` (`username`) COMMENT '用户名唯一索引'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

编写mysql容器的Dockerfile:

# 基础镜像,就是docker images命令下我们之前pull的mysql镜像,据此创建mysql容器
FROM mysql:8.0

# 执行sql脚本
# `/docker-entrypoint-initdb.d/`是MySQL官方镜像中的一个特殊目录,用于存放初始化数据库的脚本文件。
# 把刚刚的两个sql文件存放到mysql容器中
ADD ./db/*.sql /docker-entrypoint-initdb.d/
  • redis容器准备:

在这里插入图片描述

在docker/redis/conf目录下写一个redis配置文件:redis.conf,这里只写了一个密码:

requirepass 1234

同样,编写redis容器的Dockerfile:

# 基础镜像
FROM redis:7.2.3

# 挂载目录
VOLUME /home/demo/redis
# 创建目录
RUN mkdir -p /home/demo/redis
# 指定路径
WORKDIR /home/demo/redis
# 复制刚刚的redis.conf文件到容器指定路径
COPY ./conf/redis.conf /home/demo/redis/redis.conf
  • nacos容器准备:

在这里插入图片描述

在docker/nacos/conf中编写nacos配置文件:application.properties

spring.datasource.platform=mysql
spring.sql.init.platform=mysql

db.num=1
# 这里的nacos_config就是nacos在mysql容器中使用到的数据库,和前面的nacos_config.sql中创建出来的数据库要一致
# 下面的配置不一样有可能会导致意想不到的错误
db.url.0=jdbc:mysql://demo-mysql:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
# 制定用户、密码
db.user.0=root
db.password.0=20041111

# 这里后面的直接复制就可以了
nacos.naming.empty-service.auto-clean=true
nacos.naming.empty-service.clean.initial-delay-ms=50000
nacos.naming.empty-service.clean.period-time-ms=30000

management.endpoints.web.exposure.include=*

management.metrics.export.elastic.enabled=false
management.metrics.export.influx.enabled=false

server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D %{User-Agent}i %{Request-Source}i

server.tomcat.basedir=/home/demo/nacos/tomcat/logs

nacos.security.ignore.urls=/,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-ui/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/**

nacos.core.auth.system.type=nacos
nacos.core.auth.enabled=false
nacos.core.auth.default.token.expire.seconds=18000
nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
nacos.core.auth.caching.enabled=true
nacos.core.auth.enable.userAgentAuthWhite=false
nacos.core.auth.server.identity.key=serverIdentity
nacos.core.auth.server.identity.value=security

nacos.istio.mcp.server.enabled=false

编写nacos的Dockerfile文件:

# 基础镜像
FROM nacos/nacos-server:v2.2.0

# 复制刚刚的application.properties文件到nacos容器的制定路径
COPY ./conf/application.properties /home/nacos/conf/application.properties

到此,我们就准备好了环境容器和服务容器的准备工作。

编写 DockerCompose.yml 文件
version: '3'
services:
  demo-nacos:
  	# 容器名
    container_name: demo-nacos
    image: nacos/nacos-server:v2.2.0
    build:
      context: ./nacos
    environment:
      - MODE=standalone
      # 使用 mysql 作为数据库
      - SPRING_DATASOURCE_PLATFORM=mysql
      - MYSQL_SERVICE_HOST=demo-mysql
      - MYSQL_SERVICE_PORT=3306
      - MYSQL_SERVICE_DB_NAME=nacos_config
      - MYSQL_SERVICE_USER=root
      - MYSQL_SERVICE_PASSWORD=20041111
      # 设置连接 mysql 的连接参数
      - MYSQL_DB_PARAM="characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrievalyaml=true"

    volumes:
      - ./nacos/logs/:/home/nacos/logs
      - ./nacos/conf/application.properties:/home/nacos/conf/application.properties
    # 要暴露三个端口,至于为什么,可以网上查下看看
    ports:
      - "8848:8848"
      - "9848:9848"
      - "9849:9849"
    privileged: true
    networks:
      - demo-network
    # nacos依赖于mysql先启动成功
    depends_on:
      demo-mysql:
        condition: service_healthy


#      - demo-mysql
  demo-mysql:
  	# 容器名
    container_name: demo-mysql
    # 镜像
    image: mysql:8.0
    build:
      context: ./mysql
    ports:
      - "3306:3306"
    volumes:
      - ./mysql/conf:/etc/mysql/conf.d
      - ./mysql/logs:/logs
      - ./mysql/data:/var/lib/mysql
      - ./mysql/db:/docker-entrypoint-initdb.d/
    command: [
      'mysqld',
      '--innodb-buffer-pool-size=80M',
      '--character-set-server=utf8mb4',
      '--collation-server=utf8mb4_unicode_ci',
      '--default-time-zone=+8:00',
      '--lower-case-table-names=1'
    ]
    privileged: true
    networks:
      - demo-network
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      timeout: 20s
      retries: 5
    environment:
      MYSQL_ROOT_PASSWORD: '20041111'

  demo-redis:
    container_name: demo-redis
    image: redis:7.2.3
    build:
      context: ./redis
      dockerfile: Dockerfile
    ports:
      - "6379:6379"
    volumes:
      - ./redis/conf/redis.conf:/home/demo/redis/redis.conf
      - ./redis/data:/data
    command: redis-server /home/demo/redis/redis.conf
    networks:
      - demo-network
	
  # 网关服务容器
  demo-gateway:
    container_name: demo-gateway
    build:
      context: ./demo/gateway
      dockerfile: Dockerfile
    ports:
      - "8000:8000"
    depends_on:
      - demo-redis
      - demo-nacos

    networks:
      - demo-network

  # 用户服务容器
  demo-user:
    container_name: demo-user
    build:
      context: ./demo/user
      dockerfile: Dockerfile
    # 端口映射
    ports:
      - "8001:8001"
    depends_on:
      - demo-redis
      - demo-mysql
      - demo-nacos
    networks:
      - demo-network
# 确保都在同一个网络下
networks:
  demo-network:
    driver: bridge
sh脚本

上述工作完成后,我们写一个sh脚本,方便我们清理复制jar包、运行docker-compose.yml文件来启动容器。

在这里插入图片描述

  • cleanjar.sh
#!/bin/bash

# 删除jar文件
echo "开始清理jar文件"
rm -f ../demo/gateway/jar/gateway.jar
rm -f ../demo/user/jar/user.jar
echo "清理完成"
  • copy.sh
#!/bin/bash

# 创建目标目录
mkdir -p ../mysql/db
mkdir -p ../demo/gateway/jar
mkdir -p ../demo/user/jar

# 复制项目db目录下的sql文件到docker/mysql/db目录中
echo "begin copy sql "
cp ../../sql/db.sql ../mysql/db
echo "end copy sql "

# 复制target目录下的jar文件到docker目录下的demo的jar目录中
echo "begin copy jar "
cp ../../gateway/target/com.chenxw.demo.gateway-1.0-SNAPSHOT.jar ../demo/gateway/jar/gateway.jar
cp ../../user/target/com.chenxw.demo.user-1.0-SNAPSHOT.jar ../demo/user/jar/user.jar
echo "end copy jar "
  • deploy.sh:Docker Compose运行脚本
#!/bin/sh

# 使用说明,用来提示输入参数
usage(){
	echo "Usage: sh 执行脚本.sh [base|services|stop|rm]"
	exit 1
}

# 启动基础环境(必须)
base(){
	docker-compose up -d demo-mysql demo-redis demo-nacos
}

# 启动程序模块(必须)
services(){
	docker-compose up -d demo-gateway demo-user
}

# 关闭所有环境/模块
stop(){
	docker-compose stop
}

# 删除所有环境/模块
rm(){
	docker-compose rm
}

# 根据输入参数,选择执行对应方法,不输入则执行使用说明
case "$1" in
"base")
	base
;;
"services")
	services
;;
"stop")
	stop
;;
"rm")
	rm
;;
*)
	usage
;;
esac

到此,所有准备工作都完成了。但是我们要注意,在项目的apppication.yml文件中,我们要把127.0.0.1或者localhost改成指定容器名,每个容器都有自己的ip。比如这里要连接mysql就改成demo-mysql,要连接redis就改成demo-redis,要配置nacos地址就改成demo-nacos

比如gateway服务中的apppication.yml文件:

server:
  port: 8000 # 指定启动端口

spring:
  application:
    name: demo-gateway # 容器名称,就是我们在docker-compose.yml中指定的container_name
  cloud:
    config:
      enabled: false
    nacos:
      discovery:
        enabled: true # 启用服务发现
        group: DEFAULT_GROUP # 所属组
        namespace: demo # 命名空间
        server-addr: demo-nacos:8848 # 指定 Nacos 配置中心的服务器地址
        username: nacos
        password: nacos

    gateway:
      routes:
        - id: user
          uri: lb://demo-user
          predicates:
            - Path=/user/**
          filters:
            - StripPrefix=0
  data:
    redis:
      database: 1 # Redis 数据库索引
      host: demo-redis # Redis 服务器地址
      port: 6379 # Redis 服务器连接端口
      password: 1234 # Redis 服务器连接密码(默认为空)
      timeout: 5s # 读超时时间
      connect-timeout: 5s # 链接超时时间
      lettuce:
        pool:
          max-active: 200 # 连接池最大连接数
          max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
          min-idle: 0 # 连接池中的最小空闲连接
          max-idle: 10 # 连接池中的最大空闲连接

############## Sa-Token 配置 (文档: https://sa-token.cc) ##############
sa-token:
  # token 名称(同时也是 cookie 名称)
  token-name: Authorization
  # token前缀
  token-prefix: Bearer
  # token 有效期(单位:秒) 默认30天,-1 代表永久有效
  timeout: 2592000
  # token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结
  active-timeout: -1
  # 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录)
  is-concurrent: true
  # 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token)
  is-share: true
  # token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik)
  token-style: random-32
  # 是否输出操作日志
  is-log: true
微服务,启动!

运行cleanjar.sh、copy.sh复制sql、jar包。

运行sh deploy.sh base,启动环境容器!

在这里插入图片描述

在IDEA服务中也可以看到环境容器启动成功:

在这里插入图片描述

运行sh deploy.sh services,启动服务容器!

在这里插入图片描述

服务容器也启动成功:

在这里插入图片描述

在nacos控制台查看demo-gateway和demo-user服务是否注册成功:

在这里插入图片描述

两个应用都注册到nacos中了,来看下各个容器的ip:

在这里插入图片描述

从网关127.19.0.5访问:试下注册、登陆、积分查询、退出接口都没有问题。

  • 注册:

在这里插入图片描述

  • 登陆:

在这里插入图片描述

  • 查询:

在这里插入图片描述

  • 退出:

在这里插入图片描述

至此,docker compose部署微服务就完成了。

其实这个过程中还是会遇到各种奇奇怪怪的错误,可以用cursor帮忙理解整个报错原因,一步步梳理,效率嘎嘎高!

参考资料:https://github.com/timeless157/timeless-order-pay-parent.git


网站公告

今日签到

点亮在社区的每一天
去签到