Docker深入淺出系列 | Swarm多節點實戰
阿新 • • 發佈:2020-03-17
[TOC]
> Docker已經上市很多年,不是什麼新鮮事物了,很多企業或者開發同學以前也不多不少有所接觸,但是有實操經驗的人不多,本系列教程主要偏重實戰,儘量講乾貨,會根據本人理解去做闡述,具體官方概念可以查閱官方教程,因為本系列教程對前一章節有一定依賴,建議先學習前面章節內容。
本系列教程導航:
[Docker深入淺出系列 | 容器初體驗](https://www.cnblogs.com/evan-liang/p/12237400.html)
[Docker深入淺出系列 | Image實戰演練](https://www.cnblogs.com/evan-liang/p/12244304.html)
[Docker深入淺出系列 | 單節點多容器網路通訊](https://www.cnblogs.com/evan-liang/p/12271468.html)
[Docker深入淺出系列 | 容器資料持久化](https://www.cnblogs.com/evan-liang/p/12372371.html)
[Docker深入淺出系列 | 單機Nginx+Springboot實戰](https:////www.cnblogs.com/evan-liang/p/12390315.html)
[Docker深入淺出系列 | Docker Compose多容器實戰](https:////www.cnblogs.com/evan-liang/p/12390315.html)
教程目的:
- 瞭解docker swarm是什麼&為什麼要用
- 瞭解docker swarm網路模型
- 瞭解在swarm模型的核心實現機制
- 瞭解如何通過docker compose 檔案定義和管理服務
- 瞭解如何利用docker compose 檔案去建立服務
- 瞭解docker stack的基本命令
- 瞭解docker service的基本命令
- 掌握docker swarm在實戰應用
***
# **前期準備**
1.克隆```credit-facility-service```作為後面部署演示使用,使用```docker```分支
```bash
git clone https://github.com/EvanLeung08/credit-facility-service.git
```
2.虛擬機器、centos和docker環境安裝請檢視第一章,本章預設已經安裝好centos和docker
[Docker深入淺出系列 | 容器初體驗](https://www.cnblogs.com/evan-liang/p/12237400.html)
***
# **Swarm基本概念**
## **什麼是Docker Swarm**
![](https://img-blog.csdnimg.cn/2020031520595955.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0V2YW5fTGV1bmc=,size_16,color_FFFFFF,t_70)
簡單來說,Docker Swarm就是一個把多個物理主機或者虛擬機器組成的叢集上的容器群進行管理的容器編排工具,負責編排、排程和叢集管理,由叢集的活動由叢集管理器控制,加入叢集的機器稱為節點,允許使用者管理跨多個主機部署的多個容器。
SwarmKit是可擴充套件分散式系統的節點發現、基於Raft的共識、任務排程、基於基元的編排工具包,該工具包使用[Raft共識演算法](https://raft.github.io/)來協調和決策分散式系統。
以下列出了Docker Swarm的一些關鍵術語:
- **節點(Node):** 在編排方面,節點是主機。 一個節點可以是單個主機中的多個VM。
- **管理節點(Manager Node):** 此節點負責維護Swarm編排,它管理叢集環境。
- **工作節點(Worker Node):** 該節點負責執行管理節點定義的任務。 它將始終將其狀態通知給Manager節點並提供分配給它的服務。
- **服務(Service):** 這些是在Manager或Worker節點上執行的任務,可以理解成一堆相同的執行任務組成一個服務。
- **任務(Task):** 任務包含一個Docker容器和在容器內執行的命令,它是swarm的原子排程單元,如果某一個任務奔潰,那麼協調器將建立一個新的副本任務,該任務將生成一個新的容器
![](https://img-blog.csdnimg.cn/20200316212916538.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0V2YW5fTGV1bmc=,size_16,color_FFFFFF,t_70)
## **為什麼要用Swarm**
Docker Swarm和k8s都是目前的容器編排的主流技術,但是目前市場上大多數企業都是用k8s進行容器叢集管理,k8s的背靠Google這棵大樹,開源社群也非常活躍,隨著這些年雲廠商的迅速發展,k8s是未來趨勢,我個人建議在真實專案還是使用k8s進行容器編排和管理,不過這裡是docker專場,我暫不多說,會在後面k8s專題去講這一塊內容。
假如沒有Swarm這類多機容器管理技術,我們很難對容器進行管理,並且容器之間沒辦法實現跨機器通訊。而Docker swarm可以讓使用者輕鬆在多個機器上釋出和管理應用,並且我們不需要關注每個容器例項具體落在哪一個節點,swarm把我們的應用以服務的形式暴露出去,並內建服務發現和負載均衡,讓執行在多個節點上的容器叢集感覺就像只有一個應用在跑一樣簡單,可以輕鬆實現擴容和自動容錯(```一個swarm任務的容器奔潰會自動擴充套件一個新的容器```)。Swarm叢集通常有幾個工作程式節點和至少一個管理程式節點,負責高效地處理工作程式節點的資源並確保叢集有效地執行,提高了應用可用性。
![](https://img-blog.csdnimg.cn/20200316104227798.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0V2YW5fTGV1bmc=,size_16,color_FFFFFF,t_70)
***
# **Swarm的網路模型**
![](https://img-blog.csdnimg.cn/20200316171044248.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0V2YW5fTGV1bmc=,size_16,color_FFFFFF,t_70)
以下三個網路概念對於Swarm叢集服務很重要:
- **Overlay** - ```Overlay```網路管理參與叢集的Docker守護程式之間的通訊。您可以使用與獨立容器的使用者定義網路相同的方式建立```Overlay```網路。您也可以將服務附加到一個或多個現有的```Overlay```網路,以啟用服務到服務的通訊。```Overlay```網路是使用```Overlay```網路驅動程式的Docker網路。
- **ingress** - ```ingress```網路是一種特殊的```Overlay```網路,可促進服務節點之間的負載均衡。當任何叢集節點在已釋出的埠上收到請求時,會將請求轉交給名為IPVS的模組。 IPVS通過```ingress```網路跟蹤參與該服務的所有IP地址,選擇其中一個並將請求傳送給它。
當對節點進行```swarm init```或```swarm join```時,會自動建立```ingress```網路。大多數使用者不需要自定義其配置,但是Docker 17.05及更高版本允許您自定義。
- **docker_gwbridge** - ```docker_gwbridge```是一個橋接網路,它將```overlay```網路(包括```ingress```網路)連線到單個Docker守護程式的物理網路。預設情況下,服務正在執行的每個容器都連線到其本地Docker守護程式主機的```docker_gwbridge```網路。
初始化或加入叢集時會自動建立```docker_gwbridge```網路。大多數使用者不需要自定義其配置,但是Docker允許您自定義。
# **Swarm的核心實現機制**
## **服務發現機制**
Docker Engine內有一個嵌入式DNS伺服器,當Docker不以Swarm模式執行時,容器會使用這個伺服器;而當Docker Engine以Swarm模式執行時,該伺服器將用於任務。 它為```bridge```,```Overlay```或```MACVLAN```網路中主機上的所有容器提供名稱解析。 每個容器將其查詢請求轉發到Docker引擎,後者依次檢查該容器或服務是否與首先發送請求的容器在同一網路上。 如果是,它將在其內部鍵值儲存中搜索與容器、任務或服務的名稱匹配的IP(或虛擬IP)地址,並將其返回給傳送請求的容器。
如果匹配的資源與生成請求的容器在同一網路內,則Docker引擎只會返回IP地址。 這樣做的好處還在於,Docker主機僅儲存屬於該節點在其中具有容器或任務的網路的DNS條目。 這意味著它們將不會儲存實際上與他們無關的資訊,或者其他容器不需要知道的資訊。
![](https://img-blog.csdnimg.cn/20200316212237317.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0V2YW5fTGV1bmc=,size_16,color_FFFFFF,t_70)
在上圖中,有一個名為```custom-net```的自定義網路。 網路上執行著兩種服務:myservice和myclient。 myservice有兩個與之關聯的任務,而客戶端只有一個。
客戶端```myclient```然後執行對myservice的curl請求,因此,它也在對DNS進行請求。 容器內建的解析器將查詢轉發到Docker引擎的DNS伺服器。 然後,對myservice的請求將解析為10.0.0.2虛擬IP,轉發回客戶端,客戶端就可以通過虛擬ip去訪問容器。
## **負載均衡機制Routing Mesh**
### **Docker內部請求負載均衡**
建立服務後,Docker將自動啟用此功能。 因此,建立服務後,它會立即在服務的網路上獲得虛擬IP地址。 就像上文在服務發現部分中所說的那樣,當請求服務時,所得到的DNS查詢將轉發到Docker引擎,該引擎進而返回服務的IP,即虛擬IP。 傳送到該虛擬IP的流量將負載均衡到網路上該服務的所有正常執行的容器。 所有負載均衡均由Docker完成,因為只有一個入口點被分配給客戶端(一個IP)。
### **Docker外部請求負載均衡(Ingress)**
預設情況下,不會啟用負載均衡,當在建立或更新時使用```–publish```標誌公開服務時,叢集中的每個節點都會開始偵聽已釋出的埠,這意味著每個節點都可以響應對對映到該埠的服務的請求。
當某個節點接收到一個請求,但該節點沒有容器例項時,會發生什麼? 從Docker 1.12(將Swarm模式整合到Docker Engine的同一版本)開始,就有一個名為```Routing Mesh```的功能,該功能使用IP虛擬伺服器(ipvs)和iptables來負載均衡第4層中的請求。基本上,ipvs實現了第4層 Linux核心上的負載均衡功能,該功能允許將對基於```TCP / UDP```的服務的請求重定向到實際的後端(在這種情況下為容器)。 在Swarm的特定情況下,每個節點都偵聽暴露的埠,然後使用稱為```ingress```的特殊```Overlay```網路將請求轉發到暴露的服務的VIP(虛擬IP)。 僅當將外部流量傳輸到請求的服務時,才使用此```Overlay```網路。 在這種情況,docker會使用與上文描述的相同的內部負載均衡策略。
![](https://img-blog.csdnimg.cn/20200316204621202.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0V2YW5fTGV1bmc=,size_16,color_FFFFFF,t_70)
在上圖中,在appnet ```Overlay```網路上建立了具有兩個副本的服務。 我們可以看到該服務在三個節點上的```8000```埠上公開,此時,發往應用程式的流量可以轉發到任何節點。 假設在這種情況下,有一個外部負載均衡器,它恰好將請求轉發到唯一沒有該服務例項的節點, 該請求由IPVS在第三個節點上處理和轉發,該IPVS使用```ingress```網路並因此使用上述負載均衡方法將其重定向到該服務的叢集上的其中一個真實執行的容器。
![](https://img-blog.csdnimg.cn/20200316211552606.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0V2YW5fTGV1bmc=,size_16,color_FFFFFF,t_70)
## **Swarm模式執行機制**
![](https://img-blog.csdnimg.cn/20200316214646982.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0V2YW5fTGV1bmc=,size_16,color_FFFFFF,t_70)
上圖來自官方,很清晰展示了在swarm模式,manage節點和worker節點是怎麼協作的,這裡就不做細說了。
***
# **專案實戰**
## **實戰目標**
![](https://img-blog.csdnimg.cn/2020031622414695.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0V2YW5fTGV1bmc=,size_16,color_FFFFFF,t_70)
- 建立自定義overlay網路```credit-facility-net```
- 搭建Swarm叢集
- manager-node - 192.168.101.11
- worker01-node - 192.168.101.12
- worker03-node - 192.168.101.13
- 搭建額度服務叢集,三個應用例項
- [額度服務]credit-facility-net:8080
- 搭建Mysql資料庫
- [Mysql服務]db:3306
- 搭建Nginx服務,並配置負載均衡規則
- [Nginx服務]nginx:80
- 建立Volume ```credit-facility-volume```,用於持久化Mysql容器資料
- 利用docker swarm負載均衡和服務發現的特點,docker網路內容器之間通過容器名稱進行通訊
- 通過瀏覽器訪問swagger進行業務操作
因為我機器資源不夠,我這裡只是建立了三臺虛擬機器,manager節點也是可以部署服務的
## **搭建虛擬機器節點**
### **搭建虛擬機器節點**
這裡用到Vagrant來管理虛擬機器,如果不知道Vagrant是什麼,請檢視第一章內容。Vagrant指令可以檢視[Vagrant詳細指令文件](https://www.vagrantup.com/docs/cli/)
1.在我們的主機(你自己的電腦)建立一個資料夾```swarm-centos7```,然後在目錄下建立一個```Vagrantfile```檔案
**Vagrant**
```bash
boxes = [
{
:name => "manager-node",
:eth1 => "192.168.101.11",
:mem => "1024",
:cpu => "1"
},
{
:name => "worker01-node",
:eth1 => "192.168.101.12",
:mem => "1024",
:cpu => "1"
},
{
:name => "worker02-node",
:eth1 => "192.168.101.13",
:mem => "1024",
:cpu => "1"
}
]
Vagrant.configure(2) do |config|
config.vm.box = "centos7"
boxes.each do |opts|
config.vm.define opts[:name] do |config|
config.vm.hostname = opts[:name]
config.vm.provider "vmware_fusion" do |v|
v.vmx["memsize"] = opts[:mem]
v.vmx["numvcpus"] = opts[:cpu]
end
config.vm.provider "virtualbox" do |v|
v.customize ["modifyvm", :id, "--memory", opts[:mem]]
v.customize ["modifyvm", :id, "--cpus", opts[:cpu]]
v.customize ["modifyvm", :id, "--name", opts[:name]]
end
config.vm.network :public_network, ip: opts[:eth1]
end
end
end
```
這裡指定了三臺虛擬機器的配置,並且分別分配了一個靜態ip ```192.168.101.11```、```192.168.101.12```和```192.168.101.13```,並且迴圈建立虛擬機器。這裡指定了```docker swarm```最低要求配置1個CPU、1G記憶體。
2.啟動三臺虛擬機器,記得在啟動過程選擇你可用的網絡卡
```bash
evans-MacBook-Pro:swarm-centos7 evan$ vagrant up
```
當該命令執行完畢,會有三臺虛擬機器成功被初始化
### **初始化虛擬機器密碼**
因為後面需要用到ssh客戶端工具,所以這裡要把密碼開放下
修改 manager 節點訪問密碼,用於後面上傳檔案使用,這裡的密碼是```evan123```
```bash
[root@manager-node local]# passwd
Changing password for user root.
New password:
BAD PASSWORD: The password fails the dictionary check - it is too simplistic/systematic
Retype new password:
passwd: all authentication tokens updated successfully.
```
這裡只演示了manager節點,另外兩個worker節點也需要做同樣的操作
### **安裝Docker環境**
需要在每個節點安裝Docker,請使用SSH客戶端工具,分別登陸3個虛擬機器,先按以下步驟安裝docker
1.解除安裝之前的docker配置,如有
```bash
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
```
2.安裝伺服器必要的依賴
```bash
sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2
```
3.配置加速器,因為國內下載docker需要越過長城,會比較慢,這裡我用到的是我自己的阿里雲加速器,如果不知道怎麼配置的,請檢視第一章
```bash
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://6xh8u88j.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
```
4.設定Docker倉庫
```bash
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
```
5.安裝Docker
```bash
sudo yum install -y docker-ce docker-ce-cli containerd.io
```
6.安裝完畢後,分別進入manger節點和2個worker節點,啟動docker服務
```bash
[root@manager-node ~]# systemctl start docker
```
7.驗證docker,輸入```docker info```,驗證下docker是否已經安裝成功
***
## **搭建swarm叢集**
### **初始化manager節點**
這裡需要先進入manager節點```192.168.101.11```進行swarm初始化操作,
```bash
[root@manager-node credit-facility]# docker swarm init --advertise-addr=192.168.101.11
Swarm initialized: current node (tdtu8tl63zqim8jrbzf8l5bcn) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-61e18f81408f4ja2yrcn9l11y5x21okcx58d3f6gcptyydb0iz-9hquv710qpx8s4h88oy2fycei 192.168.101.11:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
```
這裡會生成一串token,隨後需要在worker節點使用該命令去加入到swarm叢集中
### **worker節點加入swarm叢集**
這裡我們需要分別進去兩個worker節點```192.168.101.12```和 ```192.168.101.13```執行以下操作
```bash
docker swarm join --token SWMTKN-1-61e18f81408f4ja2yrcn9l11y5x21okcx58d3f6gcptyydb0iz-9hquv710qpx8s4h88oy2fycei 192.168.101.11:2377
```
這裡表示當前節點加入swarm叢集
### **檢視當前節點**
只能在swarm manager節點檢視當前所有節點資訊
```bash
[root@manager-node credit-facility]# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
tdtu8tl63zqim8jrbzf8l5bcn * manager-node Ready Active Leader 19.03.7
n8m358c7ta18206gzey7xsvw8 worker01-node Ready Active 19.03.7
pgzph6ye6xl1p9fz0hif191kn worker02-node Ready Active 19.03.7
```
這裡可以看到,我們的3個節點都已經成功加入到swarm叢集,manager-node是我們的swarm叢集 leader
***
## **搭建專案**
### **建立工作目錄**
跟前一章一樣,在叢集三個節點的```/usr/local```下,分別建一個```credit-facitliy```目錄
```bash
[root@worker01-node local]# mkdir credit-facility
```
### **打包上傳jar**
- 為了讓後面我們更方便動態修改資料庫配置,額度服務的資料庫配置改為動態變數,如下:
```bash
# for docker-stack demo
spring.datasource.url = jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_NAME}?useUnicode=true&characterEncoding=utf8
#spring.datasource.url = jdbc:mysql://192.168.101.23:3301/db_credit_facility?useUnicode=true&characterEncoding=utf8
#配置資料庫使用者名稱
#spring.datasource.username = root
spring.datasource.username = ${DB_USER}
#配置資料庫密碼
#spring.datasource.password = evan123
spring.datasource.password = ${DB_PASSWORD}
```
配置檔案我已經在專案裡提前修改好了,大家直接用即可
- 接下來繼續用maven對專案打包```mvn clean package```,打包後在star目錄下
![](https://img-blog.csdnimg.cn/20200315144713173.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0V2YW5fTGV1bmc=,size_16,color_FFFFFF,t_70)
- 分別上傳專案jar包到manager、worker01、worker02節點
```bash
evans-MacBook-Pro:target evan$ sftp [email protected]
[email protected]'s password:
Connected to [email protected].
sftp> put start-1.0.0-SNAPSHOT.jar /usr/local/credit-facility
Uploading start-1.0.0-SNAPSHOT.jar to /usr/local/credit-facility/start-1.0.0-SNAPSHOT.jar
start-1.0.0-SNAPSHOT.jar 100% 43MB 76.5MB/s 00:00
sftp>
```
```bash
evans-MacBook-Pro:target evan$ sftp [email protected]
[email protected]'s password:
Connected to [email protected].
sftp> put start-1.0.0-SNAPSHOT.jar /usr/local/credit-facility
Uploading start-1.0.0-SNAPSHOT.jar to /usr/local/credit-facility/start-1.0.0-SNAPSHOT.jar
start-1.0.0-SNAPSHOT.jar 100% 43MB 76.5MB/s 00:00
sftp>
```
```bash
evans-MacBook-Pro:target evan$ sftp [email protected]
[email protected]'s password:
Connected to [email protected].
sftp> put start-1.0.0-SNAPSHOT.jar /usr/local/credit-facility
Uploading start-1.0.0-SNAPSHOT.jar to /usr/local/credit-facility/start-1.0.0-SNAPSHOT.jar
start-1.0.0-SNAPSHOT.jar 100% 43MB 76.5MB/s 00:00
sftp>
```
### **建立額度服務Image**
- 分別在三個節點```/usr/local/credit-facility```目錄下,建立Dockerfile
```bash
[root@manager-node credit-facility]# cat Dockerfile
FROM openjdk:8-jre-alpine
MAINTAINER evan
LABEL name="credit-facility" version="1.0" author="evan"
COPY start-1.0.0-SNAPSHOT.jar credit-facility-service.jar
CMD ["java","-jar","credit-facility-service.jar"]
```
該檔案我已經提前放置在額度服務專案裡,直接copy即可
![](https://img-blog.csdnimg.cn/20200315145940984.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0V2YW5fTGV1bmc=,size_16,color_FFFFFF,t_70)
- 分別在三個節點的```/usr/local/credit-facility```目錄下,執行以下命令建立額度服務映象,這裡只演示```manager```節點,其他節點操作一樣
```bash
[root@manager-node credit-facility]# docker build -t credit-facility-image .
Sending build context to Docker daemon 44.92MB
Step 1/5 : FROM openjdk:8-jre-alpine
---> f7a292bbb70c
Step 2/5 : MAINTAINER evan
---> Running in 50b0ae0125ef
Removing intermediate container 50b0ae0125ef
---> b4231d681d22
Step 3/5 : LABEL name="credit-facility" version="1.0" author="evan"
---> Running in 4a6bb0ae9f12
Removing intermediate container 4a6bb0ae9f12
---> ea441d121fc4
Step 4/5 : COPY start-1.0.0-SNAPSHOT.jar credit-facility-service.jar
---> 0bed9d9397f6
Step 5/5 : CMD ["java","-jar","credit-facility-service.jar"]
---> Running in 6bb0c14f1a85
Removing intermediate container 6bb0c14f1a85
---> de2606eea641
Successfully built de2606eea641
Successfully tagged credit-facility-image:latest
```
建立完檢視下每個節點現有的映象列表:
```bash
[root@worker01-node credit-facility]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
credit-facility-image latest 8dcef5954aaa 3 hours ago 130MB
openjdk 8-jre-alpine f7a292bbb70c 10 months ago 84.9MB
```
從上面查詢結果可以看到,我們的額度服務映象已經成功建立
### **建立Nginx配置**
因為我們後面用到```Nginx```服務,所以我們需要提前把配置建立後,然後通過```--mount```方式把配置檔案覆蓋```Nginx```容器內的預設配置
在```/usr/local/credit-facility```資料夾下,建立一個```nginx```目錄,並在```nginx```目錄下建一個```nginx.conf```配置檔案
```bash
[root@manager-node nginx]# cat nginx.conf
user nginx;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
location / {
proxy_pass http://balance;
}
}
upstream balance{
server credit-facility-service:8080;
}
include /etc/nginx/conf.d/*.conf;
}
```
我這裡利用```docker swam```內建DNS原理,我這裡配置域名是額度服務名稱```credit-facility-service```,```docker swarm```會自動幫我們路由到對應的服務節點上
### **建立Compose配置檔案**
- 在manager節點的```/usr/local/credit-facility```資料夾下,建立一個```docker-stack.yml```用於建立和管理服務(注意,這裡只需要manager節點建立即可,manager節點會把```docker service```釋出到到其他節點)
```bash
[root@manager-node credit-facility]# cat docker-stack.yml
version: '3'
services:
db:
restart: always
image: mysql
build:
context: /usr/local/credit-facility
ports:
- 3306:3306/tcp
volumes:
- "credit-facility-volume:/var/lib/mysql:rw"
environment:
- MYSQL_DATABASE=db_credit_facility
- MYSQL_ROOT_PASSWORD=evan123
networks:
- demo-overlay
deploy:
mode: global
placement:
constraints:
- node.role == manager
credit-facility-service:
restart: always
image: credit-facility-image
build:
context: /usr/local/credit-facility
ports:
- 8080:8080
environment:
- DB_HOST=db
- DB_PORT=3306
- DB_USER=root
- DB_PASSWORD=evan123
- DB_NAME=db_credit_facility
networks:
- demo-overlay
deploy:
mode: replicated
replicas: 3
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
update_config:
parallelism: 1
delay: 10s
nginx:
restart: always
depends_on:
- db
- credit-facility-service
image: nginx
ports:
- "80:80"
volumes:
- /usr/local/credit-facility/nginx/nginx.conf:/etc/nginx/nginx.conf
networks:
- demo-overlay
deploy:
mode: global
placement:
constraints:
- node.role == manager
networks:
demo-overlay:
driver: overlay
volumes:
credit-facility-volume: {}
```
### **釋出服務到Docker Swarm**
- 使用```docker stack```去釋出服務,可以將服務釋出到叢集各個節點上(```docker compose```是用於單機部署,多機部署需要用到```docker swarm stack```)
```bash
[root@manager-node credit-facility]# docker stack deploy -c docker-stack.yml web
Ignoring unsupported options: build, restart
Ignoring deprecated options:
container_name: Setting the container name is not supported.
Creating network web_credit-facility-net
Creating service web_nginx
Creating service web_db
Creating service web_credit-facility-service
...
```
- 檢視服務狀態
```bash
[root@manager-node nginx]# docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
3qcjnj7n5dkk web_credit-facility-service replicated 3/3 credit-facility-image:latest *:8080->8080/tcp
t5omqvum57ag web_db global 1/1 mysql:latest *:3306->3306/tcp
w89fkne6fzcg web_nginx global 1/1 nginx:latest *:80->80/tcp
```
從上面結果可以看到,我們釋出的各個服務已經成功啟動,額度服務的3個例項也成功釋出到3個節點中
- 檢視下額度服務每個服務例項落在哪個節點
```bash
[root@manager-node nginx]# docker service ps web_credit-facility-service
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
pc32kfmfxke0 web_credit-facility-service.1 credit-facility-image:latest worker01-node Running Running 23 minutes ago
8v9efe61p5wb web_credit-facility-service.2 credit-facility-image:latest manager-node Running Running 23 minutes ago
sg1wh95lxyca web_credit-facility-service.3 credit-facility-image:latest worker02-node Running Running 23 minutes ago
```
上面結果可以清晰看到,每一個例項被髮布到哪個節點中
### **初始化資料庫配置**
跟前面章節一樣,因為額度服務對資料庫有依賴,所以這裡需要初始化額度服務用到的表,使用Mysql客戶端,連線到資料庫,把專案裡```resources/db```的表建立語句放入執行,我這裡用Navicat去連線,資料庫連線是```192.168.101.11:3306```
![](https://img-blog.csdnimg.cn/20200315185221339.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0V2YW5fTGV1bmc=,size_16,color_FFFFFF,t_70)
![](https://img-blog.csdnimg.cn/20200315185319874.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0V2YW5fTGV1bmc=,size_16,color_FFFFFF,t_70)
### **驗證目錄檔案**
到這裡,所有的配置已經完成了,我們來一起核對下現有的檔案有哪些,看看大家有沒有遺漏的惡配置
在manager節點的```credit-facility```資料夾下,應該有以下檔案
```bash
[root@manager-node credit-facility]# ls
docker-compose.yaml Dockerfile docker-stack.yml nginx start-1.0.0-SNAPSHOT.jar
```
在2個worker節點的```credit-facility```資料夾下,應該有以下檔案
**worker-01節點**
```bash
[root@worker01-node credit-facility]# ls
Dockerfile start-1.0.0-SNAPSHOT.jar
```
**worker-02節點**
```bash
[root@worker02-node credit-facility]# ls
Dockerfile start-1.0.0-SNAPSHOT.jar
```
### **驗證服務**
- **驗證Nginx服務** - 假如Nginx代理規則沒問題,應該輸入```192.168.101.11http://192.168.101.11/swagger-ui.html```可以訪問到我們的額度服務
![](https://img-blog.csdnimg.cn/20200315190105139.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0V2YW5fTGV1bmc=,size_16,color_FFFFFF,t_70)
從上面可以看到,我們的Nginx已經起作用,成功代理我們的額度服務叢集
- **驗證額度服務每個節點** - 假如docker swarm正常執行,那麼我們應該可以分別通過三個節點的```ip+8080```訪問我們的服務
![](https://img-blog.csdnimg.cn/20200315190444911.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0V2YW5fTGV1bmc=,size_16,color_FFFFFF,t_70)
![](https://img-blog.csdnimg.cn/20200315190506942.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0V2YW5fTGV1bmc=,size_16,color_FFFFFF,t_70)
![](https://img-blog.csdnimg.cn/20200315190535663.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0V2YW5fTGV1bmc=,size_16,color_FFFFFF,t_70)
從上面顯示結果可以看到,我通過三個節點的ip和8080埠都成功訪問到我們的額度服務,證明我們的swarm叢集已經搭建成功
### **驗證額度服務功能**
因為我們額度服務有用到資料庫,這裡我們實驗下呼叫額度服務的介面,看是否可以成功入庫
請求引數如下:
```json
{
"registrationLimitCO": {
"applicationId": "1111",
"userId": 1111,
"quotaLimit": 10000,
"productCode": "tb",
"expirationTime": "2030-01-01",
"accountType": 1
}
}
```
執行額度註冊介面
![](https://img-blog.csdnimg.cn/20200315190922497.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0V2YW5fTGV1bmc=,size_16,color_FFFFFF,t_70)
執行結果:
![](https://img-blog.csdnimg.cn/2020031519100028.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0V2YW5fTGV1bmc=,size_16,color_FFFFFF,t_70)
從上面執行結果可以看到,我們的介面已經成功處理我們的請求,並且入庫成功,有興趣的同學可以到資料庫去檢視相應記錄
***
# **附錄**
## **參考引用**
[官方文件 - Swarm Networking](https://github.com/docker/docker.github.io/blob/master/engine/swarm/networking.md)
## **Docker Swarm常用指令**
### **Docker Stack**
- 檢視stack具體資訊
```bash
[root@manager-node credit-facility]# docker stack ls
NAME SERVICES ORCHESTRATOR
web 3 Swarm
```
- 根據```docker-stack.yml```建立服務
```bash
docker statck deploy -c docker-stack.yml web
```
- 檢視某個service
```bash
[root@manager-node credit-facility]# docker service inspect web_db
...
"Endpoint": {
"Spec": {
"Mode": "vip",
"Ports": [
{
"Protocol": "tcp",
"TargetPort": 3306,
"PublishedPort": 3306,
"PublishMode": "ingress"
}
]
},
"Ports": [
{
"Protocol": "tcp",
"TargetPort": 3306,
"PublishedPort": 3306,
"PublishMode": "ingress"
}
],
"VirtualIPs": [
{
"NetworkID": "5mmql4cfhoac6q3y67wm4x2uh",
"Addr": "10.0.0.122/24"
},
{
"NetworkID": "xx3b6lki8n1nvkphffretc050",
"Addr": "10.0.6.12/24"
}
]
}
...
```
### **Docker Service**
- 建立一個nginx的service
```bash
docker service create --name my-nginx nginx
```
- 檢視當前swarm的service
```bash
docker service ls
```
- 檢視service的啟動日誌
```bash
docker service logs my-nginx
```
- 檢視service的詳情
```bash
ocker service inspect my-nginx
```
- 檢視my-nginx執行在哪個node上
```bash
docker service ps my-nginx
```
- 水平擴充套件service
```bash
docker service scale my-nginx=3
docker service ls
docker service ps my-nginx
```
- 刪除service
```bash
docker service rm my-n