CentOS7中使用docker-compose部署SpringBoot+Redis+MySQL+Nginx

慕才
2023-12-01

1. 前言


在前段时间,学习了有关 Docker 部署各类应用的知识,可以明确感觉到,虽然 Docker 解决了环境不一致的问题,并且大大提升了部署速度,但还是会有太多重复性的操作;比如最近做的项目环境都很类似,需要依赖 Redis,MySQL 等等服务,这时每个环境部署的时候,都得拉取镜像,启动镜像等系列操作,当然对于之前每个环境都要从头配置已经快太多,但是作为程序员,能省时间的地方绝不含糊,所以将目光投向了 docker-compose(服务编排工具)。

 

2. 源码


GitHub 地址:https://github.com/intomylife/Docker

 

3. 概念


3.1 容器

作为最小单位,一个容器代表着一个应用。

3.2 服务

每个服务中定义了容器描述、端口映射、配置映射以及依赖关系;一个服务可以实例出多个容器。

3.3 工程

每个工程中包含了多个服务。

注:在本次部署中,有一个工程,包括四个服务:SpringBoot、Redis、MySQL 以及 Nginx,其中 SpringBoot 服务被实例两个

 

4. SpringBoot 服务


4.1 搭建

此次搭建只整合了 Redis 和 MySQL,如果对具体整合过程感兴趣,可以前往:

需要注意的地方如下

4.2 配置文件

# 数据源
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.host=127.0.0.1
spring.datasource.url=jdbc:mysql://${spring.datasource.host}:3306/base_db?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=PRC&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456

# 打印 sql 日志
logging.level.com.zwc.base.mapper=debug

# Redis 配置
## Redis 数据库索引:默认为 0。Redis 一共有 16 个数据库,索引分别为 0-15。从 Redis 客户端也可以看出,从 db0 ~ db15。
spring.redis.database=2
## Redis 服务器地址
spring.redis.host=127.0.0.1
## Redis 服务器端口
spring.redis.port=6379
## Redis 服务器密码
spring.redis.password=123456789

注:这里专门把 host 都配置为本地 127.0.0.1 环境,因为在使用 docker-compose 服务编排时会用代码主动做处理,这时一套配置文件就足够了。

4.3 提供服务

代码片段

/*
     * @ClassName BaseTableService
     * @Desc TODO   统计访问次数
     * @Date 2019/9/16 14:42
     * @Version 1.0
     */
    @Transactional
    public String comeCounts(String sessionId) {
        // 返回数量
        Integer resultCount = 1;

        // 先从缓存中取访问次数
        Object redisComeCounts = redisClient.get(BaseServiceConstant.COME_COUNTS);
        // 取出所有 sessionId
        List<BaseTable> sessionIdList = new ArrayList<>();
        // 访问次数 - 非空判断
        if(redisComeCounts != null) {
            // 取出所有 sessionId
            sessionIdList = JSON.parseObject(redisComeCounts.toString(), new TypeReference<List<BaseTable>>() {});

            // 数据库中的数量
            Integer mysqlCount = super.count(new QueryWrapper<BaseTable>());
            // 计算出返回数量:mysql + redis
            resultCount = mysqlCount + sessionIdList.size();

            // 判断是否该同步到数据库
            if(sessionIdList.size() >= BaseServiceConstant.MAX_COUNTS) {
                // 同步到数据库中
                if(save(sessionIdList)) {
                    // 同步成功,清空缓存
                    sessionIdList = new ArrayList<>();
                    redisClient.delete(BaseServiceConstant.COME_COUNTS);
                }
            }
        }
        // 存入对象
        BaseTable baseTable = new BaseTable();
        // sessionId
        baseTable.setSessionId(sessionId);
        // 添加时间
        baseTable.setCreateDatetime(new Date());
        // 放入集合中
        sessionIdList.add(baseTable);
        // 存入缓存中
        redisClient.set(BaseServiceConstant.COME_COUNTS, JSON.toJSONString(sessionIdList));

        try {
            // 返回数量
            return "ip:" + InetAddress.getLocalHost().getHostAddress() + " / count:" + String.valueOf(resultCount) + " / time:" + sdf.format(new Date());
        } catch (UnknownHostException e) {
            e.printStackTrace();
            // 返回
            return "获取地址失败";
        }
    }

    /*
     * @ClassName BaseTableService
     * @Desc TODO   批量存入数据到数据库
     * @Date 2019/9/16 14:49
     * @Version 1.0
     */
    public boolean save(List<BaseTable> baseTables) {
        // 调用批量新增方法
        return super.saveBatch(baseTables);
    }

主要做的事情及细节有:

  ① 统计访问次数,同时把 Redis 和 MySQL 都强行用上;在 Redis 中写入了足够的访问次数对象的数量后,会同步到 MySQL,也就是降低了 MySQL 的写 IO 操作。

  ② 显示了当前主机的 ip 地址,因为后面会把 SpringBoot 服务实例出多个容器,并使用 Nginx 做负载均衡。

  ③ 显示当前时间,主要是处理了容器时区问题。

 

5. Dockerfile


FROM openjdk:8-jdk-alpine
VOLUME /tmp
ADD app.jar app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
  • FROM openjdk:8-jdk-alpine:基础镜像环境 JDK1.8
  • VOLUME /tmp:指定了挂载目录
  • ADD app.jar app.jar:把指定的 jar 包拷贝到 Docker 容器中并命名为 app.jar
  • 最后一行是修改 Tomcat 随机数生成方式,加快 Tomcat 启动

注:此次 SpringBoot 项目中没有配置 Docker 插件,也仅仅就是打成了 jar 包,这时就需要一个 Dockerfile 文件来构建镜像

 

6. docker-compose.yaml


6.1 文件说明

此文件的默认名称为 docker-compose,后缀名可以为 .yml 也可以为 .yaml。

这个 docker-compose.yaml 文件对应的就是上面所说的工程。

6.2 version

version: '3'

构建文件的语法版本信息。version: '3' 表示使用第三代语法。

6.3 services

version: '3'

services:

    service_redis:
        ...
    
    service_mysql:
        ...
    
    service_springboot:
        ...
    
    service_nginx:
        ...

包含此工程中所有的服务列表。

服务可以是已存在的镜像(本地或远程),也可以是构建出来的镜像;如果其中有需要构建的镜像,则需要一个 Dockerfile 文件,正如此次部署我们需要构建 Springboot 镜像。

6.4 service_redis

    service_redis:
        container_name: container_redis
        image: redis:4.0.14
        environment:
            - TZ=Asia/Shanghai
        ports:
            - "6379:6379"
        volumes:
            - ./config/redis/redis.conf:/usr/local/etc/redis/redis.conf
            - ./data/redis/:/data/
            - ./log/redis/:/var/log/redis/
        command: redis-server /usr/local/etc/redis/redis.conf
        restart: always

Redis 服务描述:

  • service_redis:服务名称,可自定义。

  • container_name:容器名称,可自定义;也可不写,那会自动生成,生成规则为 【docker-compose.yaml 文件的父目录名称 + _ + 服务名称 + 从一开始的数字】。

  • image:指定镜像来启动容器。此处指定为 Redis 官方镜像,版本为 4.0.14。

  • environment:为启动的容器添加环境变量。此处配置了容器的时区。

  • ports:端口映射,映射规则为 宿主机端口:容器端口。此处映射 宿主机 6379 端口到 容器 6379 端口。

  • volumes:配置映射,映射规则为 宿主机:容器,可以映射文件或目录。此处映射了 配置文件,数据目录以及日志目录。

  • command:容器启动后执行的命令。此处命令为 使用配置文件来启动 Redis 容器。

  • restart:赋固定值 always,表示如果容器启动失败,会一直尝试重连。

注:redis.conf 配置文件中修改了如下几点

  ① daemonize no:前台启动,在 Docker 中后台启动 Redis 容器会报错

  ② requirepass 123456789:设置密码

  ③ # bind 127.0.0.1:注释掉了,使外网可访问

6.5 service_mysql

    service_mysql:
        container_name: container_mysql
        image: mysql:5.7
        environment:
            TZ: Asia/Shanghai
            MYSQL_ROOT_PASSWORD: 123456
            MYSQL_ROOT_HOST: '%'
        ports:
            - "3306:3306"
        volumes:
            - ./config/mysql/my.cnf:/etc/mysql/conf.d/my.cnf
            - ./data/mysql/:/var/lib/mysql/
            - ./data/init/:/docker-entrypoint-initdb.d/
            - ./log/mysql/:/var/log/mysql/
        command: [
            '--character-set-server=utf8mb4',
            '--collation-server=utf8mb4_unicode_ci'
        ]
        restart: always

MySQL 服务描述:

  • service_mysql:服务名称,可自定义。

  • container_name:容器名称,可自定义;也可不写,那会自动生成,生成规则为 【docker-compose.yaml 文件的父目录名称 + _ + 服务名称 + 从一开始的数字】。

  • image:指定镜像来启动容器。此处指定为 MySQL 官方镜像,版本为 5.7。

  • environment:为启动的容器添加环境变量。此处配置了容器的时区,以及数据库 ROOT 密码和权限。

  • ports:端口映射,映射规则为 宿主机端口:容器端口。此处映射 宿主机 3306 端口到 容器 3306 端口。

  • volumes:配置映射,映射规则为 宿主机:容器,可以映射文件或目录。此处映射了 配置文件,数据目录,初始化 SQL 目录以及日志目录。

  • command:容器启动后执行的命令。此处命令为 设置字符编码。

  • restart:赋固定值 always,表示如果容器启动失败,会一直尝试重连。

注:my.cnf 配置文件中有一个需要注意的地方如下

# 开启 bin-log,并指定文件目录和文件名前缀
log-bin=/var/log/mysql/binlog

此处配置了 bin-log 文件目录,则 volumes 中映射的 - ./log/mysql/:/var/log/mysql/ 目录才会有数据。

6.6 service_springboot

    service_springboot:
        build:
            context: .
            dockerfile: Dockerfile
        environment:
            TZ: Asia/Shanghai
            spring.datasource.host: service_mysql
            spring.redis.host: service_redis
        expose:
            - "8080"
        depends_on:
            - service_redis
            - service_mysql
        restart: always

SpringBoot 服务描述:

  • service_springboot:服务名称,可自定义。

  • 此处没有指定容器名称,是因为在启动工程时,会加上 scale 参数,此服务会被实例出多个容器,如果指定了容器名称,则会报错。这时容器名称会自动生成,生成规则为 【docker-compose.yaml 文件的父目录名称 + _ + 服务名称 + 从一开始的数字】。

  • build:指定 Dockerfile 文件位置,构建镜像,并使用这个镜像来启动容器。

  • environment:为启动的容器添加环境变量。此处配置了容器的时区;并指定了 MySQL 的 host 为 service_mysql 服务,Redis 的 host 为 service_redis 服务,这两个 host 正是对应 SpringBoot 项目的配置文件(application.properties)中两个 host;这也是上面提到的 用代码主动做处理。(注:由于 MySQL 服务和 Redis 服务都只有一个,所有这里指定服务名和容器名都是可以的)

  • expose:暴露容器内端口,不映射到宿主机。因为 SpringBoot 服务会被 Nginx 做代理转发,所以不用暴露并映射到外部。

  • depends_on:依赖服务。在整个工程启动时,会先启动依赖服务,再启动当前服务。也就是说,这里 SpringBoot 服务会等待 MySQL 服务和 Redis 服务启动完成后,才会开始启动。

  • restart:赋固定值 always,表示如果容器启动失败,会一直尝试重连。

6.7 service_nginx

    service_nginx:
        container_name: container_nginx
        image: nginx:1.8
        environment:
            - TZ=Asia/Shanghai
        ports:
            - "8000:8000"
        volumes:
            - ./config/nginx/nginx.conf:/etc/nginx/nginx.conf
            - ./data/nginx/:/usr/share/nginx/html/
            - ./log/nginx/:/var/log/nginx/
        depends_on:
            - service_springboot
        restart: always

Nginx 服务描述:

  • service_nginx:服务名称,可自定义。

  • container_name:容器名称,可自定义;也可不写,那会自动生成,生成规则为 【docker-compose.yaml 文件的父目录名称 + _ + 服务名称 + 从一开始的数字】。

  • image:指定镜像来启动容器。此处指定为 Nginx 官方镜像,版本为 1.8。

  • environment:为启动的容器添加环境变量。此处配置了容器的时区。

  • ports:端口映射,映射规则为 宿主机端口:容器端口。此处映射 宿主机 8000 端口到 容器 8000 端口。

  • volumes:配置映射,映射规则为 宿主机:容器,可以映射文件或目录。此处映射了 配置文件,数据目录以及日志目录。

  • depends_on:依赖服务。在整个工程启动时,会先启动依赖服务,再启动当前服务。也就是说,这里 Nginx 服务会等待 SpringBoot 服务启动完成后,才会开始启动。

  • restart:赋固定值 always,表示如果容器启动失败,会一直尝试重连。

注:nginx.conf 配置文件中需要注意如下地方

    upstream dispense {
        server docker-compose_service_springboot_1:8080 weight=1;
        server docker-compose_service_springboot_2:8080 weight=2;
    }

  ① 访问 Nginx 服务会转发到 SpringBoot 服务。

  ② SpringBoot 容器名称是自动生成的,生成规则为 【docker-compose.yaml 文件的父目录名称 + _ + 服务名称 + 从一开始的数字】。

  ③ SpringBoot 容器端口都是 8080。

  ④ 访问比例为 1:2。

 

7. 部署


7.1 安装环境

7.2 拷贝项目

  ① 文件具体在 build 目录,可直接下载

  ② 把 build 目录拷贝到服务器上

  ③ 进入目录

[root@zwc docker-compose]# ls -all
total 34932
drwxrwxr-x 5 root root     4096 Oct 17 13:42 .
drwxr-xr-x 9 root root     4096 Sep 17 16:05 ..
-rw-rw-r-- 1 root root 35740202 Oct 16 14:27 app.jar
drwxrwxr-x 5 root root     4096 Sep 17 14:09 config
drwxrwxr-x 6 root root     4096 Oct 16 11:56 data
-rw-rw-r-- 1 root root     1972 Oct 17 13:40 docker-compose.yaml
-rw-rw-r-- 1 root root      140 Sep 17 14:13 Dockerfile
drwxrwxrwx 5 root root     4096 Sep 18 17:37 log
[root@zwc docker-compose]# 

  ④ 日志目录需要赋值权限:chmod -R 777 log/

7.3 启动

---

启动 Docker

---

[root@zwc docker-compose]# systemctl start docker.service

---

查看当前目录

---

[root@zwc docker-compose]# ls -all
total 34932
drwxrwxr-x 5 root root     4096 Oct 17 13:42 .
drwxr-xr-x 9 root root     4096 Sep 17 16:05 ..
-rw-rw-r-- 1 root root 35740202 Oct 16 14:27 app.jar
drwxrwxr-x 5 root root     4096 Sep 17 14:09 config
drwxrwxr-x 6 root root     4096 Oct 16 11:56 data
-rw-rw-r-- 1 root root     1972 Oct 17 13:40 docker-compose.yaml
-rw-rw-r-- 1 root root      140 Sep 17 14:13 Dockerfile
drwxrwxrwx 5 root root     4096 Sep 18 17:37 log

---

使用 docker-compose 构建并启动工程
docker-compose up:最基本的启动命令
-d:后台启动
--scale:扩展服务节点,格式为 服务名=个数

---

[root@zwc docker-compose]# docker-compose up -d --scale service_springboot=2
Creating network "docker-compose_default" with the default driver
Building service_springboot
Step 1/4 : FROM openjdk:8-jdk-alpine
 ---> a3562aa0b991
Step 2/4 : VOLUME /tmp
 ---> Using cache
 ---> ceb1101d8851
Step 3/4 : ADD app.jar app.jar
 ---> e76f5dac4da4
Step 4/4 : ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
 ---> Running in ebfeefb03ef8
Removing intermediate container ebfeefb03ef8
 ---> 566f79654ab6
Successfully built 566f79654ab6
Successfully tagged docker-compose_service_springboot:latest
WARNING: Image for service service_springboot was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating container_mysql ... done
Creating container_redis ... done
Creating docker-compose_service_springboot_1 ... done
Creating docker-compose_service_springboot_2 ... done
Creating container_nginx                     ... done

---

查看容器启动情况

---

[root@zwc docker-compose]# docker-compose ps -a
               Name                              Command               State                    Ports                 
----------------------------------------------------------------------------------------------------------------------
docker-compose_service_springboot_1   java -Djava.security.egd=f ...   Up      8080/tcp                               
container_redis                       docker-entrypoint.sh redis ...   Up      0.0.0.0:6379->6379/tcp                 
container_mysql                       docker-entrypoint.sh --cha ...   Up      0.0.0.0:3306->3306/tcp, 33060/tcp      
container_nginx                       nginx -g daemon off;             Up      443/tcp, 80/tcp, 0.0.0.0:8000->8000/tcp
docker-compose_service_springboot_2   java -Djava.security.egd=f ...   Up      8080/tcp                               

---

查看镜像构建情况

---

[root@zwc docker-compose]# docker-compose images
             Container                           Repository                Tag       Image Id      Size  
---------------------------------------------------------------------------------------------------------
container_mysql                       mysql                               5.7      a1aa4f76fab9   356 MB 
container_nginx                       nginx                               1.8      0d493297b409   127 MB 
container_redis                       redis                               4.0.14   720768125f4f   79.6 MB
docker-compose_service_springboot_1   docker-compose_service_springboot   latest   566f79654ab6   134 MB 
docker-compose_service_springboot_2   docker-compose_service_springboot   latest   566f79654ab6   134 MB

7.4 访问

7.4.1 浏览器中访问 Nginx 容器

在浏览器中输入服务器 ip:8000,可看到 'ip:172.25.0.4 / count:16 / time:2019-10-17 15:50:31' 信息。

如果多次访问,可以发现:

  ① 一共会出现两个不同的 ip,并且比例为 1:2

  ② count 数会一直累计

  ③ time 为当前时间

在浏览器中输入服务器 ip:8000/index.html,可看到 'just do it'。

7.4.2 Navicat 连接 MySQL 容器

在 Navicat 中新建 MySQL 连接:

  • 主机:服务器 ip
  • 端口:3306
  • 用户名:root
  • 密码:123456

连接成功后,进入到 base_db 库中打开 base_table 表,如果访问超过五次了,这张表里就会有记录的数据了。

7.4.3 rdm 连接 Redis 容器

在 rdm 中新建连接:

  • Host:服务器 ip
  • Port:6379
  • Auth:123456789

连接成功后,进入到 db_2 库中查看 come_counts key。

7.5 停止

---

停止并删除

---

[root@zwc docker-compose]# docker-compose down
Stopping container_nginx                     ... done
Stopping docker-compose_service_springboot_1 ... done
Stopping docker-compose_service_springboot_2 ... done
Stopping container_mysql                     ... done
Stopping container_redis                     ... done
Removing container_nginx                     ... done
Removing docker-compose_service_springboot_1 ... done
Removing docker-compose_service_springboot_2 ... done
Removing container_mysql                     ... done
Removing container_redis                     ... done
Removing network docker-compose_default

---

查看容器情况

---

[root@zwc docker-compose]# docker-compose ps -a
Name   Command   State   Ports
------------------------------

---

查看镜像情况

---

[root@zwc docker-compose]# docker-compose images
Container   Repository   Tag   Image Id   Size
----------------------------------------------

 

8. 结语


单机中使用 docker-compose 部署项目可以很明显的感觉到方便快捷,在不同项目、相同环境下,仅需一个 jar 包即可完成上线工作。

 

希望能够帮助到你

over

 

 

 

 类似资料: