这个《Docker入门系列》文档,是根据Docker官网(https://docs.docker.com)的帮助文档大致翻译而成。主要是作为个人学习记录。有错误的地方,Robin欢迎大家指正。分为如下几个部分:
1 Docker入门:简介
2 Docker入门:安装运行
3 Docker入门:容器(Containers)
4 Docker入门:服务(Services)
5 Docker入门:Swarms
6 Docker入门:Stacks
7 Docker入门:部署app
8 Docker入门:稍高级的话题
6.1 引言
在第五部分,我们学习了如何搭建一个swarm。一个swarm就是运行着Docker的一组机器所组成的集群。然后学习了如何将app部署到swarm上,并让许多容器一致地运行在多个机器上。
在第六部分,我们将进入一个分布式应用程序层次结构的最高层:stack。
stack |
service |
container |
一个stack就是一组相互关联的services,这些services之间相互依赖,并能够一起进行编排和scale。单个stack就能够定义和协调整个应用程序的功能(也存在一些复杂的应用程序,可能使用多个stacks)。
好消息是,我们从第四部分就已经接触stack了:创建一个Compose文件并使用docker stack deploy。但那只是一个单service的stack,运行在单个主机上,这种情况极少在产品部署中使用。下面,我们将使多个services相互关联,并将它们运行在多个机器上。
6.2 添加一个新的service并重新部署
向我们的docker-compose.yml文件中添加services很简单。首先,添加一个免费的visualizer service,该service用于查看swarm是如何调度容器的。
分为如下4个步骤。
6.2.1 重新编辑Compose文件
用编辑器打开文件docker-compose.yml,并输入如下内容,确保用你的映像信息替换uername/repo:tag部分。
version: "" 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:
在该.yml文件中,添加了一个和web平行的service,名称为visualizer。还有两个新的关键字。一个是关键字volumes,用于给visualizer提供权限,从而访问主机上的Docker socket文件。另一个关键字是placement,用于确保这个service只能运行在swarm manager上,而不能运行在worker节点上。因为这个容器构建自Docker开源项目,用来以图表方式展示一个swarm上运行的services。
6.2.2 配置和swarm manager对话的shell
确保你的shell已经配置好,能够和myvm1进行对话:
● 运行命令docker-machine ls,来列出所有的machines,并确保你已经连上myvm1了,能够发现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
6.2.3 重新部署
在manager上重新运行命令docker stack deploy,更新需要更新的services:
$ docker stack deploy -c docker-compose.yml getstartedlab
Updating service getstartedlab_web (id: angi1bf5e4to03qu9f93trnxm)
Updating service getstartedlab_visualizer (id: l9mnwkeq2jiononb5ihz9u7a4)
6.2.4 查看visualizer服务
在Compose文件里,visualizer运行在端口8080上。运行docker-machine ls来获得任一个节点的IP地址,进入该IP的8080端口来看看visulizer的运行情况:
和期望中的一样,visualizer的单个实例运行在manager上,web的5个实例分布在整个swarm上。你可以运行命令docker stack ps <stack>来佐证一下visualizer的展示结果:
docker stack ps getstartedlab
visualizer是一个独立的服务,在stack中,它可以运行在任何app里。它不依赖任何东西。下面我们创建一个具有依赖性的service:能够提供访客计数功能的Redis service.
6.3 数据持久化
我们再一次使用之前的工作流程,来添加一个Redis数据库service,用以存储app的数据。分为如下六个步骤。
6.3.1 修改Compose文件
修改docker-compose.yml文件,内容如下面所示,这将添加一个Redis service。确保用你自己的映像信息来取代username/repo:tag部分。
version: "" 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在Docker库中有一个官方的映像,所以可以使用简写的映像名称redis,这里就不需要username/repo了。Redis已经将端口6379从容器暴露到主机,在Compose文件里,我们将该端口从主机暴露到外面的世界,所以你可以通过任一个节点的IP来访问Redis桌面管理器,从而管理这个Redis实例。
还有一些重要的Redis规范,用于指导stack多次部署时的数据持久化:
- Redis总是运行在manager上,所以它总是可以使用相同的文件系统;
- 通过访问容器中的目录/data,redis能够访问主机文件系统中的任何目录,Redis在该目录中存储数据。
以上两点结合在一起,就可以在主机的物理文件系统中为Redis数据创建一个事实上的源(source of truth)。如果没有这个机制,Redis就会在容器的文件系统中的/data目录下存储数据,一旦容器重新部署,这些数据就会丢失。
“source of truth”包含两个部分:
- Placement: 放置在Redis service上的这个约束,保证了Redis service总是使用相同的主机。
- volume: 这个关键字的配置,使得容器通过访问Redis容器中的/data目录,来间接访问主机上的/data目录。换句话说,这让容器的数据访问透明化,虽然容器逻辑*问的是Redis容器中的/data目录,而实际上容器访问的是主机上的/data目录。
6.3.2 在manager上创建目录
在manager上创建一个./data目录:
docker-machine ssh myvm1 "mkdir ./data"
6.3.3 配置和swarm manager对话的shell
确保你的shell已经配置好,能够和myvm1进行对话:
● 运行命令docker-machine ls,来列出所有的machines,并确保你已经连上myvm1了,能够发现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
6.3.4 重新部署
再一次运行命令docker stack deploy:
$ docker stack deploy -c docker-compose.yml getstartedlab
6.3.5 确认service运行状况
运行命令docker service ls,来确认3个services是否正常运行:
$ 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 orangesnap/getstarted:latest *:80->80/tcp
6.3.6 网页验证
选择一个节点的IP地址(比如:http://192.18.99.101)进入其网页,就可以看到访客的统计数量,这个数据会一直更新并存储在Redis上。
同样,选择任一个节点的IP地址,在其端口8080*问visulizer,就可以看到web、redis、visualizer三种服务一起运行。
6.4 总结
Stacks就是一组一致运行的、相互关联的services。通过修改Compose文件,可以向stack中添加更多的services。最后,通过使用placement和volumes两个关键字的组合,为持久化数据创建了一个永久的港湾,无论容器关闭或重新部署,app的数据会一直保存下来。