k8s踩过的坑

k8s踩过的坑


记录自己踩过的坑和同事的经历

1、命令自动补全
yum -y install bash-completion
source <(kubectl completion bash)
echo "source <(kubectl completion bash)" >> ~/.bashrc
2、kubelet服务无法启动,报错Failed to start Kubernetes API Server

是由于系统交换内存导致,关闭即可:swapoff -a,重新启动就好了

3、容器镜像加速
[root@master ~]# /etc/docker/deamon.json
{
    "registry-mirrors": ["https://registry.docker-cn.com"],
    "graph": "/data/lib/docker",
    "bip": "172.16.0.1/24"
}

//registry-mirrors  仓库地址,这里修改为国内的官方加速地址
//graph       镜像、容器的存储路径,默认是/var/lib/docker
//bip         容器的IP网段
4、容器时间和宿主机时间不一致

本机时区复制到宿主机即可:

docker cp /etc/localtime a9c27487faf4:/etc/localtime

然后重启容器

或者,容器内修改时区

docker exec -it <容器名> /bin/bash
ln -sf /usr/share/zoneinfo/Asia/Shanghai    /etc/localtime
docker restart <容器名>

或者修改Dockerfile

在dockerfile文件里添加

RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone

5、创建pod报错No API token found for service account “default”, retry after the token is automatically
Error from server (ServerTimeout): error when creating "./pod1-deployment.yaml": No API token found for service account "default", retry after the token is automatically created and added to the service account

原因:是service account没有设置API token引起的

解决方式一:禁用ServiceAccount

编辑/etc/kubenetes/apiserver:
将以下这行中的ServiceAccount删除即可

KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota" 

改为:

KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ResourceQuota"

这种方式比较粗暴,可能会遇到必须要用ServiceAccount的情况。

解决方式二:配置ServiceAccount

①、首先生成密钥:

openssl genrsa -out /etc/kubernetes/serviceaccount.key 2048

②、编辑/etc/kubenetes/apiserver
添加以下内容:

KUBE_API_ARGS="--service_account_key_file=/etc/kubernetes/serviceaccount.key"

③、再编辑/etc/kubernetes/controller-manager
添加以下内容:

KUBE_CONTROLLER_MANAGER_ARGS="--service_account_private_key_file=/etc/kubernetes/serviceaccount.key"

最后无论是哪种解决方式都需要再重启kubernetes服务:

systemctl restart etcd kube-apiserver kube-controller-manager kube-scheduler

推荐使用第二种方式,因为在后面配置默认从私有仓库拉取镜像也必须要有ServiceAccount。

6、 DNS 间歇性 5 秒延迟问题
问题说明及原因

在 Kubernetes 集群会碰到这个间歇性 5 延迟的问题,Weave works 发布了一篇博客 Racy conntrack and DNS lookup timeouts 详细介绍了问题的原因。

简单来说,由于 UDP 是无连接的,内核 netfilter 模块在处理同一个 socket 上的并发 UDP 包时就可能会有三个竞争问题。以下面的 conntrack 和 DNAT 工作流程为例:

+---------------------------+      Create a conntrack for a given packet if
|                           |      it does not exist; IP_CT_DIR_REPLY is
|    1. nf_conntrack_in     |      an invert of IP_CT_DIR_ORIGINAL tuple, so
|                           |      src of the reply tuple is not changed yet.
+------------+--------------+
             |
             v
+---------------------------+
|                           |
|     2. ipt_do_table       |      Find a matching DNAT rule.
|                           |
+------------+--------------+
             |
             v
+---------------------------+
|                           |      Update the reply tuples src part according
|    3. get_unique_tuple    |      to the DNAT rule in a way that it is not used
|                           |      by any already confirmed conntrack.
+------------+--------------+
             |
             v
+---------------------------+
|                           |      Mangle the packet destination port and address
|     4. nf_nat_packet      |      according to the reply tuple.
|                           |
+------------+--------------+
             |
             v
+----------------------------+
|                            |     Confirm the conntrack if there is no confirmed
|  5. __nf_conntrack_confirm |     conntrack with either the same original or
|                            |     a reply tuple; increment insert_failed counter
+----------------------------+     and drop the packet if it exists.

由于 UDP 的 connect 系统调用不会立即创建 conntrack 记录,而是在 UDP 包发送之后才去创建,这就可能会导致下面三种问题:

  1. 两个 UDP 包在第一步 nf*conntrack*in 中都没有找到 conntrack 记录,所以两个不同的包就会去创建相同的 conntrack 记录(注意五元组是相同的)。
  2. 一个 UDP 包还没有调用 get*unique*tuple 时 conntrack 记录就已经被另一个 UDP 包确认了。
  3. 两个 UDP 包在 ipt*do*table 中选择了两个不同端点的 DNAT 规则。

所有这三种场景都会导致最后一步 _*nf*conntrack_confirm 失败,从而一个 UDP 包被丢弃。由于 GNU C 库和 musl libc 库在查询 DNS 时,都会同时发出 A 和 AAAA DNS 查询,由于上述的内核竞争问题,就可能会发生其中一个包被丢掉的问题。丢弃之后客户端会超时重试,超时时间通常是 5 秒。

上述的第三个问题至今还没有修复,而前两个问题则已经修复了,分别包含在 5.0 和 4.19 中:

  1. netfilter: nf_nat: skip nat clash resolution for same-origin entries (包含在内核 v5.0 中)
  2. netfilter: nf_conntrack: resolve clash for matching conntracks (包含在内核 v4.19 中)

在公有云中,这些补丁有可能也会包含在旧的内核版本中。比如在 Azure 上,这两个问题已经包含在 v4.15.0-1030.31 和 v4.18.0-1006.6 中。

如何避免这个问题

要避免 DNS 延迟的问题,就要设法绕开上述三个问题,所以就有下面几种方法:

①. 禁止并发 DNS 查询,比如在 Pod 配置中开启 single-request-reopen 选项强制 A 查询和 AAAA 查询使用相同的 socket:

dnsConfig:
  options:
    - name: single-request-reopen

②. 禁用 IPv6 从而避免 AAAA 查询,比如可以给 Grub 配置 ipv6.disable=1 来禁止 ipv6(需要重启节点才可以生效)。

③. 使用 TCP 协议,比如在 Pod 配置中开启 use-vc 选项强制 DNS 查询使用 TCP 协议:

dnsConfig:
  options:
    - name: single-request-reopen
    - name: ndots
      value: "5"
    - name: use-vc

④. 使用 Nodelocal DNS Cache[5],所有 Pod 的 DNS 查询都通过本地的 DNS 缓存查询,避免了 DNAT,从而也绕开了内核中的竞争问题。你可以执行下面的命令来部署它(注意它会修改 Kubelet 配置并重启 Kubelet):

kubectl apply -f https://github.com/feiskyer/kubernetes-handbook/raw/master/examples/nodelocaldns/nodelocaldns-kubenet.yaml
7、k8s证书过期
①、说明

一般正常安装k8s集群,集群证书的有效期是一年,包括以下证书:

  • apiserver

  • apiserver-kubelet-client

  • apiserver-etcd-client

  • front-proxy-client

  • etcd/server

  • etcd/peer

  • etcd/healthcheck-client

②、证书过期问题解决办法

对于手动生成的证书

手动安装过程中,只需指定证书的过期时间为N天即可

对于kubeadm

方式一:升级K8S集群,自动更新证书

方式二:修改kubeadm并重新编译

方式三:重新生成证书
③、过期处理报错信息
[root@k8s-master03 ~]# kubectl get pod
Unable to connect to the server: x509: certificate has expired or is not yet valid

日志信息

The currently active client certificate has expired, but the server is not responsive. A restart may be necessary to retrieve new initial credentials.

证书备份

[root@k8s-master03 ~]# cp -rp /etc/kubernetes /etc/kubernetes.bak

apiserver证书

[root@k8s-master03 ~]# rm -f /etc/kubernetes/pki/apiserver*

front-proxy-client证书

[root@k8s-master03 ~]# rm -f /etc/kubernetes/pki/front-proxy-client.*

etcd证书

[root@k8s-master03 ~]# rm -rf /etc/kubernetes/pki/etcd/healthcheck-client.*
[root@k8s-master03 ~]# rm -rf /etc/kubernetes/pki/etcd/server.*
[root@k8s-master03 ~]# rm -rf /etc/kubernetes/pki/etcd/peer.*

重新生成证书

[root@k8s-master02 ~]# kubeadm alpha phase certs all --config kubeadm-config.yaml
[certificates] Generated apiserver-kubelet-client certificate and key.
[certificates] Generated apiserver certificate and key.
[certificates] apiserver serving cert is signed for DNS names [k8s-master02 kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local k8s-master01 k8s-master02 k8s-master03 k8s-master-lb] and IPs [10.96.0.1 192.168.20.21 192.168.20.10 192.168.20.20 192.168.20.21 192.168.20.22 192.168.20.10]
[certificates] Generated front-proxy-client certificate and key.
[certificates] Generated etcd/healthcheck-client certificate and key.
[certificates] Generated apiserver-etcd-client certificate and key.
[certificates] Generated etcd/server certificate and key.
[certificates] etcd/server serving cert is signed for DNS names [k8s-master02 localhost k8s-master02] and IPs [127.0.0.1 ::1 192.168.20.21]
[certificates] Generated etcd/peer certificate and key.
[certificates] etcd/peer serving cert is signed for DNS names [k8s-master02 localhost k8s-master02] and IPs [192.168.20.21 127.0.0.1 ::1 192.168.20.21]
[certificates] valid certificates and keys now exist in "/etc/kubernetes/pki"
[certificates] Using the existing sa key. 

重新生成配置文件

[root@k8s-master02 ~]# mv /etc/kubernetes/ admin.conf kubelet.conf pki/ scheduler.conf controller-manager.conf manifests/ pki.bak/ tmp/ 
[root@k8s-master02 ~]# mv /etc/kubernetes/*.conf /tmp/
[root@k8s-master02 ~]# kubeadm alpha phase kubeconfig all --config kubeadm-config.yaml
[endpoint] WARNING: port specified in controlPlaneEndpoint overrides bindPort in the controlplane address
[kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/admin.conf"
[kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/kubelet.conf"
[kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/controller-manager.conf"
[kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/scheduler.conf"

重启kubelet

 [root@k8s-master01 ~]# systemctl restart kubelet
④、集群确认

证书过期时间确认

# 注意:cfssl需要自行安装
[root@k8s-master01 ~]# cfssl-certinfo -cert /etc/kubernetes/pki/etcd/server.crt |grep not
  "not_before": "2020-06-09T05:15:32Z",
  "not_after": "2021-06-09T05:15:32Z",
#cfssl安装
[root@k8s-master01 ~]# wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
[root@k8s-master01 ~]# chmod +x cfssl_linux-amd64
[root@k8s-master01 ~]# mv cfssl_linux-amd64 /usr/local/bin/cfssl
[root@k8s-master01 ~]# wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
[root@k8s-master01 ~]# chmod +x cfssljson_linux-amd64
[root@k8s-master01 ~]# mv cfssljson_linux-amd64 /usr/local/bin/cfssljson
[root@k8s-master01 ~]# wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
[root@k8s-master01 ~]# chmod +x cfssl-certinfo_linux-amd64
[root@k8s-master01 ~]# mv cfssl-certinfo_linux-amd64 /usr/local/bin/cfssl-certinfo
[root@k8s-master01 ~]# export PATH=/usr/local/bin:$PATH

集群状态确认

[root@k8s-master01 ~]# kubectl get no
NAME           STATUS   ROLES    AGE     VERSION
k8s-master01   Ready    master   6d22h   v1.12.3
k8s-master02   Ready    master   6d22h   v1.12.3
k8s-master03   Ready    master   6d22h   v1.12.3
k8s-node01     Ready    <none>   6d21h   v1.12.3
k8s-node02     Ready    <none>   6d21h   v1.12.3
Worker节点不能启动

Master 节点的 IP 地址变化,导致 worker 节点不能启动。请重装集群,并确保所有节点都有固定内网 IP 地址。

许多Pod一直Crash或不能正常访问
kubectl get pods --all-namespaces

重启后会发现许多 Pod 不在 Running 状态,此时,请使用如下命令删除这些状态不正常的 Pod。通常,您的 Pod 如果是使用 Deployment、StatefulSet 等控制器创建的,kubernetes 将创建新的 Pod 作为替代,重新启动的 Pod 通常能够正常工作。

kubectl delete pod <pod-name> -n <pod-namespece>

Worker节点不能启动

Master 节点的 IP 地址变化,导致 worker 节点不能启动。请重装集群,并确保所有节点都有固定内网 IP 地址。

许多Pod一直Crash或不能正常访问
kubectl get pods --all-namespaces

重启后会发现许多 Pod 不在 Running 状态,此时,请使用如下命令删除这些状态不正常的 Pod。通常,您的 Pod 如果是使用 Deployment、StatefulSet 等控制器创建的,kubernetes 将创建新的 Pod 作为替代,重新启动的 Pod 通常能够正常工作。

kubectl delete pod <pod-name> -n <pod-namespece>
持续更新…………
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

正在输入中…………

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值