第20 章 Docker Swarm 集群实践

Docker Swarm 集群实践

Swarm介绍

Swarm这个项目名称特别贴切。在Wiki的解释中,Swarm behavior是指动物的群集行为。比如我们常见的蜂群,鱼群,秋天往南飞的雁群都可以称作Swarm behavior。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ajM1szva-1599615266540)(assets/907596-20181113172620982-1826542875.png)]

Swarm项目正是这样,通过把多个Docker Engine聚集在一起,形成一个大的docker-engine,对外提供容器的集群服务。同时这个集群对外提供Swarm API,用户可以像使用Docker Engine一样使用Docker集群。

Swarm是Docker公司在2014年12月初发布的容器管理工具,和Swarm一起发布的Docker管理工具还有Machine以及Compose。Swarm是一套较为简单的工具,用以管理Docker集群,使得Docker集群暴露给用户时相当于一个虚拟的整体。Swarm将一群Docker宿主机变成一个单一的,虚拟的主机。Swarm使用标准的Docker API接口作为其前端访问入口,换言之,各种形式的Docker Client(docker client in Go, docker_py, docker等)均可以直接与Swarm通信。Swarm几乎全部用Go语言来完成开发,Swarm0.2版本增加了一个新的策略来调度集群中的容器,使得在可用的节点上传播它们,以及支持更多的Docker命令以及集群驱动。Swarm deamon只是一个调度器(Scheduler)加路由器(router),Swarm自己不运行容器,它只是接受docker客户端发送过来的请求,调度适合的节点来运行容器,这意味着,即使Swarm由于某些原因挂掉了,集群中的节点也会照常运行,当Swarm重新恢复运行之后,它会收集重建集群信息。

Docker的Swarm(集群)模式,集成很多工具和特性,比如:跨主机上快速部署服务,服务的快速扩展,集群的管理整合到docker引擎,这意味着可以不可以不使用第三方管理工具。分散设计,声明式的服务模型,可扩展,状态协调处理,多主机网络,分布式的服务发现,负载均衡,滚动更新,安全(通信的加密)等等,下面就来认识下Swarm(对于Swarm管理的详细操作可以参考:https://www.centos.bz/tag/swarm/page/3/

Swarm 特点

  1. 对外以Docker API接口呈现,这样带来的好处是,如果现有系统使用Docker Engine,则可以平滑将Docker Engine切到Swarm上,无需改动现有系统。
  2. Swarm对用户来说,之前使用Docker的经验可以继承过来。非常容易上手,学习成本和二次开发成本都比较低。同时Swarm本身专注于Docker集群管理,非常轻量,占用资源也非常少。简单说,就是插件化机制,Swarm中的各个模块都抽象出了API,可以根据自己一些特点进行定制实现。
  3. Swarm自身对Docker命令参数支持的比较完善,Swarm目前与Docker是同步发布的。Docker的新功能,都会第一时间在Swarm中体现。

Docker自诞生以来,其容器特性以及镜像特性给DevOps爱好者带来了诸多方便。然而在很长的一段时间内,Docker只能在单host上运行,其跨host的部署、运行与管理能力颇受外界诟病。跨host能力的薄弱,直接导致Docker容器与host的紧耦合,这种情况下,Docker容器的灵活性很难令人满意,容器的迁移、分组等都成为很难实现的功能点。

Swarm架构

Swarm作为一个管理Docker集群的工具,首先需要将其部署起来,可以单独将Swarm部署于一个节点。另外,自然需要一个Docker集群,集群上每一个节点均安装有Docker。具体的Swarm架构图可以参照下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hzQeb1No-1599615266545)(assets/907596-20170518013421541-941251933.png)]

Swarm架构中最主要的处理部分自然是Swarm节点,Swarm管理的对象自然是Docker Cluster,Docker Cluster由多个Docker Node组成,而负责给Swarm发送请求的是Docker Client。

Swarm关键概念

1)Swarm

集群的管理和编排是使用嵌入到docker引擎的SwarmKit,可以在docker初始化时启动swarm模式或者加入已存在的swarm

2)Node

一个节点(node)是已加入到swarm的Docker引擎的实例 当部署应用到集群,你将会提交服务定义到管理节点,接着Manager管理节点调度任务到worker节点,manager节点还执行维护集群的状态的编排和群集管理功能,worker节点接收并执行来自manager节点的任务。通常,manager节点也可以是worker节点,worker节点会报告当前状态给manager节点.

3)服务(Service)

服务是要在worker节点上要执行任务的定义,它在工作者节点上执行,当你创建服务的时,你需要指定容器镜像

4)任务(Task)

任务是在docekr容器中执行的命令,Manager节点根据指定数量的任务副本分配任务给worker节点

5)命令

docker swarm:集群管理,子命令有init, join, leave, update。(docker swarm --help查看帮助)
docker service:服务创建,子命令有create, inspect, update, remove, tasks。(docker service–help查看帮助)
docker node:节点管理,子命令有accept, promote, demote, inspect, update, tasks, ls, rm。(docker node --help查看帮助)

node是加入到swarm集群中的一个docker引擎实体,可以在一台物理机上运行多个node,node分为:
- manager nodes,也就是管理节点
- worker nodes,也就是工作节点

1)manager node管理节点:执行集群的管理功能,维护集群的状态,选举一个leader节点去执行调度任务。
2)worker node工作节点:接收和执行任务。参与容器集群负载调度,仅用于承载task。
3)service服务:一个服务是工作节点上执行任务的定义。创建一个服务,指定了容器所使用的镜像和容器运行的命令。service是运行在worker nodes上的task的描述,service的描述包括使用哪个docker 镜像,以及在使用该镜像的容器中执行什么命令。
4)task任务:一个任务包含了一个容器及其运行的命令。task是service的执行实体,task启动docker容器并在容器中执行任务。

Swarm工作方式

1)Node

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dwp3SfgT-1599615266548)(assets/907596-20170520194231619-1867210747.png)]

2)Service(服务, 任务, 容器)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mjCl3Csu-1599615266552)(assets/907596-20170520194322822-82295838.png)]

3)任务与调度

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GAljiUGl-1599615266554)(assets/907596-20170520194435932-641450568.png)]

4)服务副本与全局服务

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lKsdbkMs-1599615266557)(assets/907596-20170520194509385-1172179581.png)]

Swarm调度策略

Swarm在scheduler节点(leader节点)运行容器的时候,会根据指定的策略来计算最适合运行容器的节点,目前支持的策略有:spread(传播, 扩展, 扩散), binpack, random.

1)Random

顾名思义,就是随机选择一个Node来运行容器,一般用作调试用,spread和binpack策略会根据各个节点可用的CPU, RAM以及正在运行的容器数量来计算应该运行容器的节点。

2)Spread

在同等条件下,Spread策略会选择运行容器最少的那台节点来运行新的容器,binpack策略会选择运行容器最集中的那台机器来运行新的节点。使用Spread策略会使得容器会均衡的分布在集群中的各个节点上运行,一旦一个节点挂掉了只会损失少部分的容器。

3)Binpack

Binpack策略最大化的避免容器碎片化,就是说binpack策略尽可能的把还未使用的节点留给需要更大空间的容器运行,尽可能的把容器运行在一个节点上面。

Swarm Cluster模式的特性

1)批量创建服务

建立容器之前先创建一个overlay的网络,用来保证在不同主机上的容器网络互通的网络模式。

2)强大的集群的容错性

当容器副本中的其中某一个或某几个节点宕机后,cluster会根据自己的服务注册发现机制,以及之前设定的值–replicas n,在集群中剩余的空闲节点上,重新拉起容器副本。整个副本迁移的过程无需人工干预,迁移后原本的集群的load balance依旧好使!不难看出,docker service其实不仅仅是批量启动服务这么简单,而是在集群中定义了一种状态。Cluster会持续检测服务的健康状态并维护集群的高可用性。

3)服务节点的可扩展性

Swarm Cluster不光只是提供了优秀的高可用性,同时也提供了节点弹性扩展或缩减的功能。当容器组想动态扩展时,只需通过scale参数即可复制出新的副本出来。仔细观察的话,可以发现所有扩展出来的容器副本都run在原先的节点下面,如果有需求想在每台节点上都run一个相同的副本,方法其实很简单,只需要在命令中将"–replicas n"更换成"–mode=global"即可!其中:
复制服务(–replicas n)将一系列复制任务分发至各节点当中,具体取决于您所需要的设置状态,例如“–replicas 3”。
全局服务(–mode=global)适用于集群内全部可用节点上的服务任务,例如“–mode global”。如果在 Swarm 集群中设有 7 台 Docker 节点,则全部节点之上都将存在对应容器。

4) 调度机制

所谓的调度其主要功能是cluster的server端去选择在哪个服务器节点上创建并启动一个容器实例的动作。它是由一个装箱算法和过滤器组合而成。每次通过过滤器(constraint)启动容器的时候,swarm cluster 都会调用调度机制筛选出匹配约束条件的服务器,并在这上面运行容器。

5)集群步骤

Swarm cluster的创建过程包含以下三个步骤===
1)发现Docker集群中的各个节点,收集节点状态、角色信息,并监视节点状态的变化
2)初始化内部调度(scheduler)模块
3)创建并启动API监听服务模块

一旦创建好这个cluster,就可以用命令docker service批量对集群内的容器进行操作,非常方便!

在启动容器后,docker 会根据当前每个swarm节点的负载判断,在负载最优的节点运行这个task任务,用"docker service ls" 和"docker service ps + taskID"
可以看到任务运行在哪个节点上。容器启动后,有时需要等待一段时间才能完成容器创建。

Swarm集群部署实例(Swarm Cluster)

1)机器环境

(均是centos7.2)

182.48.115.237 swarm的manager节点 manager-node
182.48.115.238 swarm的node节点 node1
182.48.115.239 swarm的node节点 node2

182.48.115.237      swarm的manager节点      manager-node   
182.48.115.238      swarm的node节点         node1
182.48.115.239      swarm的node节点         node2
 
设置主机名
在manager节点上
[root@manager-node ~]# hostnamectl --static set-hostname manager-node
 
在node1节点上
[root@node1 ~]# hostnamectl --static set-hostname node1
 
在node2节点上
[root@node2 ~]# hostnamectl --static set-hostname node2
 
在三台机器上都要设置hosts,均执行如下命令:
[root@manager-node ~]# vim /etc/hosts
......
182.48.115.237 manager-node
182.48.115.238 node1
182.48.115.239 node2
 
关闭三台机器上的防火墙。如果开启防火墙,则需要在所有节点的防火墙上依次放行2377/tcp(管理端口)、7946/udp(节点间通信端口)、4789/udp(overlay 网络端口)端口。
[root@manager-node ~]# systemctl disable firewalld.service
[root@manager-node ~]# systemctl stop firewalld.service

2)安装docker

分别在manager节点和node节点上安装docker,并下载swarm镜像

[root@manager-node ~]# yum install -y docker
  
配置docker
[root@manager-node ~]# vim /etc/sysconfig/docker
......
OPTIONS='-H 0.0.0.0:2375 -H unix:///var/run/docker.sock'           //在OPTIONS参数项后面的''里添加内容. 或者使用'-H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock'
  
[root@manager-node ~]# systemctl restart docker
  
下载swarm镜像
[root@manager-node ~]# docker pull swarm
[root@manager-node ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
docker.io/swarm     latest              36b1e23becab        4 months ago        15.85 MB

3)创建swarm集群

(要保存初始化后token,因为在节点加入时要使用token作为通讯的密钥)

$ docker swarm init --advertise-addr 182.48.115.237
Swarm initialized: current node (1gi8utvhu4rxy8oxar2g7h6gr) is now a manager.
 
To add a worker to this swarm, run the following command:
 
    docker swarm join \
    --token SWMTKN-1-4roc8fx10cyfgj1w1td8m0pkyim08mve578wvl03eqcg5ll3ig-f0apd81qfdwv27rnx4a4y9jej \
    182.48.115.237:2377
 
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

上面命令执行后,该机器自动加入到swarm集群。这个会创建一个集群token,获取全局唯一的 token,作为集群唯一标识。后续将其他节点加入集群都会用到这个token值。
其中,--advertise-addr参数表示其它swarm中的worker节点使用此ip地址与manager联系。命令的输出包含了其它节点如何加入集群的命令。

温馨提示:

如果再次执行上面启动swarm集群的命令,会报错说这个节点已经在集群中了
Error response from daemon: This node is already part of a swarm. Use “docker swarm leave” to leave this swarm and join another one.

解决办法:

[root@manager-node ~]# docker swarm leave --help           //查看帮助
[root@manager-node ~]# docker swarm leave --force

#使用docker info 或 docker node ls 查看集群中的相关信息
[root@manager-node ~]# docker info
.......
Swarm: active
 NodeID: 1gi8utvhu4rxy8oxar2g7h6gr
 Is Manager: true
 ClusterID: a88a9j6nwcbn31oz6zp9oc0f7
 Managers: 1
 Nodes: 1
 Orchestration:
  Task History Retention Limit: 5
.......

[root@manager-node ~]# docker node ls                 
ID                           HOSTNAME      STATUS  AVAILABILITY  MANAGER STATUS
1gi8utvhu4rxy8oxar2g7h6gr *  manager-node  Ready   Active        Leader

注意上面node ID旁边那个*号表示现在连接到这个节点上。

4)添加节点到swarm集群中

在docker swarm init 完了之后,会提示如何加入新机器到集群,如果当时没有注意到,也可以通过下面的命令来获取如何加入新机器到集群的 token:

#获取加入管理机的token
$ docker swarm join-token manager
#获取加入工作机的token
$ docker swarm join-token worker

登录到node1节点上,执行前面创建swarm集群时输出的命令:

[root@node1 ~]``# docker swarm join --token SWMTKN-1-4roc8fx10cyfgj1w1td8m0pkyim08mve578wvl03eqcg5ll3ig-f0apd81qfdwv27rnx4a4y9jej 182.48.115.237:2377
This node joined a swarm as a worker.

同理在node2节点上,也执行这个命令

[root@node2 ~]``# docker swarm join --token SWMTKN-1-4roc8fx10cyfgj1w1td8m0pkyim08mve578wvl03eqcg5ll3ig-f0apd81qfdwv27rnx4a4y9jej 182.48.115.237:2377
This node joined a swarm as a worker.

如果想要将其他更多的节点添加到这个swarm集群中,添加方法如上一致!然后在manager-node管理节点上看一下集群节点的状态:

[root@manager-node ~]``# docker node ls
ID                           HOSTNAME      STATUS  AVAILABILITY  MANAGER STATUS
1gi8utvhu4rxy8oxar2g7h6gr *  manager-node  Ready   Active        Leader
ei53e7o7jf0g36329r3szu4fi    node1         Ready   Active      
f1obgtudnykg51xzyj5fs1aev    node2         Ready   Active

温馨提示:更改节点的availablity状态

warm集群中node的availability状态可以为 active或者drain(排水, 排泄, 外流),其中:
active(上线)状态下:node可以接受来自manager节点的任务分派;
drain(下线)状态下:node节点会结束task,且不再接受来自manager节点的任务分派(也就是下线节点)。

[root@manager-node ~]``# docker node update --availability drain node1    //将node1节点下线。如果要删除node1节点,命令是"docker node rm --force node1"
[root@manager-node ~]``# docker node ls
ID                           HOSTNAME      STATUS  AVAILABILITY  MANAGER STATUS
1gi8utvhu4rxy8oxar2g7h6gr *  manager-node  Ready   Active        Leader
ei53e7o7jf0g36329r3szu4fi    node1         Ready   drain      
f1obgtudnykg51xzyj5fs1aev    node2         Ready   Active

如上,当node1的状态改为drain后,那么该节点就不会接受task任务分发,就算之前已经接受的任务也会转移到别的节点上。再次修改为active状态(及将下线的节点再次上线)

$ docker node update --availability active node1

5)在Swarm中部署服务

Docker 1.12版本提供服务的Scaling、health check、滚动升级等功能,并提供了内置的dns、vip机制,实现service的服务发现和负载均衡能力。(这里以nginx服务为例)

在启动容器之前,先来创建一个覆盖网络,用来保证在不同主机上的容器网络互通的网络模式

[root@manager-node ~]# docker network create -d overlay ngx_net
[root@manager-node ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
8bbd1b7302a3        bridge              bridge              local
9e637a97a3b9        docker_gwbridge     bridge              local
b5a41c8c71e7        host                host                local
1x45zepuysip        ingress             overlay             swarm            
3ye6vfp996i6        ngx_net             overlay             swarm            
0808a5c72a0a        none                null                local

在manager-node节点上使用上面这个覆盖网络创建nginx服务:
其中,–replicas 参数指定服务由几个实例组成。
注意:不需要提前在节点上下载nginx镜像,这个命令执行后会自动下载这个容器镜像(比如此处创建tomcat容器,就将下面命令中的镜像改为tomcat镜像)。

[root@manager-node ~]# docker service create --replicas 1 --network ngx_net --name my-test -p 80:80 nginx

就创建了一个具有一个副本(–replicas 1 )的nginx服务,使用镜像nginx

使用 docker service ls 查看正在运行服务的列表

[root@manager-node ~]# docker service ls
ID            NAME     REPLICAS  IMAGE            COMMAND
0jb5eebo8j9q  my-test`  `1/1`       `nginx

查询Swarm中服务的信息
-pretty 使命令输出格式化为可读的格式,不加 --pretty 可以输出更详细的信息:

[root@manager-node ~]# docker service inspect --pretty my-test
ID:   0jb5eebo8j9qb1zc795vx3py3
Name:   my-test
Mode:   Replicated
 Replicas:  1
Placement:
UpdateConfig:
 Parallelism: 1
 On failure:  pause
ContainerSpec:
 Image:   nginx
Resources:
Networks: 3ye6vfp996i6eq17tue0c2jv9
Ports:
 Protocol = tcp
 TargetPort = 80
 PublishedPort = 80

查询到哪个节点正在运行该服务。如下该容器被调度到manager-node节点上启动了,然后访问http://182.48.115.237即可访问这个容器应用(如果调度到其他节点,访问也是如此)

[root@manager-node ~]# docker service ps my-test
ID                         NAME       IMAGE            NODE          DESIRED STATE  CURRENT STATE          ERROR
2m8qqpoa0dpeua5jbgz1infuy  my-test.1  nginx  manager-node  Running        Running 3 minutes ago

注意,如果上面命令执行后,上面的 STATE 字段中刚开始的服务状态为 Preparing,需要等一会才能变为 Running 状态,其中最费时间的应该是下载镜像的过程。

有上面命令可知,该服务在manager-node节点上运行。登陆该节点,可以查看到nginx容器在运行中

[root@manager-node ~]# docker ps
CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS              PORTS               NAMES
1ea1d72007da        nginx:latest   "nginx -g 'daemon off"`   `4 minutes ago       Up 4 minutes        80/tcp`              `my-test.1.2m8qqpoa0dpeua5jbgz1infuy

-------------------------------------------在Swarm中动态扩展服务(scale)-----------------------------------------------
当然,如果只是通过service启动容器,swarm也算不上什么新鲜东西了。Service还提供了复制(类似kubernetes里的副本)功能。可以通过 docker service scale 命令来设置服务中容器的副本数:

比如将上面的my-test容器动态扩展到5个,命令如下:

[root@manager-node ~]``# docker service scale my-test=5

和创建服务一样,增加scale数之后,将会创建新的容器,这些新启动的容器也会经历从准备到运行的过程,过一分钟左右,服务应该就会启动完成,这时候可以再来看一下 nginx 服务中的容器

[root@manager-node ~]# docker service ps my-test
ID                         NAME       IMAGE            NODE          DESIRED STATE  CURRENT STATE          ERROR
2m8qqpoa0dpeua5jbgz1infuy  my-test.1  nginx  manager-node  Running        Running 9 minutes ago
aqko8yhmdj53gmzs8gqhoylc2  my-test.2  nginx  node2         Running        Running 2 minutes ago
erqk394hd4ay7nfwgaz4zp3s0  my-test.3  nginx  node1         Running        Running 2 minutes ago
2dslg6w16wzcgboa2hxw1c6k1  my-test.4  nginx  node1         Running        Running 2 minutes ago
bmyddndlx6xi18hx4yinpakf3  my-test.5  nginx  manager-node  Running        Running 2 minutes ago

可以看到,之前my-test容器只在manager-node节点上有一个实例,而现在又增加了4个实例。这5个副本的my-test容器分别运行在这三个节点上,登陆这三个节点,就会发现已经存在运行着的my-test容器。


特别需要清楚的一点:

果一个节点宕机了(即该节点就会从swarm集群中被踢出),则Docker应该会将在该节点运行的容器,调度到其他节点,以满足指定数量的副本保持运行状态。

比如:
将node1宕机后或将node1的docker服务关闭,那么它上面的task实例就会转移到别的节点上。当node1节点恢复后,它转移出去的task实例不会主动转移回来,
只能等别的节点出现故障后转移task实例到它的上面。使用命令"docker node ls",发现node1节点已不在swarm集群中了。

然后过一会查询服务的状态列表

[root@manager-node ~]# docker service ps my-test
ID                         NAME           IMAGE            NODE          DESIRED STATE  CURRENT STATE           ERROR
2m8qqpoa0dpeua5jbgz1infuy  my-test.1      docker.io/nginxmanager-node  Running        Running 33 minutes ago
aqko8yhmdj53gmzs8gqhoylc2  my-test.2      docker.io/nginx`  `node2         Running        Running 26 minutes ago
di99oj7l9x6firw1ai25sewwc  my-test.3      docker.io/nginxnode2         Running        Running 6 minutes ago
erqk394hd4ay7nfwgaz4zp3s0   _ my-test.3  docker.io/nginx`  `node1         Shutdown       Complete 5 minutes ago
aibl3u3pph3fartub0mhwxvzr  my-test.4      docker.io/nginxnode2         Running        Running 6 minutes ago
2dslg6w16wzcgboa2hxw1c6k1   _ my-test.4  docker.io/nginx`  `node1         Shutdown       Complete 5 minutes ago
bmyddndlx6xi18hx4yinpakf3  my-test.5      docker.io/nginxmanager-node  Running        Running 26 minutes ago

发现,node1节点出现故障后,它上面之前的两个task任务已经转移到node2节点上了。
登陆到node2节点上,可以看到这两个运行的task任务。当访问182.48.115.239节点的80端口,swarm的负载均衡会把请求路由到一个任意节点的可用的容器上。

[root@node2 ~]# docker ps
CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS              PORTS               NAMES
216abf6bebea        docker.io/nginx:latest"nginx -g 'daemon off"7 minutes ago       Up 7 minutes        80/tcp`              `my-test.3.di99oj7l9x6firw1ai25sewwc
1afd12cc9140        docker.io/nginx:latest"nginx -g 'daemon off"7 minutes ago       Up 7 minutes        80/tcp`              `my-test.4.aibl3u3pph3fartub0mhwxvzr
cc90da57c25e        docker.io/nginx:latest"nginx -g 'daemon off"27 minutes ago      Up 27 minutes       80/tcp`              `my-test.2.aqko8yhmdj53gmzs8gqhoylc2

再次在node2节点上将从node1上转移过来的两个task关闭

[root@node2 ~]# docker stop my-test.3.di99oj7l9x6firw1ai25sewwc my-test.4.aibl3u3pph3fartub0mhwxvzr
my-test.3.di99oj7l9x6firw1ai25sewwc
my-test.4.aibl3u3pph3fartub0mhwxvzr

再次查询服务的状态列表,发现这两个task又转移到node1上了(即在swarm cluster集群中启动的容器,在worker node节点上删除或停用后,该容器会自动转移到其他的worker node节点上)

[root@manager-node ~]# docker service ps my-test
ID                         NAME           IMAGE            NODE          DESIRED STATE  CURRENT STATE                ERROR
2m8qqpoa0dpeua5jbgz1infuy  my-test.1      docker.io/nginxmanager-node  Running        Running 38 minutes ago    
aqko8yhmdj53gmzs8gqhoylc2  my-test.2      docker.io/nginx`  `node2         Running        Running 31 minutes ago    
7dhmc63rk0bc8ngt59ix38l44  my-test.3      docker.io/nginxnode1         Running        Running about a minute ago
di99oj7l9x6firw1ai25sewwc   _ my-test.3  docker.io/nginx`  `node2         Shutdown       Complete about a minute ago
erqk394hd4ay7nfwgaz4zp3s0   \_ my-test.3  docker.io/nginxnode1         Shutdown       Complete 9 minutes ago    
607tyjv6foc0ztjjvdo3l3lge  my-test.4      docker.io/nginx`  `node1         Running        Running about a minute ago
aibl3u3pph3fartub0mhwxvzr   \_ my-test.4  docker.io/nginxnode2         Shutdown       Complete about a minute ago
2dslg6w16wzcgboa2hxw1c6k1   _ my-test.4  docker.io/nginx`  `node1         Shutdown       Complete 9 minutes ago    
bmyddndlx6xi18hx4yinpakf3  my-test.5      docker.io/nginxmanager-node  Running        Running 31 minutes ago

同理,swarm还可以缩容,如下,将my-test容器变为1个。

[root@manager-node ~]# docker service scale my-test=1
[root@manager-node ~]# docker service ps my-test
ID                         NAME       IMAGE            NODE          DESIRED STATE  CURRENT STATE          ERROR
2m8qqpoa0dpeuasdfsdfdfsdf  my-test.1  nginx  manager-node  Running        Running 3 minutes ago

登录node2节点,使用docker ps查看,会发现容器被stop而非 rm


删除容器服务

[root@manager-node ~]# docker service --help       //查看帮助
[root@manager-node ~]# docker service rm my-test    //这样就会把所有节点上的所有容器(task任务实例)全部删除了my-nginx

除了上面使用scale进行容器的扩容或缩容之外,还可以使用docker service update 命令。 可对 服务的启动 参数 进行 更新/修改。

[root@manager-node ~]# docker service update --replicas 3 my-test
my-test

更新完毕以后,可以查看到REPLICAS已经变成3/3

[root@manager-node ~]# docker service ls
ID            NAME          REPLICAS  IMAGE      COMMAND 
d7cygmer0yy5  my-test`       `3/3nginx     /bin/bash

[root@manager-node ~]# docker service ps my-test
ID                         NAME             IMAGE  NODE          DESIRED STATE  CURRENT STATE            ERROR
ddkidkz0jgor751ffst55kvx4  my-test.1      nginx  node1         Running          Preparing 4 seconds ago
1aucul1b3qwlmu6ocu312nyst   \_ my-test.1  nginx  manager-node  Shutdown       Complete 5 seconds ago 
4w9xof53f0falej9nqgq064jz   \_ my-test.1  nginx  manager-node  Shutdown       Complete 19 seconds ago
0e9szyfbimaow9tffxfeymci2   \_ my-test.1  nginx  manager-node  Shutdown       Complete 30 seconds ago
27aqnlclp0capnp1us1wuiaxm  my-test.2      nginx  manager-node  Running        Preparing 1 seconds ago
7dmmmle29uuiz8ey3tq06ebb8  my-test.3      nginx  manager-node  Running        Preparing 1 seconds ago

docker service update 命令,也可用于直接 升级 镜像等。

[root@manager-node ~]``# docker service update --image nginx:new my-test

[root@manager-node ~]# docker service ls
ID            NAME          REPLICAS  IMAGE         COMMAND 
d7cygmer0yy5  my-test3/3`       `nginx:new/bin/bash

6)Swarm中使用Volume

(挂载目录: --mount type=volume 或者 --mount type=bind )

#查看docker volume的帮助信息
[root@manager-node ~]``# docker volume --help
    
Usage:  docker volume COMMAND
    
Manage Docker volumes
    
Options:
      ``--help   Print usage
    
Commands:
  ``create      Create a volume
  ``inspect     Display detailed information on one or ``more` `volumes
  ``ls`          `List volumes
  ``rm`          `Remove one or ``more` `volumes
    
Run ``'docker volume COMMAND --help'` `for` `more` `information on a ``command``.
    
[root@manager-node ~]``# docker volume create --name myvolume
myvolume
   
[root@manager-node ~]``# docker volume ls
DRIVER              VOLUME NAME
local`               `11b68dce3fff0d57172e18bc4e4cfc252b984354485d747bf24abc9b11688171
local`               `1cd106ed7416f52d6c77ed19ee7e954df4fa810493bb7e6cf01775da8f9c475f
local`               `myvolume
   

参数src写成source也可以;dst表示容器内的路径,也可以写成destination

[root@manager-node ~]``# docker service create --replicas 2 --network ngx_net --mount type=volume,src=myvolume,dst=/wangshibo --name test-nginx nginx

温馨提示:

必须确保各节点服务器的selinux永久关闭,即:

[root@manager-node ~]``# cat /etc/sysconfig/selinux
SELINUX=disabled
[root@manager-node ~]``# reboot
[root@manager-node ~]``# getenforce
Disabled

必须是永久关闭,临时关闭可能都不行,否则上面创建命令后,可能会出现如下报错:

[root@manager-node ~]``# docker service ps test-nginx
"SELinux relabeling of is not allowed"
[root@manager-node ~]# docker service ls
ID            NAME        REPLICAS  IMAGE   COMMAND
8s9m0okwlhvl  test-nginx  2/2`       `nginx
[root@manager-node ~]# docker service ps test-nginx
ID                         NAME          IMAGE  NODE   DESIRED STATE  CURRENT STATE           ERROR
32bqjjhqcl1k5z74ijjli35z3  test-nginx.1  nginx  node1  Running        Running 23 seconds ago
48xoypunb3g401jkn690lx7xt  test-nginx.2  nginx  node2  Running        Running 23 seconds ago

登录node1节点的test-nginx容器查看

[root@node1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
d471569629b2        nginx:latest        "nginx -g 'daemon off"`   `2 minutes ago       Up 2 minutes        80/tcp`              `test-nginx.1.32bqjjhqcl1k5z74ijjli35z3
    
[root@node1 ~]# docker exec -ti d471569629b2 /bin/bash
root@d471569629b2:/# cd /wangshibo/
root@d471569629b2:/wangshibo# ls
root@d471569629b2:/wangshibo# echo "ahahha" > test
root@d471569629b2:/wangshibo# ls
test
    
[root@node1 ~]# docker volume inspect myvolume
[
    {
    
    
        "Name": "myvolume",
        "Driver": "local",
        "Mountpoint": "/var/lib/docker/volumes/myvolume/_data",
        "Labels": null,
        "Scope": "local"
    }
]
[root@node1 ~]# cd /var/lib/docker/volumes/myvolume/_data/
[root@node1 _data]# ls
test
[root@node1 _data]# cat test
ahahha
[root@node1 _data]# echo "12313" > 123
[root@node1 _data]# ls
123  test
    
root@d471569629b2:/wangshibo# ls
123  test
root@d471569629b2:/wangshibo# cat test
ahahha

需要注意:

  1. 挂载volume后,宿主机和容器之间就可以通过volume进行双向实时同步.
  2. 如果replicas是多份,则每个节点宿主机上都会有一个volume路径,即每个节点宿主机的/var/lib/docker/volumes/myvolume/_data 和分布到它上面的容器里的/wangshibo进行实时同步。

第二种方法:命令格式:

docker service create --mount` `type=bind,source=/host_data/,destination=/container_data/

其中,参数target表示容器里面的路径,source表示本地硬盘路径

[root@manager-node ~]# docker service create --replicas 1 --mount type=bind,source=/opt/web/,destination=/usr/share/nginx/html/ --network ngx_net --name haha-nginx -p 8880:80 nginx
[root@manager-node ~]# docker service ls
ID            NAME        REPLICAS  IMAGE  COMMAND
9t9d58b5bq4u  haha-nginx  1/1`       `nginx
[root@manager-node ~]# docker service ps haha-nginx
ID                         NAME              IMAGE  NODE          DESIRED STATE  CURRENT STATE            ERROR
bji4f5tikhvm7nf5ief3jk2is  haha-nginx.1      nginx  node2         Running        Running 18 seconds ago

登录node2节点,在挂载目录/opt/web下写测试数据

[root@node2 _data]# cd /opt/web/
[root@node2 web]# ls
[root@node2 web]# cat wang.html
sdfasdf

登录容器查看,发现已经实现数据同步

====================================================
温馨提示:
必须确保各节点服务器的selinux永久关闭,即:
[root@manager-node ~]# cat /etc/sysconfig/selinux
SELINUX=disabled
[root@manager-node ~]# reboot
[root@manager-node ~]# getenforce
Disabled
 
必须是永久关闭,临时关闭可能都不行,否则上面创建命令后,可能会出现如下报错:
[root@manager-node ~]# docker service ps test-nginx
"SELinux relabeling of is not allowed"
====================================================
 
[root@manager-node ~]# docker service ls
ID            NAME        REPLICAS  IMAGE   COMMAND
8s9m0okwlhvl  test-nginx  2/2`       `nginx
[root@manager-node ~]# docker service ps test-nginx
ID                         NAME          IMAGE  NODE   DESIRED STATE  CURRENT STATE           ERROR
32bqjjhqcl1k5z74ijjli35z3  test-nginx.1  nginx  node1  Running        Running 23 seconds ago
48xoypunb3g401jkn690lx7xt  test-nginx.2  nginx  node2  Running        Running 23 seconds ago
    
登录node1节点的test-nginx容器查看
[root@node1 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
d471569629b2        nginx:latest        "nginx -g 'daemon off"`   `2 minutes ago       Up 2 minutes        80/tcp`              `test-nginx.1.32bqjjhqcl1k5z74ijjli35z3
    
[root@node1 ~]# docker exec -ti d471569629b2 /bin/bash
root@d471569629b2:/# cd /wangshibo/
root@d471569629b2:/wangshibo# ls
root@d471569629b2:/wangshibo# echo "ahahha" > test
root@d471569629b2:/wangshibo# ls
test
    
[root@node1 ~]# docker volume inspect myvolume
[
    {
    
    
        "Name": "myvolume",
        "Driver": "local",
        "Mountpoint": "/var/lib/docker/volumes/myvolume/_data",
        "Labels": null,
        "Scope": "local"
    }
]
[root@node1 ~]# cd /var/lib/docker/volumes/myvolume/_data/
[root@node1 _data]# ls
test
[root@node1 _data]# cat test
ahahha
[root@node1 _data]# echo "12313" > 123
[root@node1 _data]# ls
123  test
    
root@d471569629b2:/wangshibo# ls
123  test
root@d471569629b2:/wangshibo# cat test
ahahha
    
需要注意:
1) 挂载volume后,宿主机和容器之间就可以通过volume进行双向实时同步.
2) 如果replicas是多份,则每个节点宿主机上都会有一个volume路径,即每个节点宿主机的/var/lib/docker/volumes/myvolume/_data和分布到它上面的
    容器里的/wangshibo进行实时同步.
 
============================================================
第二种方法:
  
命令格式:
docker service create --mount` `type=bind,source=/host_data/,destination=/container_data/
其中,参数target表示容器里面的路径,source表示本地硬盘路径
  
[root@manager-node ~]# docker service create --replicas 1 --mount type=bind,source=/opt/web/,destination=/usr/share/nginx/html/ --network ngx_net --name haha-nginx -p 8880:80 nginx
[root@manager-node ~]# docker service ls
ID            NAME        REPLICAS  IMAGE  COMMAND
9t9d58b5bq4u  haha-nginx  1/1`       `nginx
[root@manager-node ~]# docker service ps haha-nginx
ID                         NAME              IMAGE  NODE          DESIRED STATE  CURRENT STATE            ERROR
bji4f5tikhvm7nf5ief3jk2is  haha-nginx.1      nginx  node2         Running        Running 18 seconds ago
  
登录node2节点,在挂载目录/opt/web下写测试数据
[root@node2 _data]# cd /opt/web/
[root@node2 web]# ls
[root@node2 web]# cat wang.html
sdfasdf
  
登录容器查看,发现已经实现数据同步
[root@node2 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
3618e3d1b966        nginx:latest        "nginx -g 'daemon off"`   `28 seconds ago      Up 24 seconds       80/tcp`              `haha-nginx.1.bji4f5tikhvm7nf5ief3jk2is
[root@node2 ~]# docker exec -ti 3618e3d1b966 /bin/bash
root@3618e3d1b966:/# cd /usr/share/nginx/html
root@3618e3d1b966:/usr/share/nginx/html# ls
wang.html
root@3618e3d1b966:/usr/share/nginx/html# cat wang.html
sdfasdf
root@3618e3d1b966:/usr/share/nginx/html# touch test
touch: cannot touch` `'test': Permission denied
  
由此可见,以上设置后,在容器里的同步目录下没有写权限,更新内容时只要放到宿主机的挂在目录下即可!

由此可见,以上设置后,在容器里的同步目录下没有写权限,更新内容时只要放到宿主机的挂在目录下即可!

Swarm 网络

在Docker版本1.12之后swarm模式原生支持覆盖网络(overlay networks),可以先创建一个覆盖网络,然后启动容器的时候启用这个覆盖网络,这样只要是这个覆盖网络内的容器,不管在不在同一个宿主机上都能相互通信,即跨主机通信!不同覆盖网络内的容器组之间是相互隔离的(相互ping不通)。

Swarm 集群产生两种不同类型的流量:

  • 控制和管理层面:包括 Swarm 消息管理等,例如请求加入或离开Swarm,这种类型的流量总是被加密的。(涉及到集群内部的hostname、ip-address、subnet、gateway等)
  • 应用数据层面:包括容器与客户端的通信等。(涉及到防火墙、端口映射、网口映射、VIP等)

在 Swarm Service 中有三个重要的网络概念:

  • Overlay networks 管理 Swarm 中 Docker 守护进程间的通信。你可以将服务附加到一个或多个已存在的 overlay 网络上,使得服务与服务之间能够通信。
  • ingress network 是一个特殊的 overlay 网络,用于服务节点间的负载均衡。当任何 Swarm 节点在发布的端口上接收到请求时,它将该请求交给一个名为 IPVS 的模块。IPVS 跟踪参与该服务的所有IP地址,选择其中的一个,并通过 ingress 网络将请求路由到它。
    初始化或加入 Swarm 集群时会自动创建 ingress 网络,大多数情况下,用户不需要自定义配置,但是 docker 17.05 和更高版本允许你自定义。
  • docker_gwbridge是一种桥接网络,将 overlay 网络(包括 ingress 网络)连接到一个单独的 Docker 守护进程的物理网络。默认情况下,服务正在运行的每个容器都连接到本地 Docker 守护进程主机的 docker_gwbridge 网络。
    docker_gwbridge 网络在初始化或加入 Swarm 时自动创建。大多数情况下,用户不需要自定义配置,但是 Docker 允许自定义。

swarm模式的overlay networks包含以下特性:

  • 可以将多个服务连接到同一个网络中。

  • 默认情况下,容器网络的服务发现机制给swarm集群中的每个服务都分配一个虚拟IP地址和一个DNS条目,所以在同一网络中的容器可以通过服务名称访问服务。

  • 可以将服务配置成使用DNS轮询机制而不是VIP机制来进行负载均衡。

swarm模式的覆盖网络包括以下功能:
1)可以附加多个服务到同一个网络。
2)默认情况下,service discovery为每个swarm服务分配一个虚拟IP地址(vip)和DNS名称,使得在同一个网络中容器之间可以使用服务名称互相连接。
3)可以配置使用DNS轮循而不使用VIP
4)为了可以使用swarm的覆盖网络,在启用swarm模式之间你需要在swarm节点之间开放以下端口:
5)TCP/UDP端口7946 – 用于容器网络发现
6)UDP端口4789 – 用于容器覆盖网络

-----------在Swarm集群中创建overlay网络------------实例如下:

$ docker network create --driver overlay --opt encrypted --subnet 10.10.19.0/24 ngx_net

参数解释:
–opt encrypted: 默认情况下swarm中的节点通信是加密的。在不同节点的容器之间,可选的–opt encrypted参数能在它们的vxlan流量启用附加的加密层。
--subnet:命令行参数指定overlay网络使用的子网网段。当不指定一个子网时,swarm管理器自动选择一个子网并分配给网络。

$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
d7aa48d3e485        bridge              bridge              local
9e637a97a3b9        docker_gwbridge     bridge              local
b5a41c8c71e7        host                host                local
7f4fx3jf4dbr        ingress             overlay             swarm             
3x2wgugr6zmn        ngx_net             overlay             swarm             
0808a5c72a0a        none                null                local

由上可知,Swarm当中拥有2套覆盖网络。其中"ngx_net"网络正是我们在部署容器时所创建的成果。"ingress"覆盖网络则为默认提供。Swarm 管理节点会利用 ingress 负载均衡以将服务公布至集群之外。
在将服务连接到这个创建的网络之前,网络覆盖到manager节点。上面输出的SCOPE为 swarm 表示将服务部署到Swarm时可以使用此网络。
在将服务连接到这个网络后,Swarm只将该网络扩展到特定的worker节点,这个worker节点被swarm调度器分配了运行服务的任务。在那些没有运行该服务任务的worker节点上,网络并不扩展到该节点。

------------------将服务连接到overlay网络-------------------

$ docker service create --replicas 3 --network ngx_net --name my-test -p 80:80 nginx

上面名为"my-test"的服务启动了3个task,用于运行每个任务的容器都可以彼此通过overlay网络进行通信。Swarm集群将网络扩展到所有任务处于Running状态的节点上。

$ docker service ls
ID            NAME     REPLICAS  IMAGE  COMMAND
dsaxs6v463g9  my-test  3/3       nginx

在manager-node节点上,通过下面的命令查看哪些节点有处于running状态的任务:

$ docker service ps my-test
ID                         NAME       IMAGE  NODE          DESIRED STATE  CURRENT STATE          ERROR
8433fuiy7vpu0p80arl7vggfe  my-test.1  nginx  node2         Running        Running 2 minutes ago
f1h7a0vtojv18zrsiw8j0rzaw  my-test.2  nginx  node1         Running        Running 2 minutes ago
ex73ifk3jvzw8ukurl8yu7fyq  my-test.3  nginx  node1         Running        Running 2 minutes ago

可见三个节点都有处于running状态的任务,所以my-network网络扩展到三个节点上。

可以查询某个节点上关于my-network的详细信息:

$ docker network inspect ngx_net
[{
    
    
        "Name": "ngx_net",
        "Id": "3x2wgugr6zmn1mcyf9k1du27p",
        "Scope": "swarm",
        "Driver": "overlay",
        "EnableIPv6": false,
        "IPAM": {
    
    
            "Driver": "default",
            "Options": null,
            "Config": [
                {
    
    "Subnet":"10.10.19.0/24","Gateway":"10.10.19.1"
                }]
        },"Internal":false,"Containers": {
    
    "00f47e38deea76269eb03ba13695ec0b0c740601c85019546d6a9a17fd434663": {
    
    "Name":"my-test.5.btorxekfix4hcqh4v83dr0tzw","EndpointID":"ea962d07eee150b263ae631b8a7f8c1950337c11ef2c3d488a7c3717defd8601","MacAddress":"02:42:0a:0a:13:03","IPv4Address":"10.10.19.3/24","IPv6Address":""
            },"957620c6f7abb44ad8dd2d842d333f5e5c1655034dc43e49abbbd680de3a5341": {
    
    "Name":"my-test.4.cyu73jd8psupfhken23vvmpud","EndpointID":"f33a6e9ddf1dd01bcfc43ffefd19e19514658f001cdf9b2fbe23bc3fdf56a42a","MacAddress":"02:42:0a:0a:13:07","IPv4Address":"10.10.19.7/24","IPv6Address":""
            }},
        "Options": {
    
    
            "com.docker.network.driver.overlay.vxlanid_list": "257"},
        "Labels": {
    
    }
    }
]

从上面的信息可以看出在manager-node节点上,名为my-test的服务有一个名为my-test.5.btorxekfix4hcqh4v83dr0tzw和
my-test.4.cyu73jd8psupfhken23vvmpud的task连接到名为ngx_net的网络上(另外两个节点node1和node2同样可以用上面命令查看)

$ docker network inspect ngx_net
......."Containers": {
    
    "7d9986fad5a7d834676ba76ae75aff2258f840953f1dc633c3ef3c0efd2b2501": {
    
    "Name":"my-test.3.ex73ifk3jvzw8ukurl8yu7fyq","EndpointID":"957ca19f3d5480762dbd14fd9a6a1cd01a8deac3e8e35b23d1350f480a7b2f37","MacAddress":"02:42:0a:0a:13:06","IPv4Address":"10.10.19.6/24","IPv6Address":""
            },"9e50fceada1d7c653a886ca29d2bf2606debafe8c8a97f2d79104faf3ecf8a46": {
    
    "Name":"my-test.2.f1h7a0vtojv18zrsiw8j0rzaw","EndpointID":"b1c209c7b68634e88e0bf5e100fe03435b3096054da6555c61e6c207ac651ac2","MacAddress":"02:42:0a:0a:13:05","IPv4Address":"10.10.19.5/24","IPv6Address":""
            }},
.........
$ docker network inspect ngx_net
........
        "Containers": {
    
    
            "4bdcce0ee63edc08d943cf4a049eac027719ff2dc14b7c3aa85fdddc5d1da968": {
    
    
                "Name": "my-test.1.8433fuiy7vpu0p80arl7vggfe",
                "EndpointID": "df58de85b0a0e4d128bf332fc783f6528d1f179b0f9f3b7aa70ebc832640d3bc",
                "MacAddress": "02:42:0a:0a:13:04",
                "IPv4Address": "10.10.19.4/24",
                "IPv6Address": ""
            }
        },

可以通过查询服务来获得服务的虚拟IP地址,如下:

$ docker service inspect --format='{
    
    {json .Endpoint.VirtualIPs}}' my-test
[{
    
    "NetworkID":"7f4fx3jf4dbrp97aioc05pul4","Addr":"10.255.0.6/16"},{
    
    "NetworkID":"3x2wgugr6zmn1mcyf9k1du27p","Addr":"10.10.19.2/24"}]

由上结果可知,10.10.19.2其实就是swarm集群内部的vip,整个网络结构如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ljv91XfQ-1599615266560)(assets/907596-20170521012939869-251304626.png)]

加入ngx_net网络的容器彼此之间可以通过IP地址通信,也可以通过名称通信。

$ docker ps
CONTAINER ID    IMAGE           COMMAND                  CREATED         STATUS             PORTS    NAMES
4bdcce0ee63e    nginx:latest    "nginx -g 'daemon off"   22 minutes ago  Up 22 minutes      80/tcp   my-test.1.8433fuiy7vpu0p80arl7vggfe
$ docker exec -ti 4bdcce0ee63e /bin/bash
root@4bdcce0ee63e:/# ip addr                                                                                           
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
1786: eth0@if1787: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default
    link/ether 02:42:0a:ff:00:08 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.255.0.8/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet 10.255.0.6/32 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:aff:feff:8/64 scope link
       valid_lft forever preferred_lft forever
1788: eth1@if1789: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:12:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet 172.18.0.3/16 scope global eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::42:acff:fe12:3/64 scope link
       valid_lft forever preferred_lft forever
1791: eth2@if1792: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default
    link/ether 02:42:0a:0a:13:04 brd ff:ff:ff:ff:ff:ff link-netnsid 2
    inet 10.10.19.4/24 scope global eth2
       valid_lft forever preferred_lft forever
    inet 10.10.19.2/32 scope global eth2
       valid_lft forever preferred_lft forever
    inet6 fe80::42:aff:fe0a:1304/64 scope link
       valid_lft forever preferred_lft forever
 
root@4bdcce0ee63e:/# ping 10.10.19.3
PING 10.10.19.3 (10.10.19.3): 56 data bytes
64 bytes from 10.10.19.3: icmp_seq=0 ttl=64 time=0.890 ms
64 bytes from 10.10.19.3: icmp_seq=1 ttl=64 time=0.622 ms
.....-
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.622/0.756/0.890/0.134 ms
 
root@4bdcce0ee63e:/# ping 10.10.19.6
PING 10.10.19.6 (10.10.19.6): 56 data bytes
64 bytes from 10.10.19.6: icmp_seq=0 ttl=64 time=0.939 ms
64 bytes from 10.10.19.6: icmp_seq=1 ttl=64 time=0.590 ms

----------------------------使用swarm模式的服务发现--------------------------
默认情况下,当创建了一个服务并连接到某个网络后,swarm会为该服务分配一个VIP。此VIP根据服务名映射到DNS。在网络上的容器共享该服务的DNS映射,所以网络上的任意容器可以通过服务名访问服务

在同一个overlay网络中,不用通过端口映射来使某个服务可以被其它服务访问。Swarm内部的负载均衡器自动将请求发送到服务的VIP上,然后分发到所有的active的task上。

如下示例:在同一个网络中添加了一个centos服务,此服务可以通过名称my-test访问前面创建的nginx服务:

$ docker service create --name my-centos --network ngx_net centos        

查询centos运行在哪个节点上(上面创建命令执行后,需要一段时间才能完成这个centos服务的创建)

$ docker service ps my-centos
ID                         NAME             IMAGE   NODE   DESIRED STATE  CURRENT STATE            ERROR
e03pqgkjs3l1qizc6v4aqaune  my-centos.1      centos  node2  Running        Preparing 4 seconds ago

登录centos运行的节点(由上可知是node2节点):

$ docker ps
CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS            NAMES
e4554490d891        centos:latest            "/bin/bash"`             `About an hour ago   Up About an hour   my-centos.1.9yk5ie28gwk9mw1h1jovb68ki

打开centos的交互shell:

$ docker exec -ti my-centos.1.9yk5ie28gwk9mw1h1jovb68ki /bin/bash
root@4bdcce0ee63e:/# nslookup my-test
Server: 127.0.0.11
Address 1: 127.0.0.11
Name: my-test
Address 1: 10.10.19.2 10.10.19.2

从centos容器内部,使用特殊查询,查询DNS,来找到my-test服务的所有容器的IP地址:

root@4bdcce0ee63e:/# nslookup tasks.my-test
Server: 127.0.0.11
Address 1: 127.0.0.11
Name: tasks.my-test
Address 1: 10.10.19.4 my-test.1.8433fuiy7vpu0p80arl7vggfe
Address 2: 10.10.19.5 my-test.2.f1h7a0vtojv18zrsiw8j0rzaw
Address 3: 10.10.19.6 my-test.3.ex73ifk3jvzw8ukurl8yu7fyq
Address 2: 10.10.19.7 my-test.4.cyu73jd8psupfhken23vvmpud
Address 3: 10.10.19.3 my-test.5.btorxekfix4hcqh4v83dr0tzw

从centos容器内部,通过wget来访问my-test服务中运行的nginx网页服务器

root@4bdcce0ee63e:/# wget -O- my-test      
Connecting to my-test(10.10.19.2:80)
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...

Swarm的负载均衡器自动将HTTP请求路由到VIP上,然后到一个active的task容器上。它根据round-robin选择算法将后续的请求分发到另一个active的task上。

-----------------------------------为服务使用DNS round-robin-----------------------------
在创建服务时,可以配置服务直接使用DNS round-robin而无需使用VIP。这是通过在创建服务时指定 --endpoint-mode dnsrr 命令行参数实现的。当你想要使用自己的负载均衡器时可以使用这种方式。

如下示例(注意:使用DNS round-robin方式创建服务,不能直接在命令里使用-p指定端口)

$ docker service create --replicas 3 --name my-dnsrr-nginx --network ngx_net --endpoint-mode dnsrr nginx
$ docker service ps my-dnsrr-nginx
ID                         NAME              IMAGE  NODE          DESIRED STATE  CURRENT STATE          ERROR
65li2zbhxvvoaesndmwjokouj  my-dnsrr-nginx.1  nginx  node1         Running        Running 2 minutes ago 
5hjw7wm4xr877879m0ewjciuj  my-dnsrr-nginx.2  nginx  manager-node  Running        Running 2 minutes ago 
afo7acduge2qfy60e87liz557  my-dnsrr-nginx.3  nginx  manager-node  Running        Running 2 minutes ago

当通过服务名称查询DNS时,DNS服务返回所有任务容器的IP地址:

$ nslookup my-dnsrr-nginx 
Server:    127.0.0.11
Address 1: 127.0.0.11
Name:      my-dnsrr-nginx
Address 1: 10.10.19.10 my-dnsrr-nginx.3.0sm1n9o8hygzarv5t5eq46okn.my-network
Address 2: 10.10.19.9  my-dnsrr-nginx.2.b3o1uoa8m003b2kk0ytl9lawh.my-network
Address 3: 10.10.19.8  my-dnsrr-nginx.1.55za4c83jq9846rle6eigiq15.my-network

需要注意的是:一定要确认VIP的连通性。通常Docker官方推荐使用dig,nslookup或其它DNS查询工具来查询通过DNS对服务名的访问。因为VIP是逻辑IP,ping并不是确认VIP连通性的正确的工具。

单主机容器网络通信

不同网络间通信

不同网络之间加上路由就可以通信了。如果host上对每个网络都有一条路由,同时操作系统上打开了 ip forwarding,host就成了一个路由,挂接在不同网桥上的网络就能够相互通信。要看 docker host是否满足条件,通过 ip r 查看 host上的路由表:

$ ip r
default via 192.168.56.1 dev ens33 proto static metric 100 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 
172.18.0.0/16 dev docker_gwbridge proto kernel scope link src 172.18.0.1 
192.168.56.0/24 dev ens33 proto kernel scope link src 192.168.56.22 metric 100 

查看 ip forwarding是否开启:

$ sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1 #已开启

条件都满足,但为什么还不通?查看防火墙:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wrlDZMX2-1599615266562)(…/…/%E6%8A%80%E6%9C%AF%E5%AE%9E%E8%B7%B5%E7%AC%94%E8%AE%B0/%E5%9F%BA%E4%BA%8EDocker%E6%8A%80%E6%9C%AF%E5%AE%9E%E8%B7%B5/assets/1545620914843.png)]

从规则的命名 DOCKER-ISOLATION可知 docker 在设计上就是要隔离不同的network。那要怎么样才能让不同网络之间通信呢?

答案是为要被访问的容器添加一块网卡,这个可以通过docker network connect命令来实,如下:

$ docker network connect 要访问容器的所属网络 被访问容器id or name

这样就在被访问容器中添加了一块网卡提供在不同网络的容器之间的通信。

容器间通信

容器之间可通过IP,Docker DNS Server或joined容器三种方式通信。

IP通信

从不同网络间通信可以得出这样一个结论:两个容器要能通信,必须要属于同一个网络的网卡,也即在同一个网络中。满足这个条件后,容器间可以通过IP交互。具体做法是在容器创建时通过 --network指定相应的网络,或者通过docker network connect将现有容器加入到指定网络。

Docker DNS Server通信

通过IP访问容器虽然满足了通信的需求,但还是不够灵活。因为在部署应用之前可能无法确定IP,部署之后再指定要访问的IP会比较麻烦。对于这个问题,可以通过docker自带的DNS服务解决。

从 Docker 1.10版本开始,docker daemon 实现了一个内嵌的 DNS server,使容器可以直接通过“容器名”通信。方法很简单,只要在启动容器时用 --name 为容器命名就可以了。

下面启动两个容器container1 和 container2:

$ docker run -it --network=my-net1 --name=container1 image docker run -it --network=my-net2 --name=container2 image

然后,container2 可以直接ping 到container1了。

使用Docker DNS有一个限制:只能在user-defined网络中使用。也就是说,默认的bridge网络是无法使用DNS的。

joined 容器

joined 容器是一种实现容器间通信的方式。

joined 容器非常特别,它可以使两个或多个容器共享一个网络栈,共享网卡和配置信息,joined容器之间可以通过127.0.0.1直接通信。

joined 容器非常适合以下场景:

(1)不同容器中的程序希望通过loopback高效地通信,比如 Web Server 与 App Server。

(2)希望监控其他容器的网络流量,比如运行在独立容器中的网络监控程序。

容器与外部通信

容器与外部通信涉及两个方向:一个是容器访问外部世界;另一个是外部世界访问容器。

容器访问外部世界

容器默认就能访问外网,前提是docker host能访问外网。

注意:这里指的外网是容器网络以外的网络环境,并非特指 Internet。

现象很简单,当更重要的是理解现象下的本质。

当位于docker0这个私有bridge网络中的容器,从容器向外ping时,数据包是怎么样到达外面的呢?

这里的关键就是NAT。查看docker host上的 iptables规则:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7c0nqMHb-1599615266564)(assets/1545624758398.png)]

我们可以通过 tcpdump 查看地址是如何转换的。先查看 docker host的路由表:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jc58BksU-1599615266567)(assets/1545624849392.png)]

当在容器中 ping www.baidu.com 时,tcpdump输入如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L87xKPCu-1599615266569)(assets/1545625090391.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cEJdMBiw-1599615266571)(assets/1545625135821.png)]

外部世界访问容器

外网如何访问到容器?答案是通过端口映射。可映射到动态端口亦可指定端口。查看端口映射命令:

$ docker port container id or name

每一个映射的端口,host都会启动一个docker-proxy进程来处理访问容器的流量。查看命令:

$ ps -ef | grep docker-proxy

访问过程如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aNbHZ1ce-1599615266572)(assets/1545625667156.png)]

以上都的单个主机内的容器网络通信。

跨主机容器网络通信

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-celyiOZR-1599615266575)(assets/1545625858956.png)]

ln -s /var/run/docker/netns /var/run/netns

Service 之间如何通信?

微服务架构的应用由若干 service 组成。比如有运行 httpd 的 web 前端,有提供缓存的 memcached,有存放数据的 mysql,每一层都是 swarm 的一个 service,每个 service 运行了若干容器。在这样的架构中,service 之间是必然要通信的。

服务发现

一种实现方法是将所有 service 都 publish 出去,然后通过 routing mesh 访问。但明显的缺点是把 memcached 和 mysql 也暴露到外网,增加了安全隐患。

如果不 publish,那么 swarm 就要提供一种机制,能够:

  1. 让 service 通过简单的方法访问到其他 service。
  2. 当 service 副本的 IP 发生变化时,不会影响访问该 service 的其他 service。
  3. 当 service 的副本数发生变化时,不会影响访问该 service 的其他 service。

这其实就是服务发现(service discovery)。Docker Swarm 原生就提供了这项功能,通过服务发现,service 的使用者不需要知道 service 运行在哪里,IP 是多少,有多少个副本,就能与 service 通信。下面我们开始实践。

创建 overlay 网络

要使用服务发现,需要相互通信的 service 必须属于同一个 overlay 网络,所以我们先得创建一个新的 overlay 网络。

docker network create --driver overlay myapp_net

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cp3VKhTT-1599615266576)(assets/3f72f638e0.png)]

直接使用 ingress 行不行?

很遗憾,目前 ingress 没有提供服务发现,必须创建自己的 overlay 网络。

部署 service 到 overlay

部署一个 web 服务,并将其挂载到新创建的 overlay 网络。

docker service create --name my_web --replicas=3 --network myapp_net httpd

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MImFkgbZ-1599615266579)(assets/3f72e58e2a.png)]

部署一个 util 服务用于测试,挂载到同一个 overlay 网络。

docker service create --name util --network myapp_net busybox sleep 10000000

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8Of29Ocb-1599615266581)(assets/3f72f1dc2f.png)]

sleep 10000000 的作用是保持 busybox 容器处于运行的状态,我们才能够进入到容器中访问 service my_web

验证

通过 docker service ps util 确认 util 所在的节点为 swarm-worker1。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0xSkLOa7-1599615266583)(assets/3f72fcdd1c.png)]

登录到 swarm-worker1,在容器 util.1 中 ping 服务 my_web

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6a8zbiDg-1599615266584)(assets/3f731a840a.png)]

可以看到 my_web 的 IP 为 10.0.0.2,这是哪个副本的 IP 呢?

其实哪个副本的 IP 都不是。10.0.0.2my_web service 的 VIP(Virtual IP),swarm 会将对 VIP 的访问负载均衡到每一个副本。

我们可以执行下面的命令查看每个副本的 IP。

docker exec util.1.bpon0vvbgve6lz3fp08sgana6 nslookup tasks.my_web

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XR9hmWdp-1599615266586)(assets/3f731abd62.png)]

10.0.0.310.0.0.410.0.0.5 才是各个副本自己的 IP。不过对于服务的使用者(这里是 util.1),根本不需要知道 my_web副本的 IP,也不需要知道 my_web 的 VIP,只需直接用 service 的名字 my_web 就能访问服务。

Service 的访问就讨论到这里,下一节我们学习 Rolling Update。

部署微服务

关键问题描述:
在swarm mode 集群中,所有服务都挂接到自定义的overlay网络上,但是在服务注册到eureka的时候,会出现服务A注册到eureka时候,有些服务A的实例使用ingress网络地址,有些服务A的实例使用自定义的overlay网络地址。使用ingress网络地址的服务A实例不能被其他服务访问,例如:

[10.255.0.17:10.255.0.17:8091][10.255.0.16:10.255.0.16:8091][0fba7e6f8db1:10.0.2.11:8091]
10.255.xx.xx的是ingress网络地址,不能被其他服务访问
10.0.2.xx的是自创的overlay网络地址,可以被其他服务访问
原因:
如果服务对外公布了端口,那么服务就会被挂接到ingress网络,因此服务会使用有多个网卡(ingress的,自定义网络的),所以在服务注册时,需要指定使用的网卡(或通过网段)来确保服务的可访问性。

解决方案:
1.创建overlay网络时,指定网段:
docker network create -d overlay --subnet 10.0.3.0/24 springcloud-overlay
1
2.微服务指定网段:
eureka.instance.prefer-ip-address=true
spring.cloud.inetutils.preferred-networks=10.0.3
1
2
相同的问题:

https://stackoverflow.com/questions/43903496/swarm-networking-and-spring-cloud-apps

作者:timedifier2
来源:CSDN
原文:https://blog.csdn.net/timedifier2/article/details/78135970
版权声明:本文为博主原创文章,转载请附上博文链接!

Docker 存储

storage diver

Data Volume

DatavVolume 本质上是 Docker Host 文件系统中的目录或文件,能够直接被 mount 到容器的文件系统中。Data Volume 有以下特点:

(1)Data Volume 是目录或文件,而非没有格式化的磁盘(块设备)。

(2)容器可读写 volume 中的数据。

(3)volume数据可以被永久的保存,即使使用它的容器已经销毁。

现在我们有数据层(镜像层和容器层)和 volume 都可以存放数据,具体使用的时候要怎么选择?考虑下面几个场景:

(1)Database 软件 VS Database 数据。

(2)Web 应用 VS 应用产生的日志。

(3)数据分析软件 VS input/output 数据。

(4)Apache Server VS 静态 HTML 文件。

我们应该做出的选择是:

(1)前者放在数据层中。因为这部分内容是无状态的,应该作为镜像的一部分。

(2)后者放在 Data Volume 中。这是需要持久化的数据,并且应该与镜像分开存放。

bind mount

bind mount 是将 host 已存在的目录或文件 mount 到容器。

bind mount 可以让 host 与容器共享数据。这中管理上非常方便。即使容器销毁也不会对数据产生影响。

bind mount 可以指定数据的读写权限,默认可读可写,可指定为读。如下:

$ docker run -d -p 80:80 -v ~/htdocs:/usr/local/apache2/htdocs:ro httpd

ro 设置了只读权限,中容器中无法对 bind mount 数据进行修改。只有 host 有权修改数据,提高了安全性。

docker managed volume

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v6dojLNd-1599615266588)(assets/1545639595700.png)]

数据共享

Swarm 集群使用 compose

正如之前使用 docker-compose.yml 来一次配置、启动多个容器,在 Swarm 集群中也可以使用 compose文件 (docker-compose.yml) 来配置、启动多个服务。

上一节中,我们使用 docker service create 一次只能部署一个服务,使用 docker-compose.yml 我们可以一次启动多个关联的服务。

我们以在 Swarm 集群中部署 WordPress 为例进行说明。

version: "3"

services:
  wordpress:
    image: wordpress
    ports:
      - 80:80
    networks:
      - overlay
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
    deploy:
      mode: replicated
      replicas: 3

  db:
    image: mysql
    networks:
       - overlay
    volumes:
      - db-data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: somewordpress
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
    deploy:
      placement:
        constraints: [node.role == manager]

  visualizer:
    image: dockersamples/visualizer:stable
    ports:
      - "8080:8080"
    stop_grace_period: 1m30s
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
    deploy:
      placement:
        constraints: [node.role == manager]

volumes:
  db-data:
networks:
  overlay:

Swarm 集群管理节点新建该文件,其中的 visualizer 服务提供一个可视化页面,我们可以从浏览器中很直观的查看集群中各个服务的运行节点。

Swarm 集群中使用 docker-compose.yml 我们用 docker stack 命令,下面我们对该命令进行详细讲解。

部署服务

部署服务使用 docker stack deploy,其中 -c 参数指定 compose 文件名。

$ docker stack deploy -c docker-compose.yml wordpress

现在我们打开浏览器输入 任一节点IP:8080 即可看到各节点运行状态。如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LIGUw7gG-1599615266589)(assets/wordpress.png)]

在浏览器新的标签页输入 任一节点IP 即可看到 WordPress 安装界面,安装完成之后,输入 任一节点IP 即可看到 WordPress 页面。

查看服务

$ docker stack ls
NAME                SERVICES
wordpress           3

移除服务

要移除服务,使用 docker stack down

$ docker stack down wordpress
Removing service wordpress_db
Removing service wordpress_visualizer
Removing service wordpress_wordpress
Removing network wordpress_overlay
Removing network wordpress_default

该命令不会移除服务所使用的 数据卷,如果你想移除数据卷请使用 docker volume rm

总结

总之,Swarm上手很简单,Docker swarm可以非常方便的创建类似kubernetes那样带有副本的服务,确保一定数量的容器运行,保证服务的高可用。
然而,光从官方文档来说,功能似乎又有些简单;

swarm、kubernetes、messos总体比较而言:
1)Swarm的优点和缺点都是使用标准的Docker接口,使用简单,容易集成到现有系统,但是更困难支持更复杂的调度,比如以定制接口方式定义的调度。
2)Kubernetes 是自成体系的管理工具,有自己的服务发现和复制,需要对现有应用的重新设计,但是能支持失败冗余和扩展系统。
3)Mesos是低级别 battle-hardened调度器,支持几种容器管理框架如Marathon, Kubernetes, and Swarm,现在Kubernetes和Mesos稳定性超过Swarm,在扩展性方面,Mesos已经被证明支持超大规模的系统,比如数百数千台主机,但是,如果你需要小的集群,比如少于一打数量的节点服务器数量,Mesos也许过于复杂了。

跨 docker host 部署

网络互通

docker swarm 集群跨主机网络通信

不同主机不同网络间通信

不同主机容器间通信。

集群环境不同主机间网络通信。

非集群环境下不主机间网络通信。

容器外部通信。通过对外暴露端口实现不同主机、不同网络、不同容器间通信。

创建overlay网络

为什么需要overlay 网络?保证多台机器不同容器之间通信!

$ docker network create --attachable --driver overlay ry-net

注:--attachable 参数为了兼容单机的容器可以加入此网络。

docker swarm 集群里面服务之间无法调用

1)部署operation-service 2个点后,到注册中心一看,只有一个点,地址是10.255.0.4,
2)进入容器发现有多个网卡,10.255.0.4这个网址在2个点都有,正确的应该是10.0.0.7

3)如何选择ip参考
http://www.mamicode.com/info-detail-1873672.html
具体的几个配置参考

spring-cloud-commons项目为Spring Cloud生态提供了顶层的抽象和基础设施的实现。
网络这个最基本的基础设施也是在这里有对应的实现:InetUtils、InetUtilsProperties和UtilAutoConfiguration提供了网络配置相关的功能。

spring-cloud-commons项目为Spring Cloud生态提供了顶层的抽象和基础设施的实现。 
网络这个最基本的基础设施也是在这里有对应的实现:InetUtils、InetUtilsProperties和UtilAutoConfiguration提供了网络配置相关的功能。

spring.cloud.inetutils.default-hostname
spring.cloud.inetutils.default-ip-address
spring.cloud.inetutils.ignored-interfaces
spring.cloud.inetutils.preferred-networks
spring.cloud.inetutils.timeout-seconds
spring.cloud.inetutils.use-only-site-local-interfaces

需要解释一下的是ignored-interfaces和preferred-networks这两个配置。这两个配置决定了spring cloud应用在启动的时候所使用的网卡和IP地址。ignored-interfaces接收一个正则表达式数组,配置名字虽然是ignored-interfaces,忽略的网卡,但是因为其接收的是正则表达式,所以我们可以任意的选择和反选本机的网卡。preferred-networks是指倾向于使用的IP地址,接收一个正则表达式数组,用于选择Spring Cloud应用使用的本机的IP地址。通过这两个配置,我们可以任意指定Spring Cloud应用使用的网卡和IP地址。

4)最终一种巧妙的解决办法,配置ip选择参数:

spring.cloud.inetutils.preferred-networks=none 
#none或随便其它非ip字符串则导致一个都ip都匹配不上! 
#最终结果让其忽略所有网卡ip,这样最终会取本地host:InetAddress.getLocalHost(); 
#这个跟/etc/hosts 配置的一样,所以OK了。 附: 
#前缀匹配10.0.0开头的ip 
spring.cloud.inetutils.preferred-networks=10.0.0 
#正则允许所以ip 
spring.cloud.inetutils.preferred-networks=.+

健康检查与回滚

健康检查可以保证一个节点启动完毕才会启动另一个节点

$ docker service update –force –detach=false\ 
–health-cmd “curl –fail http://127.0.0.1:8820/startup-status?p=0 || exit 1” \ 
–health-interval 5s\ 
–health-retries=20 \ 
–health-timeout 2s\ 
gateway 

1)url必须返回0,表示成功;curl一般用127.0.0.1和内部端口,用实际ip不行(因为命令是在docker里面执行的 )
2)上面表示每5秒执行一次,每次2秒超时,一共尝试20次。 超时必须设置大一些,否则超时后会不断重启
3)如果url错误导致启动失败可以–no-healthcheck 恢复:
docker service update –force –detach=false –no-healthcheck gateway

加上回滚参数:

如下面把端口8820改成8830肯定curl是会失败,则会回滚:

$ docker service update  --force --detach=false\
  --health-cmd "curl --fail http://127.0.0.1:8830/startup-status?p=0  || exit 1" \
    --health-interval 5s\
    --health-retries=20 \
    --health-timeout 2s\
    --update-failure-action rollback\
      gateway

–update-failure-action Action on update failure (“pause”|”continue”|”rollback”)
缺省是paused

这个比–update-delay duration 保险,–update-delay 只是是两个点启动间隔,只是大概估计的时间,所以在健康检查上面的基础上加个几秒即可:–update-delay 5s

启动超时
加入健康检查后,如果重试若干次后超时,则会导致容器不断重启!!加入 restart-condition=none 来避免。

猜测:是app正常启动后有问题会触发update-failure-action;如果程序还没启动完就超时则触发restart-conditionjava

数据存储

数据存储分有状态和无状态数据存储,有状态数据根据实际情况统一放入镜像存储,有状态数据统一放入volume。

有状态数据的服务尽量不放入 docker swarm 集群,以避免带来数据维护的难度,在容器宕机、崩溃、升级、迁移、销毁过程中造成可能数据丢失的可能。

应用数据三种存储方式的选择:

第一种 bind mount。须要指明挂载源 mount src,该源在 docker host 必须存在。

第二种docker managed volume。不须要指明挂载源 mount src,只须要指明容器的挂载点即可。默认源在docker的数据卷目录:/var/lib/docker目录下。

第三种是云存储服务。数据存储到云端。

资源限制

根据资源要求限定内存和CPU。中发布部署微服务的时候可以限定服务的内存(MEMORY)、存储(BLOCK)和处理器(CPU)资源。

微服务结构划分

  • demo :demo微服务,它本身包含了两个模块,demo-api提供给第三方使用的接口;demo-service是服务的具体实现。
    为什么每个微服务多加了一层目录结构呢?因为从微服务职责划分来说,不同团队负责不同的微服务开发,每个微服务独立成项目,代码可以随时分离,不混合在一起。

  • client : 客户端调用服务。

  • 因为需要用到Feign,所以引入Feign依赖即可。
    **在pom文件中,还要引入spring-boot-thin-layout 一个很重要的maven插件。**因为spring boot 缺省是编译成fat jar(60m左右),而api是要打成jar包给第三方使用的,如果打成一个spring boot结构的fat jar,第三方肯定无法使用了,所以引入了这个maven插件,会把api打成一个我们普通使用的jar包(可能就10多K),这样才能真正实现接口跟逻辑分离的效果。

  • 调用服务。可以看到,在pom.xml 引入demo-api后,通过
    “@Autowired private Demo1Service demo1Service;” 方式,就像调用本地bean一样调用微服务。用户只要引入api jar包就行,不用关心服务部署在哪台机器,也不用care怎样拼接URL去调用服务,这是不是很符合java面向对象开发的要求?

  • 一个服务开发的流程是这样的:
    服务器端:在api模块定义服务接口,在service模块实现服务。
    客户端:直接依赖api jar包即可调用服务,无须了解调用服务器地址和具体的URL。

    例如对于user微服务,服务器端由user-api 和user-service两个模块,开发完后,user-api发布到maven服务器成user-api-1.0.0.jar;
    客户端直接依赖user-api-1.0.0.jar,引用服务接口就可以调用服务。
    注意user-api-1.0.0.jar是一个非常轻量级的jar包,只包含了interface和一些实体类定义,一般不会有微服务实现的代码逻辑。如果是使用这种方式的话,那hystrix配置在什么地方呢?

client 服务消费者。服务消费者负责对服务接口的消费,不关心接口如何实现。

api 服务接口。不关心服务具体的实现者与提供者或生产者是谁,只负责对外提供接口服务。

provider 服务实现与提供者或生产者。负责对接口的实现,即服务的实际生产者或提供者。负责业务逻辑的处理和数据的读写与存储。

参考资料

Docker集群管理工具-Kubernetes部署记录

http://www.cnblogs.com/kevingrace/p/6870359.html

生产环境中使用Docker Swarm的一些建议

https://blog.fundebug.com/2017/05/08/docker-swarm-suggestion/

Spring cloud + Swarm mode 实战二:部署微服务

https://blog.csdn.net/timedifier2/article/details/78135970

Service 之间如何通信?- 每天5分钟玩转 Docker 容器技术(101)

https://www.ibm.com/developerworks/community/blogs/132cfa78-44b0-4376-85d0-d3096cd30d3f/entry/Service_%E4%B9%8B%E9%97%B4%E5%A6%82%E4%BD%95%E9%80%9A%E4%BF%A1_%E6%AF%8F%E5%A4%A95%E5%88%86%E9%92%9F%E7%8E%A9%E8%BD%AC_Docker_%E5%AE%B9%E5%99%A8%E6%8A%80%E6%9C%AF_101?lang=en

Docker Swarm容器集群管理工具

**

  • client : 客户端调用服务。

  • 因为需要用到Feign,所以引入Feign依赖即可。
    **在pom文件中,还要引入spring-boot-thin-layout 一个很重要的maven插件。**因为spring boot 缺省是编译成fat jar(60m左右),而api是要打成jar包给第三方使用的,如果打成一个spring boot结构的fat jar,第三方肯定无法使用了,所以引入了这个maven插件,会把api打成一个我们普通使用的jar包(可能就10多K),这样才能真正实现接口跟逻辑分离的效果。

  • 调用服务。可以看到,在pom.xml 引入demo-api后,通过
    “@Autowired private Demo1Service demo1Service;” 方式,就像调用本地bean一样调用微服务。用户只要引入api jar包就行,不用关心服务部署在哪台机器,也不用care怎样拼接URL去调用服务,这是不是很符合java面向对象开发的要求?

  • 一个服务开发的流程是这样的:
    服务器端:在api模块定义服务接口,在service模块实现服务。
    客户端:直接依赖api jar包即可调用服务,无须了解调用服务器地址和具体的URL。

    例如对于user微服务,服务器端由user-api 和user-service两个模块,开发完后,user-api发布到maven服务器成user-api-1.0.0.jar;
    客户端直接依赖user-api-1.0.0.jar,引用服务接口就可以调用服务。
    注意user-api-1.0.0.jar是一个非常轻量级的jar包,只包含了interface和一些实体类定义,一般不会有微服务实现的代码逻辑。如果是使用这种方式的话,那hystrix配置在什么地方呢?

client 服务消费者。服务消费者负责对服务接口的消费,不关心接口如何实现。

api 服务接口。不关心服务具体的实现者与提供者或生产者是谁,只负责对外提供接口服务。

provider 服务实现与提供者或生产者。负责对接口的实现,即服务的实际生产者或提供者。负责业务逻辑的处理和数据的读写与存储。

参考资料

Docker集群管理工具-Kubernetes部署记录

http://www.cnblogs.com/kevingrace/p/6870359.html

生产环境中使用Docker Swarm的一些建议

https://blog.fundebug.com/2017/05/08/docker-swarm-suggestion/

Spring cloud + Swarm mode 实战二:部署微服务

https://blog.csdn.net/timedifier2/article/details/78135970

Service 之间如何通信?- 每天5分钟玩转 Docker 容器技术(101)

https://www.ibm.com/developerworks/community/blogs/132cfa78-44b0-4376-85d0-d3096cd30d3f/entry/Service_%E4%B9%8B%E9%97%B4%E5%A6%82%E4%BD%95%E9%80%9A%E4%BF%A1_%E6%AF%8F%E5%A4%A95%E5%88%86%E9%92%9F%E7%8E%A9%E8%BD%AC_Docker_%E5%AE%B9%E5%99%A8%E6%8A%80%E6%9C%AF_101?lang=en

Docker Swarm容器集群管理工具

https://jiayi.space/post/docker-swarmrong-qi-ji-qun-guan-li-gong-ju

猜你喜欢

转载自blog.csdn.net/pointdew/article/details/108482628
今日推荐