容器编排介绍(Swarm Mode)

我们之前的学习创建的容器都是在一台机器上的,但是实际生产环境中,我们创建的容器不可能都是在一台机器上的,而是在多台物理机器上。在生产环境中我们要部署一个应用,可能涉及很多个容器,而且这些容器不可能都部署在一台机器上,那么我们就需要解决一系列问题,比如:

  1. 怎么去管理这么多容器
  2. 怎么方便的横向扩展
  3. 如果容器down了,怎么自动恢复
  4. 如何去更新容器而不影响业务
  5. 如何去监控追踪这些容器
  6. 如何去调度容器的创建
  7. 如何保护隐私数据

Swarm介绍

Swarm就是做容器编排的一个工具,用于容器服务的创建删除等操作和调度,它用来解决上述问题,它是Docker内置的一个工具,但是我们要注意,容器编排的工具并不是Swarm一个,只是Docker内置的是这个,不需要安装任何其他的东西。

Swarm是一个集群的架构,它有两种角色,Manager和Worker。Manager是整个集群的大脑,一般至少要有两个机器,Worker就是实际容器的运行的节点,当然Manager节点也可以运行我们的业务容器,但是一般我们都是部署在Worker节点。

Service:Swarm中一个非常重要的概念,我们Swarm环境下的Service的概念基本和Compose中的Service是一样的,一个Service就代表了一个容器。

Replicas:作为容器横向扩展时的概念,就是我们部署一个service时,通过scale指定部署的容器个数时,我们每一个容器就是作为了一个Replica,可以理解为同一个容器的多个副本,但是这里不存在主分片的概念。

Swarm的应用

创建Swarm集群

我们这里只讲述生产环境中多个机器的Swarm的创建方式。

  1. 创建Swarm节点,方法是在一个安装了Docker环境的机器上通过命令:

docker swarm init –advertise=[本机IP地址]

我们先运行此命令的节点将会成为Manager节点,运行此命令后,终端会输出如果要添加Manager节点和添加Worker节点的命令,我们要添加此集群的节点,就复制此对应的命令,然后到另外的机器上执行即可

  1. 创建Worker节点,将上述输出的添加Worker命令粘贴,进入另外的机器(可以是多个),执行即可

  2. 我们可以在Manager节点通过命令:docker node ls 查看此集群下的所有节点信息

在swarm集群环境service操作

  1. 我们docker service的创建有点类似于docker run,但是我们在searm模式下就不用docker run命令了,因为docker run只是用于在本地创建docker容器,创建命令如下:

docker service create –name [service名称] [Image名称]

  1. 我们可以通过命令查看创建的容器信息,此信息会展示容器的Replicas数量等:

docker service ls

  1. 查看到service信息后,我们可以查看每个容器具体的部署信息,比如部署在哪个节点,状态等,通过如下命令:

docker service ps [service名称]

  1. 我们创建完成后就可以通过scale来进行容器数量的横向扩展,使用命令:

docker service scale [service名称]=[容器的总数量]

执行完成后,我们通过ls命令,查看到的service信息,Replicas的数量就是我们设置的容器总数量了,并且我们通过ps命令查看到每个容器的部署是平均的分配在了不同的机器上

  1. 上述创建的容器我们说会平均分布在不同的机器上,如果此时我们有一个机器down掉了或者我们手动将容器给停止了,我们发现过一会在通过ls命令查看的容器数量还是5,这是因为它又新扩展了一个容器在其他的机器上。这就证明scale它不仅仅是横向扩展的功能,而且它能保证横向扩展的数目是稳定有效的,当其中容器down掉之后,他们 检测到然后立即创建新的容器保证扩展的数量

  2. service的删除,我们service的删除使用如下命令,删除后会将此service下所有的容器都回收掉:

docker service rm [service名称]

Swarm网络

示例及现象介绍

首先我们搭建一个三台机器的swarm集群,有一个Manager节点和两个Worker节点,然后我们部署wordpress和mysql应用,我们在部署前创建驱动类型为 overlay 的Network Namespace,然后创建mysql和wordpress的service,并且在创建的时候通过 -p 参数指定wordpress的端口映射,使得我们可以向外部提供服务,在创建的时候指定此两个service使用的Network Namespace(具体方式与run启动指定参数一样),使他们之间可以直接通过service名称就能实现网络互通,完成我们的应用部署。

注意:我们如果要保证本机之间的容器通信,需要使用bridge驱动类型的Network,但是如果是多机之间的通信,需要使用overlay驱动类型的Network

以上出现的现象是:

  1. 我们之前挨Manager节点上创建的驱动类型为 overlay 的Network Namespace,在其他的两个Worker机器节点上也能看到并且存在

  2. 我们的mysql service容器部署在了manager机器上,wordpress service容器部署在了其中一台Worker节点上,但是我们通过我们映射好的端口,通过任何一个swarm集群机器的ip加此映射好的端口,都能访问到我们的workpress服务

Rounting Mesh的两种体现

Docker Swarm的网络技术

Internal Network

针对于Swarm service之间的访问及负载均衡,我们同一个Swarm中的容器之间是怎么通信的,他们是用过service名称来进行通信的,我们service名称对应的IP地址并不是容器的具体地址,因为我们某一个service下可能会通过scale创建多个容器,并且容器扩增或删除都会造成service下容器IP地址的变化,所以我们肯定不是直接通过容器的IP地址进行通信的,我们service名称对应的IP地址是一个VIP,就是一个虚拟IP,如果我们的横向容器扩展了之后,VIP是不会变化的,并且它会对我们的访问做负载均衡,这就是VIP的主要作用和Swarm的网络访问实现。

Internal Load Balancing,既我们通过service名称访问的容器它是通过VIP访问的,VIP会自动负载均衡到请求的不同的容器节点上去,它是基于LVS来实现的,LVS是一个很牛的中国大佬写的,已经加入到Linux内核中了,详细google或baidu了解。

Ingress Network

针对于外部访问的负载均衡,我们某个service绑定了对外的端口,这个service可能只是部署在了我们Swarm集群中的部分节点,但是我们在Swarm中的任何一个机器节点都可以通过此机器IP加端口都能访问到此容器的服务,它就是使用了Ingress网络。

Docker Stack

Docker Stack及对于一个应用包含的多个容器进行统一管理的工具,它与Docker Compose的作用及使用类似,不同的是compose是应用于单机环境的,而Stack是应用于Swarm下的多机环境的。

Docker Stack的使用也是使用docker-compose.yml文件来定义的,此文件的格式与之前介绍的compose定义一样,只不过添加了deploy参数,此参数下定义的内容有非常多,包括service部署更新等策略,容器的数量、内存CPU的使用限制等非常多,具体我们可以通过官网去查看。

docker stack 命令参数说明:

  • deploy:部署或更新stack,使用示例:docker stack depoly [指定stack名称] –compose-file=docker-compose.yml

  • ls:列举出当前所有stack及每个stack中包含的services个数,使用示例:docker stack ls

  • ps:查询指定stack的详细信息,包括容器部署的节点、状态、使用的image等信息,使用示例:docker stack ps [指定stack名称]

  • rm:删除指定的stack,使用示例:docker stack rm [指定stack名称]

  • services:列举出当前stack中包含的所有service,以及service的副本数量等信息,使用示例:docker stack services [指定stack名称]

docker-compose.yml文件示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
version: '3'

services:

web:
image: wordpress
ports:
- 8080:80
environment:
WORDPRESS_DB_HOST: mysql
WORDPRESS_DB_PASSWORD: root
networks:
- my-network
depends_on:
- mysql

# web的service stack配置
deploy:
# 部署模式-多例
mode: replicated
# 容器分片数量
replicas: 3
# 重启策略
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
# 更新策略
update_config:
# 更新时同时进行的容器数量
parallelism: 1
delay: 10s

mysql:
image: mysql
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: wordpress
volumes:
- mysql-data:/var/lib/mysql
networks:
- my-network

# mysql的service stack配置
deploy:
# 部署模式-单例
mode: global
placement:
# 容器部署的节点位置,指定部署在manager机器上
constraints:
- node.role == manager

# 一个可视化的stack工具,访问此端口可以通过可视化的界面查看具体的stack信息
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:
mysql-data:

# 指定使用的网络驱动
networks:
my-network:
driver: overlay

Docker Secret管理

什么是Secret,主要是指一下内容:

  1. 用户名密码
  2. SSH Key
  3. TLS认证
  4. 任何不想让别人看到的数据

我们之前在讲Swarm时说过,在Manager节点之间,它们有一个内置的分布式存储, 它们是基于Raft协议来同步数据的,保证他们之间的信息时实时共享同步的。

Secret Management

  1. Secret都是存储在Swarm 的 Manager节点,存储在Raft database中的,都是加密的

  2. Secret可以assign给一个service,在这个service中就可以看到这个secret

  3. 在container内部Secret看起来像文件,但实际是在内存中的

Secret的具体操作使用

Secret的创建

首先介绍查看Secret的命令: docker secret ls,表示查看当前环境中的Secret

创建有两种方式,一种是从一个文件中创建,一种是从标准的输入中创建。

  1. 我们首先创建一个文件,然后再文件中写入我们的Secret内容,例如密码等内容,然后我们通过命令:docker secret create [secret名称] [文件路径名称],这样我们就创建完成,一般我们通过文件创建好secret后,就把我们的文件删除掉,这是为了保护我们的隐私数据。创建完成我们就可以通过ls命令来查看创建的Secret。

  2. 通过标准输入创建,使用示例如下:echo “secret具体内容” | docker secret create [secret名称] -,这样我们就创建完成了,可以通过ls命令查看了

Secret的删除

使用命令:docker secret rm [secret名称]

将Secret暴露给Service容器来使用

我们在创建service容器时,指定一下即可,例如:

1
2
3
4
5
6
7
8
9
# 1.创建容器并指定要应用的Searet
docker service create --name [service名称] --secret [要使用的之前在Manager节点创建好的secret名称] [image名称]

# 2.进入创建好的容器
docker exec -it [容器ID] /bin/bash

# 3.进入 /run/secret 目录并查看文件,我们发现有一个文件跟我们指定的Secret名称一样,查看后发现内部的内容就是我们之前定义好的内容
cd /run/secret
ls

具体使用例如我们创建一个MySQL容器,并且创建时指定root用户的密码,具体使用命令如下:

1
docker service create --name [mysql service 名称] --secret [要使用的之前在Manager节点创建好的secret名称] -e MYSQL_ROOT_PASSWORD_FILE=/run.secret/[之前在Manager节点创建好的secret名称] [mysql image名称]

Searct在stack中的应用

应用原理其实与上述暴露给service中一样,只不过我们将一些命令直接写在了docker-compose.yml文件中,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# 1.首先通过上述方式在Manager节点创建好Secret

# 2.docker-compose.yml文件中引入应用
version: '3'

services:

web:
image: wordpress
ports:
- 8080:80

# 定义我们要引入的secret
secrets:
- my-pw

# 环境变量应用我们引入的secret
environment:
WORDPRESS_DB_HOST: mysql
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/my-pw

networks:
- my-network
depends_on:
- mysql
deploy:
mode: replicated
replicas: 3
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
update_config:
parallelism: 1
delay: 10s

mysql:
image: mysql

# 定义我们要引入的secret
secrets:
- my-pw

# 环境变量应用我们引入的secret
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/my-pw
MYSQL_DATABASE: wordpress

volumes:
- mysql-data:/var/lib/mysql
networks:
- my-network
deploy:
mode: global
placement:
constraints:
- node.role == manager

volumes:
mysql-data:

networks:
my-network:
driver: overlay

# 我们可以不再先前就创建好secret,可以定义一个文件在创建service时引入文件创建,但是这种做法不安全,所以我们不推荐(一般还是先创建好)
# secrets:
# my-pw:
# file: ./password

Service的更新

本节讲述的是对Swarm中运行的service进行升级,我们需要实现的是不宕机的升级,参照现在的生产环境服务升级。

Service的更新可以更新很多内容,例如Secret,暴露的端口,image等。

普通方式更新

  1. 更新image,当我们的servcie使用scale创建了多个实例的时候,我们使用如下命令更新服务,发现容器更新是逐个进行的,可以表述为优雅上下线,命令如下:

更新服务使用命令: docker service update –image [更新的新的image名称] [service名称]

  1. 更新端口,命令如下(同理更新secret):

docker service update –pulish-rm 8080:5000 –pulish-add 8088:5000 [service名称]

stack模式下的更新

stack模式下的更新我们只需要修改 docker-compose.yml 文件的内容,然后重新发布就自动完成了更新,而且更新的过程更上述一样,都是优雅的。

例如我们要升级服务更新image,只需要修改 docker-compose.yml 中对应的serivce中对应的iamge即可,更新其他内容也一样,只需要修改此文件,然后直接 depoly 即可。

最后更新: 2020年06月14日 14:51

原始链接: https://jjw-story.github.io/2020/06/06/Docker-Swarm/

× 请我吃糖~
打赏二维码