17 、什么是 stack ?
在将这个之前先回顾一下前面部署WordPress的过程:
1、创建secret
2、创建mysql service
3、创建WordPress service
也就是说,这个应用包含了两个service ; mysql + wordpress 。他们之间有明确的依赖关系,必须先启动mysql。
为了保证这个依赖关系,我们控制了 docker secret 和 docker service 命令的执行顺序,只不过这个过程是手工完成的。
假如我们需要频繁的在不同环境中部署WordPress应用,如果每次都手工执行效率就太低了,而且容器出错误。这是自动化的一个好机会,首先我们把这个工程写成一个自动化的脚本。
#!/bin/bash
# 第一步:创建 secret
openssl rand -base64 20 | docker secret create mysql_root_password -
openssl rand -base64 20 | docker secret create mysql_password -
# 第二步: 创建Mysql service
docker network create --driver overlay mysql_private
docker service create --name mysql --network mysql_private --secret source=mysql_root_password,target=mysql_root_password --secret source=mysql_password,target=mysql_password -e MYSQL_ROOT_PASSWORD_FILE='/run/secrets/mysql_root_password' -e MYSQL_PASSWORD_FILE='/run/secrets/mysql_password' -e MYSQL_USER='wordpress' -e MYSQL_DATABASE='wordpress' mysql:5.7
# 第三步 创建wordpress service
docker service create --name wordpress --network mysql_private --publish 80:80 --secret source=mysql_password,target=wp_db_password -e WORDPRESS_DB_HOST='mysql:3306' -e WORDPRESS_DB_NAME='wordpress' -e WORDPRESS_DB_USER='wordpress' -e WORDPRESS_DB_PASSWORD_FILE='/run/secrets/wp_db_password' wordpress
这个脚本大体上能够工作,实现了自动化,但是有两个缺点:
1、目前只有两个service,还比较简单,现在的应用通常包含多个service,特别是采用 microservices 架构的应用,几十个service是很正常。用shell脚本启动和管理如此多的service将是一件非常有挑战的任务。
2、我们还要维护service之间的依赖关系,比较容易出错。而且如何判断service正常运行也不是一件容易的事情,不光要看service是否存在,还要考虑service的实际运行状态。
我们希望有一种更高效和可靠的方法来部署基于service的应用,这就是stack。
stack 包含一系列 service,这些 service 组成了应用。stack 通过一个 YAML 文件定义每个 service,并描述 service 使用的资源和各种依赖。
WordPress的stack版本
version: '3.1'
services:
db:
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_root_password
- db_password
wordpress:
depends_on:
- db
image: wordpress:latest
ports:
- "80:80"
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
secrets:
db_password:
file: db_password.txt
db_root_password:
file: db_root_password.txt
volumes:
db_data:
1、service 中定义了两个 service : db 和 wordpress
2、secret 定义了两个 secret: db_password 和 db_root_password ,在 service db 和 wordpress 的定义中引用了这两个secret
3、volume定义了一个volume: db_data ,service db 使用了这个volume
4、wordpress 通过了 depends_on 指定自己依赖 db 这个 service 。 Docker 会保证 当 db 正常运行后再启动 wordpress
可以在YAML 中定义的元素远不止这些,完成的列表和使用方法可参考文档 https://docs.docker.com/compose/compose-file/
18、如何使用stack
定义好了 stack YAML 文件,就可以通过 docker stack deploy 命令部署应用,命令最后面的wpstack 是自动创建各项资源的前缀,方便区分不同的环境
[root@swarm-manager ~]# openssl rand -base64 20 > db_password.txt
[root@swarm-manager ~]# openssl rand -base64 20 > db_root_password.txt
[root@swarm-manager ~]# docker stack deploy -c wp.yaml wpstack # 部署stack
Creating network wpstack_default
Creating secret wpstack_db_root_password
Creating secret wpstack_db_password
Creating service wpstack_db
Creating service wpstack_wordpress
[root@swarm-manager ~]#
[root@swarm-manager ~]# docker stack ls # 查看stack list
NAME SERVICES ORCHESTRATOR
wpstack 2 Swarm
[root@swarm-manager ~]# docker stack services wpstack # 查看某stack包含的service list
ID NAME MODE REPLICAS IMAGE PORTS
3obhxvyqqd96 wpstack_wordpress replicated 1/1 wordpress:latest *:80->80/tcp
xui2gtvbzdpt wpstack_db replicated 1/1 mysql:5.7
[root@swarm-manager ~]#
[root@swarm-manager ~]# docker service ps wpstack_db # 查看 **_db service
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
ebbtxvgrvgzf wpstack_db.1 mysql:5.7 swarm-worker2 Running Running about a minute ago
[root@swarm-manager ~]# docker service ps wpstack_wordpress # 查看 **_wordpress service
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
q4zbhhs2nl7d wpstack_wordpress.1 wordpress:latest host02 Running Running 33 seconds ago
访问 http://[swarm-manager-ip] 验证部署结果
[root@swarm-manager ~]# sed -i 's/80:80/81:80/' wp.yaml # 修改wordpress对外端口号
[root@swarm-manager ~]# docker stack deploy -c wp.yaml wpstack # 更新stack 配置
Updating service wpstack_db (id: wpi8ieo8k89z46ahxuwbnu357)
Updating service wpstack_wordpress (id: 60gocweop7sytwa5eab7zffkf)
[root@swarm-manager ~]# docker stack ls
NAME SERVICES ORCHESTRATOR
wpstack 2 Swarm
[root@swarm-manager ~]# docker stack services wpstack
ID NAME MODE REPLICAS IMAGE PORTS
60gocweop7sy wpstack_wordpress replicated 1/1 wordpress:latest *:81->80/tcp
wpi8ieo8k89z wpstack_db replicated 1/1 mysql:5.7
[root@swarm-manager ~]# docker service ps wpstack_db
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
lmpt206stwnl wpstack_db.1 mysql:5.7 host02 Running Running 3 minutes ago
[root@swarm-manager ~]# docker service ps wpstack_wordpress # 可以看到新建并启动了一个副本
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
nqpzyhi353qt wpstack_wordpress.1 wordpress:latest host01 Running Running 45 seconds ago
q4zbhhs2nl7d \_ wpstack_wordpress.1 wordpress:latest host02 Shutdown Shutdown 47 seconds ago
访问 http://[swarm-manager-ip] 验证部署结果
root@host03:~# docker stack rm wpstack # 删除stack
Removing service wpstack_db
Removing service wpstack_wordpress
Removing secret wpstack_db_password
Removing secret wpstack_db_root_password
Removing network wpstack_default
如果想更新stack的某些属性,直接修改 YAML文件即可,然后再次执行上面的命令。
19、stack 的优势
stack 将应用所包含的 service,依赖的 secret、voluem 等资源,以及它们之间的关系定义在一个 YAML 文件中。相比较手工执行命令或是脚本,stack 有明显的优势。
-
YAML 描述的是
What
,是 stack 最终要达到的状态。
比如 service 有几个副本?使用哪个 image?映射的端口是什么?而脚本则是描述如何执行命令来达到这个状态,也就是How
。显而易见,What
更直观,也更容易理解。至于如何将What
翻译成How
,这就是 Docker swarm 的任务了,用户只需要告诉 Docker 想达到什么效果。 -
重复部署应用变得非常容易。
部署应用所需要的一切信息都已经写在 YAML 中,要部署应用只需一条命令docker stack deploy
。stack 的这种自包含特性使得在不同的 Docker 环境中部署应用变得极其简单。在开发、测试和生成环境中部署可以完全采用同一份 YAML,而且每次部署的结果都是一致的。 -
可以像管理代码一样管理部署。
YAML 本质上将应用的部署代码化了,任何对应用部署环境的修改都可以通过修改 YAML 来实现。可以将 YAML 纳入到版本控制系统中进行管理,任何对 YAML 的修改都会被记录和跟踪,甚至可以像评审代码一样对 YAML 执行 code review。应用部署不再是一个黑盒子,也不再是经验丰富的工程师专有的技能,所以的细节都在 YAML 中,清晰可见。
20、删除搭建好的Docker Swarm集群
1.删除创建的服务
[root@server1 ~]# docker service rm viz #在manager节点上删除创建好的viz服务。
[root@server1 ~]# docker service rm web #在manager节点上删除创建好的web服务。那么运行的容器也会相应的停止
[root@server1 ~]# docker ps #查看manager节点上运行的容器,发现之前运行的容器已经不存在了
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@server2 ~]# docker ps #查看node节点上(server2)上运行的容器,发现之前运行的容器已经不存在了
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@server3 ~]# docker ps #查看node节点上(server3)上运行的容器,发现之前运行的容器已经不存在了
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2.各个节点离开集群(必须先是node节点离开集群,然后manager节点才能离开集群)
[root@server2 ~]# docker swarm leave #server2对应的node节点离开集群
[root@server3 ~]# docker swarm leave #server3对应的node节点离开集群
[root@server1 ~]# docker swarm leave --force #必须使用参数--force,强制离开集群,否则会报错
[root@server1 ~]# docker node ls #此时再次查看集群的节点,会报错。这是因为i集群已经散了,该节点不再是manager节点,而只有manager节点才能查看集群的节点。
Error response from daemon: This node is not a swarm manager. Use "docker swarm init" or "docker swarm join" to connect this node to swarm and try again.