K8s HA集群的运行主要由k8s基本组件、etcd集群和docker运行环境组成的,其中etcd集群可以理解为k8s集群的数据库,它主要作用是服务发现、全局配置、以及保存一些路由相关的信息。为了保证k8s集群的高可用性,我们需要保证etcd存储数据的可靠性,所以在这个我们在搭建k8s集群的过程中搭建了一个etcd HA集群。我们搭建k8s HA集群的次序如下所示:
- 1、搭建etcd集群
- 2、启动k8s master组件
- 3、启动k8s node组件
搭建ETCD集群
etcd集群搭建的方式比较多,可以搭建一个全新的集群,也可以从已有的etcd中,将数据迁移到一个新集群上。
创建一个全新的集群
创建一个全新的集群过程比较简单,这里我们采取的是在三台机器上搭建了一个etcd集群。假如说etcd的运行路径为/home/work/etcd,我们需要手动创建一个data-dir文件夹用于保存etcd中的数据以及集群的一些属性信息,然后在每台机器上启动start-etcd.sh脚本:
1 |
|
这里需要注意的是,在每台机器上启动时,需要将etcd name和hostname改下。具体搭建过程和测试过程,参考:
Etcd集群搭建过程
数据迁移到一个新的etcd集群
这种方式下我们可以通过已有的etcd data-dir中的数据创建一个新的etcd集群,这个etcd集群会包含旧etcd的数据信息,这样就实现了etcd的数据迁移。当然也可以使用一个空的data-dir文件目录创建一个全新的集群。
大体思路:先以–force-cluster的方式创建一个仅含有一个节点的etcd集群,然后通过添加成员的方式,扩展成一个etcd集群。具体做法参考:Etcd数据迁移
创建Etcd集群中可能会遇到集群创建失败或者etcdctl无法连接本机端口等问题,请参考 常见问题列表(Q&A):1
启动master的组件
master组件主要包括:kube-apiserver、kube-controller-manager、kube-scheduler和flanneld,下面是k8s的master组件的启动过程:
Kube-apiserver
Kube-apiserver它作为集群资源对象的唯一操作入口,其他的所有组件必须通过它提供的API来操作资源数据,它的启动方式如下所示:
1 | ../bin/kube-apiserver --logtostderr=true --v=4 --etcd_servers=http://sandbox-1:2379,http://sandbox-2:2379,http://sandbox-3:2379 --address=0.0.0.0 --allow_privileged=false --service-cluster-ip-range=10.254.0.0/16 --service-node-port-range=8000-40000 >> ./log/kube-apiserver.log 2>&1 |
这里我们必须为它指定etcd集群的地址,可以指定 --advertise-address 为本机的IP地址对外提供API服务,指定 --service-cluster-ip-range 限制集群服务的分配ip的范围,指定 --service-node-port-range 限制集群服务端口分配的范围等。
启动API Server的过程中可能遇到外部无法访问本机API Server服务或者绑定IP失败等问题,请参考常见问题列表(Q&A):2、3
Kube-controller-manager
它是集群内部的管理控制中心,其主要目的是实现k8s集群的故障检测和恢复的自动化工作,比如根据RC的定义完成Pod的复制或删除。它的启动如下所示:
1 | ../bin/kube-controller-manager --logtostderr=true --v=4 --master=http://127.0.0.1:8080 --node-monitor-grace-period=10s --pod-eviction-timeout=10s --leader-elect=true >> ./log/kube-controller-manager.log 2>&1 |
kube-scheduler
集群中的调度器,负责Pod在集群节点上的调度分配。其启动方式如下所示:
1 | ../bin/kube-scheduler --logtostderr=true --v=2 --master=http://127.0.0.1:8080 --leader-elect=true >> ./log/kube-scheduler.log 2>&1 |
flanneld
这里的flanneld以对外提供服务的方式运行的,它的主要作用包括为k8s集群设置一个网段,保证每个节点的网段不发生冲突,同时充当集群的路由功能等。
1 | etcdctl set /coreos.com/network/config '{"Network": "10.1.0.0/16"}' |
这里我们首先通过etcdctl set操作,设置了整个集群网络的IP范围,然后监听本地的8888端口,与flannel的客户端通信,协商每个flannel客户端节点的网络IP范围。
Flanneld启动过程中可能会发生启动失败,日志出现HTTP状态码500等,请参见 常见问题列表(Q&A):5
启动k8s node组件
k8s的node组件主要包括docker、flanneld、kubelet、kube-proxy,下面是k8s node组件的启动过程:
flanneld
这个flanneld与master上运行的flanneld有些不同,这里的flanneld充当的是客户端的角色,它向master上的flanneld协商一个IP网段用于本地的Pod使用,并把这些信息记录在etcd中,一定程度上充当了路由的作用。它的启动选项如下所示:
1 | ETCD_CLUSTER="http://sandbox-1:2379,http://sandbox-2:2379,http://sandbox-3:2379" |
我们这里需要为flanneld指定etcd集群的地址以及master上运行的flanneld地址。
Docker
目前我们的k8s版本是v1.3.3,它支持docker和rkt两种容器类型,在我们的生产环境中主要使用的是docker。Docker的运行环境搭建脚本如下:
1 |
|
然后运行docker daemon,启动选项如下所示:
1 |
|
这里需要注意的是,我们需要先将flannel子网的环境变量导入,然后再运行docker daemon,其中cgroup的挂载部分也很重要,具体过程在docker环境搭建的脚本中有所展示了。
启动Docker过程中可能会遇到docker启动失败的一些问题,请参考 常见问题列表(Q&A):4
Kubelet
负责本Node节点上的Pod的创建、修改、监控、删除等全生命周期管理,同时Kubelet定时“上报”本Node的状态信息到API Server里,它启动是否正常直接影响到整个Node节点主机是否可用,启动选项参考如下:
1 | ../bin/kubelet --logtostderr=true --cadvisor-port=8194 --cluster_dns=10.254.88.188 --cluster_domain=Xcloud.local --v=4 --api_servers=http://127.0.0.1:8080 --address=0.0.0.0 --allow_privileged=false --pod-infra-container-image="registry.Xcloud.com/public/pause:1.0.2" --container-runtime="docker" >> ./log/kubelet.log 2>&1 |
我们定了cadvisor资源收集的端口8194,然后指定了API Server的地址,值得注意的是–pod-infra-container-image指定了我们以哪个版本的pause镜像作为启动其他镜像的基础镜像,因为在每个Pod运行的起始,内部镜像的启动停止过程都是由一个Pause镜像完成的。
Kubelet的启动过程可能会遇到无法创建Pod时无法下载镜像等问题,请参考常见问题(Q&A):6
Kube-proxy
它实现了Service的代理以及软件模式的负载均衡,主要是为节点间的通信进行服务。其启动选项参考如下:
1 | ../bin/kube-proxy --logtostderr=true --v=4 --master=http://127.0.0.1:8080 >> ./log/kube-proxy.log 2>&1 |
我们指定了API Server的所在位置。
常见问题(Q&A)
1、 按第一种方式创建一个全新的集群,通过etcdctl member list发生错误,无法连接本地的etcd服务端口
可能原因:新集群目前仅启动了一个etcd实例,造成当前集群中仅有一个etcd实例存活,直接造成集群不可用。因为etcd集群保证一致性的前提要满足M>N/2(M:集群中健康的成员数 N:集群中总的成员数)
解决方法:继续在另外一台机器上启动一个etcd实例,使M>N/2,再用etcdctl member list查看集群情况,或者通过第二种方式–force-new-cluster的方式启动集群,具体做法上文有详细描述。
2、 如果启动kube-apiserver的时候,发生了No valid IP bound类似的错误
可能原因:当前节点没有默认路由条目,造成kube-apiserver不知选哪个IP作为对外提供服务的地址
解决办法:为当前主机增加一个默认路由条目。首先查看一下本机的可用IP所在的网卡名称,然后依据本机的IP,设置一个默认路由。举个例子通过ifconfig查看本机的网卡名为:xgbe0和IP:10.207.182.18
然后增加一个默认路由
1 | ip route add default via 10.115.178.1 dev xgbe0 |
3、 启动后的API Server仅能通过本机的8080端口访问,例如 curl http://127.0.0.1:8080
可能原因:启动API Server时,默认绑定的是本机的127.0.0.1地址,也就是无法从外部使用API Server服务
解决办法:启动时添加选项–address=0.0.0.0
4、 Docker daemon启动起始就发生了错误
可能原因:没有挂载cgroup或者时没有缺少相应的可执行,比如在PATH路径中找不到docker-containerd、docker-runc等
解决办法:运行上述贴出来的Docker环境搭建脚本
5、 Master 节点上的flanneld启动失败的情况,日志出现返回状态码500的情况
可能原因:没有设置当前集群的网段,或者设置当前集群网段的操作有误
解决办法:在启动flanneld之前,先
1 | etcdctl set /coreos.com/network/config '{"Network": "10.1.0.0/16"}' |
然后再启动flanneld进程。如果日志信息发生返回状态码HTTP500的情况,可以尝试通过
1 | etcdctl member list |
查看哪台机器是etcd集群的leader,然后在这台机器上进行上述操作。
6、 Kubelet启动成功,但创建RC时,Pod的状态一直处于Pending,通过查看创建RC的事件发现kubelet pull pause镜像失败
可能原因:没有指定–pod-infra-container-image,kubelet会默认从gcr.io中拉取一个版本的pause镜像,但gcr.io中的镜像在国内的网络环境下,一般会被墙住,导致拉取失败,Pod启动不了。
解决办法:从国内某个镜像仓库中下载好google/pause镜像放到自己的私有仓库中,并指定–pod-infra-container-image选项为私有仓库的google/pause镜像