Docker入门(六):Stacks

时间:2023-03-08 21:59:33

这个《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的运行情况:

Docker入门(六):Stacks

和期望中的一样,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上。

Docker入门(六):Stacks

同样,选择任一个节点的IP地址,在其端口8080*问visulizer,就可以看到web、redis、visualizer三种服务一起运行。

Docker入门(六):Stacks

6.4 总结

Stacks就是一组一致运行的、相互关联的services。通过修改Compose文件,可以向stack中添加更多的services。最后,通过使用placement和volumes两个关键字的组合,为持久化数据创建了一个永久的港湾,无论容器关闭或重新部署,app的数据会一直保存下来。