春节期间我们更换了 kubernetes 生产集群,旧集群的 kubernetes 版本是 1.17.0,新集群版本是 1.23.3,新集群上部署了 dapr,最近准备将更多独立部署的服务器部署到 k8s 集群上,比如 redis, memcached, mongodb。

新集群和旧集群一样都是高可用集群,但新集群开始只用了 1 个 control-plane 节点,今天本来的任务是给新集群再增加 2 个 control-plane 节点,实现高可用。

如何加入 control-plane 节点呢? k8s 没有直接提供生成 join 命令的命令,下面的命令只能用于加入 worker 节点。

kubeadm token create --print-join-command

之前我们是在创建集群的时候,在执行 kubeadm init 命令之后就操作加入 control-plane 节点,kubeadm init 会生成加入命令

You can now join any number of the control-plane node running the following command on each as root:

  kubeadm join k8s-api:6443 --token ****** \
--discovery-token-ca-cert-hash ****** \
--control-plane --certificate-key ******

上面的命令实际上就是 token create --print-join-command 的输出加上 --control-plane--certificate-key,但之前使用的 certificate-key 已经过期。

开始我们用下面的命令生成 certificate-key 加入集群

kubeadm certs certificate-key

但加入失败,报错信息如下

[download-certs] Downloading the certificates in Secret "kubeadm-certs" in the "kube-system" Namespace

error execution phase control-plane-prepare/download-certs: error downloading certs: error downloading the secret: Secret "kubeadm-certs" was not found in the "kube-system" Namespace. This Secret might have expired. Please, run kubeadm init phase upload-certs --upload-certs on a control plane to generate a new one

于是改用 upload-certs 命令

$ kubeadm init phase upload-certs --upload-certs
[upload-certs] Storing the certificates in Secret "kubeadm-certs" in the "kube-system" Namespace
[upload-certs] Using certificate key:
*****

将 upload-certs 命令生成的 certificate-key 用于 kubeadm join 命令,这个 key 果然可以,但是在加入过程中卡在了下面的地方

[etcd] Announced new etcd member joining to the existing etcd cluster

[etcd] Creating static Pod manifest for "etcd"

[etcd] Waiting for the new etcd member to join the cluster. This can take up to 40s

[kubelet-check] Initial timeout of 40s passed.

本以为新 control-plane 节点加入不了不会影响现有集群的正常运行,但一个残酷的现实突然而至 —— 已有且仅有的那台 control-plane 上 api-server 容器突然无法启动了,syslog 中的其中一条错误信息如下

"Unable to authenticate the request due to an error" err="Post "https://k8s-api:6443/apis/authentication.k8s.io/v1/tokenreviews": dial tcp 10.0.9.171:6443: connect: connection refused"

这时虽然 api-server 不能正常工作,但 worker 节点上的 pod 都正常运行,应用暂时没有受影响。

面对这样如履薄冰的场景,我们首先想到的是先恢复旧集群,将负载切换到旧集群,然后从容地处理新集群的问题,但故障如此会开玩笑,旧集群的 api-server 竟然也无法正常启动。

CONTAINER ID        IMAGE                                       COMMAND                  CREATED             STATUS
0f30ff71a13d 0cae8d5cc64c "kube-apiserver --ad…" 5 seconds ago Up 3 seconds

命运会作弄人,故障也学会了。

面对如履薄冰与故障的作弄,我们做出了一个铤而走险的决定 —— 更新所有证书,之前成功操作过,但当时集群中没有负载。

用下面的命令三下五除二地完成了证书更新

$ cd /etc/kubernetes/pki/
$ mv {apiserver.crt,apiserver-etcd-client.key,apiserver-kubelet-client.crt,front-proxy-ca.crt,front-proxy-client.crt,front-proxy-client.key,front-proxy-ca.key,apiserver-kubelet-client.key,apiserver.key,apiserver-etcd-client.crt} ~/
$ kubeadm init phase certs all --control-plane-endpoint "k8s-api:6443"
$ cd /etc/kubernetes/
$ mv {admin.conf,controller-manager.conf,kubelet.conf,scheduler.conf} ~/
$ kubeadm init phase kubeconfig all --control-plane-endpoint "k8s-api:6443"

接下来就是重启 control-plane 节点服务器使用更新的证书。

重启的结局却是 —— 满园尽是502

走险失败后立即进入紧急抢险,用当前 control-plane 节点今天凌晨的快照创建镜像,用镜像重置整个系统。

重置后的 control-plane 节点成功启动后,从 control-plane 节点上看集群应该恢复了正常,worker 节点都处于 ready 状态,绝大多数 pod 都处于 running 状态,但是 pod 中的应用却不能正常工作,比如连不上其他服务、ingress 规则失效等。

开始以为要将所有 worker node 退出并重新加入集群才能恢复,但是在第1个 worker node 上操作退出,却卡在下面的地方

$ kubeadm reset
[reset] Unmounting mounted directories in "/var/lib/kubelet"

后来想到重启所有 worker node 试试,越是关键时候越是不能忽略简单方法,都重启后一切恢复了正常。

非常抱歉,今天 19:10~19:50 期间由于 k8s 集群操作引发全站全站故障,由此给您带来很大的麻烦,请您谅解。

【故障公告】k8s 开船记:增加控制舱(control-plane)造成的翻船的更多相关文章

  1. k8s 开船记-故障公告:自建 k8s 集群在阿里云上大翻船

    非常非常抱歉,新年上班第一天, 在今天阿里云上气候突变情况下,由于我们开船技术差,在今天 10:15~12:00 左右的访问高峰,我们竟然把船给开翻了,造成近2个小时整个博客站点无法访问,由此给您带来 ...

  2. k8s 开船记-触礁:四涡轮发动机撞坏3个引发502故障

    (图片来自网络) 非常抱歉,这次开船触礁故障给您带来麻烦了,请您谅解. 在我们昨天发布 k8s 开船记首航博文后,有园友在评论中发来贺词——“泰坦尼克号出发了[狗头]”,借此吉言,今天船就触礁了,还好 ...

  3. k8s 开船记:升级为豪华邮轮(高可用集群)与遇到奇怪故障(dns解析异常)

    之前我们搭建的 k8s 集群只用了1台 master ,可用性不高,这两天开始搭建高可用集群,但由于之前用 kubeadm 命令创建集群时没有使用 --control-plane-endpoint 参 ...

  4. k8s 开船记-首航:博客站点从 docker swarm 切换到 k8s

    昨天晚上,我们将博客站点的生产环境从 docker swarm 集群切换到了 k8s 集群,开船到目前,航行非常平稳,可以说首航成功! k8s 集群是我们用10台阿里云服务器自己搭建的,1台 mast ...

  5. k8s 开船记-修船:改 readinessProbe ,去 DaemonSet ,上 Autoscaler

    (图片来自网络) 改 readinessProbe 对于昨天 k8s 尼克号发生的触礁事故,我们分析下来主要是2个原因,一是当时4个节点不够用造成部分容器负载过高而宕机,二是 readinessPro ...

  6. k8s 开船记-全站登船:Powered by .NET Core on Kubernetes

    今天 18:30 左右,我们迈出了 kubernetes 航行的关键一步——全站登船,完成了全站应用从 docker swarm 集群向 k8s 集群的切换,以前所未有的决心与信心重新开起这艘巨轮,而 ...

  7. k8s 开船记-脚踏两只船:船儿还是旧的好,不翻船才是硬道理

    自从上次开始脚踏两只船(2个独立的k8s集群同时运行),园子暂时用奢侈的土豪方式过上了安稳的船上生活. 这种方式除了费钱之外,还带来一个问题,我们的集装箱自动装船系统(基于gitlab-ci的自动化部 ...

  8. 【故障公告】再次遭遇SQL语句执行超时引发网站首页访问故障

    非常抱歉,昨天 18:40~19:10 再次遭遇上次遇到的 SQL 语句执行超时引发的网站首页访问故障,由此您带来麻烦,请您谅解. 上次故障详见故障公告,上次排查下来以为是 SQL Server 参数 ...

  9. 【故障公告】redis 服务器宕机引发博客站点故障

    非常抱歉,今天下午 17:10~17:40 左右,由于博客系统所使用的 redis 服务器宕机,造成博客站点无法正常访问,由此给您带来很大的麻烦,请您谅解. 我们会针对这次故障改进 redis 服务器 ...

随机推荐

  1. css编写规则BEM

    简单来说,格式如下: .block { /* styles */ } .block__element { /* styles */ } .block--modifier { /* styles */ ...

  2. JVM完整详解:内存分配+运行原理+回收算法+GC参数等

    不管是BAT面试,还是工作实践中的JVM调优以及参数设置,或者内存溢出检测等,都需要涉及到Java虚拟机的内存模型.内存分配,以及回收算法机制等,这些都是必考.必会技能. JVM内存模型 JVM内存模 ...

  3. Chrome插件:提醒你正在摸鱼,摸鱼的时候知道自己在摸鱼,减少摸鱼的时间和频率。

    stop-mess-around 项目介绍 减少摸鱼的时间和频率的Chrome插件:在上班/学习期间很容易下意识的打开摸鱼网站,插件帮助我们减少摸鱼的时间和频率,提高我们上班和学习的效率,节省时间用于 ...

  4. Centos下安装Scala(2)

    1.下载压缩包 命令:wget https://downloads.lightbend.com/scala/2.11.8/scala-2.11.8.tgz 2.解压缩包 命令:tar -xzvf sc ...

  5. 今天太开心了,因为我知道了seastar框架

    今天听说了一个新的C++语言开发的网络框架,叫做seastar. seastar有何特别之处呢?先看看官网提供的性能数据: 性能 HTTPD benchmark: cpu # request/sec ...

  6. HBase之MinorCompact全程解析

    转自:https://blog.csdn.net/u014297175/article/details/50456147 Compact作用 当MemStore超过阀值的时候,就要flush到HDFS ...

  7. 539. Minimum Time Difference

    Given a list of 24-hour clock time points in "Hour:Minutes" format, find the minimum minut ...

  8. 一个简单的javaweb项目模板

    Controller包:表现层(视图)层.用来显示数据和接收用户数据 Service包:业务逻辑层,用来处理页面.先写接口,后写实现类 Dao包:持久层(数据访问层).用来操作数据库 其中Dao包处于 ...

  9. tcp|ip nagle算法

    在TCP传输数据流中,存在两种类型的TCP报文段,一种包含成块数据(通常是满长度的,携带一个报文段最多容纳的字节数),另一种则包含交互数据(通常只有携带几个字节数据). 对于成块数据的报文段,TCP采 ...

  10. plsql 视图中 为什么使用替代触发器

    /* 什么是视图? 视图:数据库对象,存的是一个查询命令:当作一个虚拟的数据表来使用: 应用场景: 简化查询操作:不能直接在视图上进行create,insert,update操作: 创建视图? 需要管 ...