介绍
在part4 中,学习到如何建立swarm(它是运行Docker的机器的集群),部署应用到swarm上(容器会在多台机器上和谐的运行)。
在part5, 你接触到了分布式应用(distributed applications)的顶层:堆栈(stack)。堆栈是一组相互关联的服务,它们共享依赖关系,并且可以一起协调和扩展。
单个堆栈就具备定义和协调整个应用程序的功能(尽管非常复杂的应用程序可能需要使用多个堆栈)。
这里可以学到,将多个服务互相关联,并在多个设备上运行他们。
添加一项新服务并重新部署
向我们的docker-compose.yml文件添加服务很容易。首先,我们添加一个免费的可视化服务,让我们看到swarm如何安排container。
1、docker-compose.yml在编辑器中打开并用以下内容替换它的内容。请务必使用你的image替换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:
2、确保你的shell 配置了到myvm1的对话
> docker-machine env myvm1
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.99.100:2376"
export DOCKER_CERT_PATH="/home/server2/.docker/machine/machines/myvm1"
export DOCKER_MACHINE_NAME="myvm1"
# Run this command to configure your shell:
# eval $(docker-machine env myvm1)
> part5 eval $(docker-machine env myvm1)
> part5 docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
9m7t3o4gjwxfxl7z4zz7ar9si * myvm1 Ready Active Leader 18.09.6
bial3jkpphokh6v91bmys9a33 myvm2 Ready Active 18.09.6
3、 确保登录docker,因为visualizer和redis这两个image 本地是没有的,需要下载
docker login
4、 部署
docker stack deploy -c docker-compose.yml getstartedlab
5、访问这两个服务:visualizer和web
可以通过浏览器查看,也可以通过curl命令
>curl http://192.168.99.100:4000
<h3>Hello World!</h3><b>Hostname:</b> 5a1c96676e0f<br/><b>Visits:</b> <i>cannot connect to Redis, counter disabled</i>%
>curl http://192.168.99.100:8080
><!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Visualizer</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link href='//fonts.googleapis.com/css?family=Ubuntu+Mono|Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'>
<style type="text/css">
.hidden{ display: none; }
</style>
</head>
<body style='background:#254356'>
<div class='tabs'>
<button id='tab-physical'>
<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 80 80"><path fill="#FFF" d="M14.752 32.456l-7.72.002v7.553h7.72v-7.554zm9.65 0h-7.72v7.556h7.72v-7.556zm0-9.445h-7.72v7.556h7.72V23.01zm9.65 9.446h-7.72v7.556h7.72v-7.556zm0-9.445h-7.72v7.556h7.72V23.01zm9.648 9.446h-7.72v7.556h7.72v-7.556zm0-9.445h-7.72v7.556h7.72V23.01zm9.65 9.446l-7.72.002v7.553h7.72v-7.554zm-9.65-18.89h-7.72v7.556h7.72v-7.556zm31.938 23.106c-2.51-1.417-5.85-1.61-8.693-.792-.35-2.958-2.337-5.55-4.7-7.41l-.938-.738-.79.89c-1.58 1.79-2.052 4.768-1.838 7.053.16 1.68.697 3.388 1.756 4.737-.805.473-1.717.85-2.53 1.12-1.657.55-3.456.854-5.206.854H3.544l-.105 1.107c-.354 3.7.165 7.402 1.728 10.778l.673 1.343.078.124c4.622 7.68 12.74 10.914 21.584 10.914 17.125 0 31.248-7.48 37.734-23.284 4.335.222 8.77-1.033 10.89-5.082l.54-1.033-1.028-.578zm-57.77 19.982v.002c-2.18 0-3.955-1.735-3.955-3.866 0-2.132 1.774-3.866 3.954-3.866s3.954 1.732 3.954 3.865c0 2.13-1.77 3.864-3.95 3.864zm-.01-5.854c-1.137 0-2.06.9-2.06 2.013 0 1.11.924 2.01 2.06 2.01 1.134 0 2.057-.9 2.057-2.01 0-1.11-.922-2.013-2.057-2.013z"/></svg>
</button>
</div>
<div id="app">
<!-- content goes here -->
</div>
<script type="text/javascript">
window.MS = '1000';
</script>
<script type="text/javascript" src="app.js"></script>
</body>
</html>
6、visualizer的一个复本运行在manager上,web的5个实例分布在swarm上,如下所示:
➜ part5 docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
frpsia7vvf1b getstartedlab_visualizer replicated 1/1 dockersamples/visualizer:stable *:8080->8080/tcp
kj2sd6m25fdy getstartedlab_web replicated 3/5 yolanda99/get-started:part2 *:4000->80/tcp
➜ part5 docker stack ps getstartedlab
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
j81pk3hnl1ad getstartedlab_visualizer.1 dockersamples/visualizer:stable myvm1 Running Running 25 minutes ago
6htlbxq59t3h \_ getstartedlab_visualizer.1 dockersamples/visualizer:stable myvm1 Shutdown Rejected 27 minutes ago "No such image: dockersamples/…"
av3xt5q8m9st getstartedlab_web.1 yolanda99/get-started:part2 myvm1 Running Running 27 minutes ago
sth14vz6ygk0 getstartedlab_web.2 yolanda99/get-started:part2 myvm1 Running Running 27 minutes ago
on60wknqbp5p getstartedlab_web.3 yolanda99/get-started:part2 myvm2 Running Preparing 27 minutes ago
9o2b40wt2sax getstartedlab_web.4 yolanda99/get-started:part2 myvm1 Running Running 27 minutes ago
z5x9tbz5sgfk getstartedlab_web.6 yolanda99/get-started:part2 myvm2 Running Preparing 27 minutes ago
bdjq3de7ns8n getstartedlab_web.10 yolanda99/get-started:part2 myvm2 Shutdown Rejected 27 minutes ago "No such image: yolanda99/get-…"
持久化数据
visualizer 是一个单独的服务,可以跑在任何包含它的应用的stack中。它没有依赖。现在我们创建一个需要依赖的服务:Redis 服务,提供访问用户数。
1、修改docker-compose.yml 文件,如下所示:
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:
Redis 有一个官方image,且已经授权了短 image 名字:redis,所以这里不用谢username/repo. Redis 的端口是6379,已由Redis预先配置为从容器暴露给主机,在我们的Compose文件中,我们将它从主机暴露给世界,所以你可以在Redis 桌面管理器中输入任何节点的IP,来管理Redis实例。
最重要的是,redis规范中有一些事情会使数据在此堆栈的部署之间保持不变
- redis 总是运行的manager上,所以总是使用同样的文件管理系统
- redis访问主机文件系统中的任意目录作为/data容器内部,这是Redis存储数据的位置。
总之,这是在主机的物理文件系统中为Redis数据创建的“真实的资源”。如果没有这个,Redis会将其数据存储 在容器的文件系统中的 /data 目录。如果重新部署该容器,数据将会被删除。
这个“真实的资源”有两个组成部分:
- Redis服务中配置的placement constraint,确保它始终使用相同的主机。
- 您创建的volume,让容器访问 ./data(在主机上)和访问 /data(在Redis容器内)一样。当容器来来往往时,./data(存储在指定主机上)仍然存在,从而实现连续性。
2、在manager上创建 ./data 目录
docker-machine ssh myvm1 "mkdir ./data"
3、再次运行 “docker stack deploy”
> docker stack deploy -c docker-compose.yml getstartedlab
Updating service getstartedlab_visualizer (id: frpsia7vvf1ba0va8sy4fwax5)
Creating service getstartedlab_redis
Updating service getstartedlab_web (id: kj2sd6m25fdya6cqqdajzod06)
4、验证三个服务都如期运行
docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
tsllzfezz0ha getstartedlab_redis replicated 0/1 redis:latest *:6379->6379/tcp
frpsia7vvf1b getstartedlab_visualizer replicated 1/1 dockersamples/visualizer:stable *:8080->8080/tcp
kj2sd6m25fdy getstartedlab_web replicated 3/5 yolanda99/get-started:part2 *:4000->80/tcp
redis 没有启动,暂时没找到原因。。。。