End-Of-Life
最近遇到了一件倒霉的事,我使用的CoreOS家的Container Linux
居然宣布要在五月终止产品线了,提示在使用这款操作系统的用户尽快切换到其它操作系统,官方推荐了被Red Hat收购后搞起的Fedora CoreOS
。这件事对我影响非常大,因为我有一个Kubernetes集群全部20+节点使用了Container Linux
操作系统,这意味着我必须把我的集群所有节点都要重新更换操作系统才能让其在安全的环境下继续工作。
天啊~~这得是多大的工作量?还不能影响现有集群的服务,因为这是一个生产环境。
但无论工作量再大,还是必须做,且越快越好。经历了CoreOS的End-Of-Life,我可不敢再用它推荐的Fedora CoreOS
了,转而使用了我比较熟悉的Debian,我相信它不会在未来五年会End-Of-Life。
Worker节点
具体怎么做呢?这么多节点,要替换操作系统,但不能同时大量操作节点,因为还要保障集群要有足够的Worker节点工作,所以采用了最保险也是最累的方式,一台台操作。
步骤
- 下线一台Worker节点
- 重新安装操作系统
- 安装Docker
- 安装NFS客户端,因为我部分Pod会挂载NFS目录
- 安装对应版本的kubeadm, kubelet和kubectl
- 利用kubeadm join重新加入集群
Master节点
Worker节点还好,最难搞的就是Master节点,还好我这个集群使用了高可用方案,有3台Master节点,所以我可以不中断服务,一台台操作,类似Worker节点。
- 先在负载均衡把要下线的Master节点干掉
- kubectl drain下线master节点
- etcdctl移除所在Master的member
- 在kube-config里把相应的apiEndpoints删除
- 重新安装操作系统
- 安装Docker
- 安装NFS客户端,因为我部分Pod会挂载NFS目录
- 安装对应版本的kubeadm, kubelet和kubectl
- 在其它Master节点创建certificate key
- 利用kubeadm join带certificate key重新以Control Plane加入集群
相关命令
# 下线节点
kubectl drain <node> --delete-local-data --ignore-daemonsets
# 删除节点
kubectl delete node <node>
# 上线节点
kubectl uncordon <node>
# 创建join需要的token,并打印join命令
kubeadm token create --print-join-command
# 移除known_hosts相关记录
ssh-keygen -f "/root/.ssh/known_hosts" -R <host>
# 获取kubeadm配置
kubectl describe cm -n kube-system kubeadm-config
# 生成certificate key,这个值在以Master身份加入集群时用到
kubeadm init phase upload-certs --upload-certs
# 加入Worker
kubeadm join server.cluster.local:8443 --token bvvnho.bcmh67jtd1j4kpg5 --discovery-token-ca-cert-hash sha256:d4a9885c9cecc03b3be523ec4dc1a32a60ecf7908534b26d4b13f0aca494aa3c
# 加入Master
kubeadm join server.cluster.local:8443 --token bvvnho.bcmh67jtd1j4kpg5 --discovery-token-ca-cert-hash sha256:d4a9885c9cecc03b3be523ec4dc1a32a60ecf7908534b26d4b13f0aca494aa3c --control-plane --certificate-key 68119cd6aa49f5845d759d7a8075a16281da9b317efd7e7ae3e38dfe97e018d3
# 查看Etcd成员
ETCDCTL_API=3 etcdctl --endpoints 127.0.0.1:2379 --cacert /etc/kubernetes/pki/etcd/ca.crt --cert /etc/kubernetes/pki/etcd/server.crt --key /etc/kubernetes/pki/etcd/server.key member list
# 删除成员
ETCDCTL_API=3 etcdctl --endpoints 127.0.0.1:2379 --cacert /etc/kubernetes/pki/etcd/ca.crt --cert /etc/kubernetes/pki/etcd/server.crt --key /etc/kubernetes/pki/etcd/server.key member remove <id>
# Apt下安装指定的版本
apt-get install -y --allow-change-held-packages kubelet=1.16.9-00 kubectl=1.16.9-00 kubebadm=1.16.9-00
# 内核修改
cat <<EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
问题
即使思维缜密,文档查阅无数,在替换操作系统的过程中也还是出现了一些问题,简单记录一下
Timeout
访问应用,提示Timeout,查看源代码发现是在连接Redis服务时引起的。查看Redis所在Pod IP与Service IP,用redis-cli可以连接,可以读写。那就是App与Redis通讯有问题了。
exec进入容器,nslookup redis-svc
竟然找不到??? ping 一下显示Bad address
。查看/etc/resolv.conf
发现仅仅继承了host的内容,没有CoreDNS的地址,也没有search svc.cluster.local
记录。
退出容器,ip addr
看网络接口,有很多,但就是找不到redis-svc
IP的网络接口
实在不知道什么原因,着急,最粗暴就是重启Worker节点,但有时候好使有时候也不好使
kubelet配置修改
kubelet的配置文件在/var/lib/kubelet/config.yaml
,既然Pod的/etc/resolv.conf
有问题,我就干脆建一个可用的,位置在/etc/k8s-resolv.conf
,然后修改kubelet配置文件里的resolvConf
字段为以下值
resolvConf: /etc/k8s-resolv.conf
结果发现每次重启,值又自动恢复默认
resolvConf: /etc/resolv.conf
感觉/var/lib/kubelet/config.yaml
这个文件被同步刷写了,极有可能是从API同步过来的,目前还没找到解决方法,只能被迫使用默认配置。