Docker详解--下

321 阅读48分钟

九、Docker Compose

1、Docker Compose简介

开源地址:github.com/docker/comp…

微服务架构的应用系统一般包含若干个微服务,每个微服务一般都会部署多个实例,如果每个微服务都要手动启停,那么效率之低,维护量之大可想而知。

Compose 是用于定义和运行多容器Docker应用程序的编排工具。通过 Compose可以轻松、高效的管理容器,您可以使用 YML 文件来配置应用程序需要的所有服务。然后使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。

Compose创建的容器是基于Docker的,所以可以使用Docker进行管理,但是推荐使用声明式管理方式,也就是通过修改配置文件来管理。

2、Docker compose安装

# 方法一:
sudo curl -L "https://github.com/docker/compose/releases/download/v2.7.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

# 方法二:使用pip安装,版本可能比较旧
$ yum install python-pip python-dev
$ pip install docker-compose

# 方法三:作为容器安装
$ curl -L https://github.com/docker/compose/releases/download/1.25.5/run.sh > /usr/local/bin/docker-compose
$ chmod +x /usr/local/bin/docker-compose

# 方法四:离线安装
# 下载[docker-compose-Linux-x86_64](https://github.com/docker/compose/releases/download/1.8.1/docker-compose-Linux-x86_64),然后重新命名添加可执行权限即可:
$ mv docker-compose-Linux-x86_64 /usr/local/bin/docker-compose;
$ chmod +x /usr/local/bin/docker-compose
# docker官方离线地址:https://dl.bintray.com/docker-compose/master/

如果github下载非常慢,离线文件下载地址:pan.baidu.com/s/1rsk7rHA6…

如果要卸载直接删除文件

sudo rm /usr/local/bin/docker-compose

3、Docker-compose.yml配置详解

(1)顶级配置项

  • version 定义了版本信息
  • services 定义了服务的配置信息
  • networks 定义了网络信息,提供给 services 中的 具体容器使用
  • volumes 定义了卷信息,提供给 services 中的具体容器使用

格式:

version: "3.8" #这边的版本yml文件的版本号

services: # 容器
  servicename: # 服务名字,这个名字也是内部 bridge网络可以使用的 DNS name
    image: # 镜像的名字
    command: # 可选,如果设置,则会覆盖默认镜像里的 CMD命令
    environment: # 可选,相当于 docker run里的 --env
    volumes: # 可选,相当于docker run里的 -v
    networks: # 可选,相当于 docker run里的 --network
    ports: # 可选,相当于 docker run里的 -p
  servicename2:

volumes: # 可选,相当于 docker volume create

networks: # 可选,相当于 docker network create

yaml基础知识:

  • 大小写敏感,缩进表示层级关系
  • 缩进空格数不重要,相同层级左侧对齐即可。(不允许使用 tab 缩进!)
  • 由冒号分隔的键值对表示对象;一组连词线开头的行,构成一个数组;字符串默认不使用引号

(2)version配置指令

YML文件版本兼容性 详情请看官网文档

Compose file formatDocker Engine release
Compose specification19.03.0+
3.819.03.0+
3.718.06.0+
3.618.02.0+
3.517.12.0+
3.417.09.0+
3.317.06.0+
3.217.04.0+
3.11.13.1+
3.01.13.0+
2.417.12.0+
2.317.06.0+
2.21.13.0+
2.11.12.0+
2.01.10.0+

(3)networks配置指令

未显示声明网络,容器会被加入app_default网络中

配置自定义网络

version: '3'

services:
  proxy:
    build: ./proxy
    networks:
      - front
  db:
    image: postgres
    networks:
      - back

networks:
  front:
    driver: host
  back:
    driver: bridge

配置默认网络

version: '3'

services:
  web:
    build: .
    ports:
      - "8000:8000"
  db:
    image: postgres

networks:
  default:
    driver: overlay

使用已存在的网络

version: '3'

services:
  web:
    build: .
    ports:
      - "8000:8000"
  db:
    image: postgres

networks:
  default:
    external:
      name: my-pre-existing-network

(4)volumes配置指令

自定义卷供容器挂载使用

version: '3'

services:
   db: 
     volumes:
       - db_data:/var/lib/mysql
   wordpress:
     volumes:
       - wordpress_files:/var/www/html
       
volumes:
  wordpress_files:
  db_data:

4、Service配置指令详解

container_name(指定容器名称)

version: "3"

services:
  redis:
    image: redis:alpine
    container_name: redis_test

image(指定为镜像名称或镜像ID)

如果镜像在本地不存在,Compose 将会尝试拉取这个镜像。

version: "3"

services:
  redis:
    image: redis:alpine

build(指定Dockerfile文件夹路径)

可以是绝对路径,或者相对docker-compose.yml文件的路径。 Compose将会自动构建镜像,然后使用镜像。

version: '3'

services:
  webapp:    
    build: ./dir

如果同时指定了 image和 build,image 不在具有单独使用它的意义,而是指定了目前要构建的镜像的名称。

version: '3'

services:
  webapp:    
    image: myimage
    build: ./dir

context(指定 Dockerfile文件夹路径)

也可以是到链接到git仓库的url,同时使用dockerfile指令指定Dockerfile文件名。

version: '3'

services:
   webapp:       
      build:
        context: ./dir
        dockerfile: Dockerfile-name

command(覆盖容器启动默认命令)

#写成shell形式
command: bundle exec thin -p 3000
#写成Dockerfile中的exec格式
command: [bundle, exec, thin, -p, 3000]

depends_on(容器依赖)

解决容器的依赖、启动先后的问题,只有依赖的启动完成了才能启动当前的服务。

version: '3'

services:
  web:
    image: redis:alpine
    container_name: redis_test
    depends_on:
      - db
   db:   
     image: mysql:5.7

environment(设置环境变量)

可以使用数组或字典两种格式。只给定名称没有值的变量会自动获宿主机上的对应系统变量。

environment:
  RACK_ENV: development
  SHOW: 'true'
  SESSION_SECRET:

environment:
  - RACK_ENV=development
  - SHOW=true
  - SESSION_SECRET

如果变量名称或者值中用到 true|false,yes|no 等表达布尔含义的词汇,最好放到引号里,避免 YAML 自动解析某些内容为对应的布尔语义。

y|Y|yes|Yes|YES|n|N|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF

expose(暴露端口)

expose:
 - "3000"
 - "8000"

ports(映射端口信息)

宿主端口:容器端口的格式,或者仅仅指定容器的端口,宿主将会随机选择端口。

ports:
 - "3000"
 - "3000-3005"
 - "8000:8000"
 - "9090-9091:8080-8081"
 - "49100:22"
 - "127.0.0.1:8001:8001"
 - "127.0.0.1:5000-5010:5000-5010"
 - "6060:6060/udp"

注意:当使用 HOST:CONTAINER 格式来映射端口时,如果你使用的容器端口小于 60 并且没放到引号里,可能会得到错误结果,因为 YAML 会自动解析 xx:yy 这种数字格式为 60 进制。为避免出现这种问题,建议数字串都采用引号包括起来的字符串格式。

extra_hosts(指定额外host映射)

类似Docker中的–add-host参数,会在启动后的服务容器中/etc/hosts文件中添加host映射信息。

extra_hosts:
 - "somehost:162.242.195.82"
 - "otherhost:50.31.209.229"

dns(自定义DNS服务器)

可以是一个值,也可以是一个列表。

dns:8.8.8.8
dns:
    - 8.8.8.8   
      - 9.9.9.9

links(链接到其它服务中的容器)

links:
    - db
    - db:database
    - redis

net(设置网络模式)

net: "bridge"
net: "none"
net: "host"

pid(跟主机系统共享进程命名空间)

将PID模式设置为hos模式,跟主机系统共享进程命名空间。容器使用pid标签将能够访问和操纵其他容器和宿主机的名称空间。

pid: "host"

entrypoint(指定服务启动后执行的程序)

user(指定容器中运行应用的用户名)

working_dir(指定容器中工作目录)

restart(指定容器退出后的重启策略)

该命令对保持服务始终运行十分有效,在生产环境 中推荐配置为 always 或者 unless-stopped 。

restart: always

alias(网络上此服务的别名)

同一网络上的其他容器可以使用服务名称或此别名连接到其中一个服务的容器。由于aliases是网络范围的,因此相同的服务可以在不同的网络上具有不同的别名。 注意:网络范围的别名可以多个容器共享,甚至可以多个服务共享。如果是,则无法保证名称解析到正确的容器。

services:
  some-service:
    networks:
      some-network:
        aliases:
         - alias1
         - alias3
      other-network:
        aliases:
         - alias2

volumes(挂载宿主机路径到容器)

挂载一个目录或者一个已存在的数据卷容器,可以直接使用 [HOST:CONTAINER]格式,或者使用[HOST:CONTAINER:ro]格式,后者对于容器来说,数据卷是只读的,可以有效保护宿主机的文件系统。 Compose的数据卷指定路径可以是相对路径,使用 . 或者 .. 来指定相对目录。

volumes:
  // 只是指定一个路径,Docker 会自动在创建一个数据卷(这个路径是容器内部的)。
  - /var/lib/mysql
  // 使用绝对路径挂载数据卷
  - /opt/data:/var/lib/mysql
  //  Compose 配置文件为中心的相对路径作为数据卷挂载到容器。
  - ./cache:/tmp/cache
  // 使用用户的相对路径(~/ 表示的目录是 /home/<用户目录>/ 或者 /root/)。
  - ~/configs:/etc/configs/:ro
  // 已经存在的命名的数据卷。
  - datavolume:/var/lib/mysql

volumes_from(从另一个服务或容器挂载)

volumes_from:
   - service_name   
     - container_name

5、Docker-Compose常用命令

[root@bluecusliyou image-save]# docker-compose --help

Usage:  docker compose [OPTIONS] COMMAND

Docker Compose

Options:
      --ansi string                Control when to print ANSI control characters ("never"|"always"|"auto") (default "auto")
      --compatibility              Run compose in backward compatibility mode
      --env-file string            Specify an alternate environment file.
  -f, --file stringArray           Compose configuration files
      --profile stringArray        Specify a profile to enable
      --project-directory string   Specify an alternate working directory
                                   (default: the path of the Compose file)
  -p, --project-name string        Project name

Commands:
  build       Build or rebuild services
  convert     Converts the compose file to platform's canonical format
  cp          Copy files/folders between a service container and the local filesystem
  create      Creates containers for a service.
  down        Stop and remove containers, networks
  events      Receive real time events from containers.
  exec        Execute a command in a running container.
  images      List images used by the created containers
  kill        Force stop service containers.
  logs        View output from containers
  ls          List running compose projects
  pause       Pause services
  port        Print the public port for a port binding.
  ps          List containers
  pull        Pull service images
  push        Push service images
  restart     Restart containers
  rm          Removes stopped service containers
  run         Run a one-off command on a service.
  start       Start services
  stop        Stop services
  top         Display the running processes
  unpause     Unpause services
  up          Create and start containers
  version     Show the Docker Compose version information

Run 'docker compose COMMAND --help' for more information on a command.

docker-compose up(启动服务)

用于部署一个 Compose 应用。默认情况下该命令会读取名为 docker-compose.yml 或 docker-compose.yaml 的文件。当然用户也可以使用 -f 指定其他文件名。通常情况下,会使用 -d 参数令应用在后台启动。

docker compose创建的容器,名字都会加入一个对应文件夹的名字,比如我当前所在的文件夹叫做test,而我在yaml文件中起的名字是my-wordpress。最终容器的名字就是test_my-wordpress_1。这个前缀其实是可以改的,比如我们希望前缀加上bluecusliyou。就可以使用-p参数指定。

docker-compose up [options] [--scale SERVICE=NUM...] [SERVICE...]
选项包括:
-d 在后台运行服务容器
-no-color 不是有颜色来区分不同的服务的控制输出
-no-deps 不启动服务所链接的容器
--force-recreate 强制重新创建容器,不能与-no-recreate同时使用
–no-recreate 如果容器已经存在,则不重新创建,不能与–force-recreate同时使用
–no-build 不自动构建缺失的服务镜像
–build 在启动容器前构建服务镜像
–abort-on-container-exit 停止所有容器,如果任何一个容器被停止,不能与-d同时使用
-t, –timeout TIMEOUT 停止容器时候的超时(默认为10秒)
–remove-orphans 删除服务中没有在compose文件中定义的容器

docker-compose ps(列出服务)

[root@bluecusliyou ~]# docker-compose ps --help

Usage:  docker compose ps [SERVICE...]

List containers

Options:
  -a, --all                  Show all stopped containers (including those created by the run command)
      --format string        Format the output. Values: [pretty | json] (default "pretty")
  -q, --quiet                Only display IDs
      --services             Display services
      --status stringArray   Filter services by status. Values: [paused | restarting | removing | running | dead | created | exited]

docker-compose create(为服务创建容器)

docker-compose create [options] [SERVICE...]
为服务创建容器。
选项包括:
–force-recreate:重新创建容器,即使配置和镜像没有改变,不兼容–no-recreate参数
–no-recreate:如果容器已经存在,不需要重新创建,不兼容–force-recreate参数
–no-build:不创建镜像,即使缺失
–build:创建容器前,生成镜像

docker-compose run(在指定服务上执行命令)

docker-compose run [options] [-v VOLUME...] [-p PORT...] [-e KEY=VAL...] SERVICE [COMMAND] [ARGS...]
在指定服务上执行命令。
docker-compose run ubuntu ping www.baidu.com
在指定容器上执行一个ping命令。

docker-compose scale(指定服务运行的容器个数)

docker-compose scale web=3 db=2
指定服务运行的容器个数。通过service=num的参数来设置数量

docker-compose exec(进入服务的容器)

docker-compose exec [options] SERVICE COMMAND [ARGS...]
选项包括:
-d 分离模式,后台运行命令。
–privileged 获取特权。
–user USER 指定运行的用户。
-T 禁用分配TTY,默认docker-compose exec分配TTY。
–index=index,当一个服务拥有多个容器时,可通过该参数登陆到该服务下的任何容器,例如:docker-compose exec –index=1 web /bin/bash ,web服务中包含多个容器

docker-compose start(启动服务)

docker-compose pause(暂停一个服务)

docker-compose uppause(恢复暂停状态中的服务)

docker-compose kill(强制停止服务)

docker-compose kill [options] [SERVICE...]
通过发送SIGKILL信号来强制停止服务容器。
支持通过-s参数来指定发送的信号,例如通过如下指令发送SIGINT信号:
docker-compose kill -s SIGINT

docker-compose stop(停止服务)

docker-compose stop [options] [SERVICE...]
选项包括
-t, –timeout TIMEOUT 停止容器时候的超时(默认为10秒)
docker-compose stop
停止正在运行的容器,可以通过docker-compose start 再次启动

docker-compose restart(重启服务)

如果用户在停止该应用后对其进行了变更,那么变更的内容不会反映在重启后的应用中,这时需要重新部署应用使变更生效。

docker-compose restart [options] [SERVICE...]
重启项目中的服务。
选项包括:
-t, –timeout TIMEOUT,指定重启前停止容器的超时(默认为10秒)
docker-compose restart
重启项目中的服务

docker-compose down(停止并删除服务)

docker-compose down [options]
停止和删除容器,它会删除容器和网络,但是不会删除卷和镜像。
选项包括:
–rmi type,删除镜像,类型必须是:all,删除compose文件中定义的所有镜像;local,删除镜像名为空的镜像
-v, –volumes,删除已经在compose文件中定义的和匿名的附在容器上的数据卷
–remove-orphans,删除服务中没有在compose中定义的容器
docker-compose down
停用移除所有容器以及网络相关

docker-compose rm(删除服务)

用于删除已停止的 Compose 应用。它会删除容器和网络,但是不会删除卷和镜像。

docker-compose rm [options] [SERVICE...]
删除所有(停止状态的)服务容器,它会删除容器和网络,但是不会删除卷和镜像。
选项包括:
–f, –force,强制直接删除,包括非停止状态的容器
-v,删除容器所挂载的数据卷
docker-compose rm
删除所有(停止状态的)服务容器。推荐先执行docker-compose stop命令来停止容器。

docker-compose pull(拉取服务依赖的镜像)

docker-compose pull [options] [SERVICE...]
拉取服务依赖的镜像。
选项包括:
–ignore-pull-failures,忽略拉取镜像过程中的错误
–parallel,多个镜像同时拉取
–quiet,拉取镜像过程中不打印进度信息
docker-compose pull
拉取服务依赖的镜像

docker-compose push(推送服务依赖的镜像)

docker-compose push [options] [SERVICE...]
推送服务依赖的镜像。
选项包括:
–ignore-push-failures 忽略推送镜像过程中的错误

docker-compose bulid(构建服务依赖的镜像)

docker-compose build [options] [--build-arg key=val...] [SERVICE...]
构建服务依赖的镜像。
选项包括:
–compress 通过gzip压缩构建上下环境
–force-rm 删除构建过程中的临时容器
–no-cache 构建镜像过程中不使用缓存
–pull 始终尝试通过拉取操作来获取更新版本的镜像
-m, –memory MEM为构建的容器设置内存大小
–build-arg key=val为服务设置build-time变量
服务容器一旦构建后,将会带上一个标记名。可以随时在项目目录下运行docker-compose build来重新构建服务

docker-compose logs(查看应用容器日志)

docker-compose logs [options] [SERVICE...]
查看服务容器的输出。默认情况下,docker-compose将对不同的服务输出使用不同的颜色来区分。可以通过–no-color来关闭颜色。
docker-compose logs
查看服务容器的输出
-f 跟踪日志输出

docker-compose config(查看compose文件配置)

docker-compose config [options]
验证并查看compose文件配置。
选项包括:
–resolve-image-digests 将镜像标签标记为摘要
-q, –quiet 只验证配置,不输出。 当配置正确时,不输出任何内容,当文件配置错误,输出错误信息
–services 打印服务名,一行一个
–volumes 打印数据卷名,一行一个

docker-compose port(显示容器端口映射的端口)

docker-compose port [options] SERVICE PRIVATE_PORT
显示某个容器端口所映射的公共端口。
选项包括:
–protocol=proto,指定端口协议,TCP(默认值)或者UDP
–index=index,如果同一服务存在多个容器,指定命令对象容器的序号(默认为1)

6、实战:wordpress

(1)编写docker-compose.yaml文件

version: '3.3'           #compose文件版本

services:
   db:                   # 服务1:db
     image: mysql:5.7    # 使用镜像 mysql:5.7版本
     volumes:
       - db_data:/var/lib/mysql   # 数据持久化
     restart: always     # 容器服务宕机后总是重启
     environment:        # 环境配置
       MYSQL_ROOT_PASSWORD: somewordpress
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress

   wordpress:          # 服务2:wordpress
     depends_on:       # wordpress服务启动时依赖db服务,所以会自动先启动db服务
       - db
     image: wordpress:latest    # 使用镜像 wordpress:latest最新版
     volumes:
       - wordpress_files:/var/www/html   # 数据持久化
     ports:
       - "8000:80"          #端口映射8000:80
     restart: always
     environment:        # 环境
       WORDPRESS_DB_HOST: db:3306     # wordpress连接db的3306端口
       WORDPRESS_DB_USER: wordpress    # wordpress的数据库用户为wordpress
       WORDPRESS_DB_PASSWORD: wordpress   # wordpress的数据库密码是wordpress
       WORDPRESS_DB_NAME: wordpress    # wordpress的数据库名字是wordpress
volumes:
  wordpress_files:
  db_data:

(2)运行docker-compose.yaml

在docker-compose.yaml文件夹下运行命令

[root@bluecusliyou docker-compose-wordpress]# docker-compose up -d
[+] Running 2/2
 ⠿ Container docker-compose-wordpress-db-1         Started                 0.7s
 ⠿ Container docker-compose-wordpress-wordpress-1  Started                 1.4s 

(3)首次配置界面

地址:IP:8000

(4)后台管理界面

地址:IP:8000/wp-admin/

(5)前端界面

地址:IP:8000

十、Docker Swarm

1、Docker Swarm简介

(1)Docker Swarm简介

Docker Swarm 是 Docker 的集群管理工具,在之前我们只是在一台机器来进行docker的管理。

但是有时容器并不一定都在一台主机上,如果是分布式的处于多台主机上,这时就可以借助于Swarm,Swarm是Docker自带的编排工具,自 Docker 1.12 版本之后,它已经完全集成在 Docker 引擎中,只要你安装了Docker就会存在Docker Swarm工具。

(2)manager和worker节点

Swarm中有两大类节点,一类是manager节点,另一类是worker节点,manager节点是对服务的创建和调度,worker节点主要是运行容器服务,当然manager节点也是可以运行的。

manager节点状态、信息是用Raft consensus group的网络进行通信同步的,而worker之间的通信依靠的是Gossip network做到的。

管理节点负责集群控制,进行诸如监控集群状态、分发任务至工作节点等操作。工作节点接收来自管理节点的任务并执行。

Swarm 的配置和状态信息保存在一套位于所有管理节点上的分布式 etcd 数据库中。该数据库运行于内存中,并保持数据的最新状态。关于该数据库最棒的是,它几乎不需要任何配置,作为 Swarm 的一部分被安装,无须管理。

(3)服务service

另外一个重要的概念就是service,我们可以在一个manager节点上创建一个服务,但是可以根据这一个服务创建多个容器的任务,这些容器任务运行在不同的节点上。

(4)单引擎模式和Swarm 模式

不包含在任何 Swarm 中的 Docker 节点,称为运行于单引擎(Single-Engine)模式。一旦被加入 Swarm 集群,则切换为 Swarm 模式,如下图所示。

在单引擎模式下的 Docker 主机上运行docker swarm init将其切换到 Swarm 模式,并创建一个新的 Swarm,将自身设置为 Swarm 的第一个管理节点。

更多的节点可以作为管理节点或工作节点加入进来。这一操作也会将新加入的节点切换为 Swarm 模式。

(5)集群安全性

Swarm 默认内置有加密的分布式集群存储(encrypted distributed cluster store)、加密网络(Encrypted Network)、公用TLS(Mutual TLS)、安全集群接入令牌 Secure Cluster Join Token)以及一套简化数字证书管理的 PKI(Public Key Infrastructure)。

关于集群管理,最大的挑战在于保证其安全性。搭建 Swarm 集群时将不可避免地使用 TLS,因为它被 Swarm 紧密集成。

Swarm 使用 TLS 进行通信加密、节点认证和角色授权。自动密钥轮换(Automatic Key Rotation)更是锦上添花!其在后台默默进行,用户甚至感知不到这一功能的存在。

(6)如何进行Swarm集群的搭建

  • 在swarm模式下初始化一个Swarm集群,并且将当前主机加入到该集群作为manager节点
  • 加入其它节点到该集群中
  • 部署service到该集群中

2、Docker Swarm集群搭建

(1)集群创建命令

集群管理命令

[root@bluecusliyou ~]# docker swarm --help

Usage:    docker swarm COMMAND

Manage Swarm

Commands:
  ca          Display and rotate the root CA
  init        Initialize a swarm
  join        Join a swarm as a node and/or manager
  join-token  Manage join tokens
  leave       Leave the swarm
  unlock      Unlock swarm
  unlock-key  Manage the unlock key
  update      Update the swarm

Run 'docker swarm COMMAND --help' for more information on a command.

节点管理命令

[root@bluecusliyou ~]# docker node --help

Usage:  docker node COMMAND

Manage Swarm nodes

Commands:
  demote      Demote one or more nodes from manager in the swarm
  inspect     Display detailed information on one or more nodes
  ls          List nodes in the swarm
  promote     Promote one or more nodes to manager in the swarm
  ps          List tasks running on one or more nodes, defaults to current node
  rm          Remove one or more nodes from the swarm
  update      Update a node

Run 'docker node COMMAND --help' for more information on a command.

(2)集群搭建前提

每个节点都需要安装 Docker,并且能够与 Swarm 的其他节点通信。

在网络方面,需要在路由器和防火墙中开放如下端口。

  • 2377/tcp:用于客户端与 Swarm 进行安全通信。
  • 7946/tcp 与 7946/udp:用于控制面 gossip 分发。
  • 4789/udp:用于基于 VXLAN 的覆盖网络。

(3)初始化一个全新的Swarm集群

docker swarm init会通知 Docker 来初始化一个新的 Swarm,并将自身设置为第一个管理节点,作为leader。同时也会使该节点开启 Swarm 模式,且生成worker节点加入集群的命令。

--advertise-addr指定其他节点用来连接到当前管理节点的 IP 和端口。这一属性是可选的,当节点上有多个 IP 时,可以用于指定使用哪个IP。此外,还可以用于指定一个节点上没有的 IP,比如一个负载均衡的 IP。

--listen-addr指定用于承载 Swarm 流量的 IP 和端口。其设置通常与 --advertise-addr 相匹配,但是当节点上有多个 IP 的时候,可用于指定具体某个 IP。并且,如果 --advertise-addr 设置了一个远程 IP 地址(如负载均衡的IP地址),该属性也是需要设置的。建议执行命令时总是使用这两个属性来指定具体 IP 和端口。

Swarm 模式下的操作默认运行于 2337 端口。虽然它是可配置的,但 2377/tcp 是用于客户端与 Swarm 进行安全(HTTPS)通信的约定俗成的端口配置。

[root@manager1 ~]# docker swarm init --advertise-addr 192.168.0.108:2377
Swarm initialized: current node (sz7bfcmk637qhqfvzqhdnk3t2) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-0zzpk3xqq2ykb5d5jcd6hqeimckhrg5qu82xs7nw2wwnwyjmzg-9tmof9880m9r92vz5rygaa42e 192.168.0.108:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

(4)其他manager和worker节点加入集群

初始化结束后,重新生成节点添加的token命令,后面的参数是manager就是生成manager节点添加的命令,worker就是生成worker节点添加的命令。

工作节点和管理节点的接入命令中使用的接入 Token是不同的。因此,一个节点是作为工作节点还是管理节点接入,完全依赖于使用了哪个 Token。接入 Token 应该被妥善保管,因为这是将一个节点加入 Swarm 的唯一所需!

#给manager节点加入集群使用
[root@manager1 ~]# docker swarm join-token manager
To add a manager to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-0zzpk3xqq2ykb5d5jcd6hqeimckhrg5qu82xs7nw2wwnwyjmzg-9tmof9880m9r92vz5rygaa42e 192.168.0.108:2377
#给worker节点加入集群使用
[root@manager1 ~]# docker swarm join-token worker
To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-0zzpk3xqq2ykb5d5jcd6hqeimckhrg5qu82xs7nw2wwnwyjmzg-9tmof9880m9r92vz5rygaa4aa 192.168.0.108:2377

--advertise-addr 与 --listen-addr 属性是可选的。在网络配置方面,请尽量明确指定相关参数,这是一种好的实践。

另外再开启worker1服务器,将这台机器加入到swarm中成为worker节点

[root@worker1 ~]#docker swarm join --token SWMTKN-1-0zzpk3xqq2ykb5d5jcd6hqeimckhrg5qu82xs7nw2wwnwyjmzg-9tmof9880m9r92vz5rygaa42e 192.168.0.108:2377 --advertise-addr 192.168.0.109:2377
This node joined a swarm as a worker.

另外再开启worker2服务器,将这台机器加入到swarm中成为worker节点

[root@worker2 ~]#docker swarm join --token SWMTKN-1-0zzpk3xqq2ykb5d5jcd6hqeimckhrg5qu82xs7nw2wwnwyjmzg-9tmof9880m9r92vz5rygaa42e 192.168.0.108:2377 --advertise-addr 192.168.0.110:2377
This node joined a swarm as a worker.

另外再开启manager2服务器,将这台机器加入到swarm中成为manager节点

[root@manager2 ~]#docker swarm join --token SWMTKN-1-0zzpk3xqq2ykb5d5jcd6hqeimckhrg5qu82xs7nw2wwnwyjmzg-9tmof9880m9r92vz5rygaa4aa 192.168.0.108:2377 --advertise-addr 192.168.0.111:2377
This node joined a swarm as a manager.

另外再开启manager3服务器,将这台机器加入到swarm中成为manager节点

[root@manager3 ~]#docker swarm join --token SWMTKN-1-0zzpk3xqq2ykb5d5jcd6hqeimckhrg5qu82xs7nw2wwnwyjmzg-9tmof9880m9r92vz5rygaa4aa 192.168.0.108:2377 --advertise-addr 192.168.0.112:2377
This node joined a swarm as a manager.

(5)查看集群中的节点状态

查看节点状态只能在manager节点机器上查看,普通节点无法执行查看,带*的就是本机。

manager status是Leader和Reachable的是manager节点,其他没有值的是worker节点。

[root@manager1 ~]# docker node ls
ID                            HOSTNAME   STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
4lzeh497bcpqlkd7hjwne8k0p *   manager1   Ready     Active         Leader           20.10.12
oqvua8epbvhjl9ikqj0igsim9     manager2   Ready     Active         Reachable        20.10.12
nllsbxz3sv5n3tn2zakoa07s0     manager3   Ready     Active         Reachable        20.10.12
giv1k7vci8znkqizvakv899pc     worker1    Ready     Active                          20.10.12
m9xdyriql28urfiep116ni6wj     worker2    Ready     Active                          20.10.12

3、Docker Swarm集群管理

(1)集群中移除节点

集群中的manager或worker节点执行命令

[root@worker1 ~]# docker swarm leave -f
Node left the swarm.

manager节点执行命令

worker节点执行完命令,节点的status会变成down,然后才能删除这个节点,状态是ready的节点无法删除

[root@manager1 ~]# docker node ls
ID                            HOSTNAME   STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
w3o3qywuwjqcq64igexbln881 *   manager1   Ready     Active         Leader           20.10.12
jfs3h490ikpc13i9hv55x29eg     manager2   Ready     Active         Reachable        20.10.12
swa8o3cy7zg42tza0sy6gwl9i     manager3   Ready     Active         Reachable        20.10.12
06rckc92r53ssksfjx46uskyi     worker1    Down      Active                          20.10.12
mtny8rj6xkeqwabwsj4jhgok9     worker2    Ready     Active                          20.10.12
[root@manager1 ~]# docker node rm worker1
worker1
[root@manager1 ~]# docker node ls
ID                            HOSTNAME   STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
w3o3qywuwjqcq64igexbln881 *   manager1   Ready     Active         Leader           20.10.12
jfs3h490ikpc13i9hv55x29eg     manager2   Ready     Active         Reachable        20.10.12
swa8o3cy7zg42tza0sy6gwl9i     manager3   Ready     Active         Reachable        20.10.12
mtny8rj6xkeqwabwsj4jhgok9     worker2    Ready     Active                          20.10.12

(2)更新节点的可获得状态

节点状态是Active,表示可以接受新的任务分配,如果是Drain,表示不接受新的任务分配,不影响集群的运行,集群的负载能力有所下降。扩展的节点会转移到其他节点上,保持运行的容器数量保持不变。

[root@manager1 ~]# docker node ls
ID                            HOSTNAME   STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
w3o3qywuwjqcq64igexbln881 *   manager1   Ready     Active         Leader           20.10.12
jfs3h490ikpc13i9hv55x29eg     manager2   Ready     Active         Reachable        20.10.12
swa8o3cy7zg42tza0sy6gwl9i     manager3   Ready     Active         Reachable        20.10.12
djjv90fb8n4qpjpu6cogfiinz     worker1    Ready     Active                          20.10.12
mtny8rj6xkeqwabwsj4jhgok9     worker2    Ready     Active                          20.10.12
[root@manager1 ~]# docker node update --availability drain worker1
worker1
[root@manager1 ~]# docker node ls
ID                            HOSTNAME   STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
w3o3qywuwjqcq64igexbln881 *   manager1   Ready     Active         Leader           20.10.12
jfs3h490ikpc13i9hv55x29eg     manager2   Ready     Active         Reachable        20.10.12
swa8o3cy7zg42tza0sy6gwl9i     manager3   Ready     Active         Reachable        20.10.12
djjv90fb8n4qpjpu6cogfiinz     worker1    Ready     Drain                           20.10.12
mtny8rj6xkeqwabwsj4jhgok9     worker2    Ready     Active                          20.10.12
[root@manager1 ~]# docker node update --availability active worker1
worker1
[root@manager1 ~]# docker node ls
ID                            HOSTNAME   STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
w3o3qywuwjqcq64igexbln881 *   manager1   Ready     Active         Leader           20.10.12
jfs3h490ikpc13i9hv55x29eg     manager2   Ready     Active         Reachable        20.10.12
swa8o3cy7zg42tza0sy6gwl9i     manager3   Ready     Active         Reachable        20.10.12
djjv90fb8n4qpjpu6cogfiinz     worker1    Ready     Active                          20.10.12
mtny8rj6xkeqwabwsj4jhgok9     worker2    Ready     Active                          20.10.12

(3)Swarm 管理器高可用性(HA)

Swarm 的管理节点内置有对 HA 的支持。这意味着,即使一个或多个节点发生故障,剩余管理节点也会继续保证 Swarm 的运转。

从技术上来说,Swarm 实现了一种主从方式的多管理节点的 HA。这意味着,即使你可能有多个管理节点,也总是仅有一个节点处于活动状态。

通常处于活动状态的管理节点被称为“主节点”(leader),而主节点也是唯一一个会对 Swarm 发送控制命令的节点。也就是说,只有主节点才会变更配置,或发送任务到工作节点。如果一个备用(非活动)管理节点接收到了 Swarm 命令,则它会将其转发给主节点。

锁定 Swarm

一个旧的管理节点重新接入 Swarm 会自动解密并获得 Raft 数据库中长时间序列的访问权,这会带来安全隐患。

进行备份恢复可能会抹掉最新的 Swarm 配置。为了规避以上问题,Docker 提供了自动锁机制来锁定 Swarm,这会强制要求重启的管理节点在提供一个集群解锁码之后才有权重新接入集群。

通过在执行 docker swarm init 命令来创建一个新的 Swarm 集群时传入 --autolock 参数可以直接启用锁。

对于已经搭建的Swarm 集群,这时也可以使用 docker swarm update 命令来启用锁。在某个 Swarm 管理节点上运行如下命令。请确保将解锁码妥善保管在安全的地方!

[root@manager1 ~]# docker swarm update --autolock=true
Swarm updated.
To unlock a swarm manager after it restarts, run the `docker swarm unlock`
command and provide the following key:

    SWMKEY-1-UNq+ZHjM0DpBDSFDrAMrBhq/kDJZXohG3d6wxcH91dE

Please remember to store this key in a password manager, since without it you
will not be able to restart the manager.

重启某一个管理节点,尽管 Docker 服务已经重启,该管理节点仍然未被允许重新接入集群。如果重启的节点是Leader节点,Leader节点会自动转移到其他manager节点上。

[root@manager2 ~]# systemctl restart docker
[root@manager2 ~]# docker node ls
Error response from daemon: Swarm is encrypted and needs to be unlocked before it can be used. Please use "docker swarm unlock" to unlock it.

其他管理节点执行 docker node ls 命令,会发现重启的管理节点会显示 down 以及 unreachable。

[root@manager1 ~]# docker node ls
ID                            HOSTNAME   STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
w3o3qywuwjqcq64igexbln881 *   manager1   Ready     Active         Leader           20.10.12
jfs3h490ikpc13i9hv55x29eg     manager2   Down      Active         Unreachable      20.10.12
swa8o3cy7zg42tza0sy6gwl9i     manager3   Ready     Active         Reachable        20.10.12
djjv90fb8n4qpjpu6cogfiinz     worker1    Ready     Active                          20.10.12
mtny8rj6xkeqwabwsj4jhgok9     worker2    Ready     Active                          20.10.12

重启的节点上执行 docker swarm unlock 命令来为重启的管理节点解锁 Swarm,需要提供解锁码。该节点将重新接入Swarm,并且再次执行 docker node ls 命令会显示 ready 和 reachable。

[root@manager2 ~]# docker swarm unlock
Please enter unlock key: 
[root@manager2 ~]# docker node ls
ID                            HOSTNAME   STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
w3o3qywuwjqcq64igexbln881     manager1   Ready     Active         Leader           20.10.12
jfs3h490ikpc13i9hv55x29eg *   manager2   Ready     Active         Reachable        20.10.12
swa8o3cy7zg42tza0sy6gwl9i     manager3   Ready     Active         Reachable        20.10.12
djjv90fb8n4qpjpu6cogfiinz     worker1    Ready     Active                          20.10.12
mtny8rj6xkeqwabwsj4jhgok9     worker2    Ready     Active                          20.10.12

4、Docker Swarm集群服务搭建

服务是自Docker1.12 后新引入的概念,并且仅适用于Swarm模式。

使用服务仍能够配置大多数熟悉的容器属性,比如容器名、端口映射、接入网络和镜像。此外还增加了额外的特性,比如可以声明应用服务的期望状态,将其告知 Docker 后,Docker 会负责进行服务的部署和管理。

(1)服务创建命令

[root@bluecusliyou ~]# docker service --help

Usage:    docker service COMMAND

Manage services

Commands:
  create      Create a new service
  inspect     Display detailed information on one or more services
  logs        Fetch the logs of a service or task
  ls          List services
  ps          List the tasks of one or more services
  rm          Remove one or more services
  rollback    Revert changes to a service's configuration
  scale       Scale one or multiple replicated services
  update      Update a service

Run 'docker service COMMAND --help' for more information on a command.

(2)创建一个新的服务

使用 docker service create 命令创建一个新的服务。 该命令与熟悉的 docker run 命令的许多参数是相同的。使用 --name 和 -p 定义服务的方式,与单机启动容器的定义方式是一样的。

--name 将服务名称设定为nginx_swarm。-p将每个节点上的8566端口映射到服务副本内部的80端口。--replicas告知 Docker应该总是有6个此服务的副本。

主管理节点会在 Swarm 中实例化6个副本,管理节点也会作为工作节点运行。相关各工作节点或管理节点会拉取镜像,然后启动一个运行在8566端口上的容器。

所有的服务都会被Swarm持续监控,Swarm 会在后台进行轮训检查(Reconciliation Loop),来持续比较服务的实际状态和期望状态是否一致。如果一致,则无须任何额外操作;如果不一致,Swarm 会使其一致。

服务的默认复制模式(Replication Mode)是副本模式(replicated),这种模式会部署期望数量的服务副本,并尽可能均匀地将各个副本分布在整个集群中。另一种模式是全局模式(global),在这种模式下,每个节点上仅运行一个副本。可以通过给 docker service create 命令传递 --mode global 参数来设置。

[root@manager1 ~]# docker service create -d --name nginx_swarm -p 8566:80 --replicas 6 nginx
7px0w1u46bxuywuf3lq7gqvpa
overall progress: 6 out of 6 tasks 
1/6: running   [==================================================>] 
2/6: running   [==================================================>] 
3/6: running   [==================================================>] 
4/6: running   [==================================================>] 
5/6: running   [==================================================>] 
6/6: running   [==================================================>] 
verify: Service converged

(3)查看服务部署情况

#查看集群中服务列表
[root@manager1 ~]# docker service ls
ID             NAME          MODE         REPLICAS   IMAGE          PORTS
7px0w1u46bxu   nginx_swarm   replicated   6/6        nginx:latest   *:8566->80/tcp
#查看具体服务的容器实例
[root@manager1 ~]# docker service ps nginx_swarm
ID             NAME            IMAGE          NODE       DESIRED STATE   CURRENT STATE           ERROR     PORTS
j70a563za8da   nginx_swarm.1   nginx:latest   worker1    Running         Running 9 minutes ago             
jb69xwxk8zxi   nginx_swarm.2   nginx:latest   worker2    Running         Running 9 minutes ago             
4pre2ed32v0z   nginx_swarm.3   nginx:latest   manager2   Running         Running 9 minutes ago             
6exvevlbaq0v   nginx_swarm.4   nginx:latest   manager3   Running         Running 9 minutes ago             
y6aajhqpi6fc   nginx_swarm.5   nginx:latest   manager3   Running         Running 9 minutes ago             
qskh35pqdrsd   nginx_swarm.6   nginx:latest   manager1   Running         Running 9 minutes ago
#查看具体服务的详情信息,--pretty 参数,限制输出中仅包含最感兴趣的内容,并以易于阅读的格式打印出来
[root@manager1 ~]# docker service inspect --pretty nginx_swarm

ID:             7px0w1u46bxuywuf3lq7gqvpa
Name:           nginx_swarm
Service Mode:   Replicated
 Replicas:      6
Placement:
UpdateConfig:
 Parallelism:   1
 On failure:    pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Update order:      stop-first
RollbackConfig:
 Parallelism:   1
 On failure:    pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Rollback order:    stop-first
ContainerSpec:
 Image:         nginx:latest@sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31
 Init:          false
Resources:
Endpoint Mode:  vip
Ports:
 PublishedPort = 8566
  Protocol = tcp
  TargetPort = 80
  PublishMode = ingress

5、Docker Swarm集群服务管理

(1)删除集群服务

请谨慎使用 docker service rm 命令,因为它在删除所有服务副本时并不会进行确认。

[root@bluecusliyou ~]# docker service rm nginx_swarm
nginx_swam
[root@bluecusliyou ~]# docker service ls
ID        NAME      MODE      REPLICAS   IMAGE     PORTS

(2)服务的扩缩容

服务副本在各个节点上是均衡分布的,在底层实现上,Swarm 执行了一个调度算法,默认将副本尽量均衡分配给 Swarm 中的所有节点。各节点分配的副本数是平均分配的,并未将 CPU 负载等指标考虑在内。

#开启一个服务,三个副本
[root@manager1 ~]# docker service create --name nginx_swarm -p 8566:80 --replicas 3 nginx
cfx1kn6ogu9fk9lt5xkl5xqmb
overall progress: 3 out of 3 tasks 
1/3: running   [==================================================>] 
2/3: running   [==================================================>] 
3/3: running   [==================================================>] 
verify: Service converged 
#查看具体服务的容器实例
[root@manager1 ~]# docker service ps nginx_swarm
ID             NAME            IMAGE          NODE       DESIRED STATE   CURRENT STATE                ERROR     PORTS
idg8nh6gtevo   nginx_swarm.1   nginx:latest   manager2   Running         Running about a minute ago             
lfyb0hfcgd0s   nginx_swarm.2   nginx:latest   manager3   Running         Running about a minute ago             
ug2c06495cv6   nginx_swarm.3   nginx:latest   worker2    Running         Running about a minute ago
#扩容到6个副本
[root@manager1 ~]# docker service scale nginx_swarm=6
nginx_swarm scaled to 6
overall progress: 6 out of 6 tasks 
1/6: running   [==================================================>] 
2/6: running   [==================================================>] 
3/6: running   [==================================================>] 
4/6: running   [==================================================>] 
5/6: running   [==================================================>] 
6/6: running   [==================================================>] 
verify: Service converged 
[root@manager1 ~]# docker service ps nginx_swarm
ID             NAME            IMAGE          NODE       DESIRED STATE   CURRENT STATE            ERROR     PORTS
idg8nh6gtevo   nginx_swarm.1   nginx:latest   manager2   Running         Running 3 minutes ago              
lfyb0hfcgd0s   nginx_swarm.2   nginx:latest   manager3   Running         Running 3 minutes ago              
ug2c06495cv6   nginx_swarm.3   nginx:latest   worker2    Running         Running 3 minutes ago              
bfse0t7ho5e6   nginx_swarm.4   nginx:latest   worker1    Running         Running 20 seconds ago             
4pbw6cmvb879   nginx_swarm.5   nginx:latest   worker1    Running         Running 20 seconds ago             
evcun2vt3a5i   nginx_swarm.6   nginx:latest   manager1   Running         Running 21 seconds ago #缩容回4个副本           
[root@manager1 ~]# docker service scale nginx_swarm=4
nginx_swarm scaled to 4
overall progress: 4 out of 4 tasks 
1/4: running   [==================================================>] 
2/4: running   [==================================================>] 
3/4: running   [==================================================>] 
4/4: running   [==================================================>] 
verify: Service converged 
[root@manager1 ~]# docker service ps nginx_swarm
ID             NAME            IMAGE          NODE       DESIRED STATE   CURRENT STATE            ERROR     PORTS
idg8nh6gtevo   nginx_swarm.1   nginx:latest   manager2   Running         Running 3 minutes ago              
lfyb0hfcgd0s   nginx_swarm.2   nginx:latest   manager3   Running         Running 3 minutes ago              
ug2c06495cv6   nginx_swarm.3   nginx:latest   worker2    Running         Running 3 minutes ago              
bfse0t7ho5e6   nginx_swarm.4   nginx:latest   worker1    Running         Running 45 seconds ago

(3)服务自动修复

Scale在swarm中除了扩缩容外,还有修复作用,比如将某一个节点中的容器stop掉,那么很快swarm中发觉并进行修复,数量保持原先的样子。

现在停掉节点中的一个容器

[root@worker2 ~]# docker ps -a
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS     NAMES
7b2e42d0faab   nginx:latest   "/docker-entrypoint.…"   8 minutes ago   Up 8 minutes   80/tcp    nginx_swarm.3.ug2c06495cv6hz0kzq2hmm4em
[root@worker2 ~]# docker stop nginx_swarm.3.ug2c06495cv6hz0kzq2hmm4em
nginx_swarm.3.ug2c06495cv6hz0kzq2hmm4em

在manager节点中查看容器数量情况,自动又补上了一个,保持了整个系统的稳定性

[root@manager1 ~]# docker service ps nginx_swarm
ID             NAME                IMAGE          NODE       DESIRED STATE   CURRENT STATE                     ERROR     PORTS
idg8nh6gtevo   nginx_swarm.1       nginx:latest   manager2   Running         Running 9 minutes ago                       
lfyb0hfcgd0s   nginx_swarm.2       nginx:latest   manager3   Running         Running 9 minutes ago                       
yf36djugxz0c   nginx_swarm.3       nginx:latest   manager1   Running         Starting less than a second ago             
ug2c06495cv6    \_ nginx_swarm.3   nginx:latest   worker2    Shutdown        Complete 5 seconds ago                      
bfse0t7ho5e6   nginx_swarm.4       nginx:latest   worker1    Running         Running 6 minutes ago     

(4)服务滚动升级

可以采用如下的 docker service update 命令来完成滚动升级。该命令通过变更该服务期望状态的方式来更新运行中的服务。--image声明升级镜像版本,--update-parallelism声明每次更新副本数量,--update-delay声明每次升级有20s的延迟。

对服务执行 docker service inspect --pretty 命令,会发现更新时对并行和延迟的设置已经成为服务定义的一部分。之后的更新操作将会自动使用这些设置,直到再次使用 docker service update 命令覆盖它们。

#先创建redis3.0.6版本的集群服务
[root@manager1 ~]# docker service create --replicas 5 --name redis_swarm redis:3.0.6
g1k5zrnc0j78h5yeus297q1c4
overall progress: 5 out of 5 tasks 
1/5: running   [==================================================>] 
2/5: running   [==================================================>] 
3/5: running   [==================================================>] 
4/5: running   [==================================================>] 
5/5: running   [==================================================>] 
verify: Service converged 
[root@manager1 ~]# docker service ps redis_swarm
ID             NAME            IMAGE         NODE       DESIRED STATE   CURRENT STATE                ERROR     PORTS
y1k9a26s2ynj   redis_swarm.1   redis:3.0.6   manager3   Running         Running about a minute ago             
zprcqg933uex   redis_swarm.2   redis:3.0.6   manager1   Running         Running about a minute ago             
7l7knsjkx3fw   redis_swarm.3   redis:3.0.6   worker2    Running         Running about a minute ago             
iyz9y4zn9q85   redis_swarm.4   redis:3.0.6   worker1    Running         Running about a minute ago             
r3ny1fehq7mr   redis_swarm.5   redis:3.0.6   manager2   Running         Running about a minute ago
#滚动升级redis版本到3.0.7服务集群
[root@manager1 ~]# docker service update --image redis:3.0.7 --update-parallelism 2 --update-delay 20s redis_swarm
redis_swarm
overall progress: 5 out of 5 tasks 
1/5: running   [==================================================>] 
2/5: running   [==================================================>] 
3/5: running   [==================================================>] 
4/5: running   [==================================================>] 
5/5: running   [==================================================>] 
verify: Service converged 
[root@manager1 ~]# docker service ps redis_swarm
ID             NAME                IMAGE         NODE       DESIRED STATE   CURRENT STATE                 ERROR     PORTS
pohkqzmc8b0i   redis_swarm.1       redis:3.0.7   manager3   Running         Running about a minute ago              
y1k9a26s2ynj    \_ redis_swarm.1   redis:3.0.6   manager3   Shutdown        Shutdown about a minute ago             
huibhseqmb8f   redis_swarm.2       redis:3.0.7   manager1   Running         Running 38 seconds ago                  
zprcqg933uex    \_ redis_swarm.2   redis:3.0.6   manager1   Shutdown        Shutdown 45 seconds ago                 
snele4vxak24   redis_swarm.3       redis:3.0.7   worker2    Running         Running about a minute ago              
7l7knsjkx3fw    \_ redis_swarm.3   redis:3.0.6   worker2    Shutdown        Shutdown about a minute ago             
gbleodcf9sgf   redis_swarm.4       redis:3.0.7   worker1    Running         Running about a minute ago              
iyz9y4zn9q85    \_ redis_swarm.4   redis:3.0.6   worker1    Shutdown        Shutdown about a minute ago             
2o3u88asoioh   redis_swarm.5       redis:3.0.7   manager2   Running         Running about a minute ago              
r3ny1fehq7mr    \_ redis_swarm.5   redis:3.0.6   manager2   Shutdown        Shutdown about a minute ago
#查看服务详情
[root@manager1 ~]# docker service inspect --pretty redis_swarm
ID:             g1k5zrnc0j78h5yeus297q1c4
Name:           redis_swarm
Service Mode:   Replicated
 Replicas:      5
UpdateStatus:
 State:         completed
 Started:       28 minutes ago
 Completed:     26 minutes ago
 Message:       update completed
Placement:
UpdateConfig:
 Parallelism:   2
 Delay:         20s
 On failure:    pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Update order:      stop-first
RollbackConfig:
 Parallelism:   1
 On failure:    pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Rollback order:    stop-first
ContainerSpec:
 Image:         redis:3.0.7@sha256:730b765df9fe96af414da64a2b67f3a5f70b8fd13a31e5096fee4807ed802e20
 Init:          false
Resources:
Endpoint Mode:  vip

6、Docker Swarm服务发布模式

(1)两种服务发布模式区别

两种模式均保证服务从集群外可访问。

  • Ingress模式(默认)。
  • Host模式。

通过 Ingress 模式发布的服务,可以保证从 Swarm 集群内任一节点(即使没有运行服务的副本)都能访问该服务;以 Host 模式发布的服务只能通过运行服务副本的节点来访问。下图展示了两种模式的区别。

(2)Host模式发布服务

Ingress 模式是默认方式,使用简单格式即可配置-p 8567:80,如果需要以 Host 模式发布服务,则读者需要使用 --publish 参数的完整格式--publish published=8567,target=80,mode=host

  • published=8567 表示服务通过端口8567提供外部服务。

  • target=80 表示发送到 published 端口8567的请求,会映射到服务副本的 80 端口之上。

  • mode=host 表示只有外部请求发送到运行了服务副本的节点才可以访问该服务。

Host 模式发布的服务只能通过运行服务副本的节点访问,所以没有运行副本的节点访问失败,有运行副本的节点访问成功。所以只有worker1节点能访问成功。

[root@manager1 ~]# docker service create -d --name nginx_swarm_host --publish published=8567,target=80,mode=host nginx
x4vgmlo4zkoiczprijeou8rj6
[root@manager1 ~]# docker service ps nginx_swarm_host
ID             NAME                 IMAGE          NODE      DESIRED STATE   CURRENT STATE            ERROR     PORTS
tid2yzqijqdx   nginx_swarm_host.1   nginx:latest   worker1   Running         Running 24 seconds ago             *:8567->80/tcp,*:8567->80/tcp

(3)Ingress模式发布服务

通常使用 Ingress 模式。在底层,Ingress 模式采用名为 Service Mesh 或者 Swarm Mode Service Mesh 的四层路由网络来实现。

使用Ingress模式发布服务的集群,会自动创建一个overlay类型的Ingress 网络,Swarm全部节点都接入了 Ingress 网络。入站流量可能访问Swarm节点中的任意一个,都会通过Ingress网络路由到有服务副本的那个节点上,所有的节点都会访问成功。如果存在多个运行的副本,流量会平均到每个副本。

[root@manager1 ~]# docker service create -d --name nginx_swarm_ingress --publish published=8568,target=80 nginx
a0bbxe346nv3bf8g5ydlkm6on
[root@manager1 ~]# docker service ps nginx_swarm_ingress
ID             NAME                    IMAGE          NODE      DESIRED STATE   CURRENT STATE           ERROR     PORTS
ng9303ty5o6h   nginx_swarm_ingress.1   nginx:latest   worker1   Running         Running 7 seconds ago
[root@manager1 ~]# docker network ls
NETWORK ID     NAME              DRIVER    SCOPE
...
th1jayy9x342   ingress           overlay   swarm
...

7、Docker Swarm集群服务日志

Docker Swarm 服务的日志可以通过执行 docker service logs 命令来查看,然而并非所有的日志驱动(Logging Driver)都支持该命令。

Docker 节点默认的配置是,服务使用 json-file 日志驱动,其他的驱动还有 journald(仅用于运行有 systemd 的 Linux 主机)、syslog、splunk 和 gelf。json-file 和 journald 是较容易配置的,二者都可用于 docker service logs 命令。

若使用第三方日志驱动,那么就需要用相应日志平台的原生工具来查看日志。

通过在执行 docker service create 命令时传入 --logdriver 和 --log-opts 参数可以强制某服务使用一个不同的日志驱动,这会覆盖 daemon.json 中的配置。

对于查看日志命令,可以使用 --follow 进行跟踪、使用 --tail 显示最近的日志,并使用 --details 获取额外细节。

[root@manager1 ~]# docker service logs redis_swarm
redis_swarm.2.zprcqg933uex@manager1    | 1:C 18 Jan 05:45:48.073 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
redis_swarm.2.zprcqg933uex@manager1    |                 _._                                                  
redis_swarm.2.zprcqg933uex@manager1    |            _.-``__ ''-._                                             
redis_swarm.2.zprcqg933uex@manager1    |       _.-``    `.  `_.  ''-._           Redis 3.0.6 (00000000/0) 64 bit
redis_swarm.2.zprcqg933uex@manager1    |   .-`` .-```.  ```\/    _.,_ ''-._                                   
redis_swarm.2.zprcqg933uex@manager1    |  (    '      ,       .-`  | `,    )     Running in standalone mode
redis_swarm.2.zprcqg933uex@manager1    |  |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
redis_swarm.2.zprcqg933uex@manager1    |  |    `-._   `._    /     _.-'    |     PID: 1
redis_swarm.2.zprcqg933uex@manager1    |   `-._    `-._  `-./  _.-'    _.-'                                   
redis_swarm.2.zprcqg933uex@manager1    |  |`-._`-._    `-.__.-'    _.-'_.-'|                                  
redis_swarm.2.zprcqg933uex@manager1    |  |    `-._`-._        _.-'_.-'    |           http://redis.io        
redis_swarm.2.zprcqg933uex@manager1    |   `-._    `-._`-.__.-'_.-'    _.-'                                   
redis_swarm.2.zprcqg933uex@manager1    |  |`-._`-._    `-.__.-'    _.-'_.-'|                                  
redis_swarm.2.zprcqg933uex@manager1    |  |    `-._`-._        _.-'_.-'    |                                  
redis_swarm.2.zprcqg933uex@manager1    |   `-._    `-._`-.__.-'_.-'    _.-'                                   
redis_swarm.2.zprcqg933uex@manager1    |       `-._    `-.__.-'    _.-'                                       
redis_swarm.2.zprcqg933uex@manager1    |           `-._        _.-'                                           
redis_swarm.2.zprcqg933uex@manager1    |               `-.__.-'                                               
redis_swarm.2.zprcqg933uex@manager1    | 
...

8、Docker overlay覆盖网络

在现实世界中,容器间通信的可靠性和安全性相当重要,即使容器分属于不同网络中的不同主机。这也是覆盖网络大展拳脚的地方,它允许创建扁平的、安全的二层网络来连接多个主机,容器可以连接到覆盖网络并互相通信。

(1)初始化一个swarm集群

[root@manager1 ~]# docker swarm init --advertise-addr 192.168.0.108:2377
Swarm initialized: current node (sz7bfcmk637qhqfvzqhdnk3t2) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-0zzpk3xqq2ykb5d5jcd6hqeimckhrg5qu82xs7nw2wwnwyjmzg-9tmof9880m9r92vz5rygaa42e 192.168.0.108:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

集群中加入一个worker节点

[root@worker1 ~]#docker swarm join --token SWMTKN-1-0zzpk3xqq2ykb5d5jcd6hqeimckhrg5qu82xs7nw2wwnwyjmzg-9tmof9880m9r92vz5rygaa42e 192.168.0.108:2377 --advertise-addr 192.168.0.109:2377
This node joined a swarm as a worker.

集群中有一个manager节点和一个worker节点

[root@manager1 ~]# docker node ls
ID                            HOSTNAME   STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
3mo8nt1otbn9uibulj4qi1nu3 *   manager1   Ready     Active         Leader           20.10.12
ye94i4sxnhlvakspxu8svn3e8     worker1    Ready     Active                          20.10.12

(2)创建一个覆盖网络

创建崭新的覆盖网络,能连接 Swarm 集群内的所有主机,并且该网络还包括一个 TLS 加密的控制层!如果还想对数据层加密的话,只需在命令中增加 -o encrypted 参数。

[root@manager1 ~]# docker network create -d overlay myoverlaynet
usw79xsf1lp0y794922u40msa
[root@manager1 ~]# docker network ls
NETWORK ID     NAME              DRIVER    SCOPE
083de6e47320   bridge            bridge    local
c48bbcc5c882   docker_gwbridge   bridge    local
9697f77248e1   host              host      local
ug21bjpmptdf   ingress           overlay   swarm
usw79xsf1lp0   myoverlaynet      overlay   swarm
abc08bbf4c8b   none              null      local

在worker1节点上无法看到myoverlaynet网络,这是因为只有当运行中的容器连接到覆盖网络的时候,该网络才变为可用状态。这种延迟生效策略通过减少网络梳理,提升了网络的扩展性。

[root@worker1 ~]# docker network ls
NETWORK ID     NAME              DRIVER    SCOPE
e1fa76d56b00   bridge            bridge    local
5751e9e9f8b0   docker_gwbridge   bridge    local
bcfac75c67eb   harbor_harbor     bridge    local
c852370b55e1   host              host      local
ug21bjpmptdf   ingress           overlay   swarm
df18d3322d54   none              null      local

(3)将服务连接到覆盖网络

将服务连接到覆盖网络,服务会包含两个副本,一个运行manager1节点上,一个运行在worker1节点上。两个容器副本自动加入到myoverlaynet网络当中。此时worker1节点就能看到myoverlaynet网络了。

目前已经成功在两个由物理网络连接的节点上创建了新的覆盖网络,同时还将两个容器连接到了该网络当中。

[root@manager1 ~]# docker service create -d --name nginx_swarm_overlay -p 8569:80 --network myoverlaynet --replicas 2 nginx
npq5d4rfn0sh5oijx3ligod2y
[root@manager1 ~]# docker service ps nginx_swarm_overlay
ID             NAME                    IMAGE          NODE       DESIRED STATE   CURRENT STATE            ERROR     PORTS
d6zccckkmmtj   nginx_swarm_overlay.1   nginx:latest   worker1    Running         Running 17 seconds ago             
t92hguhiypy1   nginx_swarm_overlay.2   nginx:latest   manager1   Running         Running 16 seconds ago
[root@worker1 ~]#  docker network ls
NETWORK ID     NAME              DRIVER    SCOPE
e1fa76d56b00   bridge            bridge    local
5751e9e9f8b0   docker_gwbridge   bridge    local
bcfac75c67eb   harbor_harbor     bridge    local
c852370b55e1   host              host      local
ug21bjpmptdf   ingress           overlay   swarm
usw79xsf1lp0   myoverlaynet      overlay   swarm
df18d3322d54   none              null      local

(4)测试覆盖网络

#查看网络详情
[root@manager1 ~]# docker network inspect myoverlaynet
[
    {
        "Name": "myoverlaynet",
        "Id": "usw79xsf1lp0y794922u40msa",
        "Created": "2022-01-18T18:34:40.779699867+08:00",
        "Scope": "swarm",
        "Driver": "overlay",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "10.0.1.0/24",
                    "Gateway": "10.0.1.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "996637f32621c17806947c050790ee55720e25ca6472110a9e9a803b8c0c9826": {
                "Name": "nginx_swarm_overlay.2.t92hguhiypy1fq4jglu390k0x",
                "EndpointID": "86acca9356da1e95a9137176f167029ce794695966521241e176a928f6ff3bbd",
                "MacAddress": "02:42:0a:00:01:04",
                "IPv4Address": "10.0.1.4/24",
                "IPv6Address": ""
            },
            "lb-myoverlaynet": {
                "Name": "myoverlaynet-endpoint",
                "EndpointID": "5aa3481b71fa9044afa17197bbd0af8c7aa2bff65d9b6c402c662a0b7a99e1cd",
                "MacAddress": "02:42:0a:00:01:06",
                "IPv4Address": "10.0.1.6/24",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.driver.overlay.vxlanid_list": "4097"
        },
        "Labels": {},
        "Peers": [
            {
                "Name": "bd2e94d02380",
                "IP": "47.93.238.134"
            },
            {
                "Name": "f28881a12924",
                "IP": "150.158.80.231"
            }
        ]
    }
]
#查看容器ID,判断manager1上的副本IP是10.0.1.4
[root@manager1 ~]# docker ps -l
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS     NAMES
996637f32621   nginx:latest   "/docker-entrypoint.…"   18 minutes ago   Up 18 minutes   80/tcp    nginx_swarm_overlay.2.t92hguhiypy1fq4jglu390k0x
#进入容器,请求另一台服务器,请求成功
[root@manager1 ~]# docker exec -it nginx_swarm_overlay.2.t92hguhiypy1fq4jglu390k0x /bin/bash
root@996637f32621:/# curl 10.0.1.6
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

十一、Docker Stack

1、Docker Stack简介

Docker Stack 通过提供期望状态、滚动升级、简单易用、扩缩容、健康检查等特性简化了大规模场景下的多服务部署和管理,这些功能都封装在一个完美的声明式模型当中。

Stack 能够在单个声明文件docker-stack.yml中定义复杂的多服务应用,然后通过 docker stack deploy 命令完成部署和管理。Stack 是基于 Docker Swarm 之上来完成应用的部署。因此诸如安全等高级特性,其实都是来自 Swarm。简单的说是Stack=Compose+Swarm。

Stack创建的容器是基于Docker的,所以可以使用Docker进行管理,但是推荐使用声明式管理方式,也就是通过修改配置文件来管理。

2、Docker Stack和Docker Compose区别

  • Docker stack会忽略了“构建”指令,无法使用stack命令构建新镜像,它是需要镜像是预先已经构建好的。 所以docker-compose更适合于开发场景。
  • Docker Compose是一个Python项目,在内部,它使用Docker API规范来操作容器。使用Docker -compose需要安装,Docker Stack功能包含在Docker引擎中不需要额外安装,docker stacks 只是swarm mode的一部分。
  • Docker stack不支持基于第2版写的docker-compose.yml ,也就是version版本至少为3。然而Docker Compose对版本为2和3的 文件仍然可以处理。
  • docker stack把docker compose的所有工作都做完了,因此docker stack将占主导地位。同时,对于大多数用户来说,切换到使用docker stack既不困难,也不需要太多的开销。如果您是Docker新手,或正在选择用于新项目的技术,推荐使用docker stack。

3、Docker Stack命令说明

[root@manager1 ~]# docker stack --help

Usage:  docker stack [OPTIONS] COMMAND

Manage Docker stacks

Options:
      --orchestrator string   Orchestrator to use (swarm|kubernetes|all)

Commands:
  deploy      Deploy a new stack or update an existing stack
  ls          List stacks
  ps          List the tasks in the stack
  rm          Remove one or more stacks
  services    List the services in the stack

Run 'docker stack COMMAND --help' for more information on a command.

(1)docker stack deploy(部署服务)

[root@manager1 ~]# docker stack deploy --help

Usage:  docker stack deploy [OPTIONS] STACK

Deploy a new stack or update an existing stack

Aliases:
  deploy, up

Options:
  -c, --compose-file strings   Path to a Compose file, or "-" to read from stdin
      --orchestrator string    Orchestrator to use (swarm|kubernetes|all)
      --prune                  Prune services that are no longer referenced
      --resolve-image string   Query the registry to resolve image digest and supported platforms ("always"|"changed"|"never") (default "always")
      --with-registry-auth     Send registry authentication details to Swarm agents

(2)docker stack ls(查看服务列表)

(3)docker stack services(查看service列表)

[root@manager1 ~]# docker stack services --help

Usage:  docker stack services [OPTIONS] STACK

List the services in the stack

Options:
  -f, --filter filter         Filter output based on conditions provided
      --format string         Pretty-print services using a Go template
      --orchestrator string   Orchestrator to use (swarm|kubernetes|all)
  -q, --quiet                 Only display IDs

(4)docker stack ps(查看服务详情)

[root@manager1 ~]# docker stack ps --help

Usage:  docker stack ps [OPTIONS] STACK

List the tasks in the stack

Options:
  -f, --filter filter         Filter output based on conditions provided
      --format string         Pretty-print tasks using a Go template
      --no-resolve            Do not map IDs to Names
      --no-trunc              Do not truncate output
      --orchestrator string   Orchestrator to use (swarm|kubernetes|all)
  -q, --quiet                 Only display task IDs

(5)docker stack rm(删除服务)

4、Docker Stack应用部署和管理

(1)初始化 Swarm集群,添加节点

(2)创建Stack文件docker-stack.yml

(3)通过docker stack deploy -c stack文件名 服务名 部署服务

(4)通过docker stack ls查看服务列表

(5)通过docker stack services查看service列表

(6)通过docker stack ps 服务名查看服务详情

(7)修改stack文件,重新docker stack deploy部署服务

(8)通过docker stack rm 服务名删除服务

案例项目:github.com/dockersampl…

version: "3.2"

services:
  reverse_proxy:
    image: dockersamples/atseasampleshopapp_reverse_proxy
    ports:
      - "80:80"
      - "443:443"
    secrets:
      - source: revprox_cert
        target: revprox_cert
      - source: revprox_key
        target: revprox_key
    networks:
      - front-tier

  database:
    image: dockersamples/atsea_db
    environment:
      POSTGRES_USER: gordonuser
      POSTGRES_DB_PASSWORD_FILE: /run/secrets/postgres_password
      POSTGRES_DB: atsea
    networks:
      - back-tier
    secrets:
      - postgres_password
    deploy:
      placement:
        constraints:
          - 'node.role == worker'

  appserver:
    image: dockersamples/atsea_app
    networks:
      - front-tier
      - back-tier
      - payment
    deploy:
      replicas: 2
      update_config:
        parallelism: 2
        failure_action: rollback
      placement:
        constraints:
          - 'node.role == worker'
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
        window: 120s
    secrets:
      - postgres_password

  visualizer:
    image: dockersamples/visualizer:stable
    ports:
      - "8001:8080"
    stop_grace_period: 1m30s
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
    deploy:
      update_config:
        failure_action: rollback
      placement:
        constraints:
          - 'node.role == manager'

  payment_gateway:
    image: dockersamples/atseasampleshopapp_payment_gateway
    secrets:
      - source: staging_token
        target: payment_token
    networks:
      - payment
    deploy:
      update_config:
        failure_action: rollback
      placement:
        constraints:
          - 'node.role == worker'
          - 'node.labels.pcidss == yes'

networks:
  front-tier:
  back-tier:
  payment:
    driver: overlay
    driver_opts:
      encrypted: 'yes'

secrets:
  postgres_password:
    external: true
  staging_token:
    external: true
  revprox_key:
    external: true
  revprox_cert:
    external: true