kubectl命令详解+证书申请原理

需要配合老师写的文档一起学习。

文档名称叫常见问题排查及提问问题格式lts.docx,可使用everything工具快速查找到该文件。

1.1 kubectl命令详解

参考文档:https://kubernetes.io/zh-cn/docs/reference/kubectl/cheatsheet/

查看集群状态

[root@k8s-master01 calico]# kubectl get node
NAME           STATUS   ROLES                  AGE   VERSION
k8s-master01   Ready    control-plane,master   55m   v1.23.12
k8s-master02   Ready    control-plane,master   27m   v1.23.12
k8s-master03   Ready    <none>                 52m   v1.23.12
k8s-node01     Ready    <none>                 50m   v1.23.12
k8s-node02     Ready    <none>                 50m   v1.23.12

查看每个节点的Ip地址

[root@k8s-master01 calico]# kubectl get node -owide
NAME           STATUS   ROLES                  AGE   VERSION    INTERNAL-IP      EXTERNAL-IP   OS-IMAGE                KERNEL-VERSION                CONTAINER-RUNTIME
k8s-master01   Ready    control-plane,master   56m   v1.23.12   10.103.236.201   <none>        CentOS Linux 7 (Core)   4.19.12-1.el7.elrepo.x86_64   containerd://1.6.8
k8s-master02   Ready    control-plane,master   27m   v1.23.12   10.103.236.202   <none>        CentOS Linux 7 (Core)   4.19.12-1.el7.elrepo.x86_64   containerd://1.6.8
k8s-master03   Ready    <none>                 53m   v1.23.12   10.103.236.203   <none>        CentOS Linux 7 (Core)   4.19.12-1.el7.elrepo.x86_64   containerd://1.6.8
k8s-node01     Ready    <none>                 50m   v1.23.12   10.103.236.204   <none>        CentOS Linux 7 (Core)   4.19.12-1.el7.elrepo.x86_64   containerd://1.6.8
k8s-node02     Ready    <none>                 50m   v1.23.12   10.103.236.205   <none>        CentOS Linux 7 (Core)   4.19.12-1.el7.elrepo.x86_64   containerd://1.6.8

自动补全,考试的时候可以用自动补全

#安装bash-completion包
yum -y install bash-completion #或者
apt-get install bash-completion

source <(kubectl completion bash) # 在当前 shell 中设置自动补全
echo "source <(kubectl completion bash)" >> ~/.bashrc # 在你的 bash shell 中永久地添加自动补全
#设置完后需要重新连接机器才生效

kubectl工具是通过环境变量去找集群的,所以有时候报错找不到集群就检查一下环境变量

#如之前初始化加的环境变量
cat <<EOF >> /root/.bashrc
export KUBECONFIG=/etc/kubernetes/admin.conf #里面有集群地址跟证书
EOF
source /root/.bashrc

[root@k8s-master01 ~]# less /etc/kubernetes/admin.conf | grep server
    server: https://10.103.236.236:16443
    
#如果没有配置上述的环境变量,k8s会默认在这个目录下找,所以也可以把admin.conf放在该目录下
cat ~/.kube/config

# 显示合并的 kubeconfig 配置。视频04min04
kubectl config view 

#切换集群,用于多个集群的情况,考试会用到
kubectl config use-context my-cluster-name 

没有命名空间隔离的资源主要2个,一个是node,一个是角色clusterrole

#查看角色
kubectl get clusterrole

#查看使用命名空间的资源
kubectl api-resources --namespaced=true

#查看没有命名空间的资源
kubectl api-resources --namespaced=false

查询

kubectl get svc -n kube-system
kubectl get svc -A

#查看svc通过名称排序,考试会考
kubectl get services --sort-by=.metadata.name
# 列出 Pods,按重启次数排序,这里使用的是json的语法,视频20.33
kubectl get pods --sort-by='.status.containerStatuses[0].restartCount' -n kube-system

#查看标签 
kubectl get po -n kube-system --show-labels
#查看标签为k8s-app=calico-node的pod
kubectl get po -n kube-system -l k8s-app=calico-node
kubectl get po -n kube-system -l k8s-app=calico-node |grep Running

新增

kubectl create -f dashboard.yaml #如果已经存在会提示存在
kubectl apply -f dashboard.yaml #如果已经存在会更新配置

#执行多个
kubectl apply -f xx.yaml -f xx.yaml
kubectl apply -f xx.yaml,xx.yaml

#使用命令创建,之前使用的是yaml
kubectl create deployment nginx --image=nginx
kubectl get deploy nginx

考试的时候,不要手写yaml,用生成的pod导出,这样避免出错

kubectl get deploy nginx -oyaml

#只生成yaml文件,不创建资源
kubectl create deployment nginx --image=nginx --dry-run=client -oyaml > nginx-dp.yaml

删除

kubectl delete deploy nginx

#之前通过yaml文件创建了个用户,也可以使用yaml文件删除用户
kubectl delete -f user.yaml

#删pod需要指定命名空间,需要注意,删除pod会重启一个新的,因为他是通过deploy管理的
kubectl delete po dashboard-xxxxx -n kubernetes-dashboard

更新

kubectl create deploy nginx --image=nginx
kubectl get deploy 
kubectl get deploy nginx -oyaml #可以看到里面的容器会自动起名叫nginx ,视频23.33
kubectl set image deploy nginx nginx=nginx:v2 #更改镜像地址为nginx:v2

image-20221027172457994

kubectl edit deploy nginx #直接打开他的yaml文件

#查看帮助文档,一定要会看,写的很详细
kubectl set -h

#配置生效
kubectl replace -f user.yaml
kubectl apply -f user.yaml

查看容器日志

kubectl get pod 
kubectl logs -f xxxx #-f会一直追踪日志,如果有命名空间隔离的需要指定命名空间
kubectl logs -f xxxx --tail 20 #只看最后20行 

#如果pod中有多个容器,需要指定容器名字
kubectl edit deploy nginx #配两个容器,如下图

#查看pod中的指定容器
kubectl logs -f nginx-xxx -c redis

故障排查

pod正在创建中

image-20221027174306692

可以看到正在下载nginx镜像

image-20221027174325100

kubectl logs #这个命令只针对pod使用,而describe哪种资源都能使用
kubectl describe deploy nginx

执行命令

kubectl exec nginx-xxxx -- ls #对容器nginx执行ls命令
#进入容器
kubectl exec -it nginx-xxx -- bash #没有bash用sh

查看资源,考试必考

kubectl top node
kubectl top pod
#cpu单位m:代表 “千分之一核心”,譬如50m的含义是指50/1000核心,即5%

1.2 Kubelet启动过程

apiserver,ControllerManager,Scheduler的证书是我们手动颁发的,kubelet的证书是自动颁发的。

#kubeconfig配置文件目录如下
[root@k8s-master01 kubernetes]# ls /etc/kubernetes/
admin.kubeconfig              controller-manager.kubeconfig  kubelet.kubeconfig     kube-proxy.yaml  pki
bootstrap-kubelet.kubeconfig  kubelet-conf.yml               kube-proxy.kubeconfig  manifests        scheduler.kubeconfig

kubeconfig文件中有证书信息以及apiserver的地址

image-20221108123927127

回顾二进制安装k8s那一章,我们会把证书路径跟kubeconfig文件写入.service启动文件中

[root@k8s-master01 kubernetes]# ls /usr/lib/systemd/system/kube
kube-apiserver.service           kubelet.service                  kube-scheduler.service
kube-controller-manager.service  kube-proxy.service

这样启动服务就会去找证书跟kubeconfig文件,去访问apiserver。

但是kubelet不建议使用手动颁发证书,因为当节点有成百上千个的时候,手动颁发证书不现实。

所以kubelet引用了TLS Bootstrapping来帮我们自动颁发证书。

颁发过程如下

当kubelet进程启动时发现没有kubelet.kubeconfig文件,就会带着bootstrap-kubelet.kubeconfig跟apiserver进行交互,然后生成kubelet.kubeconfig文件,之后再启动kubelet进程。

kubelet.service启动文件中会指定bootstrap-kubelet.kubeconfig跟kubelet.kubeconfig文件路径。

#测试
rm -rf /etc/kubernetes/kubelet.kubeconfig
systemctl restart kubelet
ls /etc/kubernetes/kubelet.kubeconfig

官方文档:https://kubernetes.io/docs/reference/access-authn-authz/kubelet-tls-bootstrapping/

中文文档:https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/kubelet-tls-bootstrapping/

k8s 1.4版本引入TLS Bootstrapping

kubelet启动步骤:

a) 查找kubeconfig文件,文件一般位于/etc/kubernetes/kubelet.kubeconfig

b) 从kubeconfig文件中检索APIServer的URL和证书

c) 然后去和APIServer进行交互

查看kubelet证书有效期,证书是经过base64加密的

cd  /etc/kubernetes/
#复制证书
more kubelet.kubeconfig 
#解密
echo "xxxxxxxxxxx==" " | base64 --decode > /tmp/decode.txt

#查看证书有效期
openssl x509 -in /tmp/1 -noout -dates
#输出
notBefore=Oct 28 14:05:00 2022 GMT
notAfter=Oct  4 14:05:00 2122 GMT #可以看到证书是2122年10月4日过期

1.3 CSR申请和证书颁发原理

  1. Kubelet服务进程启动
  2. Kubelet查找kubelet.kubeconfig文件,如果没有这个文件
  3. Kubelet会找本地的bootstrap.kubeconfig文件
  4. Kubelet读取bootstrap.kubeconfig文件,检索apiserver的url和一个token
  5. Kubelet连接apiserver,使用这个token进行认证
    1. Apiserver会识别token id,apiserver会查看该token id对应的secret是否一致,如果一致
    2. 接着apiserver会找到这个secret中的auth-extra-groups字段,经过base64解密后发现属于system:bootstrappers:default-node-token组,该组的权限绑定在一个叫system:node-bootstrapper的clusterrole上,该clusterrole具有申请csr的权限(具体查看后续的补充说明)
    3. 可简记为找tokenid→secret→用户组→用户组绑定角色→角色具有申请csr权限。
  6. 经过上面的认证,kubelet就有了一个创建和检索CSR的权限
  7. Kubelet为自己创建一个CSR,名称为kubernetes.io/kube-apiserver-client-kubelet
  8. CSR被允许有两种方式:
  9. K8s管理员使用kubectl命令手动颁发证书
  10. 如果配置了相关权限,kube-controller-manager会自动同意。
    1. Controller-manager有一个名为CSRApprovingController控制器。他会校验kubelet发来的csr的group是否有创建csr的权限,而且还要验证签发者是否是kubernetes.io/kube-apiserver-client-kubelet(具体查看后续的补充说明)
    2. Controller-manager同意CSR请求
  11. CSR被同意后,controller-manager创建kubelet的证书文件
  12. Controller-manager将证书更新至csr的status字段
  13. Kubelet从apiserver获取证书
  14. Kubelet从获取到的key和证书文件创建kubelet.kubeconfig
  15. Kubelet启动完成并正常工作
  16. 可选:如果配置了自动续期,kubelet会在证书文件过期的时候利用之前的kubeconfig文件去申请一个新的证书,相当于续约。
  17. 新的证书被同意或签发,取决于我们配置的是手动签发还是自动签发,如果是自动签发,自动生成的CSR文件同样会有O(组织),CN等信息(具体查看后续的补充说明)
    1. Kubelet自动创建的CSR是属于一个名为system:nodes的组织,即O:system:nodes
    2. 创建的CN格式为CN:system:nodes:主机名

补充说明:

我们需要搞明白bootstrap-kubelet.kubeconfig文件中的token是kubectl命令配置上下文写入到该文件中的。

bootstrap创建的secret,使用的是/root/k8s-ha-install/bootstrap/bootstrap.secret.yaml文件,该文件中有token,与上述kubeconfig文件中的token是一一对应的。

apiserver会通过token id找到对应的secret,检查两者secret是否一致。

#使用 bootstrap.secret.yaml 创建的secret
kubectl create -f bootstrap.secret.yaml 
secret/bootstrap-token-c8ad9c created #secret在这里
clusterrolebinding.rbac.authorization.k8s.io/kubelet-bootstrap created 
clusterrolebinding.rbac.authorization.k8s.io/node-autoapprove-bootstrap created
clusterrolebinding.rbac.authorization.k8s.io/node-autoapprove-certificate-rotation created
clusterrole.rbac.authorization.k8s.io/system:kube-apiserver-to-kubelet created
clusterrolebinding.rbac.authorization.k8s.io/system:kube-apiserver created

#查看secret,有个bootstrap-token-c8ad9c证书
kubectl get secret -n kube-system
kubectl get secret bootstrap-token-c8ad9c -n kube-system -oyaml

#因为是base64加密的,所以需要解密
echo "YzhhZDlj" | base64 -d
c8ad9c #可以看到跟bootstrap-kubelet.kubeconfig中的token id是一样的
echo "MmU0ZDYxMGNmM2U3NDI2ZQ==" | base64 -d
2e4d610cf3e7426e #可以看到解密出来的secret跟token是一致的

image-20221108155334080

image-20221108155037666

补充说明

  1. clusterrole 是集群权限角色,定义拥有什么权限,比如申请证书的权限
  2. clusterrolebinding 是集群权限的绑定,将clusterrole绑定到组,该组就拥有了某些权限
  3. CSR:相当于一个申请表,用来申请证书,里面有公司,域名等信息

我们先来查看名为system:node-bootstrapper的clusterrole

kubectl get clusterrole | grep system:node-bootstrapper
kubectl get clusterrole system:node-bootstrapper -oyaml

可以看到system:node-bootstrapper角色具有申请证书的权限,即create,get,list,watch

image-20221108164745151

再来看看之前的secret所属组

kubectl get secret bootstrap-token-c8ad9c -n kube-system -oyaml
#查看auth-extra-groups字段,这个是token id的所属组

echo "c3lzdGVtOmJvb3RzdHJhcHBlcnM6ZGVmYXVsdC1ub2RlLXRva2VuLHN5c3RlbTpib290c3RyYXBwZXJzOndvcmtlcixzeXN0ZW06Ym9vdHN0cmFwcGVyczppbmdyZXNz"  | base64 -d
#解密后发现该token是属于system:bootstrappers:default-node-token组
system:bootstrappers:default-node-token,system:bootstrappers:worker,system:bootstrappers:ingress

那么角色跟组是如何绑定在一起的呢?这就需要另外一个名为clusterrolebinding的东西。

查看之前使用 bootstrap.secret.yaml文件创建的名为kubelet-bootstrap的clusterrolebinding

#使用 bootstrap.secret.yaml 创建的kubelet-bootstrap
kubectl create -f bootstrap.secret.yaml 
secret/bootstrap-token-c8ad9c created
clusterrolebinding.rbac.authorization.k8s.io/kubelet-bootstrap created #创建的kubelet-bootstrap
clusterrolebinding.rbac.authorization.k8s.io/node-autoapprove-bootstrap created
clusterrolebinding.rbac.authorization.k8s.io/node-autoapprove-certificate-rotation created
clusterrole.rbac.authorization.k8s.io/system:kube-apiserver-to-kubelet created
clusterrolebinding.rbac.authorization.k8s.io/system:kube-apiserver created

kubectl get clusterrolebinding kubelet-bootstrap
kubectl get clusterrolebinding kubelet-bootstrap -oyaml

可以看到将角色system:node-bootstrapper绑定到system:bootstrappers:default-node-token组上。

image-20221108165539373

参考:二进制安装k8s集群文档中的 五、TLS Bootstrapping配置

补充说明

查看自动同意签发证书的clusterrolebinding

#使用 bootstrap.secret.yaml 创建的node-autoapprove-bootstrap,该clusterrolebinding为我们自动同意签发证书
kubectl create -f bootstrap.secret.yaml 
secret/bootstrap-token-c8ad9c created
clusterrolebinding.rbac.authorization.k8s.io/kubelet-bootstrap created
clusterrolebinding.rbac.authorization.k8s.io/node-autoapprove-bootstrap created #在这里
clusterrolebinding.rbac.authorization.k8s.io/node-autoapprove-certificate-rotation created
clusterrole.rbac.authorization.k8s.io/system:kube-apiserver-to-kubelet created
clusterrolebinding.rbac.authorization.k8s.io/system:kube-apiserver created

kubectl get clusterrolebinding node-autoapprove-bootstrap -oyaml

可以看到clusterrolebinding绑定的角色image-20221108172820458

kubectl get clusterrole system:certificates.k8s.io:certificatesigningrequests:nodeclient -oyaml

可以看到该角色拥有创建证书的权限

补充说明

如果配置的是自动续期,会自动创建的CSR文件,但是该会被自动清理,所以我们看不到CSR文件,但是可以看到绑定的角色的权限是续期证书的权限。

#使用 bootstrap.secret.yaml 创建的node-autoapprove-certificate-rotation,该clusterrolebinding可以为证书续期
kubectl create -f bootstrap.secret.yaml 
secret/bootstrap-token-c8ad9c created
clusterrolebinding.rbac.authorization.k8s.io/kubelet-bootstrap created
clusterrolebinding.rbac.authorization.k8s.io/node-autoapprove-bootstrap created
clusterrolebinding.rbac.authorization.k8s.io/node-autoapprove-certificate-rotation created #在这里
clusterrole.rbac.authorization.k8s.io/system:kube-apiserver-to-kubelet created
clusterrolebinding.rbac.authorization.k8s.io/system:kube-apiserver created

#查看该clusterrolebinding绑定的clusterrole
kubectl get clusterrolebinding node-autoapprove-certificate-rotation -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  creationTimestamp: "2022-10-30T08:27:28Z"
  name: node-autoapprove-certificate-rotation
  resourceVersion: "43367"
  uid: 9840b03b-20d9-48b3-8564-56736c9eab2d
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:certificates.k8s.io:certificatesigningrequests:selfnodeclient #这里
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: system:nodes #绑定的system:nodes组
  
#查看该clusterrole的权限
kubectl get clusterrole system:certificates.k8s.io:certificatesigningrequests:selfnodeclient -oyaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  creationTimestamp: "2022-10-29T06:40:43Z"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
  resourceVersion: "107"
  uid: 41d24b9c-ae11-42f6-8fe6-1d810e25960f
rules:
- apiGroups:
  - certificates.k8s.io
  resources:
  - certificatesigningrequests/selfnodeclient #证书续期权限
  verbs:
  - create

如果配置的是手动续期,是可以看到CSR文件的

kubectl get csr #可以看到请求的scr

#一个标准的CSR文件内容如下
[root@k8s-master01 bootstrap]# cd /root/k8s-ha-install/pki/
[root@k8s-master01 pki]# more kubelet-csr.json 
{
  "CN": "system:node:$NODE",  #可以看到跟主机名相关,所以说每个服务器的CSR都不是一样的,手动申请证书需要一个一个来,续约也是,所以很麻烦,需要自动申请跟续约
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "L": "Beijing",
      "ST": "Beijing",
      "O": "system:nodes", 
      "OU": "Kubernetes-manual"
    }
  ]
}

1.4 生产环境中的配置

配置一

如果使用的是docker作为runtime

vim /etc/docker/daemon.json
{
 "registry-mirrors": [
    "https://registry.docker-cn.com",
    "http://hub-mirror.c.163.com",
    "https://docker.mirrors.ustc.edu.cn"
  ],
 "exec-opts": ["native.cgroupdriver=systemd"],
 "max-concurrent-downloads": 10, 

 "max-concurrent-uploads": 5, 

 "log-opts": { 

   "max-size": "300m", 

   "max-file": "2" 

 }, 

 "live-restore": true 

} 

配置二

证书轮询配置

我目前使用的是v1.23.13版本

中文文档:https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/kubelet-tls-bootstrapping/

打开中文文档,可以看到有两种认证方式,我们目前使用的是Bootstrap Token验证。

也可以使用Token认证文件认证,需要自行研究一下。

image-20221108220126982

注意一下证书轮换,参数已经默认开启了

image-20221108221022574

可以看到参数是默认开启的

kube-controller-manager -h | grep RotateKubeletServerCertificate

image-20221108222351425

还有一个参数RotateKubeletClientCertificate,在v1.19版本就不在这里了,但也是默认开启的。

可以看到kubelet-conf.yml文件中rotateCertificates也是开启的。

该kubelet-conf.yml被/etc/systemd/system/kubelet.service.d/10-kubelet.conf文件引用,kubelet启动时会被自动读取。

vim /etc/kubernetes/kubelet-conf.yml
...
rotateCertificates: true
...

1.5 集群注意事项

自动化安装可以使用Ansible

  1. Master节点安装不需要写自动化。
  2. 添加Node节点,playbook。

生产环境中etcd一定要和系统盘分开,一定要用ssd硬盘。

Docker数据盘也要和系统盘分开,有条件的话可以使用ssd硬盘

1.6 参考资料

posted @ 2022-12-20 12:26  努力吧阿团  阅读(1013)  评论(0编辑  收藏  举报