2017-08-20 17:05

(十)Docker - 高可用集群

商业转载请联系作者获得授权,非商业转载请注明出处. Leon(weippt.com)

这一节我们综合之前介绍到的功能和工具,来搭建一个小型分布式集群投票系统,同时实现负载均衡、热备等功能。这个架构我们将会用到 6 台主机,1台Machine主机,3台Apache+PHP提供应用服务,2台HAProxy做负载(你也可以用 LVS 或 Nginx等),另外再为负载做 Keepalived 热备。其 ip 关系如下表:
Machine: 10.0.0.18
HostA  : 10.0.0.130
HostA  : 10.0.0.128
HostA  : 10.0.0.129
ProxyA : 10.0.0.160
ProxyB : 10.0.0.161
MySQL1 : 10.0.0.150

安装 Docker Machine

不过这一次,我们将不用再在不同的宿主间频繁切换操作,我们将使用 Docker Machine 对所有主机统一管理部署。Machine 的介绍和安装见(https://docs.docker.com/machine/install-machine),其常用命令有:

  • docker-machine create --driver virtualbox host-name  # 创建新的 virtualbox 主机;

  • docker-machine restart HostA  #重启 HostA;

  • docker-machine stop HostA # 关闭;

  • docker-machine rm HostA #移除;

  • docker-machine ls  # 查看主机列表,其中 Active 状态为 '*' 的主机是当前操作环境主机;

  • docker-machine ssh HostA ls # 以ssh到HostA的方式执行 ls 命令;

  • eval $(docker-machine env HostA)  # 设置操作环境主机变量,设置之后进行的操作命令可以视为直接操作HostA。

事实上,我们只需要上述的一条 create 命令,就可以创建一台完整的宿主,其内部已自动为用户依次创建了CA证书、虚拟机、然后在虚拟机中安装了Doker Engine。但我手上已经有我们要用到的主机了,所以我们同样使用 create 命令和几台宿主建立连接就可用了!在开始之前,我们确保操作 Docker Machine 主机(以后简称 DM)的用户具有 Docker 操作权限,避免频繁使用 sudo 带来的麻烦 !然后我们配置 DM 对其他主机的免密登陆:

# 免密登陆
DM$ ssh-keygen -t rsa
DM$ for i in {130,128,129}; do ssh-copy-id -i ~/.ssh/id_rsa.pub root@10.0.0.$i; done

# 然后把几台主机加入到 Machine 中:
DM$ dm create --driver generic --generic-ip-address=10.0.0.130 --generic-ssh-key ~/.ssh/id_rsa HostA
DM$ dm create --driver generic --generic-ip-address=10.0.0.128 --generic-ssh-key ~/.ssh/id_rsa HostB
DM$ dm .....依次添加所有主机

# 为了操作方便,你也可用像我一样使用 dm 命令: 
DM$ echo "alias dm='docker-machine'" >> ~/.bashrc && source ~/.bashrc
DM$ echo "alias dm-env='dmenv() { eval $(dm env $1);}; dmenv'" >> ~/.bashrc && source ~/.bashrc
 配置 Swarm mode

有了 Docker Machine,我们就不用在依次登陆每一台宿主配置 Swarm 了。Swarm 的使用方法上一小节都已介绍,这里我们仅说明怎么在 Machine 主机上操作 Swarm !

我们只把 HostA/B/C 三台主机添加到一个集群里!

DM$ eval $(docker-machine env HostA)    # 切换到 HostA 主机环境;

DM$ dm ls   # 可用看到 HostA 的 ACTIVE 是 * 号,说明现已处于 HostA 环境;

DM$ docker swarm init  # 即可在 HostA 上初始化;

DM$ eval $(docker-machine env HostB/C)  

DM$ ... 请依次切换到 HostB、HostC 主机,然后执行 join 操作!

部署 Web 应用

这里我们只用到一台DB,所以我们单独部署这一台 MySQL 服务器:

DM$ eval $(docker-machine env MySQL1)
DM$ docker run --name some-mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7

有了数据库,我们使用 Swarm 部署来部署应用:Wordpress !

DM$ eval $(docker-machine env HostA)

DM$ docker network create --driver overlay web-net

DM$ docker service create --replicas 3 --network web-net --publish 80:80 --name some-wordpress -e WORDPRESS_DB_HOST=10.0.0.150:3306 -e WORDPRESS_DB_USER=root -e WORDPRESS_DB_PASSWORD=123456 -d wordpress

现在我们通过 $dm ls 看到 REPLICAS 进度,当任务部署完成之后,我们在浏览器中访问任意一台 Host 都可用访问 wordpress 了。

Docker stack deploy

你可以可以参考官方文档,使用 docker stack deploy、docker-compose.yml 构建一个投票系统服务:https://docs.docker.com/datacenter/ucp/2.2/guides/user/services/deploy-app-cli

HAProxy 负载均衡

既然 Swarm 拥有负载均衡,为什么我们还需要负载均衡:一个原因是 Swarm 负载均衡器是 TCP 层负载均衡器。许多应用程序需要额外的功能,如SSL/TLS终端;基于内容的路由(例如,基于URL或header);访问控制和授权;重写和重定向。接下来,我们在 webapp 前搭建一组 HAProxy 代理,你也可用用Nginx!首先我们准备 2 个文件备用:

# haproxy Dockerfile
FROM haproxy:1.8
COPY haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg

haproxy.cfg:

global
    daemon
    maxconn 256

defaults
    mode http
    timeout connect 5000ms
    timeout client 50000ms
    timeout server 50000ms

frontend http-in
    bind *:80
    default_backend servers

backend servers
    server server1 10.0.0.130:80 maxconn 32
    server server2 10.0.0.128:80 maxconn 32
    server server3 10.0.0.129:80 maxconn 32

DM$ dm ssh ProxyA  # 登陆到 ProxyA,然后创建上面 2 个文件;

DM$ docker build -t my-haproxy .  #构建 my-haproxy

DM$ docker run -it --rm --name haproxy-syntax-check my-haproxy haproxy -c -f /usr/local/etc/haproxy/haproxy.cfg # 测试配置文件

DM$ docker run -d -p 80:80 --restart=always --name haproxy my-haproxy # 启动HAProxy!

DM$ 按照同样的方法配置 ProxyB!!!

现在已经可以在浏览器里分布访问 10.0.0.160 / 161 了,同样我们可以看到 WordPress 的安装页面;

Keepalived 热备

现在我们已经有了2台 HAProxy,但他们同一时间只需要一台提供服务,为了保障其高可用,我们使用 Keepalived 实现简单的热备功能。

DM$ dm ssh ProxyA / B # 分布登陆 2 台 Proxy

DM$ apt-get install keepalived  # 直接仓库源安装

在 ProxyA 主机上配置 /etc/keepalived/keepalived.conf

global_defs {
   notification_email_from test@weippt.com
   router_id LVS_DEVEL
}

vrrp_instance VI_1 {
    state MASTER
    interface ens33
    virtual_router_id 50
    nopreempt
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass leonX666
    }
    virtual_ipaddress {
        10.0.0.100
    }
}

再在 ProxyB 主机上配置 /etc/keepalived/keepalived.conf

global_defs {
   notification_email_from test@weippt.com
   router_id LVS_DEVEL
}

vrrp_instance VI_1 {
    state BACKUP
    interface ens33
    virtual_router_id 50
    nopreempt
    priority 99
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass leonX666
    }
    virtual_ipaddress {
        10.0.0.100
    }
}

对比上面的配置文件,可以看到,我们2台主机分布是 Master 和 Backup 主备模式,其中 priority 为Master优先级,投票权重;auth_pass 要保证相同;virtual_ipaddress 虚拟IP,负载对外提供服务;现在我们重启 2 台主机的服务 :

ProxyA/B$ /etc/init.d/keepalived restart

现在我们已经可以通过 10.0.0.100 访问 WordPress 了,现在除了负载,我们还具备了热备。您可以把 2 台 HAProxy 主机分布关闭/开启试试,10.0.0.100 可以不间断提供服务!

会话保持

现在您会遇到一个诡异的现象,刚刚登陆过了,为什么又退出了。那是因为现在的集群是没办法保持 Session 状态的!这里我们仅简单介绍一下,有时间在探讨实现方法了,网上资料也很多。

  • 保持会话:固定客户端ip访问到指定一台服务,缺点就是影响负载的均衡;

  • 会话复制:在每一台服务器上复制会话,集群量越大弊端越明显;

  • 会话共享:常用如 Redis 或 Memcached 实现;

Consul

最后,附一个关于在 Swarm 中的 ATTX 项目:

https://attx-project.github.io/Consul-for-Service-Discovery-on-Docker-Swarm.html

https://attx-project.github.io/Deploying-ATTX-Components-on-Docker-Swarm.html

商业转载请联系作者获得授权,非商业转载请注明出处. Leon(weippt.com)