docker 入门2
from: chenj_x12@foxmali.com
Docker Compose
Compose 简介
Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务
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 轻松地扩展到多个主机。

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,以下情况可能会发生:
- 如果该manager节点只是被分配了nginx服务,并且它仍然能够处理manager节点的职责,那么它仍然可以保持leader的角色。
- 如果部署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:

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