Docker深入浅出系列 | Swarm多节点实战
EvanLeung 人气:3
[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.下载mysql
```bash
docker pull mysql
```
2.下载nginx
```bash
docker pull nginx
```
3.克隆```credit-facility-service```作为后面部署演示使用,使用```docker```分支
```bash
git clone https://github.com/EvanLeung08/credit-facility-service.git
```
4.虚拟机、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.comhttps://img.qb5200.com/download-x/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 /etchttps://img.qb5200.com/download-x/docker
sudo tee /etchttps://img.qb5200.com/download-x/dockerhttps://img.qb5200.com/download-x/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:/https://img.qb5200.com/download-x/download.docker.com/linux/centoshttps://img.qb5200.com/download-x/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:3301https://img.qb5200.com/download-x/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 root@192.168.101.11
root@192.168.101.11's password:
Connected to root@192.168.101.11.
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 root@192.168.101.12
root@192.168.101.11's password:
Connected to root@192.168.101.12.
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 root@192.168.101.13
root@192.168.101.11's password:
Connected to root@192.168.101.13.
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客户端,连接到数据库,把项目里```resourceshttps://img.qb5200.com/download-x/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.comhttps://img.qb5200.com/download-x/dockerhttps://img.qb5200.com/download-x/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-nginx
```
加载全部内容