Kubelet bootstrap 流程

首先,什么是kubelet bootstrap?在安装 k8s worker node 时,基本上 worker 的初始状态仅仅是安装了 docker 和 kubelet,worker 需要一种机制跟 master 通信。但网络通信的基本假设是通信双方谁也不信任谁。所以,kubelet bootstrap要以自动化的方式解决如下几个问题:

  • 在只知道 api server IP 地址的情况下,worker node 如何获取 api server 的 CA 证书?
  • 如何让 api server 信任 worker?因为在 api server 信任 worker 之前,worker 没有途径拿到自己的证书,有点鸡生蛋蛋生鸡的感觉

本文的实验目的就是将一个新的 worker node(主机名为 test-node) 添加到已有的 k8s 集群中。

其实,使用 kubeadm 工具完成这个工作就是简单的一行命令,kubeadm 会自动完成很多工作。但为了更好的了解kubelet bootstrap的流程,本文不考虑使用 kubeadm

什么是 bootstrap token

要让 api server 信任 worker,worker 得需要先过 master 认证鉴权这一关。k8s 以插件化的方式支持很多种认证方式,比如 token 文件,x509证书,service account 等等,其中就包含一个名为“Bootstrap Token Authentication”的认证方式,基本上 k8s 的默认安装就默认支持这种认证方式。这种方式最初就是设计用来给添加 worker node 用的。使用 Bootstrap Token Authentication 时,只需告诉 kubelet 一个特殊的 token,kubelet 自然就能通过 api server 的认证。所以,首先得保证 k8s 中定义了这个 token:

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: bootstrap-token-abcdef
  namespace: kube-system
type: bootstrap.kubernetes.io/token
stringData:
  description: "The bootstrap token for testing."
  token-id: abcdef
  token-secret: 0123456789abcdef
  expiration: 2019-09-16T00:00:00Z
  usage-bootstrap-authentication: "true"
  usage-bootstrap-signing: "true"
  auth-extra-groups: system:bootstrappers:test-nodes
EOF

在上面的 token 定义中,需要注意:

  • token 的 name 必须是 bootstrap-token-<token-id> 的格式
  • token 的 type 必须是 bootstrap.kubernetes.io/token
  • token 的 token-id 和 token-secret 分别是6位和16位数字和字母的组合
  • auth-extra-groups 定义了 token 代表的用户所属的额外的 group,而默认 group 名为 system:bootstrappers
  • 这种类型 token 代表的用户名为 system:bootstrap:<token-id>,在本文中就是 system:bootstrap:abcdef

如何生成 kubelet 证书

有了 token,kubelet 就能通过 api server 的认证,连接建立,至此是不是万事大吉了。NO!

也许你已经注意到了,上面的 token 定义有 expiration 字段,表示这个 token 是有有效期的,过了有效期,token 失效,kubelet 就无法使用 token 跟 api server 通信,所以这个 token 只能作为 kubelet 初始化时跟 api server 的临时通信,而并非持久方案。

kubelet 最终还是需要使用证书跟 api server 通信,证书从何而来?如果让 k8s 的安装人员为每一个 worker node 生成并维护一份证书,工作量太大太繁琐,这也是设计 bootstrap token 要解决的问题之一,即:kubelet 使用低权限的 bootstrap token 跟 api server 建立连接后,要能够自动向 api server 申请自己的证书,并且 api server 要能够自动审批证书。

是的,很多人都会想到,k8s 支持 cert sign API。在 k8s 的证书认证中,要么由管理员手动为用户生成证书,要么是使用更为服务化的方式,由需要证书的用户自己向 k8s 申请,k8s 管理员只需在后台审批即可。但手动的为每一个用户审批,并没有带来很大的便利性,所以 k8s 还支持自动审批,只不过目前自动审批仅仅针对 kubelet。下面我们就模拟一个用户手动发送 csr,让 k8s 自动审批。

首先生成一个名为 vip 的用户证书,该证书需要管理员审批,下面的操作都是以 k8s admin 用户身份执行:

name=vip
group=newlands
cat <<EOF | cfssl genkey - | cfssljson -bare $name
{
  "hosts": [],
  "CN": "$name",
  "key": {
    "algo": "ecdsa",
    "size": 256
  },
  "names": [
    {
      "C": "NZ",
      "ST": "Wellington",
      "L": "Wellington",
      "O": "$group",
      "OU": "Test"
    }
  ]
}
EOF
# 创建 csr
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1beta1
kind: CertificateSigningRequest
metadata:
  name: $name
spec:
  groups:
    - $group
  request: $(cat ${name}.csr | base64 | tr -d ‘\n‘)
  usages:
    - key encipherment
    - digital signature
    - client auth
EOF
# 管理员手动审批
kubectl get csr $name -o json | jq -r ‘.status.certificate‘ | base64 -d > $name.crt

我们的目的是让 vip 用户发起的 csr 能够被自动审批。所以首先得允许 vip 用户访问 csr api,使用 kubeadm 安装 k8s 时已经默认创建了该 clusterrole,我们要做的就是给 vip 用户赋予这个 clusterrole:

$ kubectl describe clusterrole system:node-bootstrapper
Name:         system:node-bootstrapper
Labels:       kubernetes.io/bootstrapping=rbac-defaults
Annotations:  rbac.authorization.kubernetes.io/autoupdate=true
PolicyRule:
  Resources                                       Non-Resource URLs  Resource Names  Verbs
  ---------                                       -----------------  --------------  -----
  certificatesigningrequests.certificates.k8s.io  []                 []              [create get list watch]
[email protected] [~]
$ kubectl create clusterrolebinding csr-vip --clusterrole system:node-bootstrapper --user vip
clusterrolebinding.rbac.authorization.k8s.io/csr-vip created

其次,我们需要给 vip 用户另一个特殊的 clusterrole,这个 clusterrole 在使用 kubeadm 安装 k8s 时也已经被自动创建:

$ kubectl describe clusterrole system:certificates.k8s.io:certificatesigningrequests:nodeclient
Name:         system:certificates.k8s.io:certificatesigningrequests:nodeclient
Labels:       kubernetes.io/bootstrapping=rbac-defaults
Annotations:  rbac.authorization.kubernetes.io/autoupdate=true
PolicyRule:
  Resources                                                  Non-Resource URLs  Resource Names  Verbs
  ---------                                                  -----------------  --------------  -----
  certificatesigningrequests.certificates.k8s.io/nodeclient  []                 []              [create]
$ kubectl create clusterrolebinding   nodeclient-vip   --clusterrole system:certificates.k8s.io:certificatesigningrequests:nodeclient   --user vip

然后我们以 vip 用户身份执行如下命令(与上文类似),注意因为自动审批目前只针对 kubelet,所以 vip 申请的 csr 用户名必须是 system:node:<name> 的形式,group 必须是 system:nodes,并且 usages 也必须是命令中所示:

name=system:node:test-node
group=system:nodes
cat <<EOF | cfssl genkey - | cfssljson -bare $name
{
  "hosts": [],
  "CN": "$name",
  "key": {
    "algo": "ecdsa",
    "size": 256
  },
  "names": [
    {
      "C": "NZ",
      "ST": "Wellington",
      "L": "Wellington",
      "O": "$group",
      "OU": "Test"
    }
  ]
}
EOF
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1beta1
kind: CertificateSigningRequest
metadata:
  name: $name
spec:
  groups:
    - $group
  request: $(cat ${name}.csr | base64 | tr -d ‘\n‘)
  usages:
    - key encipherment
    - digital signature
    - client auth
EOF

然后查看 csr,可以看到 csr 的状态已经是 Approved,Issued,实验结束:

$ kubectl get csr
NAME                    AGE       REQUESTOR   CONDITION
system:node:test-node   3s        vip         Approved,Issued

由上述实验可以得知,为了让 bootstrap token 所代表的用户(username:system:bootstrap:<token-id>,group:system:bootstrappers)申请的 csr 能够被自动审批,必须要给该用户或组赋予两个 clusterrole:certificatesigningrequests.certificates.k8s.io/nodeclient 和 system:node-bootstrapper

kubectl create clusterrolebinding nodeclient-test-node   --clusterrole system:certificates.k8s.io:certificatesigningrequests:nodeclient   --user system:bootstrap:abcdef
kubectl create clusterrolebinding csr-test-node   --clusterrole system:node-bootstrapper   --user system:bootstrap:abcdef

bootstrap token 后处理

通过上述讲解我们知道,bootstrap token 是 kubelet 引导的关键,如果其他人知道了 bootstrap token 那就意味着可以访问 k8s 的某些资源,所以要么给 bootstrap token 设定一个很短的有效期,要么 kubelet 引导结束后就手动删除,防止 bootstrap token 被再次使用。

kubelet 客户端证书 renewal

现在,kubelet 有了自己跟 api server 通信的证书,剩下的一个任务就是处理证书过期的问题。既然证书的生成都是自动化的,如果证书的 renew 需要手动那就太 low 了,所以跟生成证书的原理相似,k8s 也提供一个 clusterrole 可以赋予 kubelet 用户或组让 renew 证书的请求也能够被自动审批:

$ kubectl describe clusterrole system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
Name:         system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
Labels:       kubernetes.io/bootstrapping=rbac-defaults
Annotations:  rbac.authorization.kubernetes.io/autoupdate=true
PolicyRule:
  Resources                                                      Non-Resource URLs  Resource Names  Verbs
  ---------                                                      -----------------  --------------  -----
  certificatesigningrequests.certificates.k8s.io/selfnodeclient  []                 []              [create]

但这个 clusterrole 可不是赋予 bootstrap token 所代表的用户了,而是使用 bootstrap token 所获取到的证书所代表的用户。在 k8s 中,其用户名是 system:node:<node-name> 的形式,group 是system:nodes,所以就需要:

kubectl create clusterrolebinding nodeclient-cert-renewal   --clusterrole system:certificates.k8s.io:certificatesigningrequests:selfnodeclient   --user system:node:test-node

在执行上面的命令前,你可以先检查一下相应的 clusterrolebinding 是否已经创建了:

kubectl get clusterrolebindings -o json | jq -r ‘.items[] | select(.subjects // [] | .[] | [.kind,.name] == ["Group","system:nodes"]) | .metadata.name‘

如果是使用 kubeadm 安装的 k8s cluster,你会看到上面的命令返回 kubeadm:node-autoapprove-certificate-rotation,继续查看这个 clusterrolebinding,你会发现正是我们想要的:

$ kubectl describe clusterrolebinding kubeadm:node-autoapprove-certificate-rotation
Name:         kubeadm:node-autoapprove-certificate-rotation
Labels:       <none>
Annotations:  <none>
Role:
  Kind:  ClusterRole
  Name:  system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
Subjects:
  Kind   Name          Namespace
  ----   ----          ---------
  Group  system:nodes

引导 kubelet

有了上述背景知识,在一个新的 worker node 上配置 kubelet service 就比较简单了。先总结一下我们都创建了什么东西:

  1. 创建了 bootstrap token
  2. 给 bootstrap token 代表的用户 system:bootstrap:abcdef 赋予 clusterole certificatesigningrequests.certificates.k8s.io/nodeclient 和 system:node-bootstrapper,让该用户可以访问 csr API 以及自动审批其创建的 csr
  3. 给新的 work node 代表的用户 system:node:test-node 赋予 clusterrole system:certificates.k8s.io:certificatesigningrequests:selfnodeclient,让它发送的证书 renew 的请求能被自动审批

接下来,需要生成 bootstrap 配置文件,这里假设我们已经知道 api server 的地址以及 ca 证书(关于如何获取这些信息后续会补充),你可以在 master node 执行如下命令生成 bootstrap-kubeconfig 文件并拷贝到 test-node 上:

kubectl config set-cluster k8s --server https://10.0.0.11:6443 --certificate-authority=/etc/kubernetes/pki/ca.crt --embed-certs=true --kubeconfig=/var/lib/kubelet/bootstrap-kubeconfig
kubectl config set-credentials test-node --token=abcdef.0123456789abcdef --kubeconfig=/var/lib/kubelet/bootstrap-kubeconfig
kubectl config set-context test-node-bootstrap --cluster k8s --user test-node --kubeconfig=/var/lib/kubelet/bootstrap-kubeconfig
kubectl config use-context test-node-bootstrap --kubeconfig=/var/lib/kubelet/bootstrap-kubeconfig

配置 kubelet systemd 配置文件,需要指定 --kubeconfig 以存放 bootstrap token 获取的证书信息,kubelet 会动态创建该文件,而证书文件本身默认存放在 /var/lib/kubelet/pki 目录下,可以指定 --cert-dir 自定义证书路径:

cat <<EOF > /etc/systemd/system/kubelet.service
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/kubernetes/kubernetes
After=docker.service
Requires=docker.service

[Service]
ExecStart=/usr/bin/kubelet \  --bootstrap-kubeconfig=/var/lib/kubelet/bootstrap-kubeconfig \  --kubeconfig=/var/lib/kubelet/kubeconfig \  --network-plugin=cni \  --rotate-certificates=true \  --register-node=true \  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

重启 kubelet 服务:

systemctl daemon-reload; systemctl restart kubelet

待 kubelet 服务启动后,你可以在 worker node 上 /var/lib/kubelet/pki 目录下看到生成的证书,并且 kubelet 自动生成了 /var/lib/kubelet/kubeconfig 文件。

$ ll /var/lib/kubelet/pki
total 12
-rw------- 1 root root 1114 Sep 17 13:38 kubelet-client-2018-09-17-13-38-33.pem
lrwxrwxrwx 1 root root   59 Sep 17 13:38 kubelet-client-current.pem -> /var/lib/kubelet/pki/kubelet-client-2018-09-17-13-38-33.pem
-rw-r--r-- 1 root root 2193 Sep 15 08:48 kubelet.crt
-rw------- 1 root root 1675 Sep 15 08:48 kubelet.key
$ ll /var/lib/kubelet/kubeconfig
-rw------- 1 root root 1850 Sep 17 13:38 /var/lib/kubelet/kubeconfig

查看证书信息,仅关注 CN 和 O 字段信息,与之前的讲解一致:

$ openssl x509 -noout -text -in /var/lib/kubelet/pki/kubelet-client-current.pem
        Subject: O=system:nodes, CN=system:node:test-node

使用 kubectl 查看 node 信息可以看到该 node 状态已经 ready:

$ kubectl get node
NAME                      STATUS    ROLES     AGE       VERSION
lingxiantest-k8s-master   Ready     master    6d        v1.11.1
lingxiantest-k8s-node1    Ready     <none>    6d        v1.11.1
test-node                 Ready     <none>    3m        v1.11.1

总结

总结一下 kubelet 的 bootstrap 流程:

如果使用 kubeadm

上面的所有步骤都是假设 kubeadm 不可用,但如果是你自己的环境,那么使用 kubeadm 引导一个新的 kubelet 节点是最简单的,因为 kubeadm 会自动帮你干很多事儿。

  1. 在 master node 生成一个新的 token

    因为 bootstrap token 有效期默认是24小时,所以当你考虑向 cluster 中新增 node 时,原来创建的 token 可能早已过期,你需要创建一个新的 bootstrap token。

    $ kubeadm token list
    TOKEN                     TTL         EXPIRES                USAGES                   DESCRIPTION   EXTRA GROUPS
    ebpxef.6059low577z0imyv   <invalid>   2018-09-30T05:45:38Z   authentication,signing   <none>        system:bootstrappers:kubeadm:default-node-token
    $ kubeadm token create
    mfa708.ppxrbz1g945jj2un
    
  2. 在新 worker node 上:
    kubeadm join --discovery-token-unsafe-skip-ca-verification --token mfa708.ppxrbz1g945jj2un 10.0.0.18:6443
    

    这里我为了省事儿,没有去验证 master 的 CA 公钥。命令执行后,你就会看到一个新的 node 已经加入 k8s cluster,是不是很简单?

原文地址:https://www.cnblogs.com/wjoyxt/p/9963392.html

时间: 2024-08-30 18:04:11

Kubelet bootstrap 流程的相关文章

k8s 生成kubelet bootstrap文件

接着上面的博客继续写 pwd /etc/kubernetes kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/ssl/ca.pem --server=https://192.168.1.71:6443 --kubeconfig=bootstrap.kubeconfig 设置k8s bootstrap.kubeconfig token kubectl config set-credentia

bootstrap之Click大事

上一篇文章中谈到了bootstrap流程,本文开始把目光bootstrap它可以接受指令(从源代码视图的透视.因为appium该项目现在还处于不断更新,因此,一些指令已经实现.也许未来会实现一些.从视图的源代码的点的优点是对未来要知道将来也许appium哪些功能可以做). 在bootstrap项目中的io.appium.android.bootstrap.handler包中的类都是相应的相应的指令的类,里面都有execute方法来运行命令.先上上一篇文章中讲的map. private stati

07-2.部署 kubelet 组件

07-2.部署 kubelet 组件 kublet 运行在每个 worker 节点上,接收 kube-apiserver 发送的请求,管理 Pod 容器,执行交互式命令,如 exec.run.logs 等. kublet 启动时自动向 kube-apiserver 注册节点信息,内置的 cadvisor 统计和监控节点的资源使用情况. 为确保安全,本文档只开启接收 https 请求的安全端口,对请求进行认证和授权,拒绝未授权的访问(如 apiserver.heapster). 下载和分发 kub

[转贴]CentOS7.5 Kubernetes V1.13(最新版)二进制部署集群

CentOS7.5 Kubernetes V1.13(最新版)二进制部署集群 http://blog.51cto.com/10880347/2326146 一.概述 kubernetes 1.13 已发布,这是 2018 年年内第四次也是最后一次发布新版本.Kubernetes 1.13 是迄今为止发布间隔最短的版本之一(与上一版本间隔十周),主要关注 Kubernetes 的稳定性与可扩展性,其中存储与集群生命周期相关的三项主要功能已逐步实现普遍可用性. Kubernetes 1.13 的核心

K8S集群安装

主要参考 https://github.com/opsnull/follow-me-install-kubernetes-cluster 01.系统初始化和全局变量 添加 k8s 和 docker 账户 在每台机器上添加 k8s 账户,可以无密码 sudo: $ sudo useradd -m k8s $ sudo visudo $ sudo grep '%wheel.*NOPASSWD: ALL' /etc/sudoers %wheel ALL=(ALL) NOPASSWD: ALL $ su

二进制搭建kubernetes多master集群【四、配置k8s node】

上一篇我们部署了kubernetes的master集群,参考:二进制搭建kubernetes多master集群[三.配置k8s master及高可用] 本文在以下主机上操作部署k8s node k8s-node1:192.168.80.10 k8s-node2:192.168.80.11 k8s-node3:192.168.80.12 以下kubeadm和kubectl命令操作都是在k8s-master1上执行的. kubernetes work 节点运行如下组件: docker kubelet

高可用已填坑

01.系统初始化和全局变量 集群机器 test1:192.168.0.91 test2:192.168.0.92 test3:192.168.0.93 主机名 设置永久主机名称,然后重新登录: sudo hostnamectl set-hostname test1 # 将 test1 替换为当前主机名 设置的主机名保存在 /etc/hostname 文件中: 修改每台机器的 /etc/hosts 文件,添加主机名和 IP 的对应关系: grep kube-node /etc/hosts 192.

k8s控制平面apiserver集群安装

注意:如果没有特殊指明,本文档的所有操作均在 k8s-master 节点上执行,然后远程分发文件和执行命令. 1.创建 kubernetes 证书和私钥 创建证书签名请求: cd /opt/k8s/work source /opt/k8s/bin/environment.sh cat > kubernetes-csr.json <<EOF { "CN": "kubernetes", "hosts": [ "127.0.

K8S集群证书已过期且etcd和apiserver已不能正常使用下的恢复方案

在这种比较极端的情况下,要小心翼翼的规划和操作,才不会让集群彻底死翘翘.首先,几个ca根证书是10年期,应该还没有过期.我们可以基于这几个根证书,来重新生成一套可用的各组件认证证书. 前期,先制定以下方案步骤,能否实现,待验证. 一,制作证书的基本文件. Ca-csr.json(因为根证书是OK的,所以这个文件,可是列在这里,不会用上) { "CN": "kubernetes", "key": { "algo": "