详解基于docker-swarm搭建持续集成集群服务

前言

本文只为自己搭建过程中的一些简单的记录。如果实践中有疑问,可以一起探讨。

为了能在本机(macOS)模拟集群环境,使用了vb和docker-machine。整体持续集成的几个机器设施如下:

1、服务节点:三个manager节点,一个worker节点。manager需要占用更多的资源,manager配置尽量高一些。swarm的manager节点的容错率是 (N-1)/2 。N是manager节点数。也就是如果有3个manager,那就能容忍一个manager节点挂掉。官方的算法说明:Raft consensus in swarm mode。

2、本地的镜像仓库 registry:用来存储所有需要部署的服务docker镜像。

https://docs.docker.com/registry/deploying/

因为使用swarm机制,所以不需要在服务间通信问题考虑服务发现以及负载均衡的问题(代替原有的consul&registor方式)。

3、构建镜像的运维节点 ops:

也即运维机器。一个独立的节点即可。主要负责build镜像,push镜像。在ops里可以构建gitlab的私库。维护构建脚本。机器所需配置不高,对网络宽带还是尽量多一些。

用docker-machine 模拟集群环境

创建registry节点

docker-machine create -d virtualbox --virtualbox-memory "512" registry 

–engine-registry-mirror 这个参数是可以设置一些加速仓库的地址。

创建manager,worker节点

manager

代码如下:

docker-machine create -d virtualbox --virtualbox-memory "800"  manager1

worker:

docker-machine create -d virtualbox --virtualbox-memory "800" worker1
docker-machine create -d virtualbox --virtualbox-memory "800" worker2
docker-machine create -d virtualbox --virtualbox-memory "800" worker3 

创建ops 节点

docker-machine create -d virtualbox --virtualbox-memory "512" ops 

查看机器列表状态

docker-machine ls 

创建registry服务

登录到registry机器上。

docker-machine ssh registry

创建一个registry服务。

docker run -d -p 5000:5000 --restart=always --name registry \
 -v `pwd`/data:/var/lib/registry \
 registry:2

命令设置了-v volumn选项,这样在每次容器服务重启的时候,不会丢失已经pull的镜像数据。registry,mysql等存储类型的容器,建议设置一下volumn.如果为了更好的扩展,也可以将镜像仓库备份到其他driver里,如阿里云的OSS.

运行docker ps就可以看到一个启动好的registry服务。当然,为了更好的扩展,也可以挂载在自己的域名下,重新run 的时候添加认证信息。

为了更方便管理容器,可以使用docker-compose 组件。安装:

代码如下:

curl -L "https://github.com/docker/compose/releases/download/1.9.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

也可以写好compose文件之后直接启动:

docker-compose up -d

本地仓库push镜像

现在可以尝试拉一个镜像,然后tag到本地的registry仓库,如

代码如下:

docker pull lijingyao0909/see:1.0.3 && docker tag lijingyao0909/see:1.0.3 localhost:5000/see:1.0.3

然后再执行push 命令:

docker push localhost:5000/see:1.0.3

这个镜像就push到了registry服务中,最直接的方式可以通过查看本地的volumn目录,如本例中的 data目录查看到镜像数据。
如果为了更方便的可视化管理registry,也可以试用下registry UI 相关的镜像如hyper/docker-registry-web

代码如下:

docker run -it -p 8080:8080 --name registry-web --link registry-srv -e REGISTRY_URL=http://registry-srv:5000/v2 -e REGISTRY_NAME=localhost:5000 hyper/docker-registry-web

然后访问 hostname:5000/registory/index可以看到简单的镜像列表UI。

https 问题

在本地测试时如果执行以上步骤,在push,或者在其他vb中pull镜像时遇到以下问题:

Error response from daemon: Get https://registry:5000/v1/_ping: dial tcp 218.205.57.154:5000: i/o timeout

处理方式是,修改registry的认证,如下先修改“/var/lib/boot2docker/profile”:

sudo vi /var/lib/boot2docker/profile

添加

DOCKER_OPTS="--insecure-registry <host-name>:5000"
DOCKER_OPTS="--insecure-registry registry:5000"

因为registry的hostname就是 registry。所以执行docker ifno命令可以看到:

Insecure Registries:
 registry:5000
 127.0.0.0/8 

同时,在其他的worker机器,manager机器也需要修改–insecure-registry属性,才可以pull私库的镜像。修改之后需重新restart vb。

重启后,在manager重新尝试pull

docker pull registry:5000/see:1.0.3 

可以看到成功连接仓库并拉取镜像。注意,本示例使用的是机器名,registry,而不是IP地址。所以,在拉取镜像的时候,需在各自的vb 的etc/hosts文件配置ip和机器名的映射。用机器名的方式比较操作易记。当然最好的方式还是通过域名访问仓库。

参考资源

部署registry服务

创建ops服务

swarm的服务集群会直接从registry上pull镜像,直接启动应用的service服务。服务的镜像直接打在registry仓库中,但是源码可以维护在ops机器上。前面创建的ops的virtual-box,可以部署gitlab服务。启动参数可以参考Deploy GitLab Docker images

先pull一个gitlab镜像

docker run --detach \
 --hostname gitlab.lijingyao.com \
 --publish 443:443 --publish 80:80 --publish 22:22 \
 --name gitlab \
 --restart always \
 --volume `pwd`/gitlab/config:/etc/gitlab \
 --volume `pwd`/gitlab/logs:/var/log/gitlab \
 --volume `pwd`/gitlab/data:/var/opt/gitlab \
 gitlab/gitlab-ce:8.14.4-ce.0

使用git私库

因绑定了80端口,启动gitlab后访问:http://machine-host/

第一次进入gitlab会自动跳转到重置密码。可以设置一个新的密码,这个是root账号的密码。后续就可以注册其他git用户使用了。
这里,如果申请了域名服务,或者本地绑定gitlab.lijingyao.com 到这个virtualbox的ip地址,就可以直接访问gitlab.lijingyao.com地址。在实际生产环境有固定公网ip,自己的dns服务,就不需要绑定host。这里只是本地测试,所以暂时就通过绑定host的方式。

swarm

本例中的服务是一个简单的springboot 和gradle的工程,服务镜像可以在docker hub pull,see service image。打包好镜像后,直接在gradle task中push到registry仓库中。在本地环境可以直接在工程目录里执行。gradle task然后push到vb的registry中,再在registry 仓库pull镜像即可。现在开始准备初始化swarm 集群。

现在整个vb 集群的机器,查看如下:

$docker-machine ls

NAME  ACTIVE DRIVER  STATE  URL       SWARM DOCKER ERRORS
haproxy -  virtualbox Running tcp://192.168.99.103:2376   v1.12.3
manager1 -  virtualbox Running tcp://192.168.99.100:2376   v1.12.3
ops  -  virtualbox Running tcp://192.168.99.106:2376   v1.12.3
registry -  virtualbox Running tcp://192.168.99.107:2376   v1.12.3
worker1 -  virtualbox Running tcp://192.168.99.101:2376   v1.12.3
worker2 -  virtualbox Running tcp://192.168.99.102:2376   v1.12.3
worker3 -  virtualbox Running tcp://192.168.99.105:2376   v1.12.3 

然后用docker-machine ssh manager1登陆到manager1机器上。

初始化swarm manager节点

在manager1 机器上初始化swarm,这个初始化的机器就是swarm的manager.执行:

 docker swarm init --advertise-addr 192.168.99.100

会看到以下执行输出:

Swarm initialized: current node (03x5vnxmk2gc43i0d7xpycvjg) is now a manager.

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

 docker swarm join \
 --token SWMTKN-1-5ru6lyco3upj7oje6hidug3erqczok84wk7bekzfaca4uv51r9-22bcjhkbxnclmw3nl3ui8601l \
 192.168.99.100:2377

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

这个生成的token值,是其他swarm集群节点join到整个swarm的key。如果忘记了token,可以在manager1上执行:

$docker swarm join-token manager 

来查看目前的token值。官方建议至少6个月更换以下token。更换命令:

$docker swarm join-token --rotate worker 

添加worker节点

分别登录 worker1,worker2,worker3,执行join命令。

在join之前,先查看下docker 网络设施。执行

$ docker network ls
NETWORK ID   NAME    DRIVER    SCOPE
4b7fe1416322  bridge    bridge    local
06ab6f3352b0  host    host    local
eebd5c8e0d5d  none    null    local 

按照manager1 初始化之后的命令,执行:

docker swarm join \
 --token SWMTKN-1-5ru6lyco3upj7oje6hidug3erqczok84wk7bekzfaca4uv51r9-22bcjhkbxnclmw3nl3ui8601l \
 192.168.99.100:2377

此时在任何worker节点再执行docker network ls 即可看到多了一个overlay的覆盖范围为swarm的网络通道。

三个worker都加入之后,在manager1 上即可看到manager的node节点情况

docker node ls
ID       HOSTNAME STATUS AVAILABILITY MANAGER STATUS
03x5vnxmk2gc43i0d7xpycvjg * manager1 Ready Active  Leader
2y5wrndibe8c8sqv6851vrlgp worker1 Ready Active  Reachable
dwgol1uinkpsybigc1gm5jgsv worker2 Ready Active
etgyky6zztrapucm59yx33tg1 worker3 Ready Active  Reachable

manager status的Reachable状态表示该节点也是manager节点。这是因为我们在worker1,worker3分别执行了

docker node promote worker1
docker node promote worker3

worker1,worker3此时也可以执行swarm命令,在manager1关停时,就会选举其中之一作为新的leader。如果要去除node的manager状态,可以通过demote命令去除。执行后,worker节点就变成普通的任务节点。

docker node demote worker1 worker3 

swarm节点的其他状态

swarm节点可以设置drain状态,drain状态的节点不会执行任何service。

将某个node设置不可用:

docker node update --availability drain worker1 

Pause,Drain,Active三个状态,pause标识有任务运行,不接受新任务。

如果要将worker1 节点去除swarm中心,现在需被移除的节点(worker1)执行:docker swarm leave 然后在manager上执行:docker node rm worker1,即可移除一个swarm节点。

创建swarm服务

本例中使用swarm部署一个基于springboot的rest api服务。仓库的地址:springboot-restful-exam,创建的服务name是deftsee,绑定80端口,并且扩展4个运行容器服务。

docker service create \
 --replicas 4 \
 --name deftsee \
 --update-delay 10s \
 --publish 8080:80 \
 lijingyao0909/see:1.0.3

服务创建之后,可以查看服务节点的状态

docker@manager1:~$ docker service ls
ID   NAME  REPLICAS IMAGE     COMMAND
a6s5dpsyz7st deftsee 4/4  lijingyao0909/see:1.0.3

REPLICAS 代表服务的运行容器数,如果是0/4就代表所有服务都没有起来。详细查看各个节点运行状态可以用docker service ps servicename

docker@manager1:~$ docker service ps deftsee
ID       NAME  IMAGE     NODE  DESIRED STATE CURRENT STATE   ERROR
8lsdkf357lk0nmdeqk7bi33mp deftsee.1 lijingyao0909/see:1.0.3 worker2 Running  Running 5 minutes ago
cvqm5xn7t0bveo4btfjsm04jp deftsee.2 lijingyao0909/see:1.0.3 manager1 Running  Running 7 minutes ago
6s5km76w2vxmt0j4zgzi4xi5f deftsee.3 lijingyao0909/see:1.0.3 worker1 Running  Running 5 minutes ago
4cl9vnkssedpvu2wtzu6rtgxl deftsee.4 lijingyao0909/see:1.0.3 worker3 Running  Running 6 minutes ago 

可以看到任务被平分到所有的四个任务节点运行。下面再扩容deftsee服务

docker@manager1:~$ docker service scale deftsee=6
deftsee scaled to 6
docker@manager1:~$ docker service ps deftsee
ID       NAME  IMAGE     NODE  DESIRED STATE CURRENT STATE   ERROR
8lsdkf357lk0nmdeqk7bi33mp deftsee.1 lijingyao0909/see:1.0.3 worker2 Running  Running 8 minutes ago
cvqm5xn7t0bveo4btfjsm04jp deftsee.2 lijingyao0909/see:1.0.3 manager1 Running  Running 10 minutes ago
6s5km76w2vxmt0j4zgzi4xi5f deftsee.3 lijingyao0909/see:1.0.3 worker1 Running  Running 8 minutes ago
4cl9vnkssedpvu2wtzu6rtgxl deftsee.4 lijingyao0909/see:1.0.3 worker3 Running  Running 9 minutes ago
71uv51uwvso4l340xfkbacp2i deftsee.5 lijingyao0909/see:1.0.3 manager1 Running  Running 5 seconds ago
4r2q7q782ab9fp49mdriq0ssk deftsee.6 lijingyao0909/see:1.0.3 worker2 Running  Running 5 seconds ago 

lijingyao0909/see:1.0.3是dockerhub的公共仓库的镜像,服务创建时会去pull镜像,整体速度偏慢,所以可以结合私有仓库,直接在registry机器上pull镜像。服务可以直接用docker service rm deftsee移除服务,然后通过registry重建服务。

docker service create \
 --replicas 6 \
 --name deftsee \
 --update-delay 10s \
 --publish 8080:80 \
 registry:5000/see:1.0.4

此时登录任何一台worker服务,查看运行的容器镜像:

docker@worker2:~$ docker ps
CONTAINER ID  IMAGE      COMMAND     CREATED    STATUS    PORTS    NAMES
89d4f588290b  registry:5000/see:1.0.4 "/bin/sh -c 'java -Dc" About a minute ago Up About a minute 8080/tcp   deftsee.1.eldpgb1aqtf9v49cxolydfjm9

如果要更新服务,可以直接通过update命令更新版本,并且服务滚动发布,通过设置*–update-delay 10s *可以改变更新时各个节点的延迟时间。

docker service update --image registry:5000/see:1.0.5 deftsee

重启某个node的服务

关闭:docker node update –availability drain worker1

开启:docker node update –availability active worker1

更新服务端口

更新一个服务的端口会重启服务(关闭原有服务,重新创建服务并启动):

 docker service update \
 --publish-add <PUBLISHED-PORT>:<TARGET-PORT> \
 <SERVICE>

docker@manager1:~$docker service update \
 --publish-add 8099:8080 \
 deftsee

docker@manager1:~$ docker service ps deftsee
ID       NAME   IMAGE     NODE  DESIRED STATE CURRENT STATE    ERROR
3xoe34msrht9eqv7eplnmlrz5 deftsee.1  registry:5000/see:1.0.4 manager1 Running  Running 39 seconds ago
eldpgb1aqtf9v49cxolydfjm9 \_ deftsee.1 registry:5000/see:1.0.4 worker2 Shutdown  Shutdown 39 seconds ago
9u4fh3mi5kxb14y6gih5d8tqv deftsee.2  registry:5000/see:1.0.4 manager1 Running  Running about a minute ago
0skgr5fx4xtt6y71yliksoft0 \_ deftsee.2 registry:5000/see:1.0.4 worker1 Shutdown  Shutdown about a minute ago
8hposdkqe92k7am084z6kt1j0 deftsee.3  registry:5000/see:1.0.4 worker3 Running  Running about a minute ago
c5vhx1wx0q8mxaweaq0mia6n7 \_ deftsee.3 registry:5000/see:1.0.4 manager1 Shutdown  Shutdown about a minute ago
9se1juxiinmetuaccgkjc3rr2 deftsee.4  registry:5000/see:1.0.4 worker1 Running  Running about a minute ago
4wofho0axvrjildxhckl52s41 \_ deftsee.4 registry:5000/see:1.0.4 worker3 Shutdown  Shutdown about a minute ago 

服务验证和网络

例子中的服务启动后,可以直接通过ip:port访问。如http://192.168.99.100:8099/see,可以看到服务请求会分发到各个运行的节点中。也就是swarm的overlay网络层,各个节点的网络是互通的,swarm做了load balance,在swarm的lb的基础上也可搭建自己定义的overlay网络,创建的这个overlay 网络,所有节点都可以和这个network互通。但是在服务创建的时候需要制定network选项。

$docker network create \
 --driver overlay \
 --subnet 10.0.9.0/24 \
 --opt encrypted \
 my-network

$docker service create \
 --name deftsee \
 --publish 8099:80 \
 --replicas 4 \
 --network my-network \
 -l com.df.serviceDomain=deftsee.com \
 -l com.df.notify=true \
 lijingyao0909/see:1.0.3

–network my-network制定了服务可连接到的docker network,可以在swarm的节点创建一个name为my-network的网络。所以也可以在swarm机制中搭建consul和haproxy的服务发现和lb机制。

当为一个服务指定一个network的时候,swarm上执行的任务也必须都在这个指定的网络上才能和服务互通。如果节点上没有加入到swarm模式的node中,或者没有运行挂载在这个指定网络的时候,也不会和这个network互通.docker network ls也不会查出该网络。创建服务时通过–network my-network这个标签链接到这个网络。在查看网络时,docker network inspect my-network可以查看返回的Containers 列出的该节点的挂载容器。

创建了一个网络服务,有service连接到网络时,swarm会给这个网络下的服务(service)指定一个vip. swarm 内部的lb会自动分发服务,不需要指定每个服务端口,即在同一个network连接的容器,通过service name就可以访问到服务。因为所有加入到这个network的容器都会通过gossip协议共享一个DNS映射(vip映射根据service name 绑定到的dns别名映射)。

查看服务的vip网络信息:

$docker service inspect \
 --format='{{json .Endpoint.VirtualIPs}}' \
 deftsee

输出:[{"NetworkID":"dn05pshfagohpebgonkhj5kxi","Addr":"10.255.0.6/16"}]

swarm管理

为了保持manager节点的可用性(心跳机制,leader选举),可以将manager节点设置成不接受服务运行,节省manager节点资源,将manager节点隔离出任务环境。

docker node update --availability drain <NODE>

备份/var/lib/docker/swarm/raft 状态

清理不可用的节点

docker node demote <NODE>
docker node rm <id-node>.

节点重新加入manager re-join

$docker node demote <NODE>.
$docker node rm <NODE>.
$docker swarm join ...

初始化的时候指定固定ip ,init –advertise-addr。worker节点可以用动态ip 。

参考资源

Swarm mode

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Docker使用Swarm组建集群的方法

    Swarm 在 Docker 1.12 版本之前属于一个独立的项目,在 Docker 1.12 版本发布之后,该项目合并到了 Docker 中,成为 Docker 的一个子命令.目前,Swarm 是 Docker 社区提供的唯一一个原生支持 Docker 集群管理的工具.它可以把多个 Docker 主机组成的系统转换为单一的虚拟 Docker 主机,使得容器可以组成跨主机的子网网络. Docker 使用 Swarm 可以很方便的在多个主机上创建容器集群,并且容器之间可以跨主机网络通信. Swar

  • Docker的安装方法及运行Docker Swarm模式的使用

    Docker简介 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化.容器是完全使用沙箱机制,相互之间不会有任何接口. 概要 docker就给简单介绍这么多,这里主要说说docker swarm. docker engine本身只提供了容器技术,没有解决集群环境下的容器编排和通信.docker swarm是一个容器编排管理工具,docker-engine在1.12版本之后集成了docker

  • 使用Docker Swarm搭建分布式爬虫集群的方法示例

    在爬虫开发过程中,你肯定遇到过需要把爬虫部署在多个服务器上面的情况.此时你是怎么操作的呢?逐一SSH登录每个服务器,使用git拉下代码,然后运行?代码修改了,于是又要一个服务器一个服务器登录上去依次更新? 有时候爬虫只需要在一个服务器上面运行,有时候需要在200个服务器上面运行.你是怎么快速切换的呢?一个服务器一个服务器登录上去开关?或者聪明一点,在Redis里面设置一个可以修改的标记,只有标记对应的服务器上面的爬虫运行? A爬虫已经在所有服务器上面部署了,现在又做了一个B爬虫,你是不是又得依次

  • 在Ubuntu 16.04上用Docker Swarm和DigitalOcean创建一个Docker容器集群的方法

    介绍 Docker Swarm是用于部署Docker主机集群的Docker本地解决方案.您可以使用它来快速部署在本地计算机或受支持的云平台上运行的Docker主机集群. 在Docker 1.12之前,设置和部署Docker主机集群需要使用外部键值存储(如etcd或Consul)来进行服务发现.但是,使用Docker 1.12,不再需要外部发现服务,因为Docker提供了一个内置的键值存储,可以开箱即用. 在本教程中,您将了解如何使用Docker 1.12上的Swarm功能部署一组Docker机器

  • Docker Swarm入门实例详解

    Swarm 在 Docker 1.12 版本之前属于一个独立的项目,在 Docker 1.12 版本发布之后,该项目合并到了 Docker 中,成为 Docker 的一个子命令.目前,Swarm 是 Docker 社区提供的唯一一个原生支持 Docker 集群管理的工具.它可以把多个 Docker 主机组成的系统转换为单一的虚拟 Docker 主机,使得容器可以组成跨主机的子网网络. 1. Swarm 认识 Swarm 是目前 Docker 官方唯一指定(绑定)的集群管理工具.Docker 1.

  • 详解使用docker 1.12 搭建多主机docker swarm集群

    swarm是docker公司自己的容器集群管理工具,本文介绍了使用docker 1.12 搭建多主机docker swarm集群,分享给大家 准备 准备至少两台的centos 7 主机(全新最小安装, 可以使用虚拟机安装) 开放端口2377 tcp端口, 7946 4789 tcp udp 端口 本文使用192.168.99.101(hostname:centos-node4) 作为swarm manager 192.168.99.102(hostname:centos-node5) 作为sw

  • 轻松安装docker并运行docker swarm模式

    概要 docker 1.12版本最大的改变在于集成了docker swarm,在docker engine下提供了 swarm 模式,这里主要说一下docker swarm. docker engine本身只提供了容器技术,没有解决集群环境下的容器编排和通信.docker swarm是一个容器编排管理工具,docker-engine在1.12版本之后集成了docker swarm,不需要再单独安装. docker swarm的功能,举个例子,有3台机器都安装了docker环境,称为3台docke

  • docker swarm 集群故障与异常详解

    本文介绍了docker swarm 集群故障与异常详解,分享给大家,具体如下: 在上次遭遇 docker swarm 集群故障后,我们将 docker 由 17.10.0-ce 升级为最新稳定版 docker 17.12.0-ce . 前天晚上22:00之后集群中的2个节点突然出现CPU波动,在CPU波动之后,在凌晨夜深人静.访问量极低的时候,整个集群出现了故障,访问集群上的所有站点都出现了502,过了一段时间后自动恢复正常. ECS实例:swarm1-node5,CPU百分比于00:52发生告

  • 详解Docker Swarm服务发现和负载均衡原理

    本文将介绍基于 DNS 的负载均衡.基于 VIP 的负载均衡和路由网格(Routing Mesh). 使用的技术 Docker 使用了 Linux 内核 iptables 和 IPVS 的功能来实现服务发现和负载均衡. iptables 是 Linux 内核中可用的包过滤技术,它可用于根据数据包的内容进行分类.修改和转发决策. IPVS 是 Linux 内核中可用的传输级负载均衡器. 准备工作 swarm 集群: [Manager]node1.[Worker]node2 客户端镜像: regis

  • docker swarm如何在指定的node上运行指定的容器

    描述问题 比如我们有worker1,worker2,worker3三个docker host另外加一个manager1(它是swarm的master)来管理它们. 如果在manager1上直接docker service create某一个容器的话,比如nginx容器,那么master会来决定挑哪一个node作为nginx容器的运行的host. 如果我要nginx容器只跑在worker1上面的话,应该怎么办呢? 解决方案 简单来说就是给每一个node打标签. docker node update

随机推荐