Docker 入门 第五部分:Stacks
Docker 入门 第五部分:Stacks
先决条件
- 安装 Docker 1.13 或更高版本
- 按照第三部分中的描述安装Docker Compose。
- 按照第四部分中描述安装了Docker Machine,
- 阅读第一部分
- 在第二部分中学习如何创建容器
- 确保你已经将创建的
friendlyhello镜像发布到registry。我们会在这里用到这个镜像 - 确保你的镜像已经作为容器被部署运行,运行这个命令,在你的信息中加入
username,repo, 和tag:docker run -p 80:80 username/repo:tag, 然后查看http://localhost/。 - 从第三部分复制一份
docker-compose.yml - 确保你在第四部分中设置的机器已经运行并准备就绪。运行
docker-machine ls来验证。如果机器已经停止运行,运行docker-machine start myvm1启动管理器,然后运行docker-machine start myvm2来启动worker。 - 运行第四部分中的swarm并让其准备就绪,可以运行
docker-machine ssh myvm1 "docker node ls"来验证。如果swarm已经运行,那两个节点都会报告一个ready状态,如果没有,按照第四部分中的部署swarm中的内容重新初始化swarm并加入worker。
介绍
在第四部分,我们学习了如何部署一个swarm(swarm是一个运行Docker的机器集群),部署一个应用到swarm,其中容器在多台机器上运行。
在本节,你会了解到分布式程序层次结构的顶层:Stack。Stack一组相互关联的服务,他们共享依赖关系,并可以在一起被编排和扩展。单个Stack可以定义和协调整个应用程序的功能(虽然复杂度很高的应用可能需要使用多个Stack)。
好消息是,在第三部分中当你创建Compose 文件并使用docker stack deploy时,你就已经开始使用Stack技术。但是那只是运行在一台单独的主机上的一个单个的Stack,通常在生产环境里不会这么使用。在这里,你可以根据所学内容,使多个服务彼此关联,并运行在多台机器上。
添加一个新的服务并重新部署
在docker-compose.yml文件中添加一个服务很简单。首先,我们先添加一个可视化服务,看看swarm是如何调度容器的。
1.编辑docker-compose.yml文件,使用下面的内容替换原内容。确保使用你的镜像信息替换username/repo:tag:
version: "3"
services:
web:
# replace username/repo:tag with your name and image details
image: username/repo:tag
deploy:
replicas: 5
restart_policy:
condition: on-failure
resources:
limits:
cpus: "0.1"
memory: 50M
ports:
- "80:80"
networks:
- webnet
visualizer:
image: dockersamples/visualizer:stable
ports:
- "8080:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
placement:
constraints: [node.role == manager]
networks:
- webnet
networks:
webnet:
这里唯一改变的地方是新增了和web同级的visualizer服务。有两个事情需要注意: volumes密钥让可视化工具可以拦截到Docker的主机套接字文件;placement密钥,确保该服务只运行在swarm管理器上,而不是worker上。这是因为这个容器是由Docker创建的开源项目构建的,使用图示的方式显示swarm上运行的docker服务。
我们现在就来看看placement约束和volumes。
2.确保你的shell已被配置为可与myvm1进行通信。(完整的例子点这里)
- 运行
docker-machine ls列出机器,并确保你已经连接到myvm1. - 如果有必要,重新运行
docker-machine env myvm1,然后运行指定的命令来配置shell。
Mac 和 Linux上的命令:
eval $(docker-machine env myvm1)
Windows上的命令:
& "C:\Program Files\Docker\Docker\Resources\bin\docker-machine.exe" env myvm1 | Invoke-Expression
3.在管理器上重新运行docker stack deploy,并更新需要更新的服务。
$ docker stack deploy -c docker-compose.yml getstartedlab
Updating service getstartedlab_web (id: angi1bf5e4to03qu9f93trnxm)
Creating service getstartedlab_visualizer (id: l9mnwkeq2jiononb5ihz9u7a4)
4.在可视化工具中查看
从Compose文件中可以看出visualizer运行在8080端口。运行docker-machine ls获取其中一个节点
的IP地址。访问该IP地址的8080端口就可以看到正在运行的visualizer:

visualizer的其中一个副本正如我们预期的一样运行在管理器上。我们可以运行docker stack ps <stack> 来确认这个
docker stack ps getstartedlab
该可视化工具是一个独立的服务,可以在stack里任何包含它的app上运行。它不依赖任何其他内容。现在我们创建一个具有依赖关系的服务:提供浏览器计数器的Redis服务。
保存数据
我们可以通过相同的步骤来添加一个Redis数据库来存储应用数据。
1.在docker-compose.yml文件末尾点击一个Redis服务,并保存这个新文件。确保使用你的镜像信息替换username/repo:tag。
version: "3"
services:
web:
# replace username/repo:tag with your name and image details
image: username/repo:tag
deploy:
replicas: 5
restart_policy:
condition: on-failure
resources:
limits:
cpus: "0.1"
memory: 50M
ports:
- "80:80"
networks:
- webnet
visualizer:
image: dockersamples/visualizer:stable
ports:
- "8080:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
placement:
constraints: [node.role == manager]
networks:
- webnet
redis:
image: redis
ports:
- "6379:6379"
volumes:
- "/home/docker/data:/data"
deploy:
placement:
constraints: [node.role == manager]
command: redis-server --appendonly yes
networks:
- webnet
networks:
webnet:
Docker库中有一个Redis的官方镜像,使用了一个很短的镜像名字:redis,因此这里没有使用username/repo来表示。Redis的6379端口已经被预设为从容器暴露给主机,在我们的compose文件中,我们将其从主机暴露给公网,因此,如果你选择这样做,你就可以在任何节点连接Redis桌面管理器并管理该redis节点。
最重要的是,在该stack上部署redis期间,redis规范中有一些内容可以使数据保持不变。
- redis总是运行在管理器上,所有它总是使用相同的文件系统
- redis访问主机上文件系统的任意目录将其作为容器内的
/data目录,用来存储redis数据。
总之,这会在主机的物理文件系统上为Redis数据创建一个”真实数据源(官方叫“source of truth”)“。如果没有这个,Redis会把数据保存在容器内的/data目录,如果容器被重新部署,那么数据就会被删除。
真实的数据源有两部分组成:
- Redis服务有位置约束,确保它总是使用相同的主机。
- 创建的卷让容器可以将
./data(主机上的)作为/data(redis容器上)来进行访问。当容器创建删除时,在指定主机上的。/data下存储的文件会一直存在,从而实现连续性。
到这里,我们就做好了部署Redis stack的准备。
2.在管理器上创建./data目录
docker-machine ssh myvm1 "mkdir ./data"
3.确保你的shell已被配置为可与myvm1通信(点此查看完成例子)
- 运行
docker-machine ls,列出机器,确保你已经链接上myvm1,如下条所示。 - 如有必要,重新运行
docker-machine env myvm1,然后运行给定的命令来配置shell。
# Mac 或 Linux上的命令:
eval $(docker-machine env myvm1)
# Winidows上的命令:
& "C:\Program Files\Docker\Docker\Resources\bin\docker-machine.exe" env myvm1 | Invoke-Expression
4.再次运行docker stack deploy
$ docker stack deploy -c docker-compose.yml getstartedlab
5.运行docker service ls来验证三个服务是否按照预期运行。
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
x7uij6xb4foj getstartedlab_redis replicated 1/1 redis:latest *:6379->6379/tcp
n5rvhm52ykq7 getstartedlab_visualizer replicated 1/1 dockersamples/visualizer:stable *:8080->8080/tcp
mifd433bti1d getstartedlab_web replicated 5/5 gordon/getstarted:latest *:80->80/tcp
6.在其中一个检点上检查web页面,例如http://192.168.99.101,查看浏览计数器的结果,该计数器已存在并将信息存储在redis上。

另外,检查任意节点IP地址上的8080端口的可视化工具,注意redis服务与web服务和visualizer服务都在运行,

回顾
下面是本节内容的回顾:
bash-3.2$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
myvm1 - virtualbox Running tcp://192.168.99.104:2376 v17.04.0-ce
myvm2 - virtualbox Running tcp://192.168.99.105:2376 v17.04.0-ce
bash-3.2$ docker-machine ssh myvm1 "docker node ls"
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
fvenziy5o4xmziyzqxianzd65 myvm2 Ready Active
x500bs7lrweto9chkg6xq2ybd * myvm1 Ready Active Leader
bash-3.2$ docker-machine ssh myvm1 "docker stack ps getstartedlab"
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
kjeymj6rp0y8 getstartedlab_web.1 johndmulhausen/get-started:part1 myvm2 Running Running 15 minutes ago
dehkjrmu0fxn getstartedlab_web.2 johndmulhausen/get-started:part1 myvm1 Running Running 15 minutes ago
acnejfyy1cmg getstartedlab_web.3 johndmulhausen/get-started:part1 myvm2 Running Running 15 minutes ago
36lpsek707gj getstartedlab_web.4 johndmulhausen/get-started:part1 myvm1 Running Running 15 minutes ago
q5yb5uj97ef1 getstartedlab_web.5 johndmulhausen/get-started:part1 myvm2 Running Running 15 minutes ago
bash-3.2$ ls
docker-compose.yml
bash-3.2$ more docker-compose.yml
version: "3"
services:
web:
image: johndmulhausen/get-started:part1
deploy:
replicas: 5
restart_policy:
condition: on-failure
resources:
limits:
cpus: "0.1"
memory: 50M
ports:
- "80:80"
networks:
- webnet
visualizer:
image: dockersamples/visualizer:stable
ports:
- "8080:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
placement:
constraints: [node.role == manager]
networks:
- webnet
networks:
webnet:
bash-3.2$ docker-machine scp docker-compose.yml myvm1:~
docker-compose.yml
bash-3.2$ docker-machine ssh myvm1 "docker stack deploy -c docker-compose.yml getstartedlab"
Creating service getstartedlab_visualizer
Updating service getstartedlab_web (id: a3mhoq23ydyut4uje16slqum2)
bash-3.2$ docker-machine ssh myvm1 "docker stack ps getstartedlab"
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
ts3ud4mdf9qi getstartedlab_visualizer.1 dockersamples/visualizer:stable myvm1 Running Running 34 seconds ago
kjeymj6rp0y8 getstartedlab_web.1 johndmulhausen/get-started:part1 myvm2 Running Running 20 minutes ago
dehkjrmu0fxn getstartedlab_web.2 johndmulhausen/get-started:part1 myvm1 Running Running 19 minutes ago
acnejfyy1cmg getstartedlab_web.3 johndmulhausen/get-started:part1 myvm2 Running Running 20 minutes ago
36lpsek707gj getstartedlab_web.4 johndmulhausen/get-started:part1 myvm1 Running Running 19 minutes ago
q5yb5uj97ef1 getstartedlab_web.5 johndmulhausen/get-started:part1 myvm2
bash-3.2$ more docker-compose-WITH-REDIS.yml
version: "3"
services:
web:
image: johndmulhausen/get-started:part1
deploy:
replicas: 5
restart_policy:
condition: on-failure
resources:
limits:
cpus: "0.1"
memory: 50M
ports:
- "80:80"
networks:
- webnet
visualizer:
image: dockersamples/visualizer:stable
ports:
- "8080:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
placement:
constraints: [node.role == manager]
networks:
- webnet
redis:
image: redis
ports:
- "6379:6739"
volumes:
- ./data:/data
deploy:
placement:
constraints: [node.role == manager]
networks:
- webnet
networks:
webnet:
bash-3.2$ docker-machine scp docker-compose-WITH-REDIS.yml myvm1:~
docker-compose-WITH-REDIS.yml
bash-3.2$ docker-machine ssh myvm1 "docker stack deploy -c docker-compose-WITH-REDIS.yml getstartedlab"
Updating service getstartedlab_web (id: a3mhoq23ydyut4uje16slqum2)
Updating service getstartedlab_visualizer (id: uwd8tja3fpcpsy8kumk19orr8)
Creating service getstartedlab_redis
bash-3.2$ docker-machine ssh myvm1 "docker stack ps getstartedlab"
PORTS
o2xct1jotx55 getstartedlab_redis.1 redis:latest myvm1 Ready Rejected 1 second ago "invalid mount config for type…
"
tf1s212hfh9c \_ getstartedlab_redis.1 redis:latest myvm1 Shutdown Rejected 6 seconds ago "invalid mount config for type…
"
sizyxk5f0a5h \_ getstartedlab_redis.1 redis:latest myvm1 Shutdown Rejected 11 seconds ago "invalid mount config for type…
"
xd8s1ljsj9oq \_ getstartedlab_redis.1 redis:latest myvm1 Shutdown Rejected 16 seconds ago "invalid mount config for type…
"
6h4wfo8nophs \_ getstartedlab_redis.1 redis:latest myvm1 Shutdown Rejected 21 seconds ago "invalid mount config for type…
"
ts3ud4mdf9qi getstartedlab_visualizer.1 dockersamples/visualizer:stable myvm1 Running Running 4 minutes ago
kjeymj6rp0y8 getstartedlab_web.1 johndmulhausen/get-started:part1 myvm2 Running Running 24 minutes ago
dehkjrmu0fxn getstartedlab_web.2 johndmulhausen/get-started:part1 myvm1 Running Running 23 minutes ago
acnejfyy1cmg getstartedlab_web.3 johndmulhausen/get-started:part1 myvm2 Running Running 24 minutes ago
36lpsek707gj getstartedlab_web.4 johndmulhausen/get-started:part1 myvm1 Running Running 23 minutes ago
q5yb5uj97ef1 getstartedlab_web.5 johndmulhausen/get-started:part1 myvm2
bash-3.2$ docker-machine ssh myvm1 "mkdir ./data"
bash-3.2$ docker-machine ssh myvm1 "docker stack deploy -c docker-compose-WITH-REDIS.yml getstartedlab"
Updating service getstartedlab_web (id: a3mhoq23ydyut4uje16slqum2)
Updating service getstartedlab_visualizer (id: uwd8tja3fpcpsy8kumk19orr8)
Updating service getstartedlab_redis (id: oxlqkgq0vcmlzc5k1gk0rthdf)
bash-3.2$ docker-machine ssh myvm1 "docker stack ps getstartedlab"
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
xl9qttm6cg7v getstartedlab_redis.1 redis:latest myvm1 Running Running 32 seconds ago
ihuhl093b492 getstartedlab_visualizer.1 dockersamples/visualizer:stable myvm1 Running Running 33 seconds ago
3jpjjz6hdmex getstartedlab_web.1 johndmulhausen/get-started:part1 myvm2 Running Running 31 seconds ago
q9w4v6g14bxm getstartedlab_web.2 johndmulhausen/get-started:part1 myvm1 Running Running 34 seconds ago
w8z6vyae3cyb getstartedlab_web.3 johndmulhausen/get-started:part1 myvm2 Running Running 31 seconds ago
xgpfmyhp2uub getstartedlab_web.4 johndmulhausen/get-started:part1 myvm1 Running Running 34 seconds ago
jdkgknm7wlip getstartedlab_web.5 johndmulhausen/get-started:part1 myvm2 Running Running 31 seconds ago
bash-3.2$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
myvm1 - virtualbox Running tcp://192.168.99.104:2376 v17.04.0-ce
myvm2 - virtualbox Running tcp://192.168.99.105:2376 v17.04.0-ce
bash-3.2$ curl http://192.168.99.105/
<h3>Hello World!</h3><b>Hostname:</b> cfc0b7af2d99<br/><b>Visits:</b> 1
bash-3.2$ curl http://192.168.99.105/
<h3>Hello World!</h3><b>Hostname:</b> 8900768882f9<br/><b>Visits:</b> 2
bash-3.2$ curl http://192.168.99.105/
<h3>Hello World!</h3><b>Hostname:</b> 3adb6b451c2e<br/><b>Visits:</b> 3
bash-3.2$ curl http://192.168.99.105/
<h3>Hello World!</h3><b>Hostname:</b> 8398387efdb7<br/><b>Visits:</b> 4
bash-3.2$ curl http://192.168.99.105/
<h3>Hello World!</h3><b>Hostname:</b> 67e3e4c066ee<br/><b>Visits:</b> 5
bash-3.2$ curl http://192.168.99.105/
<h3>Hello World!</h3><b>Hostname:</b> cfc0b7af2d99<br/><b>Visits:</b> 6
本节了解到stack是全部一致运行的相互关联的服务,并且,从第三节就开始使用stack。还学习了想stakc中添加服务,将它们加氟Compose文件中。最后,学习了通过位置约束和卷组的组合,你可以创建一个永久的源来保存数据,一般在销毁并重部署容器时,app的数据仍会存在。
Docker 入门 第五部分:Stacks的更多相关文章
- Docker入门(五):Swarms
这个<Docker入门系列>文档,是根据Docker官网(https://docs.docker.com)的帮助文档大致翻译而成.主要是作为个人学习记录.有错误的地方,Robin欢迎大家指 ...
- Docker入门(六):Stacks
这个<Docker入门系列>文档,是根据Docker官网(https://docs.docker.com)的帮助文档大致翻译而成.主要是作为个人学习记录.有错误的地方,Robin欢迎大家指 ...
- Docker入门教程(五)Docker安全
Docker入门教程(五)Docker安全 [编者的话]DockOne组织翻译了Flux7的Docker入门教程,本文是系列入门教程的第五篇,介绍了Docker的安全问题,依然是老话重谈,入门者可以通 ...
- Docker 入门 第四部分: Swarms
目录 Docker 入门 第四部分: Swarms 先决条件 介绍 理解Swarm集群 部署swarm 创建一个集群 在swarm集群上部署你的app应用 为 swarm管理器配置一个docker-m ...
- Docker入门教程(四)Docker Registry
Docker入门教程(四)Docker Registry [编者的话]DockerOne组织翻译了Flux7的Docker入门教程,本文是系列入门教程的第四篇,介绍了Docker Registry,它 ...
- Docker入门
-----------------------------------------Docker入门教程(一)介绍Docker入门教程(二)命令Docker入门教程(三)DockerFileDocker ...
- Docker 入门实践
欢迎大家前往腾讯云技术社区,获取更多腾讯海量技术实践干货哦~ 作者:张戈 导语 本文从新手视角记录了一个实际的Dokcer应用场景从创建.上传直到部署的详细过程,并简单的介绍了腾讯云容器服务的使用方法 ...
- Docker入门 第一课 --.Net Core 使用Docker全程记录
微服务架构无疑是当前最火热的开发架构,而Docker作为微服务架构的首选工具,是我们必须要了解掌握的. 我通过一天的时间,网上查文档,了解基础概念,安装Docker,试验Docker命令,通过Dock ...
- Docker 入门 第六部分:部署app
目录 Docker 入门 第六部分:部署app 先决条件 介绍 选择一个选项 Docker CE(Cloud provider) Enterprise(Cloud provider)这里不做介绍 En ...
随机推荐
- vCenter简单查看多少虚拟机在开机状态和一共多少虚拟机
vCenter 界面上面不好找 具体的开机 运行数目 但是数据库里面比较好差 登录vCenter的数据库. 查看表主要是 查看正在开机的虚拟机 select * from dbo.VPX_VM WHE ...
- [转帖]速度快散热好 为什么U.2 SSD还没普及?
速度快散热好 为什么U.2 SSD还没普及? 经典的影视剧中总有那么几位武林高手,江湖上只闻其名,不见其形.今天我们要聊的这位爷,誓要拳打南山M.2,脚踩北海SATA 3!它就是固态硬盘界久负盛名 ...
- jquery 選擇器
jquery 選擇器有: 元素選擇器: $("p")選擇所有<p> $("p.intro")選擇所有class=“intro”的<p> ...
- BZOJ3159决战——树链剖分+非旋转treap(平衡树动态维护dfs序)
题目描述 输入 第一行有三个整数N.M和R,分别表示树的节点数.指令和询问总数,以及X国的据点. 接下来N-1行,每行两个整数X和Y,表示Katharon国的一条道路. 接下来M行,每行描述一个指令或 ...
- 【Linux】自动执行Mysql常用命令脚本
wamp环境下,我可以手敲一遍,但是lamp环境下我绝对不会手敲一遍 好吧~写脚本的确也是一遍~~~~(>_<)~~~~ 函数和后面的触发器中文档上局部是有错误的,所以大家不要一味的相信文 ...
- python 模块 - 序列化 json 和 pickle
1,引入 之前我们学习过用eval内置方法可以将一个字符串转成python对象,不过,eval方法是有局限性的,对于普通的数据类型,json.loads和eval都能用,但遇到特殊类型的时候,eval ...
- MT【60】几个不常见的函数图像
此讲部分内容属于课外阅读拓展,学有余力的可以看看. [We need to know, and we will know.]----大卫·希尔伯特(1862-1943) $y=sin\frac{1}{ ...
- 自学Linux Shell12.1-结构化命令if-then
点击返回 自学Linux命令行与Shell脚本之路 12.1-结构化命令if-then 许多程序要求对shell脚本中的命令施加一些逻辑流程控制.有一类命令会根据条件使脚本跳过某些命令.这样的命令通常 ...
- 批量导入导出站点权限site permissions
批量导入站点权限 cls $Web = Get-SPWeb "http://16.178.115.14:91/" Get-Content c:\export\account.t ...
- luogu3707 相关分析 (线段树)
把式子展开以后会发现,可以用线段树维护$x,y,x*y,x^2$分别的区间和 然后操作有区间加和区间修改 这个pushdown的时候,如果改和加的标记同时存在,那一定是先改再加,要不然加的标记已经被清 ...