接上文:手动搭建高可用的kubernetes集群(二)
7. kube-apiserver 高可用 按照上面的方式在master01与master02机器上安装kube-apiserver、kube-controller-manager、kube-scheduler,但是现在我们还是手动指定访问的6443和8080端口的,因为我们的域名k8s-api.virtual.local对应的master01节点直接通过http 和https 还不能访问,这里我们使用haproxy 来代替请求。
明白什么意思吗?就是我们需要将http默认的80端口请求转发到apiserver的8080端口,将https默认的443端口请求转发到apiserver的6443端口,所以我们这里使用haproxy来做请求转发。
安装haproxy 1 $ yum install -y haproxy
配置haproxy 由于集群内部有的组建是通过非安全端口访问apiserver 的,有的是通过安全端口访问apiserver 的,所以我们要配置http 和https 两种代理方式,配置文件 /etc/haproxy/haproxy.cfg:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 listen stats bind *:9000 mode http stats enable stats hide-version stats uri /stats stats refresh 30 s stats realm Haproxy\ Statistics stats auth Admin:Password frontend k8s-api bind 192.168.1.137:443 mode tcp option tcplog tcp -request inspect-delay 5 s tcp -request content accept if { req.ssl_hello_type 1 } default_backend k8s-api backend k8s-api mode tcp option tcplog option tcp-check balance roundrobin default -server inter 10 s downinter 5 s rise 2 fall 2 slowstart 60 s maxconn 250 maxqueue 256 weight 100 server k8s-api-1 192.168.1.137:6443 check server k8s-api-2 192.168.1.138:6443 check frontend k8s-http-api bind 192.168.1.137:80 mode tcp option tcplog default_backend k8s-http-api backend k8s-http-api mode tcp option tcplog option tcp-check balance roundrobin default -server inter 10 s downinter 5 s rise 2 fall 2 slowstart 60 s maxconn 250 maxqueue 256 weight 100 server k8s-http-api-1 192.168.1.137:8080 check server k8s-http-api-2 192.168.1.138:8080 check
通过上面的配置文件我们可以看出通过https的访问将请求转发给apiserver 的6443端口了,http的请求转发到了apiserver 的8080端口。
启动haproxy 1 2 3 $ sudo systemctl start haproxy$ sudo systemctl enable haproxy$ sudo systemctl status haproxy
然后我们可以通过上面9000端口监控我们的haproxy的运行状态(192.168.1.137:9000/stats):
haproxy stats
问题 上面我们的haproxy的确可以代理我们的两个master 上的apiserver 了,但是还不是高可用的,如果master01 这个节点down 掉了,那么我们haproxy 就不能正常提供服务了。这里我们可以使用两种方法来实现高可用
方式1:使用阿里云SLB 这种方式实际上是最省心的,在阿里云上建一个内网的SLB,将master01 与master02 添加到SLB 机器组中,转发80(http)和443(https)端口即可(注意下面的提示)
注意:阿里云的负载均衡是四层TCP负责,不支持后端ECS实例既作为Real Server又作为客户端向所在的负载均衡实例发送请求。因为返回的数据包只在云服务器内部转发,不经过负载均衡,所以在后端ECS实例上去访问负载均衡的服务地址是不通的。什么意思?就是如果你要使用阿里云的SLB的话,那么你不能在apiserver节点上使用SLB(比如在apiserver 上安装kubectl,然后将apiserver的地址设置为SLB的负载地址使用),因为这样的话就可能造成回环了,所以简单的做法是另外用两个新的节点做HA实例,然后将这两个实例添加到SLB 机器组中。
方式2:使用keepalived KeepAlived 是一个高可用方案,通过 VIP(即虚拟 IP)和心跳检测来实现高可用。其原理是存在一组(两台)服务器,分别赋予 Master、Backup 两个角色,默认情况下Master 会绑定VIP 到自己的网卡上,对外提供服务。Master、Backup 会在一定的时间间隔向对方发送心跳数据包来检测对方的状态,这个时间间隔一般为 2 秒钟,如果Backup 发现Master 宕机,那么Backup 会发送ARP 包到网关,把VIP 绑定到自己的网卡,此时Backup 对外提供服务,实现自动化的故障转移,当Master 恢复的时候会重新接管服务。非常类似于路由器中的虚拟路由器冗余协议(VRRP)
开启路由转发,这里我们定义虚拟IP为:192.168.1.139
1 2 3 4 5 6 7 8 9 10 $ vi /etc/sysctl.conf # 添加以下内容 net.ipv4.ip_forward = 1 net.ipv4.ip_nonlocal_bind = 1 # 验证并生效 $ sysctl -p # 验证是否生效 $ cat /proc/sys/net/ipv4/ip_forward1
安装keepalived:
1 $ yum install -y keepalived
我们这里将master01 设置为Master,master02 设置为Backup,修改配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 $ vi /etc/keepalived/keepalived.conf ! Configuration File for keepalived global_defs { notification_email { } router_id kube_api } vrrp_script check_haproxy { # 自身状态检测 script "killall -0 haproxy" int erval 3 weight 5 } vrrp_instance haproxy-vip { # 使用单播通信,默认是组播通信 unicast_src_ip 192.168 .1 .137 unicast_peer { 192.168 .1 .138 } # 初始化状态 state MASTER # 虚拟ip 绑定的网卡 (这里根据你自己的实际情况选择网卡) interface eth0 # 此ID 要与Backup 配置一致 virtual_router_id 51 # 默认启动优先级,要比Backup 大点,但要控制量,保证自身状态检测生效 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { # 虚拟ip 地址 192.168 .1 .139 } track_script { check_haproxy } } virtual_server 192.168 .1 .139 80 { delay_loop 5 lvs_sched wlc lvs_method NAT persistence_timeout 1800 protocol TCP real_server 192.168 .1 .137 80 { weight 1 TCP_CHECK { connect_port 80 connect_timeout 3 } } } virtual_server 192.168 .1 .139 443 { delay_loop 5 lvs_sched wlc lvs_method NAT persistence_timeout 1800 protocol TCP real_server 192.168 .1 .137 443 { weight 1 TCP_CHECK { connect_port 443 connect_timeout 3 } } }
统一的方式在master02 节点上安装keepalived,修改配置,只需要将state 更改成BACKUP,priority更改成99,unicast_src_ip 与unicast_peer 地址修改即可。
启动keepalived:
1 2 3 4 $ systemctl start keepalived$ systemctl enable keepalived$ journalctl -f -u keepalived
验证虚拟IP:
1 2 3 4 5 6 7 8 9 10 11 12 $ ip addr 1 : lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1 link/loopback 00 :00 :00 :00 :00 :00 brd 00 :00 :00 :00 :00 :00 inet 127.0 .0.1 /8 scope host lo valid_lft forever preferred_lft forever 2 : eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00 :16 :3 e:00 :55 :c1 brd ff:ff:ff:ff:ff:ff inet 192.168 .1.137 /24 brd 192.168 .1.255 scope global dynamic eth0 valid_lft 31447746 sec preferred_lft 31447746 sec inet 192.168 .1.139 /24 brd 192.168 .1.255 scope global secondary eth0-vip valid_lft forever preferred_lft forever
到这里,我们就可以将上面的6443端口和8080端口去掉了,可以手动将kubectl生成的config文件(~/.kube/config)中的server 地址6443端口去掉,另外kube-controller-manager和kube-scheduler的–master参数中的8080端口去掉了,然后分别重启这两个组件即可。
验证apiserver:关闭master01 节点上的kube-apiserver 进程,然后查看虚拟ip是否漂移到了master02 节点。
然后我们就可以将第一步在/etc/hosts里面设置的域名对应的IP 更改为我们的虚拟IP了
master01 与master 02 节点都需要安装keepalived 和haproxy,实际上我们虚拟IP的自身检测应该是检测haproxy,脚本大家可以自行更改
kube-apiserver ha
这样我们就实现了接入层apiserver 的高可用了,一个部分是多活的apiserver 服务,另一个部分是一主一备的haproxy 服务。
kube-controller-manager 和kube-scheduler的高可用 Kubernetes 的管理层服务包括kube-scheduler和kube-controller-manager。kube-scheduler和kube-controller-manager使用一主多从的高可用方案,在同一时刻只允许一个服务处以具体的任务。Kubernetes中实现了一套简单的选主逻辑,依赖Etcd实现scheduler和controller-manager的选主功能。如果scheduler和controller-manager在启动的时候设置了leader-elect参数,它们在启动后会先尝试获取leader节点身份,只有在获取leader节点身份后才可以执行具体的业务逻辑。它们分别会在Etcd中创建kube-scheduler和kube-controller-manager的endpoint,endpoint的信息中记录了当前的leader节点信息,以及记录的上次更新时间。leader节点会定期更新endpoint的信息,维护自己的leader身份。每个从节点的服务都会定期检查endpoint的信息,如果endpoint的信息在时间范围内没有更新,它们会尝试更新自己为leader节点。scheduler服务以及controller-manager服务之间不会进行通信,利用Etcd的强一致性,能够保证在分布式高并发情况下leader节点的全局唯一性。整体方案如下图所示:
高可用
8. 部署Node 节点 kubernetes Node 节点包含如下组件:
flanneld
docker
kubelet
kube-proxy
环境变量 1 2 3 $ source /usr/k8s/bin/env.sh$ export KUBE_APISERVER="https://${MASTER_URL} " // 如果你没有安装`haproxy`的话,还是需要使用6443端口的哦$ export NODE_IP=192.168.1.170
按照上面的步骤安装配置好flanneld
开启路由转发 修改/etc/sysctl.conf文件,添加下面的规则:
1 2 3 net.ipv4.ip_forward =1 net.bridge.bridge-nf-call-iptables =1 net.bridge.bridge-nf-call-ip6tables =1
执行下面的命令立即生效:
配置docker 你可以用二进制或yum install 的方式来安装docker,然后修改docker 的systemd unit 文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 $ cat /usr/lib/systemd/system/docker.service # 用systemctl status docker 命令可查看unit 文件路径 [Unit] Description =Docker Application Container EngineDocumentation =https://docs.docker.comAfter =network-online.target firewalld.serviceWants =network-online.target[Service] Type =notifyEnvironmentFile =-/run/flannel/dockerExecStart =/usr/bin/dockerd --log-level =info $DOCKER_NETWORK_OPTIONS ExecReload =/bin/kill -s HUP $MAINPID LimitNOFILE =infinityLimitNPROC =infinityLimitCORE =infinityTimeoutStartSec =0Delegate =yes KillMode =processRestart =on-failureStartLimitBurst =3StartLimitInterval =60s[Install] WantedBy =multi-user.target
dockerd 运行时会调用其它 docker 命令,如 docker-proxy,所以需要将 docker 命令所在的目录加到 PATH 环境变量中
flanneld 启动时将网络配置写入到 /run/flannel/docker 文件中的变量 DOCKER_NETWORK_OPTIONS,dockerd 命令行上指定该变量值来设置 docker0 网桥参数
如果指定了多个 EnvironmentFile 选项,则必须将 /run/flannel/docker 放在最后(确保 docker0 使用 flanneld 生成的 bip 参数)
不能关闭默认开启的 –iptables 和 –ip-masq 选项
如果内核版本比较新,建议使用 overlay 存储驱动
docker 从 1.13 版本开始,可能将 iptables FORWARD chain的默认策略设置为DROP,从而导致 ping 其它 Node 上的 Pod IP 失败,遇到这种情况时,需要手动设置策略为 ACCEPT:
1 $ sudo iptables -P FORWARD ACCEPT
如果没有开启上面的路由转发(net.ipv4.ip_forward=1),则需要把以下命令写入/etc/rc.local文件中,防止节点重启iptables FORWARD chain的默认策略又还原为DROP (下面的开机脚本我测试了几次都没生效,不知道是不是方法有误,所以最好的方式还是开启上面的路由转发功能,一劳永逸)
1 sleep 60 && /sbin/iptables -P FORWARD ACCEPT
为了加快 pull image 的速度,可以使用国内的仓库镜像服务器,同时增加下载的并发数。(如果 dockerd 已经运行,则需要重启 dockerd 生效。)
1 2 3 4 $ cat /etc/docker/daemon.json { "max-concurrent-downloads" : 10 }
启动docker 1 2 3 4 5 6 $ sudo systemctl daemon-reload$ sudo systemctl stop firewalld$ sudo systemctl disable firewalld$ sudo iptables -F && sudo iptables -X && sudo iptables -F -t nat && sudo iptables -X -t nat$ sudo systemctl enable docker$ sudo systemctl start docker
需要关闭 firewalld(centos7)/ufw(ubuntu16.04),否则可能会重复创建 iptables 规则
最好清理旧的 iptables rules 和 chains 规则
执行命令:docker version,检查docker服务是否正常
安装和配置kubelet kubelet 启动时向kube-apiserver 发送TLS bootstrapping 请求,需要先将bootstrap token 文件中的kubelet-bootstrap 用户赋予system:node-bootstrapper 角色,然后kubelet 才有权限创建认证请求(certificatesigningrequests):
kubelet就是运行在Node节点上的,所以这一步安装是在所有的Node节点上,如果你想把你的Master也当做Node节点的话,当然也可以在Master节点上安装的。
1 $ kubectl create clusterrolebinding kubelet-bootstrap --clusterrole =system:node-bootstrapper --user =kubelet-bootstrap
–user=kubelet-bootstrap 是文件 /etc/kubernetes/token.csv 中指定的用户名,同时也写入了文件 /etc/kubernetes/bootstrap.kubeconfig
另外1.8 版本中还需要为Node 请求创建一个RBAC 授权规则:
1 $ kubectl create clusterrolebinding kubelet-nodes --clusterrole=system :node --group =system :nodes
然后下载最新的kubelet 和kube-proxy 二进制文件(前面下载kubernetes 目录下面其实也有):
1 2 3 4 5 $ wget https://dl.k8s.io/v1.8.2/kubernetes-server-linux-amd64.tar.gz $ tar -xzvf kubernetes-server-linux-amd64.tar.gz $ cd kubernetes$ tar -xzvf kubernetes-src.tar.gz $ sudo cp -r ./server/bin/{kube-proxy,kubelet} /usr/k8s/bin/
创建kubelet bootstapping kubeconfig 文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 $ $ kubectl config set-cluster kubernetes \ --certificate-authority=/etc/kubernetes/ssl/ca.pem \ --embed-certs=true \ --server=${KUBE_APISERVER} \ --kubeconfig=bootstrap.kubeconfig $ $ kubectl config set-credentials kubelet-bootstrap \ --token=${BOOTSTRAP_TOKEN} \ --kubeconfig=bootstrap.kubeconfig $ $ kubectl config set-context default \ --cluster=kubernetes \ --user=kubelet-bootstrap \ --kubeconfig=bootstrap.kubeconfig $ $ kubectl config use-context default --kubeconfig=bootstrap.kubeconfig $ mv bootstrap .kubeconfig /etc /kubernetes /
–embed-certs 为 true 时表示将 certificate-authority 证书写入到生成的 bootstrap.kubeconfig 文件中;
设置 kubelet 客户端认证参数时没有指定秘钥和证书,后续由 kube-apiserver 自动生成;
创建kubelet 的systemd unit 文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 $ sudo mkdir /var/lib/kubelet # 必须先创建工作目录 $ cat > kubelet.service <<EOF [Unit] Description =Kubernetes KubeletDocumentation =https://github.com/GoogleCloudPlatform/kubernetesAfter =docker.serviceRequires =docker.service[Service] WorkingDirectory =/var/lib/kubeletExecStart =/usr/k8s/bin/kubelet \\ --fail-swap-on =false \\ --cgroup-driver =cgroupfs \\ --address =${NODE_IP} \\ --hostname-override =${NODE_IP} \\ --experimental-bootstrap-kubeconfig =/etc/kubernetes/bootstrap.kubeconfig \\ --kubeconfig =/etc/kubernetes/kubelet.kubeconfig \\ --require-kubeconfig \\ --cert-dir =/etc/kubernetes/ssl \\ --cluster-dns =${CLUSTER_DNS_SVC_IP} \\ --cluster-domain =${CLUSTER_DNS_DOMAIN} \\ --hairpin-mode promiscuous-bridge \\ --allow-privileged =true \\ --serialize-image-pulls =false \\ --logtostderr =true \\ --v =2 Restart =on-failureRestartSec =5[Install] WantedBy =multi-user.targetEOF
请仔细阅读下面的注意事项,不然可能会启动失败。
–fail-swap-on参数,这个一定要注意,Kubernetes 1.8开始要求关闭系统的Swap,如果不关闭,默认配置下kubelet将无法启动,也可以通过kubelet的启动参数–fail-swap-on=false来避免该问题
–cgroup-driver参数,kubelet 用来维护主机的的 cgroups 的,默认是cgroupfs,但是这个地方的值需要你根据docker 的配置来确定(docker info |grep cgroup)
-address 不能设置为 127.0.0.1,否则后续 Pods 访问 kubelet 的 API 接口时会失败,因为 Pods 访问的 127.0.0.1指向自己而不是 kubelet
如果设置了 –hostname-override 选项,则 kube-proxy 也需要设置该选项,否则会出现找不到 Node 的情况
–experimental-bootstrap-kubeconfig 指向 bootstrap kubeconfig 文件,kubelet 使用该文件中的用户名和 token 向 kube-apiserver 发送 TLS Bootstrapping 请求
管理员通过了 CSR 请求后,kubelet 自动在 –cert-dir 目录创建证书和私钥文件(kubelet-client.crt 和 kubelet-client.key),然后写入 –kubeconfig 文件(自动创建 –kubeconfig 指定的文件)
建议在 –kubeconfig 配置文件中指定 kube-apiserver 地址,如果未指定 –api-servers 选项,则必须指定 –require-kubeconfig 选项后才从配置文件中读取 kue-apiserver 的地址,否则 kubelet 启动后将找不到 kube-apiserver (日志中提示未找到 API Server),kubectl get nodes 不会返回对应的 Node 信息
–cluster-dns 指定 kubedns 的 Service IP(可以先分配,后续创建 kubedns 服务时指定该 IP),–cluster-domain 指定域名后缀,这两个参数同时指定后才会生效
启动kubelet 1 2 3 4 5 $ sudo cp kubelet.service /etc/systemd/system/kubelet.service$ sudo systemctl daemon-reload$ sudo systemctl enable kubelet$ sudo systemctl start kubelet$ systemctl status kubelet
通过kubelet 的TLS 证书请求 kubelet 首次启动时向kube-apiserver 发送证书签名请求,必须通过后kubernetes 系统才会将该 Node 加入到集群。查看未授权的CSR 请求:
1 2 3 4 5 $ kubectl get csr NAME AGE REQUESTOR CONDITIONnode-csr $ kubectl get nodes No resources found .
通过CSR 请求:
1 2 3 4 5 $ kubectl certificate approve node-csr certificatesigningrequest "node-csr--k3G2G1EoM4h9w1FuJRjJjfbIPNxa551A8TZfW9dG-g" approved $ kubectl get nodes NAME STATUS ROLES AGE VERSION 192.168 .1 .170 Ready <none > 48 s v1.8 .1
自动生成了kubelet kubeconfig 文件和公私钥:
1 2 3 4 5 6 7 $ ls -l /etc/kubernetes/kubelet.kubeconfig -rw------- 1 root root 2280 Nov 7 10:26 /etc/kubernetes/kubelet.kubeconfig $ ls -l /etc/kubernetes/ssl/kubelet* -rw-r--r-- 1 root root 1046 Nov 7 10:26 /etc/kubernetes/ssl/kubelet-client.crt -rw------- 1 root root 227 Nov 7 10:22 /etc/kubernetes/ssl/kubelet-client.key -rw-r--r-- 1 root root 1115 Nov 7 10:16 /etc/kubernetes/ssl/kubelet.crt -rw------- 1 root root 1675 Nov 7 10:16 /etc/kubernetes/ssl/kubelet.key
配置kube-proxy 创建kube-proxy 证书签名请求:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 $ cat > kube-proxy-csr .json <<EOF{ "CN" : "system:kube-proxy" , "hosts" : [], "key" : { "algo" : "rsa" , "size" : 2048 }, "names" : [ { "C" : "CN" , "ST" : "BeiJing" , "L" : "BeiJing" , "O" : "k8s" , "OU" : "System" } ] } EOF
CN 指定该证书的 User 为 system:kube-proxy
kube-apiserver 预定义的 RoleBinding system:node-proxier 将User system:kube-proxy 与 Role system:node-proxier绑定,该 Role 授予了调用 kube-apiserver Proxy 相关 API 的权限
hosts 属性值为空列表
生成kube-proxy 客户端证书和私钥
1 2 3 4 5 6 7 $ cfssl gencert -ca=/etc/kubernetes/ssl/ca.pem \ -ca-key=/etc/kubernetes/ssl/ca-key.pem \ -config=/etc/kubernetes/ssl/ca-config.json \ -profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy $ ls kube-proxy*kube-proxy.csr kube-proxy-csr.json kube-proxy-key.pem kube-proxy.pem $ sudo mv kube-proxy*.pem /etc/kubernetes/ssl/
创建kube-proxy kubeconfig 文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 $ $ kubectl config set-cluster kubernetes \ --certificate-authority=/etc/kubernetes/ssl/ca.pem \ --embed-certs=true \ --server=${KUBE_APISERVER} \ --kubeconfig=kube-proxy.kubeconfig $ $ kubectl config set-credentials kube-proxy \ --client-certificate=/etc/kubernetes/ssl/kube-proxy.pem \ --client-key=/etc/kubernetes/ssl/kube-proxy-key.pem \ --embed-certs=true \ --kubeconfig=kube-proxy.kubeconfig $ $ kubectl config set-context default \ --cluster=kubernetes \ --user=kube-proxy \ --kubeconfig=kube-proxy.kubeconfig $ $ kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig $ mv kube-proxy .kubeconfig /etc /kubernetes /
设置集群参数和客户端认证参数时 –embed-certs 都为 true,这会将 certificate-authority、client-certificate 和 client-key 指向的证书文件内容写入到生成的 kube-proxy.kubeconfig 文件中
kube-proxy.pem 证书中 CN 为 system:kube-proxy,kube-apiserver 预定义的 RoleBinding cluster-admin 将User system:kube-proxy 与 Role system:node-proxier 绑定,该 Role 授予了调用 kube-apiserver Proxy 相关 API 的权限
创建kube-proxy 的systemd unit 文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 $ sudo mkdir -p /var/lib/kube-proxy # 必须先创建工作目录 $ cat > kube-proxy.service <<EOF [Unit] Description =Kubernetes Kube-Proxy Server Documentation =https://github.com/GoogleCloudPlatform/kubernetesAfter =network.target[Service] WorkingDirectory =/var/lib/kube-proxyExecStart =/usr/k8s/bin/kube-proxy \\ --bind-address =${NODE_IP} \\ --hostname-override =${NODE_IP} \\ --cluster-cidr =${SERVICE_CIDR} \\ --kubeconfig =/etc/kubernetes/kube-proxy.kubeconfig \\ --logtostderr =true \\ --v =2 Restart =on-failureRestartSec =5LimitNOFILE =65536[Install] WantedBy =multi-user.targetEOF
–hostname-override 参数值必须与 kubelet 的值一致,否则 kube-proxy 启动后会找不到该 Node,从而不会创建任何 iptables 规则
–cluster-cidr 必须与 kube-apiserver 的 –service-cluster-ip-range 选项值一致
kube-proxy 根据 –cluster-cidr 判断集群内部和外部流量,指定 –cluster-cidr 或 –masquerade-all 选项后 kube-proxy 才会对访问 Service IP 的请求做 SNAT
–kubeconfig 指定的配置文件嵌入了 kube-apiserver 的地址、用户名、证书、秘钥等请求和认证信息
预定义的 RoleBinding cluster-admin 将User system:kube-proxy 与 Role system:node-proxier 绑定,该 Role 授予了调用 kube-apiserver Proxy 相关 API 的权限
启动kube-proxy 1 2 3 4 5 $ sudo cp kube-proxy.service /etc/systemd/system/$ sudo systemctl daemon-reload$ sudo systemctl enable kube-proxy$ sudo systemctl start kube-proxy$ systemctl status kube-proxy
验证集群功能 定义yaml 文件:(将下面内容保存为:nginx-ds.yaml)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 apiVersion: v1 kind: Service metadata: name: nginx-ds labels: app: nginx-ds spec: type: NodePort selector: app: nginx-ds ports: - name: http port: 80 targetPort: 80 --- apiVersion: extensions/v1beta1 kind: DaemonSet metadata: name: nginx-ds labels: addonmanager.kubernetes.io/mode: Reconcile spec: template: metadata: labels: app: nginx-ds spec: containers: - name: my-nginx image: nginx:1.7.9 ports: - containerPort: 80
创建 Pod 和服务:
1 2 3 $ kubectl create -f nginx-ds .ymlservice "nginx-ds" created daemonset "nginx-ds" created
执行下面的命令查看Pod 和SVC:
1 2 3 4 5 6 $ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODEnginx-ds-f29zt 1 /1 Running 0 23 m 172.17 .0 .2 192.168 .1 .170 $ kubectl get svc NAME TYPE CLUSTER -IP EXTERNAL -IP PORT(S) AGEnginx-ds NodePort 10.254 .6 .249 <none > 80 :30813 /TCP 24 m
可以看到:
服务IP:10.254.6.249
服务端口:80
NodePort端口:30813
在所有 Node 上执行:
1 2 $ curl 10.254 .6.249 $ curl 192.168 .1.170 :30813
执行上面的命令预期都会输出nginx 欢迎页面内容,表示我们的Node 节点正常运行了。
9. 部署kubedns 插件 官方文件目录:kubernetes/cluster/addons/dns
使用的文件:
1 2 $ ls *.yaml *.base kubedns-cm.yaml kubedns-sa.yaml kubedns-controller.yaml .base kubedns-svc.yaml .base
系统预定义的RoleBinding 预定义的RoleBinding system:kube-dns将kube-system 命名空间的kube-dnsServiceAccount 与 system:kube-dns Role 绑定,该Role 具有访问kube-apiserver DNS 相关的API 权限:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 $ kubectl get clusterrolebindings system:kube-dns - o yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBindingmetadata: annotations: rbac.authorization.kubernetes.io/ autoupdate: "true" creationTimestamp: 201 7-1 1-06 T10:51 :59 Z labels: kubernetes.io/ bootstrapping: rbac-defaults name: system:kube-dns resourceVersion: "78" selfLink: / apis/ rbac.authorization.k8s.io/ v1/ clusterrolebindings/ system%3 Akube-dns uid: 83 a25fd9-c2e0-11 e7-964 6-00163 e0055c1 roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: system:kube-dns subjects: - kind: ServiceAccount name: kube-dns namespace: kube-system
kubedns-controller.yaml 中定义的 Pods 时使用了 kubedns-sa.yaml 文件定义的 kube-dns ServiceAccount,所以具有访问 kube-apiserver DNS 相关 API 的权限;
配置kube-dns ServiceAccount 无需更改
配置kube-dns 服务 1 2 3 4 5 $ diff kubedns-svc.yaml.base kubedns-svc.yaml 30c30 < clusterIP: __PILLAR__DNS__SERVER__ --- > clusterIP: 10.254 .0 .2
需要将 spec.clusterIP 设置为集群环境变量中变量 CLUSTER_DNS_SVC_IP 值,这个IP 需要和 kubelet 的 —cluster-dns 参数值一致
配置kube-dns Deployment 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 $ diff kubedns-controller.yaml.base kubedns-controller.yaml 88c88 < - --domain=__PILLAR__DNS__DOMAIN__. --- > - --domain=cluster.local 128c128 < - --server=/__PILLAR__DNS__DOMAIN__/127.0.0.1#10053 --- > - --server=/cluster.local/127.0.0.1#10053 160,161c160,161 < - --probe=kubedns,127.0.0.1:10053,kubernetes.default.svc.__PILLAR__ DNS__DOMAIN__ ,5,A < - --probe=dnsmasq,127.0.0.1:53,kubernetes.default.svc.__PILLAR__DNS__DOMAIN__,5,A --- > - --probe=kubedns,127.0.0.1:10053,kubernetes.default.svc.cluster.local,5,A > - --probe=dnsmasq,127.0.0.1:53,kubernetes.default.svc.cluster.local,5,A
–domain 为集群环境变量CLUSTER_DNS_DOMAIN 的值
使用系统已经做了 RoleBinding 的 kube-dns ServiceAccount,该账户具有访问 kube-apiserver DNS 相关 API 的权限
执行所有定义文件 1 2 3 4 5 $ pwd /home/ych/k8s-repo /kube-dns $ ls *.yamlkubedns-cm .yaml kubedns-controller .yaml kubedns-sa .yaml kubedns-svc .yaml $ kubectl create -f .
检查kubedns 功能 新建一个Deployment
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 $ cat > my-nginx.yaml< < EOF apiVersion: extensions/v1beta1 kind: Deploymentmetadata: name: my-nginx spec: replicas: 2 template: metadata: labels: run: my-nginx spec: containers: - name: my-nginx image: nginx:1.7 .9 ports: - containerPort: 80 EOF $ kubectl create - f my-nginx.yaml deployment "my-nginx" created
Expose 该Deployment,生成my-nginx 服务
1 2 3 4 5 $ kubectl expose deploy my-nginx $ kubectl get services NAME TYPE CLUSTER -IP EXTERNAL -IP PORT(S) AGEkubernetes ClusterIP 10.254 .0 .1 <none > 443 /TCP 1 d my-nginx ClusterIP 10.254 .32 .162 <none > 80 /TCP 56 s
然后创建另外一个Pod,查看/etc/resolv.conf是否包含kubelet配置的–cluster-dns 和–cluster-domain,是否能够将服务my-nginx 解析到上面显示的CLUSTER-IP 10.254.32.162上
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 $ cat > pod-nginx.yaml<<EOF apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - name: nginx image: nginx:1.7 .9 ports: - containerPort: 80 EOF $ kubectl create -f pod-nginx.yaml pod "nginx" created $ kubectl exec nginx -i -t -- /bin/bash root@nginx :/# cat /etc/resolv.conf nameserver 10.254 .0 .2 search default .svc.cluster.local . svc.cluster.local . cluster.local . options ndots:5 root@nginx :/# ping my-nginx PING my-nginx.default .svc.cluster.local (10.254 .32 .162 ): 48 data bytes^C--- my-nginx.default .svc.cluster.local ping statistics --- 14 packets transmitted, 0 packets received, 100 % packet lossroot@nginx :/# ping kubernetes PING kubernetes.default .svc.cluster.local (10.254 .0 .1 ): 48 data bytes^C--- kubernetes.default .svc.cluster.local ping statistics --- 6 packets transmitted, 0 packets received, 100 % packet lossroot@nginx :/# ping kube-dns.kube-system.svc.cluster.local PING kube-dns.kube-system.svc.cluster.local (10.254 .0 .2 ): 48 data bytes^C--- kube-dns.kube-system.svc.cluster.local ping statistics --- 2 packets transmitted, 0 packets received, 100 % packet loss
接下文:手动搭建高可用的kubernetes集群(四)