docker 入门2

from: chenj_x12@foxmali.com

Docker Compose

腾讯云

Compose 简介

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

YAML

菜鸟教程-YAML入门

基本语法

  • 大小写敏感
  • 使用缩进表示层级关系
  • 缩进不允许使用tab,只允许空格
  • 缩进的空格数不重要,只要相同层级的元素左对齐即可
  • ‘#‘表示注释

数据类型

YAML 支持以下几种数据类型:

  • 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
  • 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
  • 纯量(scalars):单个的、不可再分的值

YAML 对象

对象键值对使用冒号结构表示 key: value,冒号后面要加一个空格。

也可以使用 key:{key1: value1, key2: value2, …}。

还可以使用缩进表示层级关系;

key: 
    child-key: value
    child-key2: value2

较为复杂的对象格式,可以使用问号加一个空格代表一个复杂的 key,配合一个冒号加一个空格代表一个 value:

?  
    - complexkey1
    - complexkey2
:
    - complexvalue1
    - complexvalue2

意思即对象的属性是一个数组 [complexkey1,complexkey2],对应的值也是一个数组 [complexvalue1,complexvalue2]

YAML 数组

以 - 开头的行表示构成一个数组:

- A
- B
- C

YAML 支持多维数组,可以使用行内表示:

key: [value1, value2, ...]

数据结构的子成员是一个数组,则可以在该项下面缩进一个空格。

-
 - A
 - B
 - C

一个相对复杂的例子:

companies:
    -
        id: 1
        name: company1
        price: 200W
    -
        id: 2
        name: company2
        price: 500W

意思是 companies 属性是一个数组,每一个数组元素又是由 id、name、price 三个属性构成。

数组也可以使用流式(flow)的方式表示:

companies: [{id: 1,name: company1,price: 200W},{id: 2,name: company2,price: 500W}]

复合结构

数组和对象可以构成复合结构,例:

languages:
  - Ruby
  - Perl
  - Python 
websites:
  YAML: yaml.org 
  Ruby: ruby-lang.org 
  Python: python.org 
  Perl: use.perl.org

转换为 json 为:

{ 
  languages: [ 'Ruby', 'Perl', 'Python'],
  websites: {
    YAML: 'yaml.org',
    Ruby: 'ruby-lang.org',
    Python: 'python.org',
    Perl: 'use.perl.org' 
  } 
}

纯量

纯量是最基本的,不可再分的值,包括:

  • 字符串
  • 布尔值
  • 整数
  • 浮点数
  • Null
  • 时间
  • 日期

使用一个例子来快速了解纯量的基本使用:

boolean: 
    - TRUE  #true,True都可以
    - FALSE  #false,False都可以
float:
    - 3.14
    - 6.8523015e+5  #可以使用科学计数法
int:
    - 123
    - 0b1010_0111_0100_1010_1110    #二进制表示
null:
    nodeName: 'node'
    parent: ~  #使用~表示null
string:
    - 哈哈
    - 'Hello world'  #可以使用双引号或者单引号包裹特殊字符
    - newline
      newline2    #字符串可以拆成多行,每一行会被转化成一个空格
date:
    - 2018-02-17    #日期必须使用ISO 8601格式,即yyyy-MM-dd
datetime: 
    -  2018-02-17T15:02:31+08:00    #时间使用ISO 8601格式,时间和日期之间使用T连接,最后使用+代表时区

引用

& 锚点和 ***** 别名,可以用来引用:

defaults: &defaults
  adapter:  postgres
  host:     localhost

development:
  database: myapp_development
  <<: *defaults

test:
  database: myapp_test
  <<: *defaults

相当于:

defaults:
  adapter:  postgres
  host:     localhost

development:
  database: myapp_development
  adapter:  postgres
  host:     localhost

test:
  database: myapp_test
  adapter:  postgres
  host:     localhost

& 用来建立锚点(defaults),« 表示合并到当前数据,***** 用来引用锚点。

下面是另一个例子:

- &showell Steve 
- Clark 
- Brian 
- Oren 
- *showell 

转为 JavaScript 代码如下:

[ 'Steve', 'Clark', 'Brian', 'Oren', 'Steve' ]

\x00

compose

还是直接上例子吧

# docker-compose.yml
# version: '3.8' 这个啥时候被弃用了

services:
  web:
    build: ./flask-app
    ports:
      - "5000:5000"
    environment:
      - FLASK_ENV=development
      - DATABASE_HOST=mariadb
      - DATABASE_USER=ops
      - DATABASE_PASSWORD=password
      - DATABASE_NAME=ops_db
    volumes:
      - .:/app
    restart: always
    logging:
      driver: json-file
      options:
        max-size: "200k"
        max-file: "10"
    depends_on:
      - mariadb
    network:
      - mynetwork

  mariadb:
    build: ./mariadb
    ports:
      - "3306:3306"
    environment:
      - MYSQL_ROOT_PASSWORD=rootpassword
      - MYSQL_DATABASE=ops_db
      - MYSQL_USER=ops
      - MYSQL_PASSWORD=password
    volumes:
      - mariadb-data:/var/lib/mysql
      - ./mariadb/init.sql:/docker-entrypoint-initdb.d/init.sql
    restart: always
    logging:
      driver: json-file
      options:
        max-size: "200k"
        max-file: "10"
    network:
      - mynetwork

  nginx:
    build: ./nginx
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    depends_on:
      - web
    links:
      - web
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/common.conf:/etc/nginx/common.conf
      - ./nginx/ssl/cacert.pem:/etc/nginx/ssl/cacert.pem
      - ./nginx/ssl/privkey.pem:/etc/nginx/ssl/privkey.pem
    restart: always
    logging:
      driver: json-file
      options:
        max-size: "200k"
        max-file: "10"
	networks:
	  - mynetwork
	
volumes:
  mariadb-data:

networks:
  mynetwork:
    driver: bridge

Docker Swarm

学习来源:

Swarm 简介

Docker Swarm 是 Docker 的集群管理工具。它将 Docker 主机池转变为单个虚拟 Docker 主机。 Docker Swarm 提供了标准的 Docker API,所有任何已经与 Docker 守护程序通信的工具都可以使用 Swarm 轻松地扩展到多个主机。

Swarm 架构

docker swarm:管理集群

# 初始化一个swarm
docker swarm init [OPTIONS]
# 选项:
--advertise-addr string     # 发布的地址(格式:<ip|interface>[:port])
--force-new-cluster         # 强制从当前状态创建一个新的集群(去除本地之外的所有管理器身份)
--cert-expiry duration      # 节点证书有效期(ns|us|ms|s|m|h)(默认为2160h0m0s)
--data-path-addr string     # 用于数据路径通信的地址或接口(格式: <ip|interface>)
--data-path-port uint32     # 用于数据路径流量的端口号(1024 - 49151)。如果没有值,则默认端口号4789
--dispatcher-heartbeat duration     # 调度程序的心跳周期(ns|us|ms|s|m|h)(默认为5s)
--listen-addr node-addr     # 监听地址(格式: <ip|interface>[:port]) (默认 0.0.0.0:2377)

# 查看加入节点到集群的命令及令牌(token)
docker swarm join-token [OPTIONS] (worker|manager)
# 选项:
-q, --quiet    # 只显示令牌
    --rotate   # 使旧令牌无效并生成新令牌
# 查看加入工作节点到集群的命令及令牌
docker swarm join-token worker
# 查看加入管理节点到集群的命令及令牌
docker swarm join-token manager

# 将节点加入swarm集群,作为一个manager或worker
docker swarm join [OPTIONS] HOST:PORT
# 选项:
--advertise-addr string   # 发布的地址 (格式: <ip|interface>[:port])
--availability string     # 节点的可用性 ("active"|"pause"|"drain") (default "active")
--data-path-addr string   # 用于数据路径通信的地址或接口 (格式: <ip|interface>)
--listen-addr node-addr   # 监听地址 (格式: <ip|interface>[:port]) (default 0.0.0.0:2377)
--token string            # 进入的swarm集群的令牌     

# 主动退出集群,让节点处于down状态(在需要退出Swarm集群的节点主机上执行命令)
docker swarm leave [OPTIONS]
# 选项:
-f, --force     # 强制。Manager若要退出 Swarm 集群,需要加上强制选项
## 移除一个work-node节点主机的完整步骤:
# 1.在管理节点上操作,清空work-node节点的容器。id 可以使用命令 docker node ls 查看
docker node update --availability drain [id]
# 2.在work-node节点主机上操作,退出集群
docker swarm leave
# 3,在管理节点上操作,删除work-node节点
docker node rm [id]
# 若想解散整个集群,则需先移除所有work-node节点主机,然后所有管理节点也退出集群

# 更新 swarm 集群的配置
docker swarm update [OPTIONS]
# 选项:
--autolock                          # 更改管理器自动锁定设置(true|false)
--cert-expiry duration              # 节点证书有效期(ns|us|ms|s|m|h)(默认为2160h0m0s)
--dispatcher-heartbeat duration     # 调度程序心跳周期(ns|us|ms|s|m|h)(默认为5s)

docker node:管理swarm集群节点

# 查看集群中的节点
docker node ls
#选项:
-f, --filter filter     # 根据所提供的条件过滤输出。(格式:key=value)
                            # 目前支持的过滤器是:id, label, name, membership[=accepted|pending]
                                               # , role[manager|worker]
-q, --quiet             # 只显示id

# 查看运行的一个或多个及节点任务数,默认当前节点
docker node ps [OPTIONS] [NODE...]
#选项:
-f, --filter filter     # 根据所提供的条件过滤输出
-q, --quiet             # 只显示id

# 将worker角色升级为manager
docker node promote NODE [NODE...]
# 将manager角色降级为worker
docker node demote NODE [NODE...]

# 查看节点的详细信息,默认json格式
docker node inspect 主机名
# 查看节点信息平铺格式
docker node inspect --pretty 主机名

# 从swarm中删除一个节点
docker node rm 主机名
# 从swarm中强制删除一个节点
docker node rm -f 主机名

# 更新一个节点
docker node update [options] 主机名
# 选项
--label-add list        # 添加节点标签(key=value)
--label-rm list         # 删除节点标签
--role string           # 更改节点角色 ("worker"|"manager")
--availability active/pause/drain   # 设置节点的状态
                # active  正常
                # pause   暂停。调度程序不向节点分配新任务,但是现有任务仍然保持运行
                # drain   排除自身work任务。调度程序不向节点分配新任务,且会关闭任何现有任务并在可用节点上安排它们

docker service:服务管理

# 列出服务列表
docker service ls

# 列出服务任务信息
docker service ps [OPTIONS] SERVICE [SERVICE...]
# 选项:
    --no-trunc          # 显示完整的信息
-f, --filter filter     # 根据所提供的条件过滤输出。过滤只运行的任务信息:"desired-state=running"
-q, --quiet             # 只显示任务id

# 查看服务内输出
docker service logs [OPTIONS] SERVICE|TASK
# 选项:
    --details        # 显示提供给日志的额外细节
-f, --follow         # 跟踪日志输出
    --since string   # 显示自时间戳 (2013-01-02T13:23:37Z) 或相对时间戳 (42m for 42 minutes) 以来的日志
-n, --tail string    # 从日志末尾显示的行数(默认为“all”)
-t, --timestamps     # 显示时间戳


# 更新服务的相关配置
docker service update [options] 服务名
# 选项
--args "指令"         # 容器加入指令
--image IMAGE        # 更新服务容器镜像
--rollback              # 回滚服务容器版本
--network-add 网络名     # 添加容器网络
--network-rm 网络名      # 删除容器网络
--reserve-cpu int           # 更新分配的cpu
--reserve-memory bytes      # 更新分配的内存(示例:512m)
--publish-add 暴露端口:容器端口     # 映射容器端口到主机
--publish-rm 暴露端口:容器端口      # 移除暴露端口
--endpoint-mode dnsrr        # 修改负载均衡模式为dnsrr
--force                      # 强制重启服务
--config-rm 配置文件名称       # 删除配置文件
--constraint-add list        # 新增一个约束 
--constraint-rm list         # 移除一个约束 
--placement-pref-add pref    # 新增一个偏好 
--placement-pref-rm pref     # 移除一个偏好
--config-add 配置文件名,target=/../容器内配置文件名      # 添加新的配置文件到容器内


# 查看服务详细信息,默认json格式
docker service inspect [OPTIONS] 服务名 [SERVICE...]
# 查看服务信息平铺形式
docker service inspect --pretty 服务名

# 删除服务
docker service rm [OPTIONS] 服务名 [SERVICE...]

# 缩容扩容服务容器副本数量
docker service scale 服务名=副本数 [SERVICE=REPLICAS...]

# 创建一个服务。一般搭建好 Swarm 集群后,使用 docker stack 部署应用,此处仅作了解
docker service create [OPTIONS] IMAGE [COMMAND] [ARG...]
# 选项:
--name string           # 指定容器名称
--replicas int          # 指定副本数
--network 网络名         # 添加网络组
--mode string           # 服务模式(复制或全局)(replicated | global)
--reserve-cpu int       # 预留的cpu
--reserve-memory bytes  # 预留的内存(512m)
--limit-cpu int         # 限制CPU
--limit-memory bytes    # 限制内存(512m)
-l, --label list            # 服务的标签(key=value)
--container-label list      # 容器标签(key=value)
-p, --publish 暴露端口:容器端口   # 映射容器端口到主机
-e, --env MYVAR=myvalue         # 配置环境变量
-w, --workdir string            # 指定工作目录(示例:/tmp)
-restart-condition string       # 满足条件时重新启动(no | always | on-failure | unless-stopped)
--restart-delay duration        # 重新启动尝试之间的延迟 (ns/us/ms/s/m/h)
--restart-max-attempts int      # 放弃前的最大重启次数
--restart-window duration           # 用于评估重启策略的窗口 (ns/us/ms/s/m/h)
--stop-grace-period duration        # 强制杀死容器前的等待时间 (ns/us/ms/s/m/h)
--update-delay duration             # 更新之间的延迟(ns/us/ms/s/m/h)(默认 0s)
--update-failure-action string      # 更新失败的操作("pause"停止|"continue"继续)(默认pause)
--update-max-failure-ratio float    # 更新期间容忍的失败率
--update-monitor duration           # 每次任务更新后监控失败的持续时间(ns/us/ms/s/m/h)(默认 0s)
--update-parallelism int            # 同时更新的最大任务数(0表示一次更新全部任务)(默认为1)  
--endpoint-mode string              # 负载均衡模式(vip or dnsrr) (默认 "vip")
--rollback-monitor 20s              # 每次容器与容器之间的回滚时间间隔
--rollback-max-failure-ratio .数值    # 回滚故障率如果小于百分比允许运行(“.2”为%20)
--mount type=volume,src=volume名称,dst=容器目录    # 创建volume类型数据卷
--mount type=bind,src=宿主目录,dst=容器目录         # 创建bind读写目录挂载
--mount type=bind,src=宿主目录,dst=容器目录,readonly     # 创建bind只读目录挂载
--config source=docker配置文件,target=配置文件路径        # 创建docker配置文件到容器本地目录

docker secret:管理敏感数据存储

# 查看敏感数据卷列表
$ docker secret ls

# 显示一个或多个敏感数据卷的详细信息
$ docker secret inspect [OPTIONS] SECRET [SECRET...]
# 选项
    --pretty        # 易读的格式打印信息

# 从文件或标准输入创建一个敏感数据卷作为内容
$ docker secret create [OPTIONS] SECRET [file|-]
# 选项
  -d, --driver string            # 指定驱动
  -l, --label list               # 指定标签
      --template-driver string   # 指定模板驱动程序

# 移除一个或多个敏感数据卷
$ docker secret rm SECRET [SECRET...]
# 别名:rm, remove

docker config:管理配置文件

# 查看已创建配置文件
docker config ls [OPTIONS]
# 选项:
-f, --filter filter     # 根据所提供的条件过滤输出
-q, --quiet             # 只显示id

# 查看配置详细信息
docker config inspect 配置文件名

# 删除配置
docker config rm CONFIG [CONFIG...]

# 创建配置文件
docker config create 配置文件名 本地配置文件
# 示例:新建配置文件并添加新配置文件到服务
# 1.创建配置文件
docker config create nginx2_config nginx2.conf 
# 2.删除旧配置文件
docker service update --config-rm ce_nginx_config 服务名
# 3.添加新配置文件到服务
docker service update --config-add src=nginx2_config,target=/etc/nginx/nginx.conf ce_nginx

docker network: 网络信息

# 查看集群网络列表
docker network ls

# 将容器连接到集群网络中
$ docker network connect [OPTIONS] NETWORK CONTAINER
# 选项
    --alias strings       # 为容器添加网络范围的别名
    --driver-opt string   · # 指定网络驱动程序
    --ip string         # 指定IPv4地址(如172.30.100.104)
    --ip6 string        # 指定IPv6地址(例如,2001:db8::33)
    --link list         # 添加到另一个容器的链接
    --link-local-ip string    # 为容器添加一个链接本地地址
# 示例
docker network connect mynet nginx

# 断开一个容器与集群网络的连接
$ docker network disconnect [OPTIONS] NETWORK CONTAINER
# 选项
  -f, --force   # 强制容器从网络断开连接  

# 显示一个或多个集群网络的详细信息
$ docker network inspect [OPTIONS] NETWORK [NETWORK...]
# 选项
  -f, --format string   # 使用给定的Go模板格式化输出
  -v, --verbose         # 输出详细的诊断信息

# 创建一个集群网络
$ docker network create [OPTIONS] NETWORK
# 选项
      --attachable           # 准许手动容器连接
      --aux-address map      # 网络驱动使用的辅助IPv4或IPv6地址(默认映射[])
      --config-from string   # 要从其中复制配置的网络
      --config-only          # 创建仅配置网络
  -d, --driver string        # 管理网络的驱动程序(默认为“"bridge”)。选项:bridge、overlay、macvlan
      --gateway strings      # 指定IPv4或IPv6主子网网关。示例:172.20.0.1
      --ingress              # 创建群路由-网格网络
      --internal             # 限制外部访问网络
      --ip-range strings     # 从子范围分配容器ip
      --ipam-driver string   # IP管理驱动(默认为“default”)
      --ipam-opt map         # 设置IPAM驱动程序的特定选项(默认map[])
      --ipv6                 # 启用IPv6网络
      --label list           # 在网络中设置元数据
  -o, --opt map              # 设置驱动程序特定选项(默认map[])
      --scope string         # 控制网络的范围
      --subnet strings       # 指定一个CIDR格式的网段。示例:172.20.0.0/24
# 示例:
docker network create -d overlay --attachable apps_net

# 移除所有未使用的集群网络
$ docker network prune [OPTIONS]
# 选项
      --filter filter   # 提供过滤值(e.g. 'until=<timestamp>') 
  -f, --force           # 强制,没有提示确认

# 删除一个或多个集群网络
$ docker network rm NETWORK [NETWORK...]
# 别名:rm, remove

开始配置

环境准备

1、修改主机名 2、配置IP地址 3、关闭防火墙和SELINUX安全模式 4、配置系统YUM源和Docker镜像源 5、更新系统(yum update -y) 6、安装好docker环境

初始化集群

docker swarm init --advertise-addr 192.168.65.148

root@chenjx12-0:~# docker swarm init --advertise-addr 192.168.65.148
Swarm initialized: current node (1e0chr8bpn27vlq9g056zy7a2) is now a manager.

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

    docker swarm join --token SWMTKN-1-10u0nu575ou6thien8kscddxebzsnatljdytcas3n9sgin5jog-9cu9j19pfitelu1oap7rgdlub 192.168.65.148:2377

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


root@chenjx12-0:~# docker swarm join-token manager
To add a manager to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-10u0nu575ou6thien8kscddxebzsnatljdytcas3n9sgin5jog-ejpgz6tdq0xsm3c6qjrstq299 192.168.65.148:2377

让其他节点加入集群

root@chenjx12-0:~# docker node ls
ID                            HOSTNAME     STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
1e0chr8bpn27vlq9g056zy7a2 *   chenjx12-0   Ready     Active         Leader           27.3.1
jb55cgd88n5tl2ybdokhznq1t     chenjx12-1   Ready     Active                          27.3.1
oav94gisk9wm4mfuqvzpfhqzh     chenjx12-2   Ready     Active                          27.3.1
g6vxdk2myltc9i9lwx1zr3s4i     chenjx12-3   Ready     Active                          27.3.1

查看详细情况

root@chenjx12-0:~# docker info
Client: Docker Engine - Community
 Version:    27.3.1
 Context:    default
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.17.1
    Path:     /usr/libexec/docker/cli-plugins/docker-buildx
  compose: Docker Compose (Docker Inc.)
    Version:  v2.29.7
    Path:     /usr/libexec/docker/cli-plugins/docker-compose

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 0
 Server Version: 27.3.1
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Using metacopy: false
  Native Overlay Diff: true
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: systemd
 Cgroup Version: 2
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
 Swarm: active
  NodeID: 1e0chr8bpn27vlq9g056zy7a2
  Is Manager: true
  ClusterID: ye2nnvev8mzdyv0g56ee0ka6w
  Managers: 1
  Nodes: 4
  Data Path Port: 4789
  Orchestration:
   Task History Retention Limit: 5
  Raft:
   Snapshot Interval: 10000
   Number of Old Snapshots to Retain: 0
   Heartbeat Tick: 1
   Election Tick: 10
  Dispatcher:
   Heartbeat Period: 5 seconds
  CA Configuration:
   Expiry Duration: 3 months
   Force Rotate: 0
  Autolock Managers: false
  Root Rotation In Progress: false
  Node Address: 192.168.65.148
  Manager Addresses:
   192.168.65.148:2377
 Runtimes: io.containerd.runc.v2 runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 7f7fdf5fed64eb6a7caf99b3e12efcf9d60e311c
 runc version: v1.1.14-0-g2c9f560
 init version: de40ad0
 Security Options:
  apparmor
  seccomp
   Profile: builtin
  cgroupns
 Kernel Version: 6.1.0-26-amd64
 Operating System: Debian GNU/Linux 12 (bookworm)
 OSType: linux
 Architecture: x86_64
 CPUs: 4
 Total Memory: 1.887GiB
 Name: chenjx12-0
 ID: 8d684424-29b4-4611-8a59-d4ce19b0f9da
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false

WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled

查看网络信息

root@chenjx12-0:~# docker network ls
NETWORK ID     NAME              DRIVER    SCOPE
a162d4d5a77e   bridge            bridge    local
1f622764003c   docker_gwbridge   bridge    local
8f11bd442416   host              host      local
d8isx3sccunf   ingress           overlay   swarm
3b8eea1a0902   none              null      local

root@chenjx12-0:~# docker network inspect d8isx3sccunf
[
    {
        "Name": "ingress",
        "Id": "d8isx3sccunf33xeb63c1v21x",
        "Created": "2024-10-28T19:50:32.014998441+08:00",
        "Scope": "swarm",
        "Driver": "overlay",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "10.0.0.0/24",
                    "Gateway": "10.0.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": true,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "ingress-sbox": {
                "Name": "ingress-endpoint",
                "EndpointID": "f2dd609d5bc4ba0cb7206b7e4bdc3cd1ba232d727841b693805eecd1b591f7b9",
                "MacAddress": "02:42:0a:00:00:02",
                "IPv4Address": "10.0.0.2/24",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.driver.overlay.vxlanid_list": "4096"
        },
        "Labels": {},
        "Peers": [
            {
                "Name": "b4947f7ebf00",
                "IP": "192.168.65.148"
            },
            {
                "Name": "bac21fa67653",
                "IP": "192.168.65.154"
            },
            {
                "Name": "d6c037335dd0",
                "IP": "192.168.65.155"
            },
            {
                "Name": "3b5f5c73c94c",
                "IP": "192.168.65.152"
            }
        ]
    }
]

更换节点的角色(manager – worker)

root@chenjx12-0:~# docker node update -h
Flag shorthand -h has been deprecated, use --help

Usage:  docker node update [OPTIONS] NODE

Update a node

Options:
      --availability string   Availability of the node ("active", "pause", "drain")
      --label-add list        Add or update a node label ("key=value")
      --label-rm list         Remove a node label if exists
      --role string           Role of the node ("worker", "manager")


root@chenjx12-0:~# docker node update --role manager chenjx12-1
chenjx12-1
root@chenjx12-0:~# docker node ls
ID                            HOSTNAME     STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
1e0chr8bpn27vlq9g056zy7a2 *   chenjx12-0   Ready     Active         Leader           27.3.1
jb55cgd88n5tl2ybdokhznq1t     chenjx12-1   Ready     Active         Reachable        27.3.1
oav94gisk9wm4mfuqvzpfhqzh     chenjx12-2   Ready     Active                          27.3.1
g6vxdk2myltc9i9lwx1zr3s4i     chenjx12-3   Ready     Active                          27.3.1

root@chenjx12-0:~# docker node update --role worker chenjx12-1
chenjx12-1
root@chenjx12-0:~# docker node ls
ID                            HOSTNAME     STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
1e0chr8bpn27vlq9g056zy7a2 *   chenjx12-0   Ready     Active         Leader           27.3.1
jb55cgd88n5tl2ybdokhznq1t     chenjx12-1   Ready     Active                          27.3.1
oav94gisk9wm4mfuqvzpfhqzh     chenjx12-2   Ready     Active                          27.3.1
g6vxdk2myltc9i9lwx1zr3s4i     chenjx12-3   Ready     Active                          27.3.1

节点退出集群

在3号节点上使用命令,回到0号节点发现3号节点下线了(down)

root@chenjx12-0:~# docker swarm leave -h
Flag shorthand -h has been deprecated, use --help

Usage:  docker swarm leave [OPTIONS]

Leave the swarm

Options:
  -f, --force   Force this node to leave the swarm, ignoring warnings

root@chenjx12-3:~# docker swarm leave -f
Node left the swarm.

root@chenjx12-0:~# docker node ls
ID                            HOSTNAME     STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
1e0chr8bpn27vlq9g056zy7a2 *   chenjx12-0   Ready     Active         Leader           27.3.1
jb55cgd88n5tl2ybdokhznq1t     chenjx12-1   Ready     Active                          27.3.1
oav94gisk9wm4mfuqvzpfhqzh     chenjx12-2   Ready     Active                          27.3.1
g6vxdk2myltc9i9lwx1zr3s4i     chenjx12-3   Down      Active                          27.3.1

删除节点

docker node rm [id]

注意,删除节点无法删除manager管理节点,需要先--role worker,才能rm

服务部署

查看help

root@chenjx12-0:~# docker service

Usage:  docker service COMMAND

Manage Swarm 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.

先在leader上pull一个nginx

root@chenjx12-0:/etc/docker# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
a480a496ba95: Pull complete 
f3ace1b8ce45: Pull complete 
11d6fdd0e8a7: Pull complete 
f1091da6fd5c: Pull complete 
40eea07b53d8: Pull complete 
6476794e50f4: Pull complete 
70850b3ec6b2: Pull complete 
Digest: sha256:28402db69fec7c17e179ea87882667f1e054391138f77ffaf0c3eb388efc3ffb
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest

使用service命令启动Nginx

root@chenjx12-0:~# docker service create -p 8888:80 --name xybdiy-nginx nginx
qvx9t2qskhr8g0r1i7y5f9ub9
overall progress: 1 out of 1 tasks 
1/1: running   [==================================================>] 
verify: Service qvx9t2qskhr8g0r1i7y5f9ub9 converged 

使用docker services创建服务,具有扩缩容,滚动更新

查看服务

root@chenjx12-0:~# docker service ls
ID             NAME           MODE         REPLICAS   IMAGE          PORTS
qvx9t2qskhr8   xybdiy-nginx   replicated   1/1        nginx:latest   *:8888->80/tcp
root@chenjx12-0:~# docker service ps xybdiy-nginx
ID             NAME             IMAGE          NODE         DESIRED STATE   CURRENT STATE                ERROR     PORTS
7jzyf300ygqh   xybdiy-nginx.1   nginx:latest   chenjx12-1   Running         Running about a minute ago             
root@chenjx12-0:~# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

root@chenjx12-1:~# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS     NAMES
1efdebcefcd0   nginx:latest   "/docker-entrypoint.…"   2 minutes ago   Up 2 minutes   80/tcp    xybdiy-nginx.1.7jzyf300ygqhnj8zfukkjmrtp


root@chenjx12-0:~# docker service inspect xybdiy-nginx
[
    {
        "ID": "qvx9t2qskhr8g0r1i7y5f9ub9",
        "Version": {
            "Index": 76
        },
        "CreatedAt": "2024-10-28T13:46:32.118348646Z",
        "UpdatedAt": "2024-10-28T13:46:32.127340473Z",
        "Spec": {
            "Name": "xybdiy-nginx",
            "Labels": {},
            "TaskTemplate": {
                "ContainerSpec": {
                    "Image": "nginx:latest@sha256:28402db69fec7c17e179ea87882667f1e054391138f77ffaf0c3eb388efc3ffb",
                    "Init": false,
                    "StopGracePeriod": 10000000000,
                    "DNSConfig": {},
                    "Isolation": "default"
                },
                "Resources": {
                    "Limits": {},
                    "Reservations": {}
                },
                "RestartPolicy": {
                    "Condition": "any",
                    "Delay": 5000000000,
                    "MaxAttempts": 0
                },
                "Placement": {
                    "Platforms": [
                        {
                            "Architecture": "amd64",
                            "OS": "linux"
                        },
                        {
                            "Architecture": "unknown",
                            "OS": "unknown"
                        },
                        {
                            "OS": "linux"
                        },
                        {
                            "Architecture": "unknown",
                            "OS": "unknown"
                        },
                        {
                            "OS": "linux"
                        },
                        {
                            "Architecture": "unknown",
                            "OS": "unknown"
                        },
                        {
                            "Architecture": "arm64",
                            "OS": "linux"
                        },
                        {
                            "Architecture": "unknown",
                            "OS": "unknown"
                        },
                        {
                            "Architecture": "386",
                            "OS": "linux"
                        },
                        {
                            "Architecture": "unknown",
                            "OS": "unknown"
                        },
                        {
                            "Architecture": "mips64le",
                            "OS": "linux"
                        },
                        {
                            "Architecture": "unknown",
                            "OS": "unknown"
                        },
                        {
                            "Architecture": "ppc64le",
                            "OS": "linux"
                        },
                        {
                            "Architecture": "unknown",
                            "OS": "unknown"
                        },
                        {
                            "Architecture": "s390x",
                            "OS": "linux"
                        },
                        {
                            "Architecture": "unknown",
                            "OS": "unknown"
                        }
                    ]
                },
                "ForceUpdate": 0,
                "Runtime": "container"
            },
            "Mode": {
                "Replicated": {
                    "Replicas": 1
                }
            },
            "UpdateConfig": {
                "Parallelism": 1,
                "FailureAction": "pause",
                "Monitor": 5000000000,
                "MaxFailureRatio": 0,
                "Order": "stop-first"
            },
            "RollbackConfig": {
                "Parallelism": 1,
                "FailureAction": "pause",
                "Monitor": 5000000000,
                "MaxFailureRatio": 0,
                "Order": "stop-first"
            },
            "EndpointSpec": {
                "Mode": "vip",
                "Ports": [
                    {
                        "Protocol": "tcp",
                        "TargetPort": 80,
                        "PublishedPort": 8888,
                        "PublishMode": "ingress"
                    }
                ]
            }
        },
        "Endpoint": {
            "Spec": {
                "Mode": "vip",
                "Ports": [
                    {
                        "Protocol": "tcp",
                        "TargetPort": 80,
                        "PublishedPort": 8888,
                        "PublishMode": "ingress"
                    }
                ]
            },
            "Ports": [
                {
                    "Protocol": "tcp",
                    "TargetPort": 80,
                    "PublishedPort": 8888,
                    "PublishMode": "ingress"
                }
            ],
            "VirtualIPs": [
                {
                    "NetworkID": "d8isx3sccunf33xeb63c1v21x",
                    "Addr": "10.0.0.5/24"
                }
            ]
        }
    }
]

可以看到该服务被部署到1号节点上,0节点本地docker ps是没有的,而1节点下出现了该服务

多个部署,动态扩容

root@chenjx12-0:~# docker service update --replicas 2 xybdiy-nginx
xybdiy-nginx
overall progress: 2 out of 2 tasks 
1/2: running   [==================================================>] 
2/2: running   [==================================================>] 
verify: Service xybdiy-nginx converged 

由于第一个服务前面已经部署在1号节点上了,所以这次只需要再部署一个

root@chenjx12-0:~# docker service ls
ID             NAME           MODE         REPLICAS   IMAGE          PORTS
qvx9t2qskhr8   xybdiy-nginx   replicated   2/2        nginx:latest   *:8888->80/tcp
root@chenjx12-0:~# docker service ps xybdiy-nginx
ID             NAME             IMAGE          NODE         DESIRED STATE   CURRENT STATE           ERROR     PORTS
7jzyf300ygqh   xybdiy-nginx.1   nginx:latest   chenjx12-1   Running         Running 9 minutes ago             
i5m1yshi8p8o   xybdiy-nginx.2   nginx:latest   chenjx12-0   Running         Running 2 minutes ago  

可以看到这次部署到了0号和1号两个节点上,但是注意啊:

1号节点本身是worker,用来运行和部署服务是没问题的

但是0号节点原来是manager呀,甚至还是leader

所以,再次查看节点信息会发现:

root@chenjx12-0:~# docker node ls
ID                            HOSTNAME     STATUS    AVAILABILITY   MANAGER STATUS   ENGINE VERSION
1e0chr8bpn27vlq9g056zy7a2 *   chenjx12-0   Ready     Active         Reachable        27.3.1
jb55cgd88n5tl2ybdokhznq1t     chenjx12-1   Ready     Active                          27.3.1
oav94gisk9wm4mfuqvzpfhqzh     chenjx12-2   Ready     Active                          27.3.1
u6x1nn2xjqsfchbtlegne7swf     chenjx12-3   Ready     Active         Leader           27.3.1

leader被转移到另一个manager节点(3号)上了

在Docker Swarm集群中,如果当前的leader节点变得不可用或者其资源不足以运行新的任务,leadership(领导权)会自动转移到另一个manager节点上。这是Swarm集群的高可用特性之一。

在您描述的场景中,如果有一个manager节点被部署了nginx服务,并且这个manager节点恰好是当前的leader,以下情况可能会发生:

  1. 如果该manager节点只是被分配了nginx服务,并且它仍然能够处理manager节点的职责,那么它仍然可以保持leader的角色。
  2. 如果部署nginx服务导致该manager节点过载,或者由于某些原因它变得不可用(比如网络问题、硬件故障等),Swarm集群会检测到这个问题,并进行以下操作:
    • 集群中的其他manager节点会通过raft协议选举出一个新的leader。
    • leadership将从当前不可用的manager节点转移到新的leader节点上。

为了确保Swarm集群的稳定性和高可用性,通常建议将manager节点专用于管理任务,而不要在它们上面运行worker任务。这样可以确保manager节点有足够的资源来处理集群管理和决策任务,即使在节点故障的情况下也能保持集群的稳定运行。

如果您确实需要在manager节点上运行服务,可以通过以下策略来降低风险:

  • 限制在manager节点上运行的服务数量,确保它们不会消耗过多资源。
  • 使用资源限制和预留,确保manager节点有足够的资源来执行其管理职责。

如果我们需要保持manager节点不要运行服务,专心管理worker,并且避免leader转移,我们可以使用下面的命令

docker service create \
  --name my_nginx \
  --constraint 'node.role != manager' \
  nginx

如果我们要更具体一点,限制它不会部署在某个节点上:

使用节点ip限制
docker service create \
  --name my_nginx \
  --constraint 'node.id != node_id' \
  nginx

使用节点名称限制
docker service create \
  --name my_nginx \
  --constraint 'node.hostname != node_name' \
  nginx

虽然看上去是只部署在了0号和1号节点,但是实际上你访问集群中任意一个ip的8888端口都能够看到nginx页面

这就是swarm集群的负载均衡

故障

前面可以知道,虽然我部署只在两个服务器上但是我访问集群中任意一个ip都能得到服务

那如果我某个,或者多个服务器挂了呢

  • 首先,我把所有的(两个)manager挂了

    得到的结果是:访问剩下两个worker节点的ip均能得到服务,但是manager不行

  • 我把一个manager和一个woker挂了

    得到的结果是:还是能访问到,但是挂了的不行

    并且最后的manager报错:

    root@chenjx12-3:~# docker node ls Error response from daemon: rpc error: code = Unknown desc = The swarm does not have a leader. It’s possible that too few managers are online. Make sure more than half of the managers are online.

  • 把两个worker都挂掉

    结果是:也是仅存活的两个才能访问,但是使用docker node ls指令不会报错了

所有就引出了我们swarm集群的节点管理规则:

Docker Swarm集群节点规划

为了利用 swarm 模式的容错功能,可以根据组织的高可用性要求实现奇数个节点。 当有多个管理中心时,可以从一个管理中心节点的故障中恢复,而无需停机。

  • 三个管理器群可以容忍最多损失一个管理器。
  • 五个管理器群最多可以同时丢失两个管理器节点。
  • 七个管理器群最多可以同时丢失三个管理器节点。
  • 九个管理器群最多可以同时丢失四个管理器节点。
  • Docker 建议一个群最多有七个管理器节点。 (添加更多管理器并不意味着可伸缩性或性能的提高。一般来说,情况恰恰相反。)

1

区别 & 联系

区别:

  • 使用场景:Docker Compose 适用于开发环境和单机部署,而 Docker Swarm 适用于生产环境和多节点集群。
  • 集群管理:Docker Compose 不支持集群管理,而 Docker Swarm 是为集群环境设计的。
  • 功能:Docker Compose 更简单,主要关注于启动多个容器,而 Docker Swarm 提供了更多的生产级功能,如服务发现、负载均衡和滚动更新。

联系:

  • 配置文件:Docker Compose 和 Docker Swarm 都可以使用 docker-compose.yml 文件来定义服务。
  • 集成:Docker Compose 可以与 Docker Swarm 集成,使得在 Swarm 集群中部署多服务应用程序变得简单。通过 docker stack deploy 命令,可以在 Swarm 集群上部署由 Docker Compose 文件定义的服务堆栈。
  • 生态系统:它们都是 Docker 生态系统的一部分,旨在帮助开发者和运维人员更好地管理和部署容器化应用程序。

总结来说,Docker Compose 和 Docker Swarm 都是 Docker 的编排工具,但它们针对的场景和提供的功能有所不同。Docker Compose 适合开发和单机部署,而 Docker Swarm 适合生产环境中的集群管理。

下面这个图片就很形象的表示的compose和swarm:

compose&swarm

Docker 可以看做集装箱把杂乱的货物一个个整理归类, Compose 则是用于编排这些集装箱,最后 Swarm 就是多提供几条船,挂掉一两条还能继续走,提高稳定性。