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         | > [email protected] 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




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章