Docker 系统性入门+进阶实践-08docker swarm详解

  • 作为集群的编排工具,docker swarm虽然不如k8s流行,但是万变不离其宗,掌握起基本原理和使用将大大降低学习其它编排工具的难度

docker swarm介绍

  1. 为什么不建议在生产环境中使用docker-compose?
  • 多机器如何管理
  • 如何跨机器做scale横向扩展
  • 容器失败退出时如何新建容器确保服务正常运行
  • 如何确保零宕机时间
  • 如何管理密码、key等敏感数据
  • 其它
  1. swarm的基本架构

swarm单节点快速上手

  1. 初始化
    docker info这个命令可以查看我们的docker engine有没有激活swarm模式,默认是没有的,我们会看到
    Swarm: inactive
  2. 激活swarm有两个方法
  • 初始化一个swarm集群,自己成为manager
  • 加入一个已经存在的swarm集群
  1. docker swarm init背后发生了什么
    主要是PKI和安全相关的自动化:
  • 创建swarm集群的根证书
  • manager节点的证书
  • 其它节点加入集群需要的tokens
    创建raft数据库用户存储证书、配置、密码等数据
    raft是一个协议,这个协议主要用于分布式的、对一致性要求比较高的数据库
    raft分布式一致性,带图形界面的
    raft算法中的三个重要的概念:领导者选举、日志复制、snapshop快照。
  1. 将当前节点移除swarm集群
    sudo docker swarm leave [--force]

swarm单节点service初体验

  1. 创建一个serice服务
    sudo docker service create nginx:latest
    查看service服务列表
    sudo docker service ls
    查看刚刚创建的容器服务:
    sudo docker service ps service_id/name
    也可以通过docker命令查看刚刚创建的容器:
    sudo docker ps
  2. 通过刚刚创建的service更新为3个容器服务
    sudo docker service update x6h --replicas 3
  3. service并不仅仅是只能创建多个replicas,当service中的容器服务有挂掉之后,它还能为我们自动创建一个
    我们通过移除一个容器服务看一下:
    sudo docker container rm -f container_id
    然后我们看一下service状态:
    sudo docker service ps service_id
  4. 删除service
    sudo docker service rm service_id

swarm三节点环境的搭建

  1. 多节点的环境涉及到机器之间的通信需求,当使用云主机的时候,下面的防火墙或安全组需要打开
TCP port 2376
TCP port 2377
TCP and UDP port 7946
UDP port 4789
  1. 云厂商购买3台云服务器,安装好docker和docker-compose,安全组打开上面的端口,一切就绪,准备开始了。
  2. 在其中的一台主机器上初始化swarm集群
    sudo docker swarm init
    在其它两台机器上执行下面的命令,加入这个swarm集群:
    sudo docker swarm join --token xxxxxxxxxxxxxxxxxxxxxxxxxxx 172.17.82.242:2377
    在manager节点执行命令查看集群节点信息:
    sudo docker node ls

swarm三节点service在体验

  1. 创建一个service,并指定其名字
    sudo docker service create --name web nginx
    查看创建的service
    sudo docker service ls
    查看service详情,包括在哪一个节点上运行
    sudo docker service ps web
  2. 通过--replics复制刚刚起的nginx服务
    sudo docker service update --replicas=3 web
    我们测试杀死一个容器服务:
    sudo docker container rm -f container_id

    当我们杀死一个容器服务后,docker swarm会帮我们在起一个新的服务
  3. 另一种扩展/增加服务的方法
    sudo docker service scale web=4
  4. 将服务的数量减少为1
    sudo docker service scale web=1
    会保留swarm集群中的一个容器服务,其它节点容器服务会被删除,但是其它节点的镜像和网络会保留。
    查看service的详细信息:
    sudo docker service inspect web
  5. 查看service服务的日期信息,包括该条日志对应在哪个节点上的哪个服务上
    sudo docker service logs -f web

swarm的overlay网络初体验

  1. 对弈swarm的网络,有两个重要点
  • 外部如何访问部署在swarm集群内的服务,可以称为入方向流量,在swarm里,我们通过ingress来解决
  • 部署在swarm集群内的服务,如何对外进行访问,可以分为两块
    (1)东西向流量,也就是说不同swarm节点上的容器之间如何进行通信,swarm通过overlay网络来解决
    (2)南北向流量,也就是说swarm集群里的容器如何对外访问,比如互联网,这个是linux bridge + iptables NAT来解决
  1. 创建一个overlay网络用于swarm不同节点上的容器之间的通信
    sudo docker network create --driver overlay mynet
  2. 创建一个service服务,使用我们刚刚创建的overlay网络
    sudo docker service create --network mynet --name test --replicas 2 busybox ping 8.8.8.8
    当在worker节点上创建该服务的时候,如果没有创建该网络,就会自动创建
  3. 查看容器服务的ip地址
    sudo docker exec container_id ip addr
    我们可以发现,该容器同时连接了两个网络,一个是overlay: mynet, 另一个是bridge: docker_gwbridge

swarm的overlay网络详解

  1. 容器内查看走哪个网络
    ip route
  2. 我们通过tcpdump抓包,来测试不同节点间容器通信走overlay通信
    sudo apt-get install tcpdump
    在当前机器上开启抓包:sudo tcpdump -i eth0 port 4789
    在另外一台机器发起ping命令,与当前机器进行容器间通信
    ping 10.0.1.3 -c 3
    查看抓包结果:

swarm的ingress网络详解(上)

  1. docker swarm的ingress网络又叫Igress Routing Mesh
    主要是为了实现把service的服务端口对外发布出去,让其能够被外部网络访问到
    Ingress Routing Mesh是docker swarm网络里最复杂的一部分内容,包括一下几个方面:
  • iptables的Destination NAT流量转发
  • linux bridge, network namespace
  • 使用IPVS技术做负载均衡
  • 包括容器间的通信overlay和入方向流量的端口转发
  1. 创建一个service服务,开启两个副本
    sudo docker service create --name web --network mynet -p 8008:80 --replicas 2 containous/whoami
    通过curl请求我们刚刚创建的服务,manage节点
    curl 172.17.82.242:8008
    多次请求,会发现服务器会以负载均衡的方式向我们响应。
    当我们访问另一个容器服务所在的节点work1时:
    curl 172.17.82.241:8008
    多次请求,发现跟访问manage节点一致,
    当我们再次访问没有部署容器服务的work2节点时:
    curl 172.17.82.240
    多次请求,还能正常请求,还是进行负载均衡。

swarm的ingress网络详解(下)

  1. ingress数据包的走向
    sudo iptables -nvL -t nat
    输出
Chain DOCKER-INGRESS (2 references)
 pkts bytes target     prot opt in     out     source               destination
   14   816 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:8008 to:172.19.0.2:8008
  387 23282 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0

我们可以看到会把本机ip:8008端口转发到172.19.0.2:8008端口,为啥呢?
我们查看本机的ip地址:ip addr
我们会发现172.19.0.2和本机的docker_gwbridge:172.19.0.1在同一网络下,
2. 查看docker_gwbridge网络详情
sudo docker network inspect docker_gwbridge
我们发现该网络下有两个Containers,一个是我们运行的web容器,另一个就是ingress-sbox: 172.19.0.2IP地址的network namespace(网络命名空间)
3. 进入ingress-box命名空间
sudo docker run -it --rm -v /var/run/docker/netns:/netns --privileged=true nicolaka/netshoot nsenter --net=/netns/ingress_sbox sh
该命令会启动一个容器并加载我们的命名空间
4. 进入去命名空间后,查看ip地址
ip a
里面有两个ip地址,一个是连接到了docker_gwbridge网络,另一个是连接到了ingress网络
5. ipvs负载均衡
ipvsadm

6. 关于这里的ipvs负载均衡
这是一个stateless load balancing(无状态负载均衡)
这是三层的负载均衡,不是四层的 LB is at OSI Layer 3 (TCP), not Layer 4 (DNS)
以上两个限制可以通过Nginx或者HAProxy LB proxy解决

swarm内部的负载均衡_batch

  1. 创建一个mynet的overlay网络,创建一个service
    sudo docker network create --driver overlay mynet
    sudo docker service create --name web --network mynet --replicas 2 containous/whoami
  2. 创建一个client
    sudo docker service create --name client --network mynet 1341935532/net-box ping 8.8.8.8
  3. 尝试进入client这个容器,去ping web这个service name, 获取到的IP 10.0.1.30,称之为VIP(虚拟IP)
    sudo docker exec -it container_id sh
    ping一下我们的web服务
    ping web
    查看我们创建的网络的详情
    sudo docker network inspect mynet
    发现容器里面有一个叫lb_mynet网络命名空间network namespace
  4. 查看lb_mynet
    sudo ls /var/run/docker/netns

    参考文档

部署多service应用_batch

  1. 如何像docker-compose一样部署多服务应用,这一节我们先看手动的方式
    创建一个mynet的overlay网络
    sudo docker network create --driver overlay mynet
  2. 创建一个redis service
    sudo docker service create --network mynet --name redis redis:latest redis-server --requirepass ABC123
  3. 创建一个flask服务
    sudo docker service create --network mynet --name flask --env REDIS_PASS=ABC123 --env REDIS_HOST=redis -p 8008:5000 xiaopeng163/flask-redis:latest
    注意:swarm里面是不能进行镜像的构建、因为swarm是为了生产环境使用的,生产环境不能进行镜像的构建
    而docker-compose适用于开发环境,所以可以进行镜像的构建

stack部署多service应用

  1. 克隆代码
    git clone https://github.com/xiaopeng163/flask-redis
  2. 构建镜像,注意将docker-compose.yml中的镜像id改为自己的
    docker-compose build
  3. 将镜像推送到我们自己的docker hub上
    sudo docker-compose push
  4. stack这个命令就是swarm版本的compose
    compose是用于单机环境,stack是用于swarm集群环境
  5. 通过stack启动服务
    sudo env REDIS_PASSWORD=ABC123 docker stack deploy --compose-file docker-compose.yml flask-demo
    查看服务
    sudo docker stack ls
    查看服务列表
    sudo docker stack ps flask-demo
    访问我们刚刚启动的服务
    curl 127.0.0.1:8008
  6. 删除stack创建的服务
    sudo docker stack rm flask-demo

在swarm中使用secret

  1. 从标准输入创建一个secret
    sudo echo abc123 | sudo docker secret create mysql_pass -
    查看secret
    sudo docker secret ls
    查看secret详情
    sudo docker secret inspect secret_id
    我们可以看到secret的id、name,但是看不到secret本身,因为它存在了raft数据库里面了。
  2. 删除secret
    sudo docker secret rm mysql_pass
  3. 通过文件创建secret
    sudo docker secret create mysql_pass mysql_pass.txt
  4. 查看容器中加载的secret
sudo docker service create --name test --secret mysql_pass 1341935532/net-box ping 8.8.8.8  // 创建service服务
sudo docker service ls  // 查看服务id
sudo docker service ps service_id  // 通过服务id查看服务所在的节点
sudo docker ps -a  // 通过节点查看容器服务
sudo docker exec -it container_id sh  // 通过容器id进入容器服务
cd /run/secrets/  // 进入到secrets目录下
ls  // 查看到了mysql_pass
more mysql_pass  // 查看到了密码:abc123
  1. 使用secret
sudo docker service create --secret mysql_pass --name mysql-demo -e MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql_pass -d mysql:5.7  // 创建一个mysql服务,密码使用secret秘钥的形式
sudo docker exec -it container_id sh  // 进入容器shell
mysql -uroot -pabc123  // 使用刚刚创建的秘钥连接mysql,成功  

注意:secret并不是适用于所有的镜像,需要查看docker hub官方的文档,看支持不支持secret.
secrets 官方文档

swarm使用本地volume

  1. docker-compose.yml文件
version: "3.8"

services:
  db:
    image: mysql:5.7
    environment:
      - MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql_pass
    secrets:
      - mysql_pass
    volumes:
      - data:/var/lib/mysql

volumes:
  data:

secrets:
  mysql_pass:
    file: mysql_pass.txt
  1. mysql_pass.txt文件
    abc123456
  2. 通过stack和docker-compose.yml创建我们的集群服务, db就是stack的名字
    sudo docker stack deploy --compose-file docker-compose.yml db
  3. 删除stack
    sudo docker stack rm db

swarm练习之投票app

  1. 克隆代码
    git clone https://github.com/dockersamples/example-voting-app
  2. 通过stack构建投票服务
    sudo docker stack deploy --compose-file docker-stack.yml vote
    由于原版有点bug,所以我们需要打开docker-stack.yml文件,对postgres增加如下envrironment配置
    POSTGRES_HOST_AUTH_METHOD: "trust"
    此问题参考官方文档

投票app官方文档

posted @ 2022-06-02 14:28  专职  阅读(518)  评论(0编辑  收藏  举报