从入门到精通Docker Compose 轻松部署微服务实战教程
作者:拉里呱唧
从零到一: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
到此这篇关于从入门到精通Docker Compose 轻松部署微服务实战教程的文章就介绍到这了,更多相关docker compose部署微服务内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!