写点什么

DockerSwarm 实践及原理

作者:乌龟哥哥
  • 2023-04-24
    上海
  • 本文字数:6316 字

    阅读完需:约 21 分钟

DockerSwarm 实践及原理

基本原理

Swarm 是使用 Docker 引擎内置的集群管理和编排工具。Swarm 集群的框架与 Hadoop 集群或其他分布式系统类似,它也是由节点构成,每一个节点就是一台主机或者虚拟机。工作的机制也是主从模式(master/slaver),节点分为两种,一种是负责管理的 Manager 另一种是具体干活的 Worker。


  • 管理节点: 用于 Swarm 集群的管理,docker swarm 命令基本只能在管理节点执行(节点退出集群命令 docker swarm leave 可以在工作节点执行)。为了避免单点故障,一个 Swarm 集群可以有多个管理节点,但只有一个管理节点可以成为 leader,leader 通过 raft 协议实现。

  • 工作节点: 是任务执行节点,管理节点将任务 (Task) 下发至工作节点执行。管理节点默认也作为工作节点,也可以通过配置让服务只运行在管理节点。


多个 Docker 主机就被抽象为单个大型的虚拟 Docker 主机,在管理节点上,用户可以像在单机一样在集群上操作容器或服务

基本概念

Swarm 集群中管理的对象主要由三个,Task、Service 与 Node,其中 Node 上面已经介绍过,这里解释下 Task 与 Service 的概念

任务

Swarm 中的最小的调度单位,目前一个 Task 就是一个容器

服务

Service 一般是由一组相同的 Task 组成,Service 是这组 Task 要完成的任务的一个抽象。按照其包含的 Task 的布署方式分为两种:


  • replicated services 按照一定规则在各个工作节点上运行指定个数的任务

  • global services 每个工作节点上运行一个任务


这两种模式是在服务创建时通过创建命令 docker service create 的 --mode 参数指定的


Service 与 Task 以及容器的关系如下:


总结成一句话就是,swarm 集群(cluster)是由节点(node)组成;服务(service)一般包含若干个任务(Task),一个 Task 就是运行一个容器,所有这些 Task 都是在节点上执行的,具体在那个个节点上执行是由管理节点调度的。

初始化 swarm 集群

安装 docker 环境

curl -sL https://gitee.com/YunFeiGuoJi/Cnblog/raw/master/shell/Scripts/docker_install.sh|sh -x -
复制代码

修改 docker 配置文件

# 修改 /etc/docker/damean.json 添加配置"live-restore": false# 重启systemctl restart dockerd
复制代码

初始化 docker swarm manager

docker swarm init --advertise-addr 192.168.56.101--advertise-addr 指定与其他 node 通信的地址 
复制代码


docker swarm init 输出告诉我们:


① swarm 创建成功,swarm-manager 成为 manager node。


② 添加 worker node 需要执行的命令。


③ 添加 manager node 需要执行的命令。


如果当时没有记录下 docker swarm init 提示的添加 worker 的完整命令,可以通过 docker swarm join-token worker 查看

管理 docker swarm

节点管理

  • 查看帮助命令


[root@master ~]# 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.
复制代码


  • 管理节点


# 查看节点docker node lsID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION8x5iogo0c2d7cl9edjvbacxio *   master              Ready               Active              Leader              19.03.12shihkplhlozcttq3m8va4129c     node01              Ready               Active                                  19.03.12# 删除节点docker node rm shihkplhlozcttq3m8va4129c
复制代码

服务管理

  • 创建服务


docker service create --name app1  --network yfgj --replicas 2 --entrypoint "sleep 1d" busyboxdocker service create --name app2  --network yfgj --replicas 2 nginx# 查看生成的vipdocker service inspect --format='{{json .Endpoint.VirtualIPs}}' app1[{"NetworkID":"9ttgtpwyvnssbfnw33wchbgwi","Addr":"10.0.15.5/24"}]docker service inspect --format='{{json .Endpoint.VirtualIPs}}' app2
复制代码


  • 扩容副本


docker service scale web1=2
复制代码


  • 删除服务


docker service rm service_name
复制代码

Gui 管理界面安装

# docker-compose yml文件version: "3.8"
services: portainer: image: portainer/portainer-ce:latest ports: - "9000:9000" volumes: - "/var/run/docker.sock:/var/run/docker.sock" networks: - "tarfik-public" deploy: labels: - "traefik.enable=true" - "traefik.docker.network=traefik-public" - "traefik.http.routers.portainer.rule=Host(`portainer.local.cluster`)" - "traefik.http.routers.portainer.entrypoints=websecure" - "traefik.http.routers.portainer.tls=true" - "traefik.http.routers.portainer.tls.certresolver=foo" - "traefik.http.routers.portainer.tls.domains[0].main=local.cluster" - "traefik.http.routers.portainer.tls.domains[0].sans=*.local.cluster" - "traefik.http.services.portainer.loadbalancer.server.port=9000" replicas: 1 placement: constraints: [node.role == manager]networks: traefik-public: external: true# 执行命令docker stack deploy -c docker-compose.yaml docker-swarm-manager# 访问## 本地访问http://localhost:9000
复制代码

服务发现

实现功能:


  • 让 service 通过简单的方法访问到其他 service。

  • 当 service 副本的 IP 发生变化时,不会影响访问该 service 的其他 service。

  • 当 service 的副本数发生变化时,不会影响访问该 service 的其他 service


从使用者角度看,一个 Service 相当于它的所有 Task 的一个反向代理,它主要使用了 Linux 内核 iptables 和 IPVS 的功能来实现服务发现和负载均衡


  • iptables:Linux 内核中的包过滤技术,它可用于根据数据包的内容进行分类、修改和转发决策。

  • IPVS :Linux 内核中传输级负载均衡器


Swarm 支持三种模式的负载均衡,它们的使用方式如下:


  • 基于 DNS 的负载均衡:DNS server 内嵌于 Docker 引擎,Docker DNS 解析服务名并安装随机次序返回容器 ID 地址列表,客户端通常会挑第一个 IP 访问。在服务启动时,通过指定--endpoint-mode 参数为 dnsrr 来设定,另外服务需要加入一个覆盖网,例如


docker service create --endpoint-mode dnsrr --network overlay1  --replicas 3 --name nginx nginx
复制代码


  • 基于 VIP 的负载均衡:默认时这种模式,在服务启动时可以指定或被分配一个 IP 地址,该 IP 地址可以映射到与该服务关联的多个容器的 IP 地址。示例如下


docker service create --network overlay1  --replicas 3 --name nginx nginx
复制代码


  • 路由网格 (Routing mesh):这种模式服务暴露的端口会暴露在 Swarm 集群中的所有工作节点,通过访问任何一台主机的 ip 或域名加暴露的端口号就可以访问到该服务。使用也很简单,只需要在服务创建时添加端口号映射就可以了,如下


docker service create --network overlay1  --replicas 3 -p 80:80 --name nginx nginx
复制代码

创建覆盖网络

docker network create \  --driver overlay \  --gateway 10.0.4.1 \  --subnet 10.0.4.0/22 \  --ip-range 10.0.4.0/24 \  --attachable yfgj_net
复制代码

暴露服务外部访问

安装 traefik 代理服务

  • 编写 traefik yml 文件


version: "3.8"
secrets: aliyun_region_id: #external: true file: "/root/.ssl/aliyun_region_id" aliyun_access_key: #external: true file: "/root/.ssl/aliyun_access_key" aliyun_secret_key: #external: true file: "/root/.ssl/aliyun_secret_key"
services: traefik: image: traefik:v2.4.8 command: - "--log.level=DEBUG" - "--api.insecure=true" - "--providers.docker=true" - "--providers.docker.swarmMode=true" - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" #- "--entrypoints.webnossl.address=:8443" - "--api=true" - "--api.dashboard=true" - "--api.debug=true" - "--accesslog=true" - "--log=true" - "--log.filepath=/tmp/traefik.err.log" - "--accesslog.filepath=/tmp/traefik.access.log" - "--providers.docker.network=yfgj_net" - "--certificatesresolvers.foo.acme.dnschallenge=true" - "--certificatesresolvers.foo.acme.dnschallenge.provider=alidns" - "--certificatesresolvers.foo.acme.dnschallenge.resolvers=114.114.114.114:53,8.8.8.8:53" - "--certificatesresolvers.foo.acme.keytype=EC256" #RSA4096 #- "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory" - "--certificatesresolvers.foo.acme.email=xxxx" - "--certificatesresolvers.foo.acme.storage=/letsencrypt/acme.json" - "--metrics.prometheus=true" - "--metrics.prometheus.buckets=0.100000, 0.300000, 1.200000, 5.000000" - "--metrics.prometheus.addEntryPointsLabels=true" - "--metrics.prometheus.addServicesLabels=true" - "--entryPoints.metrics.address=:8082" - "--metrics.prometheus.entryPoint=metrics" ports: - "80:80" - "443:443" - "8080:8080" - "8020:8020" secrets: - "aliyun_region_id" - "aliyun_access_key" - "aliyun_secret_key" environment: - "ALICLOUD_REGION_ID_FILE=/run/secrets/aliyun_region_id" - "ALICLOUD_ACCESS_KEY_FILE=/run/secrets/aliyun_access_key" - "ALICLOUD_SECRET_KEY_FILE=/run/secrets/aliyun_secret_key" volumes: - "/var/run/docker.sock:/var/run/docker.sock" - "/root/letsencrypt:/letsencrypt" networks: - "yfgj_net" deploy: mode: replicated replicas: 1 labels: - "traefik.enable=true" - "traefik.docker.network=yfgj_net" - "traefik.http.services.traefik_traefik.loadbalancer.server.port=8080" # http 80 - "traefik.http.routers.traefik-ui-80.rule=Host(`traefik.ctq6.cn`)" - "traefik.http.routers.traefik-ui-80.entrypoints=web" # http 8443 - "traefik.http.routers.traefik-ui-8443.rule=Host(`traefik-8443.ctq6.cn`)" - "traefik.http.routers.traefik-ui-8443.entrypoints=webnossl" - "traefik.http.routers.traefik-ui-8443.tls=true" - "traefik.http.routers.traefik-ui-8443.tls.certresolver=foo" - "traefik.http.routers.traefik-ui-8443.tls.domains[0].main=ctq6.cn" - "traefik.http.routers.traefik-ui-8443.tls.domains[0].sans=*.ctq6.cn" - "traefik.http.routers.traefik-ui-8443.middlewares=redirect-https" # https 443 - "traefik.http.middlewares.redirect-https.redirectScheme.scheme=https" - "traefik.http.routers.traefik-ui-443.rule=Host(`traefik-443.ctq6.cn`)" - "traefik.http.routers.traefik-ui-443.tls=true" - "traefik.http.routers.traefik-ui-443.tls.certresolver=foo" - "traefik.http.routers.traefik-ui-443.tls.domains[0].main=ctq6.cn" - "traefik.http.routers.traefik-ui-443.tls.domains[0].sans=*.ctq6.cn" - "traefik.http.routers.traefik-ui-443.middlewares=redirect-https" - "traefik.http.routers.traefik-ui-443.entrypoints=websecure" placement: constraints: [node.role == manager] restart_policy: condition: on-failure delay: 5s max_attempts: 3 window: 120snetworks: yfgj_net: external: true name: yfgj_net
复制代码


  • 安装 traefik 服务


# 配置域名阿里云或者腾讯云上配置域名指向安装traefik所在节点,并将443,80,8443防火强配置为允许公网访问,配置需要访问的服务域名# 部署traefik 服务docker stack deploy -c docker-compose-traefik.yml traefik# 测试traefik 域名是否生成curl -v  localhost:8080/api/http/routers|jq .# 测试是否能访问对应的服务curl -v -H "Host:traefik.ctq6.cn" localhostcurl -v -H "Host:traefik-443.ctq6.cn" localhost:443curl -v -H "Host:traefik-8443.ctq6.cn" localhost:8443# 浏览器访问http://traefik.ctq6.cnhttps://traefik-443.ctq6.cnhttp://traefik-8443.ctq6.cn:8443
复制代码

安装 nginx web 服务

  • 编写 nginx web 服务 yml


version: "3.8"
services: nginx: image: nginx:latest logging: driver: "json-file" options: max-size: "200k" max-file: "10" ports: - 8088:80 networks: - yfgj_net volumes: - /root/yunfeiguoji:/usr/share/nginx/html/blog/yunfeiguoji:rw - ./default.conf:/etc/nginx/conf.d/default.conf:rw - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro deploy: mode: replicated replicas: 1 labels: - "traefik.enable=true" - "traefik.docker.network=yfgj_net" - "traefik.http.services.nginx_nginx.loadbalancer.server.port=80" # https 443 - "traefik.http.middlewares.redirect-https.redirectScheme.scheme=https" - "traefik.http.routers.nginx-ui-443.rule=Host(`www.ctq6.cn`)" - "traefik.http.routers.nginx-ui-443.tls=true" - "traefik.http.routers.nginx-ui-443.tls.certresolver=foo" - "traefik.http.routers.nginx-ui-443.tls.domains[0].main=ctq6.cn" - "traefik.http.routers.nginx-ui-443.tls.domains[0].sans=*.ctq6.cn" - "traefik.http.routers.nginx-ui-443.middlewares=redirect-https" - "traefik.http.routers.nginx-ui-443.entrypoints=websecure" placement: constraints: [node.role == manager] resources: limits: cpus: '0.50' memory: 50M reservations: cpus: '0.25' memory: 20M restart_policy: condition: on-failure delay: 5s max_attempts: 3 window: 120snetworks: yfgj_net: external: true name: yfgj_net
复制代码


  • 启动服务


docker stack deploy nginx -c docker-conpose-nginx.yml
复制代码


发布于: 45 分钟前阅读数: 8
用户头像

乌龟哥哥

关注

正在努力寻找offer的大四小菜鸟 2021-03-16 加入

擅长 Hbuilder、VS Code、MyEclipse、AppServ、PS 等软件的安装与卸载 精通 Html、CSS、JavaScript、jQuery、Java 等单词的拼写 熟悉 Windows、Linux、 等系统的开关机 看–时间过得多快,不说了,去搬砖了

评论

发布
暂无评论
DockerSwarm实践及原理_三周年连更_乌龟哥哥_InfoQ写作社区