实现方案
Kubernetes master高可用一般有三种实现方案:
1. kubeadm 高可用安装使用kubeadm工具安装Kubernetes集群。通过增加master节点数量和指定vip实现master高可用。
具体步骤如下:
- 安装一主两备master节点(由kubeadm完成)
- 配置vip(使用keepalived或haproxy等工具)
- kubeadm join时指定apiserver-vip参数(kubeadm join ... --apiserver-advertise-address apiserver-vip)
- 各节点apiserver配置service-cluster-ip-range参数,指向vip这种方案简单易行,kubeadm帮助完成大部分复杂配置,但是控制面扩展性较差,可靠性依赖前端vip产品。
2. etcd集群 + apiserver高可用以etcd集群为后端存储,部署多个apiserver实例,并进行LB实现高可用。
具体步骤如下:
- 部署etcd集群(3个或5个节点)
- 多个master节点分别部署apiserver,指向etcd集群
- 使用LB(如nginx)反向代理apiserver,实现负载均衡这种方案扩展性好,控制面高可用性高,但是部署和配置比较复杂,依赖额外的LB设备。
3. 使用CSKU(企业版本Kubernetes)使用企业版本Kubernetes(如GKE),它自带 master高可用实现。通过在GKE控制台选择master节点数,与高可用特性,GKE将自动完成以下配置:
- 部署etcd集群
- 部署多个master副本
- 通过内置LB实现apiserver负载均衡这种方案最简单,完全由企业版本Kubernetes平台实现和运维,但是成本较高。
这里我将介绍前两种实现
方式一
1. 准备3台机器,配置主机名和hosts
master1
master2
master3
编辑所有节点的/etc/hosts,添加三节点映射:
192.168.0.1 master1
192.168.0.2 master2
192.168.0.3 master3
2. 在所有的master节点安装kubeadm,kubelet和kubectl
apt install -y kubeadm kubelet kubectl
3. 指定vip(如10.0.0.10),在master1上使用keepalived配置,其他master节点配置keepalived backup
master1:
vrrp_instance VI_1 {
state MASTER
interface ens4
virtual_router_id 50
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.0.0.10
}
}
其它master节点:
vrrp_instance VI_1 {
state BACKUP
interface ens4
virtual_router_id 50
priority 50
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.0.0.10
}
}
4. 在所有节点初始化kubeadm配置文件
kubeadm config print init-defaults > kubeadm.yaml
修改kubeadm.yaml,指定apiserver地址为vip:
apiVersion: kubeadm.k8s.io/v1beta2
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: "10.0.0.10"
5. 在master1节点执行kubeadm init,使用--config指定kubeadm.yaml文件
kubeadm init --config=kubeadm.yaml
6. 在其他master节点执行kubeadm join,同样指定apiserver-vip
kubeadm join 10.0.0.10:6443 --token abcdef.0123456789abcdef \ --discovery-token-ca-cert-hash sha256:1234..cdef --apiserver-advertise-address=10.0.0.10
7. 将master节点的kubeconfig文件拷贝到其它节点至此,使用kubeadm工具部署的Kubernetes master高可用集群已完成!客户端只需要访问vip(10.0.0.10)即可,keepalived会自动将请求转发到可用的master节点。
至此,使用kubeadm工具部署的Kubernetes master高可用集群已完成!客户端只需要访问vip(10.0.0.10)即可,keepalived会自动将请求转发到可用的master节点。这种方案简单易行,但是扩展性和可靠性略差,依赖第三方软件(如keepalived)实现LB和vip。但对测试和体验Kubernetes HA足以。
方式二
1. 准备3台机器作为etcd集群:
- etcd1:10.0.0.11
- etcd2:10.0.0.12
- etcd3:10.0.0.13
2. 在etcd1上部署etcd
etcd --name etcd1 \
--listen-client-urls https://10.0.0.11:2379 \
--advertise-client-urls https://10.0.0.11:2379 \
--listen-peer-urls https://10.0.0.11:2380 \
--initial-advertise-peer-urls https://10.0.0.11:2380 \
--initial-cluster etcd1=https://10.0.0.11:2380,etcd2=https://10.0.0.12:2380,etcd3=https://10.0.0.13:2380 \
--initial-cluster-token etcd-token
3. 在etcd2和etcd3节点也启动etcd,命令与etcd1相同,只是名称和地址不同
4. 准备3台master节点:master1,master2,master3
5.所有master节点安装kube-apiserver、kube-controller-manager和kube-scheduler
6. 配置kube-apiserver
- --etcd-servers: 指定etcd集群地址
- --service-cluster-ip-range: 指定Cluster IP地址段
- --secure-port: apiserver端口(如6443)
- 其它参数参考 [kube-apiserver配置文档]( kube-apiserver | Kubernetes)
master1例如:
kube-apiserver --etcd-servers=https://10.0.0.11:2379,https://10.0.0.12:2379,https://10.0.0.13:2379 --service-cluster-ip-range=10.0.0.0/24 --secure-port=6443 -bind-address=10.0.0.11 ...
master2,master3...也类似,修改bind-address为对应节点IP
7. 配置反向代理(如nginx)实现kube-apiserver高可用负载均衡
upstream kube-apiserver {
server 10.0.0.11:6443;
server 10.0.0.12:6443;
server 10.0.0.13:6443;
}
server {
listen 6443;
proxy_pass http://kube-apiserver;
}
8. 其他master组件连接nginx的6443端口在
所有master节点:
kube-controller-manager --master=http://10.0.0.11:6443 ...
kube-scheduler --master=http://10.0.0.11:6443 ...
9. Node节点kubelet连接nginx的6443端口
10. kubectl客户端也连接nginx的6443端口至此,实现了高可用的多master控制面,具有高扩展性和高可用性。etcd本身作为Kubernetes的关键存储也具备高可用,nginx实现简单可靠的LB。
这种方案设计得较为复杂,但是更加灵活可靠。适用于大型产品级Kubernetes集群,可以根据需要扩展apiserver和etcd节点。也是实际Kubernetes控制面部署的经典模式。
访问集群方式
访问Kubernetes高可用集群,有以下几种方式:
1. kubectl客户端 connects 到nginx的6443端口,nginx会自动将请求转发到可用的kube-apiserver实例上。
所以,您只需要将kubectl指向任一master节点的6443端口即可:
kubectl --server=https://10.0.0.11:6443 get nodes
2. API Server Endpoint对外暴露的API Server Endpoint也是nginx的6443端口,所以调用Kubernetes API可以像这样:
curl https://10.0.0.11:6443/api/v1/nodes
3. DNS在Kubernetes集群内部,kube-dns会解析kubernetes.default.svc.cluster.local到nginx的6443端口。
所以在集群内的Pod也可以通过该DNS名称访问API Server。
4. Service可以在集群内创建kubernetes服务,将类型设置为NodePort或LoadBalancer,开放6443端口,对外提供访问入口。
例如:
yaml
apiVersion: v1
kind: Service
metadata:
name: kubernetes
spec:
type: NodePort
ports:
- port: 6443
targetPort: 6443
protocol: TCP
selector:
component: apiserver
创建该服务后,外部可以通过Node的ANY IP:31643端口访问(31643是随机分配的端口)。
以上就是几种访问Kubernetes高可用集群的方法。总体来说,对内可以直接使用kubernetes服务域名(推荐);对外可以通过NodePort服务或直接通过nginx的6443端口调用API(适用于测试)。
在日常使用中,kubectl命令行工具是最常用的方式。只需要在每个节点安装kubectl,并指定正确的apiserver地址即可使用。
相关延申
keepalived
这里最重要的是VRRP虚拟IP,VRRP虚拟IP(Virtual Router Redundancy Protocol Virtual IP)是keepalived实现高可用的关键概念。
它是一个浮动的IP地址,可以在keepalived集群中的主节点和备节点之间漂移。客户端并不直接连接主节点或备节点,而是连接这个虚拟IP。
当主节点出现故障时,VRRP虚拟IP会从主节点漂移到备节点,客户端连接的IP地址不变,实现了业务的故障切换。VRRP虚拟IP具有以下特征:
1. 它是一个逻辑IP,并不对应于主节点或备节点的物理IP地址。
2. 它会在keepalived主节点和备节点之间漂移,实现高可用。
3. 客户端只关注VRRP虚拟IP,不需要关心主节点或备节点的物理IP地址。
4. VRRP虚拟IP的MAC地址会随着IP漂移而改变,交换机会更新MAC表,无需人工干预。
5. 一个VRRP实例可以有多个VRRP虚拟IP,所有的虚拟IP会同时漂移。
6. VRRP虚拟IP所在的子网需要在主节点和备节点的网卡上都有配置。
VRRP虚拟IP是keepalived实现高可用的基石,当主节点出现故障,它实现了与备节点的无缝切换,为客户端提供了一个逻辑的浮动入口IP,自动实现了故障转移,这也是VRRP协议的初衷。
综上,VRRP虚拟IP的主要作用是:
- 为客户端提供一个逻辑入口IP
- 实现与备节点的故障切换
- 隐藏集群主节点与备节点的物理IP地址
- 简化客户端的配置
ngnix方式
nginx大家都很熟悉,反向代理服务器,暴露一个端口根据上下文负载均衡所有master节点地址
kubectl
kubectl是k8s的请求客户端命令,kubectl命令内部根据命令带的参数信息封装了个 restful http请求,向kube-apiserver发送请求。接下来列举几个命令的实际http请求的对应请求:
获取Pod列表:
GET /api/v1/namespaces/{namespace}/pods
创建Pod:
POST /api/v1/namespaces/{namespace}/pods
获取Service列表:
GET /api/v1/namespaces/{namespace}/services
创建Service:
POST /api/v1/namespaces/{namespace}/services
获取Deployment列表:
GET /apis/apps/v1/namespaces/{namespace}/deployments
创建Deployment:
POST /apis/apps/v1/namespaces/{namespace}/deployments
获取Node列表:
GET /api/v1/nodes
获取Namespace列表:
GET /api/v1/namespaces
创建Namespace:
POST /api/v1/namespaces
获取Secret列表:
GET /api/v1/namespaces/{namespace}/secrets
创建Secret:
POST /api/v1/namespaces/{namespace}/secrets
获取ConfigMap列表:
GET /api/v1/namespaces/{namespace}/configmaps
创建ConfigMap:
POST /api/v1/namespaces/{namespace}/configmaps
执行kubectl exec:
POST /api/v1/namespaces/{namespace}/pods/{pod}/exec
执行yaml文件的apply or create命令
curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" -d '{"apiVersion":"v1", "kind":"Pod"...}' https://10.0.0.1:6443/api/v1/namespaces/default/pods
这些只是常见API的一部分,kubectl封装的API还有非常多,它通过构建不同的HTTP请求,以RESTful API风格与Kubernetes API Server进行交互,从而实现所有kubectl的功能。