CentOS7中使用docker-compose快速部署前后端分离项目

1. 前言


继上次写了一篇 CentOS7中使用docker-compose部署SpringBoot+Redis+MySQL+Nginx 博客后,我把前端页面也加入其中,重新整了一套前后端分离的项目,并且还是使用 docker-compose 部署;值得关注的是,做到了快速部署发布。


2. 源码


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


3. 环境


3.1 开发工具

  • 后端: IntelliJ IDEA
  • 前端: Visual Studio Code

3.2 其它工具

  • 连接服务器: Termius
  • 文件传输: Cyberduck
  • 连接 MySQL: Navicat Premium
  • 连接 Redis: Redis Desktop Manager

3.3 版本号

  • 后端: SpringBoot 2.0.3.RELEASE
  • 前端: Vue 2.5.2
  • 其他: JDK 1.8、Maven 3.3.9、Redis 4.0.14、MySQL 5.7、npm 6.11.3、node 12.11.1、Docker 18.09.5,docker-compose 1.24.1

4. 准备工作


注:准备工作需要按步骤顺序进行

4.1 服务器

4.1.1 需要安装 Docker 以及 docker-compose,可参考:

4.1.2 开启 TCP

注:此操作可能会给服务器带来安全隐患(暴露的2375端口被攻击)。如果不幸已经被挖矿,没关系,戳这里:服务器被挖矿后的解决思路


---

1. 创建 /etc/systemd/system/docker.service.d 目录

---

[root@zwc /]# mkdir /etc/systemd/system/docker.service.d
[root@zwc /]# cd /etc/systemd/system/docker.service.d

---

2. 新建 tcp.conf 文件

---

[root@zwc docker.service.d]# vim tcp.conf

---

3. 输入内容,保存退出

---

[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2375

---

4. 重启服务,使配置生效

---

[root@zwc docker.service.d]# systemctl daemon-reload && systemctl restart docker

---

5. 如果开启了防火墙,得开放 2375 端口

---

[root@zwc docker.service.d]# firewall-cmd --zone=public --add-port=2375/tcp

---

6. 进入阿里云控制台,到安全组中添加 2375 端口

---

4.1.3 TLS 加密

注:当加密后,就不用担心因为暴露了2375端口被攻击;加密或不加密对于代码的改动量非常小,更多的只是配置操作。

  1. 首先使用如下generateCACertificate.sh脚本在服务器上生成证书文件
## 自动生成证书脚本
#!/bin/bash


## 全局变量
### 密码
PASSPHRASE="987654321"


echo "===================== 开始 ====================="


## 创建需要的目录
mkdir -p /root/ca/my
## 进入到目录
cd /root/ca/my


## 生成 ca 私钥,并设置密码
openssl genrsa -aes256 -passout pass:$PASSPHRASE -out ca-key.pem 4096
## 使用 ca 私钥创建 ca 证书
openssl req -new -x509 -sha256 -passin "pass:$PASSPHRASE" -days 365 -subj "/CN=*" -key ca-key.pem -out ca.pem


## 生成服务器私钥
openssl genrsa -out server-key.pem 4096
## 使用服务器私钥创建服务器证书
openssl req -new -sha256 -subj "/CN=*" -key server-key.pem -out server.csr

## 生成服务器自签证书
openssl x509 -req -days 365 -sha256 -in server.csr -passin "pass:$PASSPHRASE" -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem


## 生成客户端私钥
openssl genrsa -out key.pem 4096
## 使用客户端私钥创建客户端证书
openssl req -new -subj "/CN=client" -key key.pem -out client.csr

## 配置 extendedKeyUsage
sh -c 'echo extendedKeyUsage=clientAuth >> extfile.cnf'
## 生成客户端自签证书
openssl x509 -req -days 365 -sha256 -in client.csr -passin "pass:$PASSPHRASE" -CA ca.pem -CAkey ca-key.pem -CAcreateserial -extfile extfile.cnf -out cert.pem


## 删除多余文件
rm -rf ca.srl client.csr ipWhiteList.cnf server.csr extfile.cnf
## 更改密钥权限
chmod 0400 ca-key.pem server-cert.pem server-key.pem
chmod 0444 ca.pem key.pem cert.pem


echo "===================== 结束 ====================="
  1. 接下来在步骤4.1.2 开启 TCP的基础上做修改

---

1. 编辑 /etc/systemd/system/docker.service.d/tcp.conf 文件,把刚刚生成的证书路径加入其中

---

[Service]
ExecStart=
ExecStart=/usr/bin/dockerd --tlsverify --tlscacert=/root/ca/my/ca.pem --tlscert=/root/ca/my/server-cert.pem --tlskey=/root/ca/my/server-key.pem -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2375

---

2. 重启服务,使配置生效

---

[root@zwc docker.service.d]# systemctl daemon-reload && systemctl restart docker

4.2 本地

注:这里是在 macOS 系统中操作的

4.2.1 安装 Docker

注:vsCode 在构建镜像时需要用到 Docker 命令,所以本地也需要安装 Docker

我是参考菜鸟教程中手动下载安装的,下载得到 .dmg 文件后,拖拽安装就结束了。

------------------ 2020.06.06 更新 ------------------

这时发现,vsCode更新到了1.45.1版本后,不需要本地启动docker也可以推送镜像了。那么本地中4.2.1 安装 Docker步骤可以跳过了

4.2.2 拷贝服务器生成的证书

  1. 在服务器的/root/ca/my目录中,拷贝ca.pemcert.pem以及key.pem文件
  2. 拷贝到本地Docker的安装目录中,如我的是/Users/zouwencong/.docker目录

4.2.3 配置 hosts 文件

  1. 打开终端,输入sudo vim /private/etc/hosts
  2. 输入密码
  3. 写入内容xx.xxx.xxx.xxx DockerHost,xx.xxx.xxx.xxx 就是安装了 Docker 的服务器地址
  4. 保存退出

4.2.4 配置 settings.xml 文件

  1. 找到 Maven 目录中的settings.xml文件
  2. 找到<servers></servers>节点,配置如下子节点
     <server>
      <id>docker-hub</id>
      <username>your username</username>
      <password>your password</password>
      <configuration>
          <email>your email</email>
      </configuration>
    </server>
  1. 保存退出

4.2.5 vsCode 中安装 Docker 插件

  1. 打开 vsCode
  2. 点击左侧栏中的组件入口
  3. 输入Docker进行搜索
  4. 选择第一个,点击Install
  5. 下载完成后,根据提示重启 vsCode

4.2.6 vsCode 中连接远程 Docker

  1. 打开 vsCode
  2. 点击首选项->设置
  3. 在搜索框中输入docker:host
  4. 在搜索结果 Docker: Host 下面的文本框中输入tcp://DockerHost:2375/,此处的 DockerHost 就是对应上面准备工作中配置的 hosts 文件
  5. 在搜索框中输入docker:tls
  6. 在搜索结果 Docker: Tls Verify 下面的文本框中输入1
  7. 保存设置

4.2.7 vsCode 中连接远程 DockerHub

  1. 打开 vsCode
  2. 点击左侧栏中的Docker插件
  3. 点击Connect Registry...
  4. 在顶部弹出的框中选择Docker Hub
  5. 输入Docker Hub用户名,回车
  6. 输入Docker Hub密码,回车
  7. 连接成功

5. 后端


5.1 搭建

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

需要注意的地方如下

5.2 配置文件

# 端口
server.port=8080

# 数据源
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 服务编排时会用代码主动做处理,这时一套配置文件就足够了。

5.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 操作。
  • 显示当前时间,主要是处理了容器时区问题。

5.4 Dockerfile

FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG JAR_FILE
ADD ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
  • 注意此文件的路径为 :src/main/docker/
  • 此文件是构建 Docker 镜像的核心文件
  • FROM openjdk:8-jdk-alpine:基础镜像环境 JDK1.8
  • VOLUME /tmp:指定了挂载目录
  • ARG JAR_FILE:与工程中配置的 buildArgs 对应,动态获取打包后的名称
  • ADD ${JAR_FILE} app.jar:把生成的 jar 包拷贝到 Docker 容器中并命名为 app.jar
  • 最后一行是修改 Tomcat 随机数生成方式,加快 Tomcat 启动

5.5 pom.xml 文件

5.5.1 service

代码片段

<!-- 在 properties 下声明相应的版本信息,然后在 dependency 下引用的时候用 ${spring-version} 就可以引入该版本 jar 包了 -->
    <properties>
        <!-- 编码 -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <!-- jdk -->
        <java.version>1.8</java.version>

        <!-- 上传镜像 -->
        <!-- 远程仓库用户名 -->
        <docker.image.prefix>intomylife</docker.image.prefix>
        <!-- 远程 docker 服务地址 -->
        <docker.host>https://DockerHost:2375/</docker.host>
        <!-- 指定 docker hub 仓库地址,用户名密码配置在 settings.xml 文件中 -->
        <settings.docker.id>docker-hub</settings.docker.id>
        <docker.registry.url>https://index.docker.io/v1/</docker.registry.url>
    </properties>
  • 配置的 <docker.host> 节点中的 DockerHost 对应上面准备工作中配置的 hosts 文件
  • 如果你只开启了TCP没有TLS加密,那么此处https更改为http;即加密时配置:https://DockerHost:2375/,未加密时配置:http://DockerHost:2375/

5.5.2 service-core

代码片段

<!-- 插件依赖 -->
    <build>
        <!-- 打包插件 -->
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

            <!-- Docker 插件 -->
            <plugin>
                <!-- 三坐标 -->
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>1.1.1</version>
                <!-- 绑定插件执行动作 -->
                <executions>
                    <!-- mav package = mav package + docker:build + docker:push -->
                    <execution>
                        <id>build-image</id>
                        <phase>package</phase>
                        <goals>
                            <goal>build</goal>
                            <goal>push</goal>
                        </goals>
                    </execution>
                </executions>
                <!-- 配置信息 -->
                <configuration>
                    <!-- 远程 docker 服务地址 -->
                    <dockerHost>${docker.host}</dockerHost>
                    <!-- 指定 docker hub 仓库地址,用户名密码配置在 settings.xml 文件中 -->
                    <serverId>${settings.docker.id}</serverId>
                    <registryUrl>${docker.registry.url}</registryUrl>
                    <!-- 镜像名称 -->
                    <imageName>${docker.image.prefix}/${docker.image.name}:${project.version}</imageName>
                    <!-- Dockerfile 文件的位置 -->
                    <dockerDirectory>src/main/docker</dockerDirectory>
                    <!-- 文件资源 -->
                    <resources>
                        <resource>
                            <targetPath>/</targetPath>
                            <directory>${project.build.directory}</directory>
                            <include>${project.build.finalName}.jar</include>
                        </resource>
                    </resources>
                    <!-- 打包后的名称 -->
                    <buildArgs>
                        <JAR_FILE>${project.build.finalName}.jar</JAR_FILE>
                    </buildArgs>
                </configuration>
            </plugin>
        </plugins>
    </build>
  • 配置的 <execution> 节点中的内容是快速部署的关键

6. 前端


6.1 搭建

  1. 打开终端
  2. 输入命令vue如果不存在则输入命令sudo npm install -g vue-cli全局安装 vue-cli
  3. 进入到项目预存放目录
  4. 输入命令vue init webpack projectName在当前目录创建一个基于 webpack 的项目
  5. 接下来就是填写一些关于项目的信息就创建完毕
  6. 输入命令cd projectName进入项目目录
  7. 输入命令npm install安装依赖

需要注意的地方如下

6.2 config/index.js 文件

代码片段

    // Paths
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    proxyTable: {
      '/api' : {
        // target: 'https://xxx.com',
        target: 'http://127.0.0.1:8080',
        changeOrigin: true,
        pathRewrite: {
            '^/api': ''  // api 开头的接口都使用此代理,如果添加了此行代码,那么意思就是在接口中去掉 api
        },
      }
    },
  • 配置 proxyTable 解决了开发时跨域问题

6.3 utils/request.js 文件

代码片段

// create an axios instance
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API, // api 的 base_url
  // baseURL: "http://xxx", // api 的 base_url
  timeout: 5000 // request timeout
})
  • process.env.VUE_APP_BASE_API 读取环境变量,拼接到请求 url 中
  • VUE_APP_BASE_API 分别在 config/dev.env.js 和 config/prod.env.js 文件中配置,配置的值为/api,也就是上面 config/index.js 中配置的会被拦截的请求前缀

6.4 Dockerfile

FROM node:lts-alpine
# 如果你在国内,这行配置很有必要,不然打包会非常非常慢
RUN npm config set registry https://registry.npm.taobao.org
# install simple http server for serving static content
##RUN npm install -g http-server

# make the 'app' folder the current working directory
WORKDIR /app

# copy both 'package.json' and 'package-lock.json' (if available)
COPY package*.json ./

# install project dependencies
RUN npm install

# copy project files and folders to the current working directory (i.e. 'app' folder)
COPY . /app

# build app for production with minification
##RUN npm run build

# expose port
##EXPOSE 9527

# 加入端口自定义配置,避免与其他K8S容器端口冲突
##CMD [ "http-server","-p","9527", "dist" ]

# 容器启动后执行的命令
CMD [ "npm", "run", "build" ]

  • FROM node:lts-alpine:基础镜像环境 node
  • 设置国内镜像,拷贝依赖信息文件,安装依赖
  • 此时的 Docker 镜像,是 Vue 未打包成静态文件的前端代码;这点很重要,因为在启动 Docker 镜像时,需要把 Vue 打包后的静态文件映射出来,这时的流程就是 启动->映射->Vue 打包;否则如果先生成 Vue 打包后的静态文件,再启动->映射的话,容器中生成的静态文件就会被宿主机的空文件夹给覆盖掉

7. docker-compose.yaml


7.1 文件说明

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

7.2 version

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

7.3 services

version: '3'
 
services:
 
    service_redis:
        ...
    
    service_mysql:
        ...
    
    service_springboot:
        ...
        
    service_vue:
    	...
    	
    service_nginx:
        ...
  • 包含此工程中所有的服务列表。
  • 服务可以是已存在的镜像(本地或远程),也可以是构建出来的镜像;如果其中有需要构建的镜像,则需要一个 Dockerfile 文件。

7.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 配置文件中修改了如下几点

  1. daemonize no:前台启动,在 Docker 中后台启动 Redis 容器会报错
  2. requirepass 123456789:设置密码
  3. # bind 127.0.0.1:注释掉了,使外网可访问

7.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

7.6 service_springboot

    service_springboot:
        container_name: container_springboot
        image: intomylife/docker-compose-service:1.0
        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:服务名称,可自定义。
  • container_name:容器名称,可自定义;也可不写,那会自动生成,生成规则为 【docker-compose.yaml 文件的父目录名称 + _ + 服务名称 + 从一开始的数字】。
  • image:指定镜像来启动容器。此处指定为自己上传的后端镜像,版本为 1.0。
  • 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,表示如果容器启动失败,会一直尝试重连。

7.7 service_vue

    service_vue:
        container_name: container_vue
        image: intomylife/docker-compose-front:1.0
        environment:
            - TZ=Asia/Shanghai
        volumes:
            - ./data/nginx/:/app/dist/

Vue 服务描述:

  • service_vue:服务名称,可自定义。
  • container_name:容器名称,可自定义;也可不写,那会自动生成,生成规则为 【docker-compose.yaml 文件的父目录名称 + _ + 服务名称 + 从一开始的数字】。
  • image:指定镜像来启动容器。此处指定为自己上传的前端镜像,版本为 1.0。
  • environment:为启动的容器添加环境变量。此处配置了容器的时区。
  • volumes:配置映射,映射规则为 宿主机:容器,可以映射文件或目录。此处就是把 Vue 打包后的静态文件映射出来。

注:此服务的作用就是把 Vue 打包成静态页面,映射到宿主机目录;此服务在打包结束后就会自动停止。

7.8 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_vue
            - 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,表示如果容器启动失败,会一直尝试重连。

注:

  1. volumes 映射的数据目录./data/nginx/,就是 service_vue 服务从容器中映射出来的 Vue 打包后的静态文件,container_vue 容器 映射到 宿主机,宿主机 映射到 container_nginx 容器,所以这里还需要在 depends_on 中配置 service_vue 服务等待 Vue 打包结束。这样,启动时静态文件就会直接被映射到 Nginx 的访问目录中。

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

... 省略部分 ...

    # 负载均衡
    upstream dispense {
    ##    server docker-compose-rapid-deployment_service_springboot_1:8080 weight=1;
    ##    server docker-compose-rapid-deployment_service_springboot_2:8080 weight=2;
        server container_springboot:8080;
    }

... 省略部分 ...

        # 代理静态页面
        location / {
            root /usr/share/nginx/html;
            index  index.html index.htm;
        }

        # 代理接口地址
        location ^~ /api {
            proxy_pass http://dispense/;
		}
  • 直接访问 Nginx,就会访问到 Vue 打包后的静态文件,也就是前端页面
  • /api开头的请求会被转发到 SpringBoot 服务,也就是后端接口;这里也解决了发布后跨域问题
  • /api与 Vue 中 config/prod.env.js 文件配置的 VUE_APP_BASE_API 对应

8. 使用我的镜像部署发布


8.1 拷贝项目

  1. 文件具体在 build 目录,可直接下载
  2. 把 build 目录拷贝到服务器上
  3. 进入目录
[root@zwc docker-compose-rapid-deployment]# ls -all
total 24
drwxrwxr-x 5 root root 4096 Nov 14 15:44 .
drwxr-xr-x 9 root root 4096 Nov 25 13:40 ..
drwxrwxr-x 5 root root 4096 Nov 14 15:44 config
drwxrwxr-x 6 root root 4096 Nov 14 15:44 data
-rw-rw-r-- 1 root root 2246 Nov 14 15:44 docker-compose.yaml
drwxrwxrwx 5 root root 4096 Nov 14 15:44 log
  1. 日志目录需要赋值权限:chmod -R 777 log/
  2. 自动生成证书脚本需要执行权限:chmod +x generateCACertificate.sh

注:generateCACertificate.sh 文件是在准备工作中用到的,保存在build目录中只是做个备份,跟后面部署发布没有任何关系;所以在查看目录时没有粘贴出来。

8.2 启动


---

1. 启动 Docker

---

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

---

2. 使用 tree 命令查看当前目录结构树

---

[root@zwc docker-compose-rapid-deployment]# tree
.
├── config
│   ├── mysql
│   │   └── my.cnf
│   ├── nginx
│   │   └── nginx.conf
│   └── redis
│       └── redis.conf
├── data
│   ├── init
│   │   └── init.sql
│   ├── mysql
│   ├── nginx
│   └── redis
├── docker-compose.yaml
└── log
    ├── mysql
    ├── nginx
    └── redis

13 directories, 5 files

---

3. 使用 docker-compose up -d 命令后台启动

---

[root@zwc docker-compose-rapid-deployment]# docker-compose up -d
Creating network "docker-compose-rapid-deployment_default" with the default driver
Creating container_redis ... done
Creating container_mysql ... done
Creating container_vue   ... done
Creating container_springboot ... done
Creating container_nginx      ... done

---

4. 使用 docker ps -a 命令查看容器启动情况,都在正常启动中

---

[root@zwc docker-compose-rapid-deployment]# docker ps -a
CONTAINER ID        IMAGE                                   COMMAND                  CREATED             STATUS              PORTS                                     NAMES
6682af002b4a        nginx:1.8                               "nginx -g 'daemon of…"   36 seconds ago      Up 33 seconds       80/tcp, 443/tcp, 0.0.0.0:8000->8000/tcp   container_nginx
2c9568cc5f46        intomylife/docker-compose-service:1.0   "java -Djava.securit…"   37 seconds ago      Up 36 seconds       8080/tcp                                  container_springboot
7371e815f820        mysql:5.7                               "docker-entrypoint.s…"   39 seconds ago      Up 37 seconds       0.0.0.0:3306->3306/tcp, 33060/tcp         container_mysql
0ea3609afea8        redis:4.0.14                            "docker-entrypoint.s…"   39 seconds ago      Up 37 seconds       0.0.0.0:6379->6379/tcp                    container_redis
901ec5e4dc2e        intomylife/docker-compose-front:1.0     "docker-entrypoint.s…"   40 seconds ago      Up 37 seconds                                                 container_vue

---

5. 等待一分钟左右,再次使用 docker ps -a 命令查看容器启动情况,发现 container_vue 容器已经自动停止了,也就是正如上面所说,此服务的作用就是把 Vue 打包成静态页面,映射到宿主机目录;此服务在打包结束后就会自动停止。

---

[root@zwc docker-compose-rapid-deployment]# docker ps -a
CONTAINER ID        IMAGE                                   COMMAND                  CREATED             STATUS                          PORTS                                     NAMES
6682af002b4a        nginx:1.8                               "nginx -g 'daemon of…"   2 minutes ago       Up About a minute               80/tcp, 443/tcp, 0.0.0.0:8000->8000/tcp   container_nginx
2c9568cc5f46        intomylife/docker-compose-service:1.0   "java -Djava.securit…"   2 minutes ago       Up 2 minutes                    8080/tcp                                  container_springboot
7371e815f820        mysql:5.7                               "docker-entrypoint.s…"   2 minutes ago       Up 2 minutes                    0.0.0.0:3306->3306/tcp, 33060/tcp         container_mysql
0ea3609afea8        redis:4.0.14                            "docker-entrypoint.s…"   2 minutes ago       Up 2 minutes                    0.0.0.0:6379->6379/tcp                    container_redis
901ec5e4dc2e        intomylife/docker-compose-front:1.0     "docker-entrypoint.s…"   2 minutes ago       Exited (0) About a minute ago                                             container_vue

---

6. 使用 docker-compose logs service_name 命令查看容器启动日志,这里查看的是 container_vue 容器的日志,跟期望一样,是记录的 Vue 打包过程。

---

[root@zwc docker-compose-rapid-deployment]# docker-compose logs service_vue
Attaching to container_vue
container_vue         | 
container_vue         | > docker-compose-front@1.0.0 build /app
container_vue         | > node build/build.js
container_vue         | 
container_vue         | Hash: 50a22d73abcb0aec1ca2
container_vue         | Version: webpack 3.12.0
container_vue         | Time: 31700ms
container_vue         |                                                   Asset       Size  Chunks             Chunk Names
container_vue         |                static/js/vendor.a99313ee7ba8dc25e131.js     154 kB       0  [emitted]  vendor
container_vue         |                   static/js/app.fc7a4bfccef2ff584b23.js    10.7 kB       1  [emitted]  app
container_vue         |              static/js/manifest.3ad1d5771e9b13dbdad2.js  858 bytes       2  [emitted]  manifest
container_vue         |     static/css/app.d2400a32d2511dba922aebae4b8a11bb.css  432 bytes       1  [emitted]  app
container_vue         | static/css/app.d2400a32d2511dba922aebae4b8a11bb.css.map  797 bytes          [emitted]  
container_vue         |            static/js/vendor.a99313ee7ba8dc25e131.js.map     766 kB       0  [emitted]  vendor
container_vue         |               static/js/app.fc7a4bfccef2ff584b23.js.map    20.5 kB       1  [emitted]  app
container_vue         |          static/js/manifest.3ad1d5771e9b13dbdad2.js.map    4.97 kB       2  [emitted]  manifest
container_vue         |                                              index.html  526 bytes          [emitted]  
container_vue         | 
container_vue         |   Build complete.
container_vue         | 
container_vue         |   Tip: built files are meant to be served over an HTTP server.
container_vue         |   Opening index.html over file:// won't work.
container_vue         | 

---

7. 这时,再使用 tree 命令查看目录结构树,发现 Vue 打包后的静态文件成功被映射出来

---

[root@zwc docker-compose-rapid-deployment]# tree
.
├── config
│   ├── mysql
│   │   └── my.cnf
│   ├── nginx
│   │   └── nginx.conf
│   └── redis
│       └── redis.conf
├── data
│   ├── init
│   │   └── init.sql
│   ├── mysql
│   │   ├── auto.cnf
│   │   ├── base_db
│   │   │   ├── base_table.frm
│   │   │   ├── base_table.ibd
│   │   │   └── db.opt
...省略部分...
│   ├── nginx
│   │   ├── index.html
│   │   └── static
│   │       ├── css
│   │       │   ├── app.d2400a32d2511dba922aebae4b8a11bb.css
│   │       │   └── app.d2400a32d2511dba922aebae4b8a11bb.css.map
│   │       └── js
│   │           ├── app.fc7a4bfccef2ff584b23.js
│   │           ├── app.fc7a4bfccef2ff584b23.js.map
│   │           ├── manifest.3ad1d5771e9b13dbdad2.js
│   │           ├── manifest.3ad1d5771e9b13dbdad2.js.map
│   │           ├── vendor.a99313ee7ba8dc25e131.js
│   │           └── vendor.a99313ee7ba8dc25e131.js.map
│   └── redis
├── docker-compose.yaml
└── log
    ├── mysql
    │   ├── binlog.000001
    │   ├── binlog.000002
    │   ├── binlog.000003
    │   └── binlog.index
    ├── nginx
    │   ├── access.log
    │   └── error.log
    └── redis
        └── redis.log

20 directories, 307 files

8.3 访问

8.3.1 浏览器中访问 Nginx 容器

在浏览器中输入服务器 ip:8000,可看到ip:172.22.0.5 / count:1 / time:2019-11-26 20:46:30信息。
如果多次访问,可以发现:

  1. count 数会一直累计
  2. time 为当前时间

8.3.2 Navicat 连接 MySQL 容器

在 Navicat 中新建 MySQL 连接:

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

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

8.3.3 rdm 连接 Redis 容器

在 rdm 中新建连接:

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

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

8.3.4 注意

到现在,还没有结束。

前面的部署是直接使用我上传的 build 目录,镜像使用我上传到 DockerHub 的镜像,来完成部署;接下来,就得你自己在本地使用开发工具打开 GitHub 上的源码进行。

不过,在后端项目中有个地方,要做更改,就是远程仓库用户名,位置在 docker-compose-service 的 pom.xml 中,原代码片段如下

        <!-- 上传镜像 -->
        <!-- 远程仓库用户名 -->
        <docker.image.prefix>intomylife</docker.image.prefix>

也就仅仅此处需要更改,因为:

  1. DockerHub 远程库的用户名和密码已经在准备工作中配置到 Maven 的settings.xml文件中了
  2. 远程服务器的地址已经在准备工作中配置到 hosts 文件中了

9. 使用你自己的镜像部署发布


9.1 后端

9.1.1 把多工程项目使用 IntelliJ IDEA 打开

  1. 把项目源码从 GitHub 中下载到你的本地
  2. 打开 IntelliJ IDEA
  3. 点击 File -> Open
  4. 打开你下载到本地的项目目录
  5. docker-compose-rapid-deployment -> docker-compose-service(选择打开此目录)
  6. 打开 service 工程后
  7. 再次点击 File -> Project Structrue
  8. 选择 Modules,点击 ‘+’ 符号
  9. 点击 Import Module
  10. 还是打开你下载到本地的项目目录
  11. docker-compose-rapid-deployment -> docker-compose-commons -> pom.xml
  12. 点击 OK
  13. 点击 Next,Finish
  14. 点击 Apply,OK

9.1.2 部署

  1. 点击idea右侧Maven Projects
  2. 双击docker-compose-commons
  3. 双击Lifecycle
  4. 双击install
  5. 双击docker-compose-service-core
  6. 双击Lifecycle
  7. 双击package
  8. 等待控制台出现如下信息就证明成功把镜像推送到了服务器
Successfully built b9061dc27027
Successfully tagged $YOURNAME/docker-compose-service:1.0
  1. 到服务器中,查看镜像,发现了刚刚新推送的后端镜像
[root@zwc ~]# docker images
REPOSITORY                                            TAG                 IMAGE ID            CREATED             SIZE
intomylife/docker-compose-service                     1.0                 b9061dc27027        9 minutes ago       141MB

9.2 前端

9.2.1 把前端项目使用 Visual Studio Code 打开

  1. 把项目源码从 GitHub 中下载到你的本地
  2. 打开 Visual Studio Code
  3. 点击 文件 -> 打开
  4. 打开你下载到本地的项目目录
  5. docker-compose-rapid-deployment -> docker-compose-front(选择打开此目录)

9.2.2 部署

  1. 点击vsCode左侧资源管理器
  2. 找到Dockerfile右键,点击Build Image
  3. 顶部会弹一个框出来,填写镜像名称和版本信息,如intomylife/docker-compose-front:1.0
  4. 回车
  5. 等待控制台出现如下信息就证明成功把镜像推送到了服务器
Successfully built 5ecd85499f17
Successfully tagged intomylife/docker-compose-front:1.0
  1. 到服务器中,查看镜像,发现了刚刚新推送的前端镜像
[root@zwc ~]# docker images
REPOSITORY                                            TAG                 IMAGE ID            CREATED             SIZE
intomylife/docker-compose-front                       1.0                 5ecd85499f17        15 minutes ago      254MB

9.3 修改 docker-compose.yaml 文件

需要把service_springboot服务和service_vue服务的镜像指定成你刚刚推送的镜像名称。

9.4 启动及访问

与上面使用我的镜像部署时启动及访问一致,就不再赘述。


10. 快速部署


10.1 后端中更改部分输出内容

            // 返回数量
            return "!!!ip:" + InetAddress.getLocalHost().getHostAddress() + " / count:" + String.valueOf(resultCount) + " / time:" + sdf.format(new Date());

加了三个感叹号

10.2 部署后端

  1. 点击idea右侧Maven Projects
  2. 双击docker-compose-service-core
  3. 双击Lifecycle
  4. 双击package
  5. 等待控制台出现如下信息就证明成功把镜像推送到了服务器
Successfully built 245ee3d4db9c
Successfully tagged intomylife/docker-compose-service:1.0
  1. 到服务器中,查看镜像,发现了刚刚新推送的镜像,并且还发现了有一个<none>的镜像,其实它就是现在正在启动中的 container_springboot 容器的镜像
  2. 查看正在运行的镜像,发现 container_springboot 容器的镜像名称变成了镜像 ID,而这个镜像 ID 和上面<none>的镜像 ID 一样

11. 快速发布


11.1 发布


---

1. 还是在上面启动的目录,使用 docker-compose up -d 命令后台启动,发现只是重启了更改过的容器和更改过的容器的关联容器

---

[root@zwc docker-compose-rapid-deployment]# docker-compose up -d
container_redis is up-to-date
container_mysql is up-to-date
Starting container_vue          ... done
Recreating container_springboot ... done
Recreating container_nginx      ... done

11.2 访问

在浏览器中输入服务器 ip:8000,可看到ip:172.22.0.5 / count:1 / time:2019-11-26 20:46:30信息变成了!!!ip:172.22.0.2 / count:8 / time:2019-11-26 21:32:20,刚刚添加的三个感叹号成功生效。


12. 遗留问题


当服务器TLS加密后,vsCode 中的 Docker 插件就一直报错证书有问题,不显示服务器上的镜像;如果在 vsCode 的设置中去掉Docker: Host配置,是可以正常显示本地的镜像列表;或者是服务器不加密,在 vsCode 中的设置添加Docker: Host配置,去掉Docker: Tls Verify配置,也是能够正常显示服务器的镜像列表。
但是即使加密后,不显示服务器的镜像列表,还是可以正常推送镜像到服务器中的。
这个问题断断续续用了两周找原因,最终还是没找到解决办法…虽然对本篇博客的部署来说,没有太大影响,但是也是够闹心的。


13. 结语


这篇博客我从准备到写完,大概快一个月了,中间也遇到了各种各样的问题,从中也学到了不少东西。阿,快乐。


希望能够帮助到你

over




评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值