什么是Docker Swarm

Docker Engine中嵌入的群集管理和编排功能是使用swarmkit构建的。Swarmkit是一个独立的项目,实现了Docker的编排层,并直接在Docker内部使用。

一个swarm包含多个运行在swarm模式下的Docker主机,作为管理器(管理成员和委派)和工作节点(运行swarm服务)。一个给定的Docker主机可以是管理器、工作节点,或者同时扮演两个角色。当创建一个服务时,定义它的最佳状态(副本数、可用的网络和存储资源、服务对外部世界暴露的端口等)。Docker会维护该期望状态。例如,如果一个工作节点变得不可用,Docker会在其他节点上安排该节点的任务。任务是运行中的容器,是swarm服务的一部分,由swarm管理器管理,而不是独立容器。

swarm服务相对于独立容器的一个关键优势是,您可以修改服务的配置,包括它连接的网络和卷,而无需手动重启服务。Docker会更新配置,停止具有过时配置的服务任务,并创建与期望配置相匹配的新任务。

当Docker在swarm模式下运行时,您仍然可以在参与swarm的任何Docker主机上运行独立容器和swarm服务。独立容器和swarm服务之间的一个关键区别是,只有swarm管理器才能管理swarm,而独立容器可以在任何守护进程上启动。Docker守护程序可以作为管理器、工作节点或两者参与swarm。

与使用Docker Compose定义和运行容器类似,您可以定义和运行Swarm服务堆栈。

Swarm关键概念

Nodes

一个node是参与swarm的Docker Engine的一个实例,可以在一个物理机或者云服务器上运行一个或者多个node

Services and Tasks

Services是一组tasks的定义,可以指定运行哪个image以及在其上运行哪些指令

task是swarm编排和调度的最小单元,一个task只会在一个node上完成它的生命周期,不会被重新调度(和K8s类似)

Load Balancing

Swarm会给每一个你想暴露给外部的服务指定一个PublishedPort,外部组件,可以通过PublishPor访问任意节点,无论这个节点目前是否正在运行task,swarm中的所有节点会将请求路由给一个正在运行task的实例

image.png

Swarm在内部有一个DNS组件,来实现内部的负载均衡

部署Swarm

在Manager Node上创建swarm集群:

docker swarm init [--advertise-addr 192.168.0.17]

上述命令的输出可以用作Worker Node加入Swarm

docker swarm join --token SWMTKN-1-09el8cnzig7p4i0p06ug5jj1tc09c3h3sh9ycc5be6xhybo1c4-1nlxvfyg4gylq005mp2kjc5ud 192.168.0.17:2377

如果上述命令输出丢失了,可以运行docker swarm join-token worker重新获取

查看swarm当前状态

docker info | grep swarm

在Manager Node上部署一个服务

docker service create \
  --replicas 3 \
  --name redis \
  --update-delay 10s \
  redis:3.0.6

查看服务详情:

Scale the service

docker service scale redis=5

Rolling Update Service

docker service update --image redis:3.0.7 redis

暴露一个端口给外部

创建服务的时候使用--publish来指定一个暴露给外部的端口,target来指定容器内的端口,如果留空published,那么swarm会指定一个随机的端口

docker service create \
  --name my-web \
  --publish published=8080,target=80 \
  --replicas 2 \
  nginx

如果不使用路由网格而使用外部负载均衡器,请将--endpoint-mode设置为dnsrr,而不是默认值vip。在这种情况下,没有单个虚拟IP。相反,Docker为服务设置DNS条目,使得对服务名称的DNS查询返回IP地址列表,客户端直接连接其中之一。您需要提供IP地址和端口列表给您的负载均衡器。请参见“配置服务发现”。

image.png

可以按照如下配置HAProxy 作为外部的负载均衡器

vim /etc/haproxy/haproxy.cfg

global
        log /dev/log    local0
        log /dev/log    local1 notice
...snip...

# Configure HAProxy to listen on port 80
frontend http_front
   bind *:80
   stats uri /haproxy?stats
   default_backend http_back

# Configure HAProxy to route requests to swarm nodes on port 8080
backend http_back
   balance roundrobin
   server node1 192.168.99.100:8080 check
   server node2 192.168.99.101:8080 check
   server node3 192.168.99.102:8080 check