才云科技云开源高级工程师唐继元受邀DBAplus社群,在线分享《Kubernetes Master High Availability 高级实践》,介绍如何构建Kubernetes Master High Availability环境。node
如下是分享实录:git
你们好,我是才云科技的唐继元,今天给你们带来一篇技术分享,本次分享我将为你们介绍如何构建Kubernetes Master High Availability环境。这次分享内容是我在工做中经验总结,若是有不正确的或者须要改进的地方,欢迎各位大神指正。
相信你们对容器、docker和kubernetes这些概念并不陌生。下面进入本次分享的正题。
Kubernetes做为容器编排管理系统,经过Scheduler、ReplicationController等组件实现了应用层的高可用,可是针对Kubernetes集群,还须要实现Master组件的高可用。
本次分享论述的Master高可用方案主要基于社区的高可用方案(连接)的实践,可是社区的高可用方案中采用的GCE的External Loadbalancer,并未论述如何实现External Loadbalancer,并且也并无将Kubernetes集群组件容器化。因此,咱们的高可用方案在社区高可用方案的基础之上进行了以下两个方面的提高:github
第一,除了kubelet以外,Kubernetes全部组件容器化;
第二,经过haproxy和keepalived构建Loadbalancer实现Master的高可用。
下面咱们分四个章节来详细论述Kubernetes Master High Availability环境的搭建。web
HA Master总体架构docker
核心技术点和难点后端
实践中的遇到的那些坑api
社区关于HA Master的将来发展服务器
咱们已经成功将支持Master High Availability的Kubernetes集群部署到企业私有云平台,底层采用的是Ubuntu 14.04操做系统。下面是一个典型的部署环境:网络
Static Pods是由其所在节点上的kubelet直接管理,而不须要经过Apiserver来监视它们。Static Pods的资源类型只能是Pod,并且不与任何的Replication Controller相关联,它们彻底由kubelet来监视,而且当它们异常中止的时候由该kubelet负责重启它们。架构
(haproxy, keepalived):这里表示咱们将haproxy和keepalived放置在同一个pod中。
1.1.kubelet对static pod高可用的支持
咱们须要为kubelet进程配置一个manifests监视目录:
--config=/etc/kubernetes/manifests
若是有新的yaml/manifest文件添加到该目录,kubelet则根据yaml/manifest文件建立一个新的static pod;
若是咱们把某个yaml/manifest文件从该目录删除,kubelet则会删除由该yaml/manifest文件所产生的static pod;
若是该目录下的yaml/manifest文件有更新,kubelet则会删除原来的static pod,而根据更新后的yaml/manifest文件从新建立一个新的static pod;
若是manifests目录下的文件没有任何变化,可是其下某个yaml/manifest文件所产生的static pod错误退出或者被误删后,kubelet仍然会根据该yaml/manifest文件从新建立一个新的static pod。
这样,kubelet在必定程度上保证了static pod的高可用。
1.2.kubelet进程的高可用
kubelet经过manifests监视目录保证了staticpod的高可用,可是若是kubelet进程自己错误退出或者被误删后,谁来负责从新启动kubelet进程呢?
在Linux系统中,咱们能够经过Monit、Upstart、Systemd、Supervisor等工具实现对服务的监控保证服务的高可用。
在Ubuntu 14.04操做系统中,咱们将kubelet作成系统服务,利用Upstart来保证kubelet服务的高可用,下面是kubelet服务基于Upstart的服务启动脚本/etc/init/kubelet.conf:
其中:
respawn: 该命令设置服务或任务异常中止时将自动启动。除stop命令外的中止都是异常中止。
respawn limit: 该命令设置服务或任务异常中止后重启次数和间隔时间。
1.3.Master High Availability Kubernetes总体架构图
从架构图中咱们能够看到:
1) Upstart保证docker服务和kubelet服务的高可用,而Kubernetes的其余组件将以staticpod的方式由kubelet保证高可用。
2)两台lb节点经过haproxy和keepalived构建出一个ExternalLoadbalancer,并提供VIP供客户端访问。
3) Haproxy配置成“SSLTermination”方式,外网client经过HTTPS请求访问集群,而内网client则能够经过HTTPS/HTTP请求访问。
4) Kubernetes高可用集群经过flannelstatic pod构建一个Overlay网络,使集群中的docker容器可以经过Kubernetes Cluster IP进行通讯。
2.1.运行在特权模式的组件
Kubernetes集群中的一些组件须要经过内核模块来为集群提供服务,所以这些组件须要运行在特权模式下,以便能访问相应的内核模块。
2.1.1.开启特权模式
为了支持docker容器在特权模式下运行,咱们须要开启Kubernetes集群的特权模式权限:
--allow-privileged=true
这里主要体如今kubelet服务和apiserver服务。
1) Kubelet service
kubelet服务须要开启特权模式权限,以便容许docker容器向kubelet请求以特权模式运行。
2) Apiserver static pod
apiserver static pod须要开启特权模式权限,以便运行在特权模式下的docker容器可以访问apiserver服务。
2.1.2.运行在特权模式下的docker容器
运行在特权模式下的docker容器,在yaml文件中须要添加以下字段:
securityContext: privileged: true
这里主要体如今kubeproxy服务、flannel服务和keepalived服务。
1) Kubeproxy static pod
kubeproxy须要经过Iptables设置防火墙规则。
2) Flannel static pod
flannel须要访问vxlan、openvswitch等路由数据报文。
3) Keepalived static pod
keepalived须要访问IP_VS内核模块来创建VIP。
2.2.Static pod必须运行在主机网络下
如上所述的这些以static pod形式存在的Kubernetes集群组件,必须工做在主机网络下:
hostNetwork: true
虽然Overlay网络是为了让不一样节点间的docker容器进行通讯,而上述以staticpod形式存在的组件也都是docker容器,可是它们之间的心跳和信息交流都须要经过主机网络而不是相似于flannel等的Overlay网络。理由以下:
1)这些static pods不一样于应用的pods,它们的稳定保障了Kubernetes集群的稳定性,它们之间的心跳和信息交流都是经过它们配置文件中的静态IP地址进行的,而docker/flannel网络是动态的,咱们没法保证docker/flannel网络中IP地址的稳定性,同时也没法事先知道IP地址。
2) kubeproxy、flannel、haproxy须要经过主机网络修改路由规则,从而使主机上的服务能被其余主机访问。
3) haproxy须要将外网请求重定向到内网后端服务器上,也必须须要主机网络。
2.3.External Loadbalancer部署要点
对于如何配置haproxy和keepalived,网络上有很是多的资源,因此这里不在论述。下面咱们来分析一下部署过程当中的一些要点。
External Loadbalancer由至少两台lb node组成,经过haproxy和keepalived pod实现Master的负载均衡,对外提供统一的VIP。
咱们能够将haproxy和keepalived分别放置在不一样的pod中,也能够将它们放置在同一个pod中。考虑到keepalived须要监测haproxy的状态,咱们会把haproxy和keepalived放在一块儿作成一个loadbalancerpod。
2.3.1.lb node配置
1)使能内核IPVS模块
因为keepalived须要经过IPVS模块实现路由转发,因此咱们须要使能内核IPVS模块。
从Linux内核版本2.6起,ip_vs code已经被整合进了内核中,所以,只要在编译内核的时候选择了ipvs的功能,Linux即能支持LVS。所以咱们只须要配置操做系统启动时自动加载IPVS模块:
echo "ip_vs" >> /etc/modules echo "ip_vs_rr" >> /etc/modules echo "ip_vs_wrr" >> /etc/modules
咱们能够经过以下命令查看ip_vs模块是否成功加载:
lsmod | grep ip_vs
若是没有加载,咱们能够经过modprobe命令加载该模块:
modprobe ip_vs modprobe ip_vs_rr modprobe ip_vs_wrr
2)修改内核参数
为了使keepalived将数据包转发到真实的后端服务器,每个lb node都须要开启IP转发功能
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
另外,keepalived设置的VIP有可能为非本地IP地址,因此咱们还须要使能非本地IP地址绑定功能:
echo "net.ipv4.ip_nonlocal_bind = 1" >> /etc/sysctl.conf
2.3.2.keepalived监测haproxy状态的方法
对于普通进程来讲, keepalived进程能够经过“killall -0 haproxy”命令检测haproxy进程是否正常运行(注: Sending the signal 0 to a given PID just checksif any process with the given PID is running)。
然而在docker容器环境下,各容器都有本身的PidNamespace和NetworkNamespace,咱们就须要开启haproxy的健康检查页面,而后keepalived经过健康检查页面的URL来检测haproxy目前是否正常运行。
haproxy健康检查页面配置:
listen admin_stats bind 0.0.0.0:80 log global mode http maxconn 10 stats enable #Hide HAPRoxy version, a necessity for any public-facing site stats hide-version stats refresh 30s stats show-node stats realm Haproxy\ Statistics stats auth caicloud:caicloud stats uri /haproxy?stats
keepalived对haproxy的状态检测:
vrrp_script check_script { script "/etc/keepalived/check_haproxy.py http://caicloud:caicloud@127.0.0.1/haproxy?stats" interval 5 # check every 5 seconds weight 5 fall 2 # require 2 fail for KO rise 1 # require 1 successes for OK }
2.3.3.haproxy SSL配置
haproxy代理ssl配置有两种方式:
1) haproxy自己提供SSL证书,后面的web服务器走正常的http协议;
2) haproxy自己只提供代理,直接转发client端的HTTPS请求到后端的web服务器。注意:这种模式下“mode”必须是“tcp”模式, 即仅支持4层代理。
考虑到:第一,用户亲和性访问须要7层代理的支持;第二,loadbalancer和master走的都是集群内网。因此本实践采用了第一种方式,配置以下:
frontend frontend-apiserver-https # Haproxy enable SSL bind *:443 ssl crt /etc/kubernetes/master-loadblancer.pem option forwardfor default_backend backend-apiserver-http
2.3.4.haproxy配置:haproxy.cfg
2.3.5.keepalived配置:keepalived.conf
1) lb-1上keepalived配置
2) lb-2上keepalived配置
lb-2跟lb-1的配置差很少,除了下面两个字段:
state BACKUP priority 97
2.4.flannel网络设置
2.4.1Master节点flannel网络设置
对于Master节点,须要等待Etcd Pod集群启动完后,先在Master上建立Flannel网络,而后Flannel Pod客户端才能够从Etcd中获取到各个Master节点的IP网段,获取到IP网段后会在主机上产生文件:“/var/run/flannel/subnet.env”,而后根据该文件修改docker启动参数:
. /var/run/flannel/subnet.env DOCKER_OPTS="$DOCKER_OPTS --bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU}"
并重启docker服务。
2.4.2非Master节点flannel网络设置
对于非Master节点,待Loadbalancer起来以后,Node节点可以访问Apiserver以后,Flannel Pod客户端才能从Etcd获取到该Node节点的IP网段,而且一样会在主机上产生文件:“/var/run/flannel/subnet.env”。而后修改docker启动参数,并重启docker服务。
3.1.官网“haproxy docker image”的坑
Docker Hub上“haproxy image”的“docker-entrypoint.sh”内容以下:
问题就出在“haproxy-systemd-wrapper”。若是运行命令:“haproxy -f/etc/haproxy/haproxy.cfg”, 而实际上运行的是通过“haproxy-systemd-wrapper”包装后的命令:
执行命令“haproxy -f /etc/haproxy/haproxy.cfg”时,真正执行的是:“/usr/local/sbin/haproxy -p /run/haproxy.pid -f /etc/haproxy/haproxy.cfg -Ds”,对于“-Ds”选项, 官网是这么描述的:
原来,“haproxy”通过“haproxy-systemd-wrapper”包装后在后台执行,而docker container不容许进程后台执行,不然docker容器将该启动命令执行完后就退出了。官网image的这个坑很大。
因此,当咱们用官网“haproxy image”的时候,就须要用haproxy的彻底路径来执行。好比在yaml文件中:
3.2.haproxy container exited with 137
首先137退出码表示,其余进程向haproxy container发起了“kill”信号,致使haproxy container退出,容器日志以下
[WARNING] 155/053036 (1) : Setting tune.ssl.default-dh-param to 1024 by default, if your workload permits it you should set it to at least 2048. Please set a value >= 1024 to make this warning disappear.
其次,当经过“docker run”命令执行haproxy container,使用的命令与yaml文件中的同样,并且照样输出上述的“WARNING”,可是容器却不退出。
而后,无奈之下,我试着先将这个“WARNING”解决:这个错误是因为haproxy.cfg中添加了SSL证书致使的, 能够经过设置参数“default-dh-param”解决:
global ... # turn on stats unix socket stats socket /run/haproxy.stats tune.ssl.default-dh-param 2048 frontend frontend-apiserver-https # Haproxy enable SSL bind *:443 ssl crt /etc/kubernetes/master-loadbalancer.pem ...
当我解决这个“WARNING”以后,奇迹出现了,haproxy container奇迹般的正常运行了。原来在容器的世界,一个“WARNING”也不能疏忽。
熟悉kubelet配置参数的都知道,咱们在给kubelet配置apiserver的时候,能够经过“--api-servers”指定多个:
--api-servers=http://m1b:8080,http://m1c:8080,http://m2a:8080,http://m2b:8080,http://m2c:8080
这看起来彷佛已经作到apiserver的高可用配置了,可是实际上当第一个apiserver挂掉以后, 不能成功的链接到后面的apiserver,也就是说目前仍然只有第一个apiserver起做用。
若是上述问题解决以后, 彷佛不须要额外的loadbalancer也能实现master的高可用了,可是,除了kubelet须要配置apiserver,controllermanager和scheduler都须要配置apiserver,目前咱们还只能经过“--master”配置一个apiserver,没法支持多个apiserver。
社区后续打算支持multi-master配置,实现Kubernetes Master的高可用,并且计划在Kubernetes 1.4版本中合入。
即便未来社区实现了经过multi-master配置的高可用方式,本次分享的MasterHigh Availability仍然很是有意义,由于在私有云场景中,ExternalLoadbalancer除了实现Master的高可用和负载均衡外,还能够针对Worker Node实现Nodeport请求的负载均衡,从而不只实现了应用的高可用访问,同时也大大提升了应用的访问速度和性能。
参考连接:
连接
连接好了,以上是本次分享的全部内容,欢迎你们批评指正,同时也但愿能为你们带来些收益。