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
端口被攻擊;加密或不加密對於代碼的改動量非常小,更多的只是配置操作。
- 首先使用如下
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 "===================== 結束 ====================="
- 接下來在步驟
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 拷貝服務器生成的證書
- 在服務器的
/root/ca/my
目錄中,拷貝ca.pem
、cert.pem
以及key.pem
文件 - 拷貝到本地
Docker
的安裝目錄中,如我的是/Users/zouwencong/.docker
目錄
4.2.3 配置 hosts 文件
- 打開終端,輸入
sudo vim /private/etc/hosts
- 輸入密碼
- 寫入內容
xx.xxx.xxx.xxx DockerHost
,xx.xxx.xxx.xxx 就是安裝了 Docker 的服務器地址 - 保存退出
4.2.4 配置 settings.xml 文件
- 找到 Maven 目錄中的
settings.xml
文件 - 找到
<servers></servers>
節點,配置如下子節點
<server>
<id>docker-hub</id>
<username>your username</username>
<password>your password</password>
<configuration>
<email>your email</email>
</configuration>
</server>
- 保存退出
4.2.5 vsCode 中安裝 Docker 插件
- 打開 vsCode
- 點擊左側欄中的組件入口
- 輸入
Docker
進行搜索 - 選擇第一個,點擊
Install
- 下載完成後,根據提示重啓 vsCode
4.2.6 vsCode 中連接遠程 Docker
- 打開 vsCode
- 點擊
首選項
->設置
- 在搜索框中輸入
docker:host
- 在搜索結果 Docker: Host 下面的文本框中輸入
tcp://DockerHost:2375/
,此處的 DockerHost 就是對應上面準備工作中配置的 hosts 文件 - 在搜索框中輸入
docker:tls
- 在搜索結果 Docker: Tls Verify 下面的文本框中輸入
1
- 保存設置
4.2.7 vsCode 中連接遠程 DockerHub
- 打開 vsCode
- 點擊左側欄中的
Docker
插件 - 點擊
Connect Registry...
- 在頂部彈出的框中選擇
Docker Hub
- 輸入
Docker Hub
用戶名,回車 - 輸入
Docker Hub
密碼,回車 - 連接成功
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 搭建
- 打開終端
- 輸入命令
vue
如果不存在則輸入命令sudo npm install -g vue-cli
全局安裝 vue-cli - 進入到項目預存放目錄
- 輸入命令
vue init webpack projectName
在當前目錄創建一個基於 webpack 的項目 - 接下來就是填寫一些關於項目的信息就創建完畢
- 輸入命令
cd projectName
進入項目目錄 - 輸入命令
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 配置文件中修改瞭如下幾點
- daemonize no:前臺啓動,在 Docker 中後臺啓動 Redis 容器會報錯
- requirepass 123456789:設置密碼
- # 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,表示如果容器啓動失敗,會一直嘗試重連。
注:
-
volumes 映射的數據目錄
./data/nginx/
,就是 service_vue 服務從容器中映射出來的 Vue 打包後的靜態文件,container_vue 容器 映射到 宿主機,宿主機 映射到 container_nginx 容器,所以這裏還需要在 depends_on 中配置 service_vue 服務等待 Vue 打包結束。這樣,啓動時靜態文件就會直接被映射到 Nginx 的訪問目錄中。 -
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 拷貝項目
- 文件具體在 build 目錄,可直接下載
- 把 build 目錄拷貝到服務器上
- 進入目錄
[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
- 日誌目錄需要賦值權限:chmod -R 777 log/
- 自動生成證書腳本需要執行權限: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
信息。
如果多次訪問,可以發現:
- count 數會一直累計
- 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>
也就僅僅此處需要更改,因爲:
- DockerHub 遠程庫的用戶名和密碼已經在準備工作中配置到 Maven 的
settings.xml
文件中了 - 遠程服務器的地址已經在準備工作中配置到 hosts 文件中了
9. 使用你自己的鏡像部署發佈
9.1 後端
9.1.1 把多工程項目使用 IntelliJ IDEA 打開
- 把項目源碼從 GitHub 中下載到你的本地
- 打開 IntelliJ IDEA
- 點擊 File -> Open
- 打開你下載到本地的項目目錄
- docker-compose-rapid-deployment -> docker-compose-service(選擇打開此目錄)
- 打開 service 工程後
- 再次點擊 File -> Project Structrue
- 選擇 Modules,點擊 ‘+’ 符號
- 點擊 Import Module
- 還是打開你下載到本地的項目目錄
- docker-compose-rapid-deployment -> docker-compose-commons -> pom.xml
- 點擊 OK
- 點擊 Next,Finish
- 點擊 Apply,OK
9.1.2 部署
- 點擊
idea
右側Maven Projects
- 雙擊
docker-compose-commons
- 雙擊
Lifecycle
- 雙擊
install
- 雙擊
docker-compose-service-core
- 雙擊
Lifecycle
- 雙擊
package
- 等待控制檯出現如下信息就證明成功把鏡像推送到了服務器
Successfully built b9061dc27027
Successfully tagged $YOURNAME/docker-compose-service:1.0
- 到服務器中,查看鏡像,發現了剛剛新推送的後端鏡像
[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 打開
- 把項目源碼從 GitHub 中下載到你的本地
- 打開 Visual Studio Code
- 點擊 文件 -> 打開
- 打開你下載到本地的項目目錄
- docker-compose-rapid-deployment -> docker-compose-front(選擇打開此目錄)
9.2.2 部署
- 點擊
vsCode
左側資源管理器
- 找到
Dockerfile
右鍵,點擊Build Image
- 頂部會彈一個框出來,填寫鏡像名稱和版本信息,如
intomylife/docker-compose-front:1.0
- 回車
- 等待控制檯出現如下信息就證明成功把鏡像推送到了服務器
Successfully built 5ecd85499f17
Successfully tagged intomylife/docker-compose-front:1.0
- 到服務器中,查看鏡像,發現了剛剛新推送的前端鏡像
[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 部署後端
- 點擊
idea
右側Maven Projects
- 雙擊
docker-compose-service-core
- 雙擊
Lifecycle
- 雙擊
package
- 等待控制檯出現如下信息就證明成功把鏡像推送到了服務器
Successfully built 245ee3d4db9c
Successfully tagged intomylife/docker-compose-service:1.0
- 到服務器中,查看鏡像,發現了剛剛新推送的鏡像,並且還發現了有一個
<none>
的鏡像,其實它就是現在正在啓動中的 container_springboot 容器的鏡像 - 查看正在運行的鏡像,發現 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