准备工作

  • 安装1.13或者更高版本的docker。
  • 如第三部分准备工作所述那样获取docker compose。
  • 学会第四部分中的Docker Machine相关知识。
  • 已阅读第一部分中的概念。
  • 通过第二部分学会了如何创建一个容器。
  • 确保已经向仓库中提交了firendlyhello镜像,我们在本文中将使用这个已分享的公共镜像。
  • 确保你的镜像已经部署成了一个容器。执行命令docker run -p 80:80 username/repo:tag,使用你的用户名(username)、仓库名(repo)和标签名(tag)对应替换即可。然后使用http://localhost:80进行访问
  • 一份第三部分中的docker-compose.yml副本。
  • 确保你在第四部分中创建的虚拟机正在运行中,可以使用docker-machine ls进行确认。如果已经停止,先执行docker-machine start myvm1启动并作为swarm管理节点,然后执行docker-machine start myvm2启动并作为工作节点。
  • 确保第四部分中创建的swarm集群处于运行状态,可以使用docker-machine ls进行确认。如果swarm是开启状态,则两个节点都处于ready状态。否则就未启动,这时你需要初始化swarm管理节点和添加工作节点。

引言

在第四部分中,我们学会了如何创建一个docker集群运行的swarm网络,并在上面部署应用,使容器在多台docker服务器上运行。

在第五部分中,你将接触到分布式应用的最顶层:堆栈。堆栈就是一系列相互关联的服务,他们共享依赖关系,并且可以相互协调和对方在一起。单个堆栈可以定义和协调整个应用的所有功能(一些特别复杂的应用还是建议分为多个堆栈进行组合)。

其实在第三部分中创建compose文件然后部署应用就是使用了堆栈。但是这种在单个主机上运行的堆栈在生产环境中一般不会出现。所以,在这里我们将要学习的是多个服务相关关联,并运行在多台计算机上的堆栈。

添加新服务并重新部署

docker-compose.yml文件中添加新服务是非常简单的,首先需要添加一个免费的可视化服务让我们知道swarm是如何调度各个容器的。

  1. 打开docker-compose.yml文件,并把内容替换为下面的内容。主要需要将镜像的相关信息替换为你自己的信息。
version: "3"
services:
  web:
    # 替换为你的镜像的相关信息
    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的服务。注意有两个新的东西出现:一个valumes关键字,让visualizer去访问docker的主机套接字;还有一个placement关键字,用于确保这个服务使用运行在管理节点上,而不会部署到工作节点上。这个容器是由Docker创建的一个开源项目构建的(docker-swarm-visualizer),用于显示在swarm上运行的docker服务。

我们马上就会讨论关于placement约束和volumes相关的内容。

  1. 确保你的shell已经配置好与myvm1的通信(下面是完整示例)。
  • 运行docker-machine ls列举服务器并确保与myvm1相连接,可以从myvm1旁的星号看出来。

  • 如果有需要,重新运行docker-machine env myvm1,然后再运行下面的命令进行配置。

在Mac和Linux的命令为:

eval $(docker-machine env myvm1)

Window中的命令为:

& "C:\Program Files\Docker\Docker\Resources\bin\docker-machine.exe" env myvm1 | Invoke-Expression
  1. 在管理节点上执行docker stack deploy指令,更行所需要更新的服务:
$ docker stack deploy -c docker-compose.yml getstartedlab
Updating service getstartedlab_web (id: angi1bf5e4to03qu9f93trnxm)
Creating service getstartedlab_visualizer (id: l9mnwkeq2jiononb5ihz9u7a4)
  1. 在可视化服务中查看一下。
    在compose文件中可以看到可视化服务运行在8080端口上,使用docker-machine ls指令获取其中一台服务器的Ip,然后使用8080端口在浏览器中访问可以进入可视化工具:

Visualizer screenshot

单个可视化服务容器如期望般运行在管理端,然后5个web服务的容器实例分布在整个swarm集群中。你可以使用docker stack ps <stack>来验证可视化服务中的数据。

docker stack ps getstartedlab

可视化工具是一个独立的服务,可以在任何包含它的应用程序中运行。 它不依赖于任何其他东西。现在让我们创建一个具有依赖关系的服务:提供访问者计数器的Redis服务。

持久化数据

让我们再次通过相同的工作流程来添加Redis数据库来存储应用数据。

  1. 保存这个在最后添加了Redis服务的compose文件,确保其中的镜像数据替换为你的信息。
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文件中映射此端口只是想要将其暴露给外部的世界,所以,你可以使用集群中的任意一个Ip访问它,也可以使用Redis Desktop Manager管理这个Redis实例。

非常重要的是, redis规定中有一些内容可以使数据在这个堆栈部署过程中持久化:

  • redis始终在管理节点中运行,所以可以确保它总是使用相同的文件系统。
  • redis访问主机文件系统中指定的目录/home/docker/data与容器内的/data映射,这个redis保存数据的路径。

总之,这是在物理主机上为redis创建一个真实可信的数据来源。如果没有这个配置,redis将会把数据存储在容器内的/data目录中,如果重新部署容器,这些数据将会丢失。

这个真实可信的数据来源由两部分组成:
- 该服务的placement约束,确保其始终部署在相同的主机上。
- volume卷积配置了主机中的./data目录与容器内的/data目录映射。在容器的不断启停中,主机上的./data总是存在,从而实现了数据的持久化。

现在你已经完成了部署一个依赖redis的堆栈的准备工作。

  1. 在管理节点上创建./data目录:
docker-machine ssh myvm1 "mkdir ./data"
  1. 确保你的shell已经配置好与myvm1的通信(下面是完整示例)。
  • 运行docker-machine ls列举服务器并确保与myvm1相连接,可以从myvm1旁的星号看出来。

  • 如果有需要,重新运行docker-machine env myvm1,然后再运行下面的命令进行配置。

在Mac和Linux的命令为:

eval $(docker-machine env myvm1)

Window中的命令为:

& "C:\Program Files\Docker\Docker\Resources\bin\docker-machine.exe" env myvm1 | Invoke-Expression
  1. 再次执行docker stack deploy指令:
$ docker stack deploy -c docker-compose.yml getstartedlab
  1. 运行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
  1. 通过某一个节点打开网页(如:http://192.168.99.101),查看Visits计数器结果,该数字已经存在并且在redis中进行了保存。

Hello World in browser with Redis

另外,在任一节点的IP地址查看查端口8080上的可视化器,可看到redis服务与web和可视化器服务一起运行。

Visualizer with redis screenshot

——————————————————————————
行路不知花开处,蓦然回首芷兰香。