0

k8s技术圈一周精选[第6期]

 2 years ago
source link: https://www.qikqiak.com/post/k8s-tech-weekly-collection-phase6/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

k8s技术圈一周精选

本周的k8s技术圈的几个精选的问题,分享给大家。另外,也欢迎大家加入我们的【微信群】【知识星球】共同探讨,共同进步。

1.如果pod长期不重启,容器输出到 emptydir 的日志文件,有什么好的清理办法呢?

v1.7 + 支持对基于本地存储(如 hostPath, emptyDir, gitRepo 等)的容量进行调度限额。为了支持这个特性,Kubernetes 将本地存储分为两类:

  • storage.kubernetes.io/overlay,即 /var/lib/docker 的大小
  • storage.kubernetes.io/scratch,即 /var/lib/kubelet 的大小

Kubernetes 根据 storage.kubernetes.io/scratch 的大小来调度本地存储空间,而根据 storage.kubernetes.io/overlay 来调度容器的存储。比如为容器请求 64MB 的可写层存储空间:

apiVersion: v1
kind: Pod
metadata:
  name: ls1
spec:
  restartPolicy: Never
  containers:
  - name: hello
    image: busybox
    command: ["df"]
    resources:
      requests:
        storage.kubernetes.io/overlay: 64Mi

为 emptyDir 请求 64MB 的存储空间:

apiVersion: v1
kind: Pod
metadata:
  name: ls1
spec:
  restartPolicy: Never
  containers:
  - name: hello
    image: busybox
    command: ["df"]
    volumeMounts:
    - name: data
      mountPath: /data
  volumes:
  - name: data
    emptyDir:
      sizeLimit: 64Mi

2.kubeadm 搭建集群忘记了 join 的命令

在使用 kubeadm 初始化集群的时候,有时可能会忘记保存 join 命令,或者在添加节点的时候 token 失效了,要重新获取 join 命令有两种方法:

第一种方法:可以通过 kubeadm token create 重新创建一个新的 token值;然后通过 openssl 命令或者 CA 证书的 hash 值:

$ openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
<ca-cert-hash>

最终新的 join 命令为:

$ kubeadm join <apiserver> --token <new-token> --discovery-token-ca-cert-hash sha256:<ca-cert-hash>

第二种方法:新版本(>1.10)的 kubeadm 支持直接获取 join 命令:

$ kubeadm token create --print-join-command

3.ServiceAccount 如何进行权限控制

我们知道 ServiceAccount 是通过 Role 或者 ClusterRole 里面的权限声明来进行权限控制的,那么是怎样来实现的呢?我们如果在使用 ServiceAccount 来进行权限控制了,那么肯定是我们当前的 Pod 需要去访问 Kubernetes 集群中的某些资源,比如 Pod 的 CRUD 操作,这个时候就需要我们有 CRUD Pod 的权限,而我们当前的 Pod 就是通过 ServiceAccount 对应的 token 文件和 自动注入到 Pod 中的 ca.crt 文件去连接的 APIServer,而这个 token 又是绑定了相关权限的,所以我们在 Pod 中去访问 APIServer 的时候就知道当前的操作是否有对应的权限了。如果集群使用 TLS 认证方式,则我们可以在 client-go 当中通过 InCluster 的方式自动去读取集群内部的 tokenFile 和 CAFile:

// tokenFile = "/var/run/secrets/kubernetes.io/serviceaccount/token"
// rootCAFile = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
config, _ := rest.InClusterConfig()

// 根据指定的 config 创建一个新的 clientset
clientset, _ := kubernetes.NewForConfig(config)
// 然后通过 clientset 去操作集群资源
......

如果我们没有给 Pod 指定一个 ServiceAccount 的话,则会使用默认的名为 default 的这个 ServiceAccount,当然他也有一个 token 会被自动注入到 Pod 中,但是就不一定有我们想要的访问集群资源的权限了,所以我们需要自定义一个 ServiceAccount 绑定到 Pod 上面去。

4.Docerkfile 中添加交互式命令

一个有趣的问题,需要在 Dockerfile 里面添加交互式的命令,类似于我们平时安装软件的时候输入 yes,我们可以通过 yum install -y 来默认安装,避免用户输入,但是有的时候没办法避免的时候,一定需要输入交互命令的时候应该咋办呢?能想到的一个比较好的办法是暂时在 Dockerfile 中不添加这条交互式命令,先制作一个镜像,然后使用这个镜像运行一个容器,然后到容器中去运行这个交互式命令,然后配置完后 commit 下这个容器成一个新的镜像即可。

但是上面这种方式不具有通用性,在 docker 官方论坛中有关于这个问题的解答:https://forums.docker.com/t/dockerfile-how-to-answer-install-question-from-application/5240/2 通过安装 expect 工具来实现交互功能:

RUN apt-get install expect
ADD install_script
RUN install_script

安装脚本如下:

#!/usr/bin/expect
set timeout 2
spawn "./your_script"
expect “Question 1 :” { send “yes\n” }
expect “Question 2 :” { send “no\n” }
interact

5.kubeadm 升级集群配置

昨天升级了下集群到 v1.14.5 版本,升级过程很顺畅,但是今天发现 apiserver 中出现大量的 tls bad 的错误日志,而且内部服务解析都失败,第一反应说 dns 的问题,但是 CoreDNS 也没任何错误日志信息,然后再看 kube-proxy 日志,才发现出现了大量的连接 apiserver 失败的错误,仔细一看连接的居然还是 apiserver 节点的外网 IP,这就奇怪了,之前升级都是正常的,这次居然读取到了外网 IP,对应多网卡的节点,在使用 kubeadm 安装或者升级的使用要注意指定下使用的 apiserver 地址,否则可能就会读取到外网 IP了,下面说创建或升级 kubernetes 的 kubeadm 配置文件:

apiVersion: kubeadm.k8s.io/v1beta1
kind: ClusterConfiguration
networking:
  dnsDomain: cluster.local
  podSubnet: 10.244.0.0/16
  serviceSubnet: 10.96.0.0/12
kubernetesVersion: v1.15.2
imageRepository: gcr.azk8s.cn/google_containers

---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"

---
apiVersion: kubeadm.k8s.io/v1beta1
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 10.151.30.11
  bindPort: 6443

主要修改的参数就是 InitConfiguration 中的 advertiseAddress 地址为内网网卡的 IP 地址,然后使用 kubeadm 命令安装或更新即可。

对于 kubeadm 初始化集群的配置可以通过如下命令获取:

$ kubeadm config print init-defaults

但是要想完整了解上面的资源对象对应的属性,可以查看对应的 godoc 文档,地址: https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2

6.Pod 时区同步

往往都会遇到修改 Pod 时区的需求,更多的需求是要求所有的 Pod 都在同一个时区,比如我们所在的东8区,一般我们可以通过环境变量或者挂载主机的时区文件到 Pod 中来实现同步,但是这样需要我们对每一个 Pod 手动做这样的操作,一个更好的方式就是利用 PodPreset 来预设。

首先启用 PodPreset:在 kube-apiserver 启动参数 -runtime-config 增加 settings.k8s.io/v1alpha1=true;

然后在 –admission-control 增加 PodPreset 启用。最后重启 kube-apiserver 即表示启用成功。可以通过如下命令查看是否启用成功:

$ kubectl get podpresets

然后创建一个 PodPresents 资源对象:

apiVersion: settings.k8s.io/v1alpha1
kind: PodPreset
metadata:
  name: tz-env
spec:
  selector:
    matchLabels:
  env:
  - name: TZ
    values: Asia/Shanghai

这里需要注意的地方是,一定需要写 selector...matchLabels,但是 matchLabels 为空,表示应用于所有容器,这个就是我们想要的,创建上面这个资源对象,然后我们去创建一个普通的 Pod 可以查看下是否注入了上面的 TZ 这个环境变量。需要注意的是,PodPreset 是 namespace 级别的对象,其作用范围只能是同一个命名空间下的容器。

7.Prometheus 采集 Kubelet 指标

在 kubernetes 1.11 版本以后 kubelet 去掉了 10255 端口,所以在使用 prometheus 监控 kubelet 的时候就只需要使用自动发现角色为 node 类型的即可,但是要注意需要使用 https 的协议,而且有一个经常遇到的问题是访问 metrics 接口的时候出现 403 错误。遇到这种情况需要确保 kubelet 开启了下面两个参数:

--authentication-token-webhook
--authorization-mode=Webhook

此外在给 prometheus 指定 rbac 权限的时候需要绑定下面的权限:

- apiGroups:
  - ""
  resources:
  - nodes/metrics
  verbs:
  - get

8.Lease API

有同学发现集群(1.14版本+)中多了一个名为 kube-node-lease 的命名空间,不知道这个是干嘛使用的,不知道能不能删除呢?

$ kubectl get ns
NAME                  STATUS   AGE
default               Active   10d
kube-node-lease       Active   10d
kube-public           Active   10d
kube-system           Active   10d

实际上 kube-node-lease 命名空间里面包含 kubelet 用来确定节点运行状况的租约对象,kubelet 会创建并定期更新节点上的租约,kubelet 使用新的 Lease API 报告节点心跳,节点生命周期控制器使用这些心跳作为节点健康信号。

9.Prometheus 报警规则

在群里面看到群友分享的一个收集 Prometheus 各种报警规则的项目,都是比较通用的报警规则配置。🤘 🤘 🤘

地址:https://github.com/samber/awesome-prometheus-alerts

10.启动探针

在 Kubernetes 1.16 版本中为缓慢启动的 Pod 添加了一个 startupProbe 的启动探针来延迟其他探针检测。我们知道探针可以让 Kubernetes 监视您的应用程序状态。您可以使用livenessProbe 定期检查应用程序是否仍在运行。下面是一个示例容器定义了此探针:

livenessProbe:
  httpGet:
    path: /healthz
    port: liveness-port
  failureThreshold: 3
  periodSeconds: 10

如果在30秒内失败3次,则容器将重新启动。但是由于该容器很慢并且需要30秒钟以上才能启动,那么该探针肯定就会失败,并且容器将再次重新启动,这样就陷入一个死循环当中了,之前我们大部分情况是配置的一个 initialDelaySeconds 的参数来延迟第一次检测的时间,但是这个参数毕竟是写死的,不够准确。

startupProbe 这项新功能可以使您可以定义一个启动探针,该探针将推迟所有其他探针,直到 Pod 完成启动为止:

startupProbe:
  httpGet:
    path: /healthz
    port: liveness-port
  failureThreshold: 30
  periodSeconds: 10

现在,我们的慢速容器最多可以有5分钟(30个检查* 10秒= 300s)完成启动了微笑。

欢迎大家加入我们的知识星球:Kubernetes知识星球

Kubernetes进阶训练营

微信公众号

扫描下面的二维码关注我们的微信公众帐号,在微信公众帐号中回复◉加群◉即可加入到我们的 kubernetes 讨论群里面共同学习。

wechat-account-qrcode

「真诚赞赏,手留余香」


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK