Docker Swarm(二)

即便有了Docker Compose,项目的部署仍然存在问题,由于Docker Compose只能把项目全部的容器部署在同一台机器上,这在生产环境下是不现实的。html

Docker Compose通常只适用于开发环境,而对于生产环境下的项目部署,咱们须要用到Docker Swarm。前端

Docker Swarm介绍

Docker Swarm是Docker官方提供的一套容器编排系统,它将一组Docker主机虚拟成一个单独的虚拟Docker主机。node

架构以下:mysql

在这里插入图片描述

  • swarm节点:

swarm是一系列节点的集合,而节点能够是一台裸机或者一台虚拟机。一个节点能扮演一个或者两个角色,manager或者worker。web

manager
    Docker Swarm集群须要至少一个manager节点,节点之间使用Raft consensus protocol进行协同工做。
    一般,第一个启用docker swarm的节点将成为leader,后来加入的都是follower。当前的leader若是挂掉,
    剩余的节点将从新选举出一个新的leader。每个manager都有一个完整的当前集群状态的副本,能够保证manager的高可用。

worker
    worker节点是运行实际应用服务的容器所在的地方。理论上,一个manager节点也能同时成为worker节点,但在生产环境中,
    咱们不建议这样作。worker节点之间,经过control plane进行通讯,这种通讯使用gossip协议,而且是异步的。

  • task、service、stack:

多个tasks组成一个service,多个services组成一个stack。redis

task
    在Docker Swarm中,task是一个部署的最小单元,task与容器是一对一的关系。

service
    swarm service是一个抽象的概念,它只是一个对运行在swarm集群上的应用服务,所指望状态的描述。
    它就像一个描述了下面物品的清单列表同样:
        服务名称
        使用哪一个镜像来建立容器
        要运行多少个副本
        服务的容器要链接到哪一个网络上
        须要映射哪些端口

stack
    stack是描述一系列相关services的集合,能够经过在一个YAML文件中来定义一个stack,相似于docker-compose。

  • 多主机网络:

对于单主机网络,全部的容器都运行在一个docker主机上,他们之间的通讯通常使用本地的bridge network便可。sql

而对于swarm集群,针对的是一组docker主机,须要使用docker的overlay network。docker


Docker Stack

前面有讲过,docker run仅适用于单机启动单个容器;docker compose仅适用于单机启动多个容器;docker service仅适用于集群启动单个service的容器。数据库

即便在生产环境下使用docker service来部署项目,也是没法接受的。当项目足够复杂时,会有更多关联的service须要建立,经过docker service手动建立多个service,效率也是十分低下的。ubuntu

所以,Docker Stack应运而生,Docker Stack适用于集群启动多个service的容器,在集群中能够相似Docker Compose那样经过YAML文件直接部署项目。

只不过Docker Stack忽略了build指令,不能像Docker Compose那样在docker-compose.yml中引用Dockerfile构建新镜像,它须要镜像是预先已经构建好的。因此Docker Compose更适合于开发场景,而Docker Stack更适用于生产环境。

  • 对应关系:
单机 集群
docker run docker service create
docker-compose up docker stack deploy
  • 使用docker stack命令:

使用docker stack再也不须要安装docker-compose,直接使用docker stack deploy命令。

docker stack deploy project_name --compose-file docker-compose.yml

固然,后面跟着的YAML文件名不必定是docker-compose.yml,能够自定义。

  • deploy指令:

指定与service的部署和运行相关的配置。只在使用docker stack deploy部署时生效,而且会被docker-compose updocker-compose run忽略。

version: "3.7"services:
  redis:
    image: redis:alpine    deploy:
      replicas: 6
      update_config:
        parallelism: 2
        delay: 10s      restart_policy:
        condition: on-failure

  • endpoint_mode指令:

为链接到集群的外部客户端指定服务发现方法。

endpoint_mode: vip(默认配置)
    为service分配一个虚拟IP(vip),做为客户端在网络上访问service的前端。
    Docker在客户端和service可用的工做节点之间路由请求,而客户端不知道有
    多少节点参与服务或它们的IP地址或端口。

endpoint_mode: dnsrr
    DNS循环(dnsrr)服务发现不使用单个虚拟IP。Docker为服务设置DNS条目,
    针对service名称的DNS查询将返回一个IP地址列表,客户端将直接链接到其中之一。

deploy:
  mode: replicated  replicas: 2
  endpoint_mode: dnsrr

  • labels指令:

为服务指定标签。这些标签仅在service上设置,而不在service的任何容器上设置。

deploy:
  labels:
    com.example.description: "This label will appear on the web service"

要在容器上设置标签,请在deploy以外使用labels

version: "3.7"services:
  web:
    image: web    labels:
      com.example.description: "This label will appear on all containers for the web service"

  • mode指令:

mode有globalreplicated两种,默认mode是replicated。当为global时,每一个集群节点仅容许有一个service的容器,不容许有副本;当为replicated时,每一个集群节点能够有指定数量的service的容器。

version: "3.7"services:
  worker:
    image: dockersamples/examplevotingapp_worker    deploy:
      mode: global

deploy:
  mode: replicated  replicas: 5

  • placement指令:

指定约束和偏好的设置。node.role == manager表示只在manager节点建立service的容器。

deploy:
  placement:
    constraints:
      - node.role == manager      - engine.labels.operatingsystem == ubuntu 14.04    preferences:
      - spread: node.labels.zone

  • replicas指令:

若是mode为replicated,则replicas可指定在任何给定时间应该运行service的容器数量。

deploy:
  mode: replicated  replicas: 6

  • resources指令:

配置资源限制。limits限制最大资源,reservations为预留资源(始终可用)。

deploy:
  resources:
    limits:
      cpus: '0.50'
      memory: 50M    reservations:
      cpus: '0.25'
      memory: 20M

  • restart_policy指令:

配置service的容器退出时是否重启以及如何重启。

condition
    重启条件:none、on-failure、any,默认是any

delay
    延迟,两次重启尝试之间等待的时间,默认为0s

max_attempts
    最大尝试次数,在放弃以前尝试从新启动容器的次数,默认为永不放弃) 

window
    等待时间,判断一次重启是否成功以前的等待时间,默认为当即判断

deploy:
  restart_policy:
    condition: on-failure    delay: 5s    max_attempts: 3
    window: 120s

  • rollback_config指令:

配置在更新失败时应如何回滚服务。

parallelism
    并行数量,每次回滚的容器数量。若是设置为0,则全部容器同时回滚。
    
delay
    延迟,每一个容器组两次回滚之间等待的时间,默认为0s

failure_action
    若是回滚失败该继续或暂停,默认是暂停

monitor
    每次任务更新后检测失败的持续时间,默认为0s
    
max_failure_ratio
    回滚期间的容错率,默认为0
    
order
    回滚期间的操做顺序。stop-first表示旧任务在启动新任务以前中止;
    start-first表示新任务首先启动,正在运行的任务暂时重叠。默认是stop-first

deploy:
  rollback_config:
    parallelism: 2
    delay: 10s    order: stop-first

  • update_config指令:

配置如何更新服务。

parallelism
    并行数量,每次更新的容器数量。若是设置为0,则全部容器同时更新。
    
delay
    延迟,每一个容器组两次更新之间等待的时间,默认为0s

failure_action
    若是更新失败该继续或暂停,默认是暂停

monitor
    每次任务更新后检测失败的持续时间,默认为0s
    
max_failure_ratio
    更新期间的容错率,默认为0
    
order
    更新期间的操做顺序。stop-first表示旧任务在启动新任务以前中止;
    start-first表示新任务首先启动,正在运行的任务暂时重叠。默认是stop-first。
    注意:只支持v3.4或更高版本

version: "3.7"services:
  vote:
    image: dockersamples/examplevotingapp_vote:before    depends_on:
      - redis    deploy:
      update_config:
        parallelism: 2
        delay: 10s        order: stop-first


Docker Stack 示例

下面使用Docker Stack部署wordpress项目,该项目包含两个service:web和mysql。

  • 以前的环境:
role ip hostname
manager 192.168.30.128 test1
worker1 192.168.30.129 test2
worker2 192.168.30.130 test3
  • 部署wordpress:
# mkdir /wordpress && cd /wordpress# vim docker-compose.yml

version: "3.7"services:
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: 123456789
      MYSQL_DATABASE: wordpress    volumes:
      - db_data:/var/lib/mysql    networks:
      - my-network    deploy:
      mode: global      placement:
        constraints:
          - node.role == manager  web:
    depends_on:
      - db    image: wordpress    ports:
      - "80:80"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_PASSWORD: 123456789
    networks:
      - my-network    deploy:
      mode: replicated      replicas: 3
      restart_policy:
        condition: on-failure        delay: 5s        max_attempts: 3
      update_config:
        parallelism: 3
        delay: 10s        order: stop-first        
volumes:
  db_data:
  networks:
  my-network:
    driver: overlay

# docker stack deploy wordpress --compose-file docker-compose.yml

  • 查看部署状况:
# docker stack lsNAME                SERVICES            ORCHESTRATOR
wordpress           2                   Swarm# docker stack ps wordpress ID                  NAME                                     IMAGE               NODE                DESIRED STATE       CURRENT STATE                ERROR               PORTS
qgi46v9jcgkh        wordpress_db.q1n9ztahdj489pltf3gl5pomj   mysql:5.7           test1               Running             Running 18 seconds ago                           
o848jlfflzfv        wordpress_web.1                          wordpress:latest    test1               Running             Running 13 seconds ago                           
2e0yxcr3man2        wordpress_web.2                          wordpress:latest    test2               Running             Running about a minute ago                       
nsvlklmt2ce4        wordpress_web.3                          wordpress:latest    test3               Running             Running 55 seconds ago# docker psCONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                 NAMES
a42ca591eb8c        wordpress:latest    "docker-entrypoint.s…"   2 minutes ago       Up 2 minutes        80/tcp                wordpress_web.1.o848jlfflzfv2p3zgl15ubq3a
3f35d12a5bce        mysql:5.7           "docker-entrypoint.s…"   2 minutes ago       Up 2 minutes        3306/tcp, 33060/tcp   wordpress_db.q1n9ztahdj489pltf3gl5pomj.qgi46v9jcgkh70xwjtnu83t1i

当前集群中有两个service,其中web有3个副本,分别在集群各节点上。

  • 浏览器访问:

打开浏览器,分别访问192.168.30.128192.168.30.129192.168.30.130

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

能够看到,经过swarm集群的任意节点均可以访问到wordpress界面,这与以前使用Docker Service部署wordpress项目一致。

相比之下,使用Docker Stack与使用Docker Service部署项目的差异,就相似于使用Docker Compose与使用Docker Run部署服务的差异。


Docker Secret

在生产环境下,使用Docker Stack是没问题的,但把项目的一些敏感信息(如数据库密码)写在YAML文件中则是咱们不想看到的。可使用Docker Secret解决该问题。

  • 什么是secret?
用户名密码

SSH key

TLS认证

任何不想让别人看到的数据

  • secret管理:
secret存在于Swarm Manager节点的Raft database里

secret能够分配给一个service,该service就能看到这个secret

在容器内部secret看起来像文件,但其实是在内存中

  • docker secret命令:
create  从一个文件或标准输入的内容建立secret

inspect 显示一个或多个secret的详细信息

ls      列出全部的secret

rm      删除一个或多个secret

  • 建立一个secret:
# vim db_root_password123456789# docker secret create -l mysql_root_password password db_root_passwordpa6lx5kt52wtg3md8r1zhtmo2# docker secret lsID                          NAME                DRIVER              CREATED             UPDATED
pa6lx5kt52wtg3md8r1zhtmo2   password                                9 seconds ago       9 seconds ago# docker secret inspect password [
    {
        "ID": "pa6lx5kt52wtg3md8r1zhtmo2",        "Version": {
            "Index": 552        },        "CreatedAt": "2019-10-25T03:47:23.552004564Z",        "UpdatedAt": "2019-10-25T03:47:23.552004564Z",        "Spec": {
            "Name": "password",            "Labels": {
                "mysql_root_password": ""
            }
        }
    }]# rm -f db_root_password

能够看到,咱们根据db_root_password这个文件的内容来建立一个名为password的secret,并设置标签为mysql_root_password

注意:在建立完secret后,最好删除对应的secret文件。

  • 使用刚建立的secret:
# docker service create --name busybox --secret password busybox sh -c "while true; do sleep 3600; done"fefw5tlp44quh2fg01vn0k1ei
overall progress: 1 out of 1 tasks 
1/1: running   [==================================================>] verify: Service converged# docker service lsID                  NAME                MODE                REPLICAS            IMAGE               PORTS
fefw5tlp44qu        busybox             replicated          1/1                 busybox:latest      

# docker service ps busybox ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
tpzod80hckns        busybox.1           busybox:latest      test3               Running             Running 44 seconds ago

192.168.30.130

# docker psCONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS               NAMES
4ba00cff43c1        busybox:latest      "sh -c 'while true; …"   About a minute ago   Up About a minute                       busybox.1.tpzod80hcknsm6yce4mms61mz# docker exec -it busybox.1.tpzod80hcknsm6yce4mms61mz sh/ # cd /run/secrets//run/secrets # lspassword

/run/secrets # cat password 123456789

能够看到,这与以前的db_root_password文件的内容一致。经过--secret能够给一个service指定多个secret。

  • 在docker stack中使用secret:
# cd /wordpress# vim docker-compose.yml

version: "3.7"services:
  db:
    image: mysql:5.7
    secrets:
      - password    environment:
      MYSQL_ROOT_PASSWORD_FILE: /run/secrets/password      MYSQL_DATABASE: wordpress    volumes:
      - db_data:/var/lib/mysql    networks:
      - my-network    deploy:
      mode: global      placement:
        constraints:
          - node.role == manager  web:
    depends_on:
      - db    image: wordpress    ports:
      - "80:80"
    secrets:
      - password    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_PASSWORD_FILE: /run/secrets/password    networks:
      - my-network    deploy:
      mode: replicated      replicas: 3
      restart_policy:
        condition: on-failure        delay: 5s        max_attempts: 3
      update_config:
        parallelism: 3
        delay: 10s        order: stop-first        
volumes:
  db_data:
  networks:
  my-network:
    driver: overlaysecrets:
  password:
    external: true#secrets:#  password:#    file: ./db_root_password

与前面不使用secret的docker-compose.yml文件对比,上面的docker-compose.yml文件中增长了secrets指令,并指定secret所在路径,external: true表示外部已经建立好secret。

一般来讲,建议事先建立好secret,而后在YAML文件中指定便可,不然也能够取消上面docker-compose.yml文件的注释内容来建立secret。

# docker stack deploy wordpress --compose-file docker-compose.yml

  • 查看部署状况:
# docker stack lsNAME                SERVICES            ORCHESTRATOR
wordpress           2                   Swarm# docker stack ps wordpress ID                  NAME                                     IMAGE               NODE                DESIRED STATE       CURRENT STATE             ERROR               PORTS
6ozs7o5eit0i        wordpress_db.q1n9ztahdj489pltf3gl5pomj   mysql:5.7           test1               Running             Running 4 seconds ago                         
aj4mis52w7tv        wordpress_web.1                          wordpress:latest    test3               Running             Starting 38 seconds ago                       
r3cn3bs4edwu        wordpress_web.2                          wordpress:latest    test1               Running             Running 9 seconds ago                         
mt81de7ihoc4        wordpress_web.3                          wordpress:latest    test2               Running             Starting 34 seconds ago

  • 使用secret登入mysql:
# docker psCONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                 NAMES
e25a893106d5        mysql:5.7           "docker-entrypoint.s…"   About a minute ago   Up About a minute   3306/tcp, 33060/tcp   wordpress_db.q1n9ztahdj489pltf3gl5pomj.6ozs7o5eit0i299hlkaedk8nr
12ce1facb2bb        wordpress:latest    "docker-entrypoint.s…"   2 minutes ago        Up About a minute   80/tcp                wordpress_web.2.r3cn3bs4edwunnykn9t83xqvm# docker exec -it wordpress_db.q1n9ztahdj489pltf3gl5pomj.6ozs7o5eit0i299hlkaedk8nr bashroot@e25a893106d5:/# cat /run/secrets/password 123456789

root@e25a893106d5:/# mysql -uroot -p123456789mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.28 MySQL Community Server (GPL)Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;+--------------------+| Database           |+--------------------+| information_schema || mysql              || performance_schema || sys                || wordpress          |+--------------------+
5 rows in set (0.00 sec)

  • 浏览器访问:

打开浏览器,分别访问192.168.30.128

在这里插入图片描述

这说明wordpress链接mysql没有问题,咱们配置的secret也就没有问题。


Service更新

由于在生产环境中使用的是Docker Swarm集群,那么如何在项目运行中更新service呢?这是咱们须要解决的问题。

以上面经过Docker Stack部署的项目wordpress为例,更新mysql版本。

  • 查看mysql版本:
# docker exec -it wordpress_db.q1n9ztahdj489pltf3gl5pomj.6ozs7o5eit0i299hlkaedk8nr bashroot@e25a893106d5:/# mysql --versionmysql  Ver 14.14 Distrib 5.7.28, for Linux (x86_64) using  EditLine wrapper

当前版本为5.7.28,循环查看mysql版本

root@e25a893106d5:/# sh -c "while true; do mysql --version && sleep 1; done"

  • 更新mysql版本:

新开一个窗口,

# docker service update wordpress_db --image mysql:5.7.27 --update-delay 0s --update-parallelism 1wordpress_db
overall progress: 1 out of 1 tasks 
q1n9ztahdj48: running   [==================================================>] verify: Service converged

# docker exec -it wordpress_db.q1n9ztahdj489pltf3gl5pomj.c1f6ea9fpg9hg5wauihkj0ba4 bashroot@5a13c556e1d4:/# mysql --versionmysql  Ver 14.14 Distrib 5.7.27, for Linux (x86_64) using  EditLine wrapper

能够看到,mysql版本已经更新为5.7.27。

固然,这个例子并很差,由于当前只有一个mysql容器,更新时原容器直接中止运行并删除,通常对数据库容器的更新也不会如此草率,好在这里只是演示如何进行service的更新。

另外,Docker Stack对多个service同时更新仍是经过docker stack deploy命令进行的,只不过事先更改好YAML文件便可。

相关文章
相关标签/搜索