19-Kubernetes进阶之学习企业实践扩充记录

2022-09-29 17:09:38 浏览数 (1)

[TOC]

0x01 Kubernetes 中安装metrics-server以获取客户端资源监控指标

描述: 通常在集群安装完成后,我们需要对其设置持久卷、网络存储等插件, 除此之外我们还需安装metrics-server以便于获取Node与Pod相关资源消耗等信息,否则你在执行kubectl top命令时会提示error: Metrics API not available, 所以本小节将针对Metrics-server的安装进行讲解。

项目地址: https://github.com/kubernetes-sigs/metrics-server

Q: 什么是metrics-server?

Metrics Server 是 Kubernetes 内置自动缩放管道的可扩展、高效的容器资源指标来源。 Metrics Server 从 Kubelets 收集资源指标,并通过 Metrics API 在 Kubernetes apiserver 中公开它们,供 Horizo​​ntal Pod Autoscaler 和 Vertical Pod Autoscaler 使用。

简单的说: Metrics Server 是集群解析监控数据的聚合器,安装后用户可以通过标准的API(/apis/metrics.k8s.io)来访问监控数据,此处值得注意的是Metrics-Server并非kube-apiserver的一部分,而是通过Aggregator这种插件机制,在独立部署的情况下同kube-apiserver一起统一对外服务的,当进行api请求时kube-aggregator统一接口会分析访问api具体的类型,帮我们负载到具体的api上。

代码语言:javascript复制
GET /apis/metrics.k8s.io/V1beta1
            |
      Kube-aggregator
      |              |                 |
Kube-apiserver  Metrics-server another-add-onapiserver

Metrics Server 特点:

  • 适用于大多数集群的单一部署(请参阅要求)
  • 快速自动缩放,每 15 秒收集一次指标。
  • 资源效率,集群中每个节点使用 1 mili 的 CPU 核心和 2 MB 的内存。
  • 可扩展支持多达 5,000 个节点集群。

Metrics Server 功能:(horizontalpodautoscalers.autoscaling 水平扩展必备)

  • 基于CPU/内存的水平自动缩放
  • 自动调整/建议容器所需的资源

Metrics Server 访问流程图

WeiyiGeek.访问流程图

温馨提示: 我们可以通过 kubectl top 命令来访问 Metrics API 获取资源监控相关数据。 温馨提示: 注意 Metrics API 只可以查询当前度量数据,并不保存历史数据。

安装使用 步骤 01.Metrics Server 可以直接从 YAML 清单安装,也可以通过官方 Helm 图表安装。

代码语言:javascript复制

# 下载 YAML 清单
wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

# 提前下载相应的镜像加快部署
grep "image:" components.yaml
# image: k8s.gcr.io/metrics-server/metrics-server:v0.6.1

# 由于其镜像国内无法访问此处我们采用阿里云k8s.gcr.io镜像源
sed -i 's#k8s.gcr.io/metrics-server#registry.cn-hangzhou.aliyuncs.com/google_containers#g' components.yaml

# 部署资源清单
kubectl apply -f components.yaml
  # serviceaccount/metrics-server created
  ......
  # apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created

步骤 02.Metrics Server 默认是安装在kube-system名称空间下,我们可以查看其deployment、Pod运行以及SVC情况。

代码语言:javascript复制
# 1.部署清单状态查看
kubectl get deploy,pod,svc -n kube-system -l k8s-app=metrics-server
# NAME                             READY   UP-TO-DATE   AVAILABLE   AGE
# deployment.apps/metrics-server   1/1     1            0           91s

# NAME                                  READY   STATUS    RESTARTS   AGE
# pod/metrics-server-6ffc8966f5-cf2qh   1/1     Running   0          91s

# NAME                     TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
# service/metrics-server   ClusterIP   10.96.28.153   <none>        443/TCP   91s

# 2.注册到K8S集群中的 metrics.k8s.io API 查看
kubectl get apiservices.apiregistration.k8s.io  | grep "metrics"
  # v1beta1.metrics.k8s.io                 kube-system/metrics-server   True        14h

步骤 03.查看各个节点以及Pod的资源指标(CPU/MEM)

代码语言:javascript复制
$ kubectl top node
  NAME         CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
  master-223   102m         2%     1147Mi          61%
  master-224   119m         2%     2188Mi          57%
  master-225   139m         3%     3773Mi          48%
  node-1       54m          1%     921Mi           49%
  node-2       61m          1%     824Mi           44%

# 默认名称空间中Pod的资源信息
$  kubectl top pod
  NAME                          CPU(cores)   MEMORY(bytes)
  hello-nginx-7f4ff84cb-mjw79   0m           6Mi
  nginx-web-0                   0m           6Mi
  nginx-web-1                   0m           5Mi

问题解决:

问题1.部署 metrics-server 资源清单后 Pod 状态为 0/1 并报出annot validate certificate for 10.10.107.223 because it doesn't contain any IP SANs"错误问题解决。

错误信息:

代码语言:javascript复制
$ kubectl describe pod -n kube-system metrics-server-6ffc8966f5-cf2qh
  # Warning  Unhealthy  8s (x17 over 2m27s)  kubelet            Readiness probe failed: HTTP probe failed with statuscode: 500

$ kubectl logs -f --tail 50 -n kube-system metrics-server-6ffc8966f5-cf2qh
  # E0520 11:13:17.379944       1 scraper.go:140] "Failed to scrape node" err="Get "https://10.10.107.226:10250/metrics/resource": x509: cannot validate certificate for 10.10.107.226 because it doesn't contain any IP SANs" node="node-1"
  # E0520 11:13:17.382948       1 scraper.go:140] "Failed to scrape node" err="Get "https://10.10.107.223:10250/metrics/resource": x509: cannot validate certificate for 10.10.107.223 because it doesn't contain any IP SANs" node="master-223"

问题原因: 由于 metrics-server 未获得TLS Bootstrap 签发证书的导致访问各节点资源时报错。

解决办法: 启用 TLS BootStrap 证书签发

代码语言:javascript复制
# 1.分别在 Master 与 Node 节点中启用TLS BootStrap 证书签发,在 kubelet 的 yaml 配置中追加入如下K/V.
# 方式1.Kubeadm 搭建的集群
$ vim /var/lib/kubelet/config.yaml
...
serverTLSBootstrap: true

# 方式2.二进制搭建的集群(注意此路径根据你的kubelet.service进行配置), 此处我们定义的路径为 /etc/kubernetes/cfg/kubelet-config.yaml 
# /var/lib/kubelet/config.yaml
$ tee -a /etc/kubernetes/cfg/kubelet-config.yaml <<'EOF'
serverTLSBootstrap: true
EOF

# kubeadm 安装方式可以使用如下
tee -a /var/lib/kubelet/config.yaml <<'EOF'
serverTLSBootstrap: true
EOF

# 2.最后分别重启各个节点kubelet服务即可
systemctl daemon-reload && systemctl restart kubelet.service

# 3.查看节点的证书签发请求
kubectl get csr
  # NAME        AGE     SIGNERNAME                      REQUESTOR                REQUESTEDDURATION   CONDITION
  # csr-2m5d6   2m27s   kubernetes.io/kubelet-serving   system:node:master-223   <none>              Pending
  # csr-ff7vb   19m     kubernetes.io/kubelet-serving   system:node:master-225   <none>              Pending
  # csr-gg8gq   86s     kubernetes.io/kubelet-serving   system:node:master-224   <none>              Pending
  # csr-56k9s   55s     kubernetes.io/kubelet-serving   system:node:node-1       <none>              Pending
  # csr-dmghl   3s      kubernetes.io/kubelet-serving   system:node:node-2       <none>              Pending

# 4.手动允许节点证书签发请求
kubectl certificate approve $( kubectl get csr | grep -v NAME | grep "Pending"  | cut -d " " -f 1)
kubectl certificate approve csr-2m5d6
kubectl certificate approve csr-56k9s
kubectl certificate approve csr-ff7vb
kubectl certificate approve csr-gg8gq
  # certificatesigningrequest.certificates.k8s.io/csr-gg8gq approved

# 5.查看签发的 certificate 特征
kubectl get csr csr-dmghl
  # NAME        AGE     SIGNERNAME                      REQUESTOR           REQUESTEDDURATION   CONDITION
  # csr-dmghl   10m    kubernetes.io/kubelet-serving   system:node:node-2   <none>              Approved,Issued

0x02 Kubernetes 中Session的会话保持

背景说明: 基于kubernetes集群中部署Java项目,您发现在多pod模式下会出现登录成功但是页面无法跳转的问题,或验证明明输入正确却提示验证码错误无法登陆,而在单一pod时却可以成功登录并页面正常跳转,于是推测是cookie的问题。

解决方式: 进行K8S会话粘粘与保持, 但是针对于不同的实践环境又有所不同,例如采用ClusterIP、NodePort方式或者Ingress访问来访问我们的应用。

Service 描述: 网上的大部分文章提供的解决方案都是在service的配置文件中加入sessionAffinity: ClientIP,功能是选择与请求来源ip更接近的pod,这样就会固定同一个session但可能会出现流量负载不均衡的情况。

演示案例:

代码语言:javascript复制
apiVersion: v1
kind: Service
metadata:
  name: tomcat
  namespace: default
spec:
  selector:
    app: tomcat
    release: canary
  ports:
  - name: http
    targetPort: 8280
    port: 8280
  sessionAffinity: ClientIP

ingress-nginx 在ingress-nginx配置中应做以下操作:

  • 设置 nginx.ingress.kubernetes.io/affinity 属性,启用会话保持, 其值仅仅支持Cookie。
  • 设置 nginx.ingress.kubernetes.io/affinity-mode 属性,设置为balanced在集群扩大pod时,会自动分配一些会话到新创建的pod上,用于平衡服务器的负载;设置为persistent则永远保证用户访问pod的一致性,不会访问到其他pod,其值支持balanced (默认设置) or persistent
  • 设置 nginx.ingress.kubernetes.io/session-cookie-name 属性,自定义cookie名称, 其默认设置为 INGRESSCOOKIE,但我们可自定义。

演示案例:

代码语言:javascript复制
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/affinity-mode: "persistent"
    nginx.ingress.kubernetes.io/session-cookie-name: "route"
    nginx.ingress.kubernetes.io/cors-allow-origin: '*'
    nginx.ingress.kubernetes.io/cors-max-age: "64800"
  labels:
    app: front-web
    ref: front
  name: front-app
  namespace: web
spec:
  ingressClassName: ingress-nginx
  rules:
  - host: app.weiyigeek.top
    http:
      paths:
      - path: /
        pathType: ImplementationSpecific
        backend:
          service:
            name: front-index
            port:
              number: 80
      - path: /sub/
        pathType: ImplementationSpecific
        backend:
        service:
          name: front-sub
          port:
            number: 80
  tls:
  - hosts:
    - app.weiyigeek.top
    secretName: app-weiyigeek-top

官方参考: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#session-affinity


0x03 Kubernetes 中多集群接入管理实践

描述: 在pipeline中的CD环节,常常需要将业务产品部署到不同的K8S集群,比如开发环境、测试环境、生产环境,此时可以使用 kubectl config相关命令来进行多个远程集群的配置并采用rbac授权机制来创建指定用户的权限 。

下面我们从两个方面进行验证,一是在本地集群创建指定用户只能访问特定名称空间的资源,二是指定用户接入远程集群中并且只能访问特定名称空间的资源, 我们需要重点关注三大要素即 集群(clusters)、上下文(contexts)、用户(user)

config 命令下重要配置项说明:

  • clusters :配置要访问的kubernetes集群
  • contexts :配置访问kubernetes集群的具体上下文环境
  • current-context : 配置当前使用的上下文环境
  • users : 配置访问的用户信息,用户名以及证书信息

1.本地集群创建指定用户管理集群

为当前集群创建一个只管理指定名称空间权限的devopsuser用户 描述: kubernetes 中我们可将权限进行细化、使得使用者可以拥有最小的运行权限,保证集群的安全,特别是CI/CD环境中,下面将演示在kubernetes集群中创建一个只管理名称空间为devtest的devopsuser用户。

步骤 01.创建一个devtest的名称空间, 执行如下命令kubectl create namespace devtest.

步骤 02.执行kubectl config get-clusters命令查看当前集群名称,通常默认为kubernetes.

步骤 03.准备cfssl工具以及生成用户证书的相关json文件。

代码语言:javascript复制
$ tee ca-config.json << 'EOF'
{
  "signing": {
    "default": {
        "expiry": "87600h"
    },
    "profiles": {
      "kubernetes": {
          "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
          ],
          "expiry": "87600h"
        }
      }
  }
}
EOF

$ tee devopsuser-csr.json << 'EOF'
{
  "CN": "devopsuser",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "ChongQing",
      "L": "ChongQing",
      "O": "k8s",
      "OU": "System"
    }
  ]
}
EOF

步骤 04.执行如下命令为devopsuser用户生成相应的证书,并将证书复制到 /etc/kubernetes/pki/user/目录中。

代码语言:javascript复制
# 生成用户证书
cfssl gencert -ca=/etc/kubernetes/pki/ca.crt -ca-key=/etc/kubernetes/pki/ca.key -config ./ca-config.json -profile=kubernetes ./devopsuser-csr.json | cfssljson -bare devopsuser
  # 2022/03/16 19:40:19 [INFO] generate received request
  # 2022/03/16 19:40:19 [INFO] received CSR
  # 2022/03/16 19:40:19 [INFO] generating key: rsa-2048
  # 2022/03/16 19:40:19 [INFO] encoded CSR
  # 2022/03/16 19:40:19 [INFO] signed certificate with serial number 648194491978037048405922455454162128168023396626

# 查看生成的证书以及申请文件 (后三个新生成)
ls
ca-config.json devopsuser-csr.json  devopsuser.csr   devopsuser-key.pem  devopsuser.pem

# 证书到期时间
openssl x509 -in devopsuser.pem -noout -text  | grep -E 'Not'
  Not Before: Mar 16 11:35:00 2022 GMT
  Not After : Mar 13 11:35:00 2032 GMT

# 新建用户证书存放目录创建并将生成的证书密钥与证书复制到该目录中。
mkdir -vp /etc/kubernetes/pki/user/
cp -a devopsuser*.pem /etc/kubernetes/pki/user/

步骤 05.查看本地或者远程集群的API_SERVER地址,并将其写入到devopsuser.kubeconfig文件之中。

代码语言:javascript复制
kubectl cluster-info  | grep "control plan"
  # Kubernetes control plane is running at https://slb-vip.k8s:16443

# 设置集群参数写入到devopsuser.kubeconfig文件中
KUBE_APISERVER="https://slb-vip.k8s:16443"
kubectl config set-cluster kubernetes 
  --certificate-authority=/etc/kubernetes/pki/ca.crt 
  --embed-certs=true 
  --server=${KUBE_APISERVER} 
  --kubeconfig=/root/.kube/devopsuser.kubeconfig
# Cluster "kubernetes" set.

步骤 06.为devopsuser用户创建一个devops-ctx上下文,并指定名称空间为devtest(在此上下文中在有rbac权限的情况下,只能操作该空间下的资源)并将配置写入到devopsuser.kubeconfig中。

代码语言:javascript复制
kubectl config set-context devopsuser-ctx --cluster=kubernetes --user=devopsuser --namespace=devtest --kubeconfig=/root/.kube/devopsuser.kubeconfig
  # Context "devopsuser-ctx" created.

步骤 07.在kubeconfig中设置devopsuser用户条目客户端参数,并将配置写入到devopsuser.kubeconfig中。

代码语言:javascript复制
kubectl config set-credentials devopsuser --cluster=kubernetes 
  --client-certificate=/etc/kubernetes/pki/user/devopsuser.pem  
  --client-key=/etc/kubernetes/pki/user/devopsuser-key.pem 
  --embed-certs=true 
  --kubeconfig=/root/.kube/devopsuser.kubeconfig
  # User "devopsuser" set.

步骤 08.查看生成的devopsuser.kubeconfig文件.

代码语言:javascript复制
$ cat devopsuser.kubeconfig
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: [api-server CA证书-base64编码]
    server: https://slb-vip.k8s:16443  # API Server 地址
  name: kubernetes
contexts:
- context:               
    cluster: kubernetes  # 集群名称
    namespace: devtest   # 名称空间 
    user: devopsuser     # 此上下文中的用户
  name: devopsuser-ctx   # 上下文名称
current-context: ""
kind: Config
preferences: {}
users:
- name: devopsuser       # 创建的用户,认证方式为CA签名的证书。
  user:
    client-certificate-data: [客户端证书-base64编码]
    client-key-data: [客户端密钥-base64编码]

步骤 09.RoleBinding 角色绑定,为devopsuser用户创建rolerolebinding,利用rbac进行资源访问操作权限的管控。

代码语言:javascript复制
# 方式1.命令行方式(一步到位),生产环境中间建议为指定用户划分需要资源的权限。
kubectl create rolebinding devopsuser-admin --clusterrole=admin --user=devopsuser --namespace=devtest

# 方式2.资源清单方式
# Role 名称:devtest-role
# RoleBinding 名称:devopsuser-admin
tee devopsuser-rolebinding.yaml <<'EOF'
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: devtest-role
  namespace: devtest
rules:
- apiGroups:
  - ""
  resources:
  - pods
  - pods/attach
  - pods/exec
  - pods/portforward
  - pods/proxy
  verbs:
  - create
  - delete
  - deletecollection
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - ""
  resources:
  - configmaps
  - endpoints
  - persistentvolumeclaims
  - replicationcontrollers
  - replicationcontrollers/scale
  - secrets
  - serviceaccounts
  - services
  - services/proxy
  verbs:
  - create
  - delete
  - deletecollection
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - ""
  resources:
  - bindings
  - events
  - limitranges
  - pods/log
  - pods/status
  - replicationcontrollers/status
  - resourcequotas
  - resourcequotas/status
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - serviceaccounts
  verbs:
  - impersonate
- apiGroups:
  - apps
  resources:
  - deployments
  - deployments/rollback
  - deployments/scale
  - statefulsets
  verbs:
  - create
  - delete
  - deletecollection
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - autoscaling
  resources:
  - horizontalpodautoscalers
  verbs:
  - create
  - delete
  - deletecollection
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - batch
  resources:
  - cronjobs
  - jobs
  - scheduledjobs
  verbs:
  - create
  - delete
  - deletecollection
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - extensions
  resources:
  - daemonsets
  - deployments
  - deployments/rollback
  - deployments/scale
  - ingresses
  - replicasets
  - replicasets/scale
  - replicationcontrollers/scale
  verbs:
  - create
  - delete
  - deletecollection
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - authorization.k8s.io
  resources:
  - localsubjectaccessreviews
  verbs:
  - create
---
# roleRef 角色来源为 devtest-role
# subjects 赋予角色给 devopsuser 用户
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: devopsuser-admin
  namespace: devtest
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: devtest-role
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: devopsuser
EOF

kubectl apply -f devopsuser-rolebinding.yaml
  # role.rbac.authorization.k8s.io/devtest-role unchanged
  # rolebinding.rbac.authorization.k8s.io/devopsuser-admin created

步骤 10.指定devopsuser用的kubeconfig并切换用户上下文。

代码语言:javascript复制
# 切换用户上下文
kubectl config use-context devopsuser-ctx --kubeconfig=/root/.kube/devopsuser.kubeconfig
# Switched to context "devopsuser-ctx".

# 查看当前上下文
kubectl config current-context --kubeconfig=/root/.kube/devopsuser.kubeconfig
# devopsuser-ctx

# 当前上下文中的用户
kubectl config get-users --kubeconfig=/root/.kube/devopsuser.kubeconfig
  # NAME
  # devopsuser

步骤 11.验证创建devopsuser用户的权限。

代码语言:javascript复制
# 无权限查看节点以及操作其它名称空间的资源
kubectl --kubeconfig=/root/.kube/devopsuser.kubeconfig get node
  # Error from server (Forbidden): nodes is forbidden: User "devopsuser" cannot list resource "nodes" in API group "" at the cluster scope

# 创建一个pod
kubectl --kubeconfig=/root/.kube/devopsuser.kubeconfig run nginx --image=nginx:latest --namespace devtest --labels="app=nginx" --port=8080
# pod/nginx created

# 查看Pod运行状态
kubectl --kubeconfig=/root/.kube/devopsuser.kubeconfig get pod -n devtest
  # NAME    READY   STATUS    RESTARTS   AGE
  # nginx   1/1     Running   0          37s

# 保留Pod服务 
kubectl --kubeconfig=/root/.kube/devopsuser.kubeconfig expose pod nginx -n devtest --port=8080 --name=nginx-frontend
  # service/nginx-frontend exposed

# 查看服务
kubectl --kubeconfig=/root/.kube/devopsuser.kubeconfig get pod -n devtest -l app=nginx -o wide
  # NAME    READY   STATUS    RESTARTS   AGE     IP              NODE       NOMINATED NODE   READINESS GATES
  # nginx   1/1     Running   0          3h29m   10.66.182.255   weiyigeek-226   <none>           <none>

至此完毕!

2.外部集群创建指定用户管理集群

描述: 在本地集群接入外部集群时我们需要获得其api-server地址(注意如果没有域名解析请做硬解析),以及ca证书, 此处同样以访问devtes名称空间为例。

步骤 01.外部集群信息及其CA证获取。

代码语言:javascript复制
# 远程集群中执行如下命令查看集群相关
$ kubectl cluster-info
  # Kubernetes control plane is running at https://apiserver.cluster.weiyigeek:6443

$ ping apiserver.cluster.weiyigeek
  # PING apiserver.cluster.weiyigeek (192.168.12.102) 56(84) bytes of data.
  # 64 bytes from weiyigeek-102 (192.168.12.102): icmp_seq=1 ttl=64 time=0.134 ms

# 配置硬解析
sudo tee -a /etc/hosts <<'EOF'
192.168.12.102 apiserver.cluster.weiyigeek 
EOF

# 将外部集群ca证书将其复制到现有机器上
ls /etc/kubernetes/pki/ca.crt && cat /etc/kubernetes/pki/ca.crt
cat > cluster.prod.ca.crt <<'EOF'
-----BEGIN CERTIFICATE-----
[上面显示的 base64 编码]
-----END CERTIFICATE-----
EOF

步骤02.在本地集群中利用kubectl config set-cluster命令设置远程集群。

代码语言:javascript复制
KUBE_APISERVER="https://apiserver.cluster.weiyigeek:6443"
kubectl config set-cluster k8s-cluster 
  --certificate-authority=./cluster.prod.ca.crt 
  --embed-certs=true 
  --server=${KUBE_APISERVER} 
  --kubeconfig=/root/.kube/devops.kubeconfig

步骤03.在本地集群中利用 kubectl confi set-context 命令设置上下文。

代码语言:javascript复制
kubectl config set-context devops-ctx 
  --cluster=k8s-cluster 
  --user=devops 
  --namespace=devtest 
  --kubeconfig=/root/.kube/devops.kubeconfig
# Context "devopsuser-ctx" created.

步骤04.在本地集群中,同样利用cfssl工具生成devops用户证书

代码语言:javascript复制
# 证书相关配置文件
$ tee ca-config.json << 'EOF'
{
  "signing": {
    "default": {
        "expiry": "87600h"
    },
    "profiles": {
      "kubernetes": {
          "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
          ],
          "expiry": "87600h"
        }
      }
  }
}
EOF

$ tee devops-csr.json << 'EOF'
{
  "CN": "devops",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "ChongQing",
      "L": "ChongQing",
      "O": "k8s",
      "OU": "System"
    }
  ]
}
EOF

# 证书生成
tee cluster.prod.ca.key <<'EOF'
-----BEGIN RSA PRIVATE KEY-----
[远程集群 ca 私钥 base64 编码 ]
-----END RSA PRIVATE KEY-----
EOF

# 证书生成
cfssl gencert -ca=./cluster.prod.ca.crt -ca-key=./cluster.prod.ca.key -config ./ca-config.json -profile=kubernetes ./devops-csr.json | cfssljson -bare devops

# 将生成的证书以及密钥复制到/etc/kubernetes/pki/user目录中
sudo cp devops*.pem /etc/kubernetes/pki/user

步骤 05.在本地集群中利用 kubectl confi set-credentials 命令设置devops用户, 注意集群、上下文以及用户认证拼接都是写入到/root/.kube/devops.kubeconfig

代码语言:javascript复制
kubectl config set-credentials devops 
  --cluster=k8s-cluster 
  --client-certificate=/etc/kubernetes/pki/user/devops.pem  
  --client-key=/etc/kubernetes/pki/user/devops-key.pem 
  --embed-certs=true 
  --kubeconfig=/root/.kube/devops.kubeconfig

# 切换上下文为devops-ctx
kubectl config use-context devops-ctx --kubeconfig=/root/.kube/devops.kubeconfig
  # Switched to context "devops-ctx".

# 查看当前上下文
kubectl config current-context --kubeconfig=/root/.kube/devops.kubeconfig
  # devops-ctx

步骤 06.在远端集群中执行如下命令给devops用户绑定指定名称空间中(devtest)拥有的角色及其赋予的权限。

代码语言:javascript复制
kubectl create rolebinding devops --clusterrole=admin --user=devops --namespace=devtest 
kubectl get rolebindings.rbac.authorization.k8s.io -n devtest                         
  # NAME     ROLE                AGE
  # devops   ClusterRole/admin   2s

温馨提示: 上面为了演示采用了kubernetes默认的admin角色,在实践环境中建议自己按照所需权限创建role然后再绑定给指定用户。

步骤 07.在本地集群中使用–kubeconfig指定前面生成集群连接配置,访问远端集群中devtest名称空间下的资源, 如果访问其它名称空间的资源是没有权限的。

代码语言:javascript复制
kubectl --kubeconfig=/root/.kube/devops.kubeconfig get pod -n devtest
  # NAME             READY   STATUS    RESTARTS         AGE
  # oa-dev-0         1/1     Running   24 (2d17h ago)   16d
  # redis-single-0   1/1     Running   0                47d

# 非 devtest 名称空间下的 资源是无权限的。
kubectl --kubeconfig=/root/.kube/devops.kubeconfig get pod -n devops
# Error from server (Forbidden): pods is forbidden: User "devops" cannot list resource "pods" in API group "" in the namespace "devops"

0x04 Kubernetes 中拉取内部私有仓库镜像的 ImagePullSecret 创建使用

描述: 本小节记录了使用 Secret 从私有的镜像仓库或代码仓库拉取镜像来创建 Pod, 实际上是通过 imagePullSecret 资源将 Secret 提供的密码传递给 kubelet 从而在拉取镜像前完成必要的认证过程, 或者通过映射到ServiceAccount对象中然后在使用该SA对象创建出的Pod也同样拥有拉取镜像的权限。

方式1.docker-registry 方式来创建 secret

代码语言:javascript复制
# 使用kubectl命令创建密钥
kubectl create secret docker-registry myregistrykey 
  --docker-server=harbor.weiyigeek.top 
  --docker-username=weiyigeek 
  --docker-password=Harbor12345 
  --docker-email=master@weiyigeek.top 
  --namespace app

方式2.通过 docker 凭证文件来创建 secret

代码语言:javascript复制
# 通过docker login登录,本地生成凭证配置文件 ~/.docker/config.json
docker login -uweiyigeek -pHarbor12345 harbor.weiyigeek.top

# 基于该凭证文件创建secret
kubectl create secret generic myregistrykey 
  --from-file=.dockerconfigjson=/root/.docker/config.json 
  --type=kubernetes.io/dockerconfigjson 
  --namespace app

温馨提示: 此种方式的好处是如果有多个镜像仓库,都会先存在一个config.json文件中然后通过命令打入Secret, 如果有多个私有仓库都可以进行拉取。

扩展知识.将上述镜像拉取 Secret 添加到 ServicesAcount 利用 sa 进行私有镜像拉取

代码语言:javascript复制
# 此处修改default命名空间的服务帐户,以将该 Secret 用作 imagePullSecret。
kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "myregistrykey"}]}'

# 你也可以使用 kubectl edit,或者如下所示手动编辑 YAML 清单,打开 sa.yaml 文件,删除带有键名 resourceVersion 的行,添加带有 imagePullSecrets: 的行,最后保存文件。
$ kubectl get serviceaccounts default -o yaml > ./sa.yaml
$ vim sa.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: 2015-08-07T22:02:39Z
  name: default
  namespace: default
  uid: 052fb0f4-3d50-11e5-b066-42010af0d7b6
secrets:
- name: default-token-uudge
imagePullSecrets:
- name: myregistrykey

# 最后,用新的更新的 sa.yaml 文件替换服务账号。
kubectl replace serviceaccount default -f ./sa.yaml

dockerconfigjson 示例:

代码语言:javascript复制
# (1) 查看类型为 kubernetes.io/dockerconfigjson 的 myregistrykey secret
$ kubectl get secret myregistrykey -o yaml
apiVersion: v1
kind: Secret
metadata:
  name: myregistrykey
  namespace: app
data:
  .dockerconfigjson: UmVhbGx5IHJlYWxseSByZWVlZWVlZWVlZWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGx5eXl5eXl5eXl5eXl5eXl5eXl5eSBsbGxsbGxsbGxsbGxsbG9vb29vb29vb29vb29vb29vb29vb29vb29vb25ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubmdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2cgYXV0aCBrZXlzCg==
type: kubernetes.io/dockerconfigjson


# (2) .dockerconfigjson 字段的值是 Docker 凭证的 base64 表示, 我们可以将 Secret 数据转换为可读格式。
kubectl get secret myregistrykey --output="jsonpath={.data..dockerconfigjson}" | base64 --decode
  # {"auths":{"yourprivateregistry.com":{"username":"weiyigeek","password":"xxxxxxxxxxx","email":"master@weiyigeek.top","auth":"c3R...zE2"}}}

温馨提示: 我们也可手动对秘钥文件进行 base64 加密 , 例如 cat ~/.docker/config.json |base64 -w 0 其值还是与UmVhbG...ZXlzCg==一致。

使用示例

描述: 使用 imagePullSecrets 字段指定名称空间下私有仓库凭据(myregistrykey)进行内部镜像(harbor.weiyigeek.top/private/app:latest)拉取

代码语言:javascript复制
tee private-reg.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: foo
  namespace: app
spec:
  containers:
    - name: foo
      image: harbor.weiyigeek.top/private/app:latest
      command:
      - sh
      - -c
      - "sleep 160"
  imagePullSecrets:
    - name: myregistrykey
EOF

# 拉取部署私有镜像容器
kubectl apply -f private-reg.yaml

kubectl get pod -n app foo
  # NAME   READY   STATUS    RESTARTS   AGE
  # foo    1/1     Running   0          14s

0 人点赞