一、概述

有时候我们希望在 k8s 的 pod 中执行一些命令,但是又不想为了一个简单的功能去写代码调用 API,而是直接使用 kubectl 命令

二、制作 kubectl 镜像

FROM debian:bullseye

RUN apt-get update && apt-get install -y curl \
   && curl -Lo /usr/bin/kubectl https://dl.k8s.io/release/v1.20.15/bin/linux/amd64/kubectl \
   && chmod +x /usr/bin/kubectl \
   && apt-get clean \
   && rm -rf /var/lib/apt/lists/*
docker build -t win7/kubectl:v1.20.15 .

三、配置 ServiceAccount 及其 RBAC 权限

一般情况下,我们是不期望 kubectl 拥有对 k8s 的所有权限的,而是指定其对某个 namespace 下的某些指定资源拥有权限。
比如我们希望执行 kubectl set image 命令来发布应用,那我们就希望对 deployment 有对应的修改权限, 下面我以 jenkins 为例,希望 jenkins 在构建结束之后,发布 namespace 为 gray 和 stable 下的 deployment app1

---
# 创建一个 sa ,用于发布应用
apiVersion: v1
kind: ServiceAccount
metadata:
  name: sa-jenkins-release
  namespace: jenkins
---
# 创建一个角色,拥有 对 pods、services、deployments 的操作权限
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: gray
  name: role-jenkins-release
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
  resources: ["services"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

---
# 创建一个角色,拥有 对 pods、services、deployments 的操作权限
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: stable
  name: role-jenkins-release
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
  resources: ["services"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

---
# 授予 sa 在 gray 下的权限
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: rb-jenkins-release
  namespace: gray
subjects:
- kind: ServiceAccount 
  name: sa-jenkins-release
  namespace: jenkins
roleRef:
  kind: Role
  name: role-jenkins-release
  apiGroup: rbac.authorization.k8s.io

---
# 授予 sa 在 stable 下的权限
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: rb-jenkins-release
  namespace: stable
subjects:
- kind: ServiceAccount 
  name: sa-jenkins-release
  namespace: jenkins
roleRef:
  kind: Role
  name: role-jenkins-release
  apiGroup: rbac.authorization.k8s.io

四、在 gray 和 stable 下创建一个 app1 用于测试

---
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations: {}
  labels:
    k8s.kuboard.cn/name: app1
  name: app1
  namespace: gray
  resourceVersion: '31734'
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      k8s.kuboard.cn/name: app1
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        k8s.kuboard.cn/name: app1
    spec:
      containers:
        - image: 'nginx:1.20.0'
          imagePullPolicy: IfNotPresent
          name: nginx
          resources: {}
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30

五、创建一个 kubectl pod

---
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations: {}
  labels:
    k8s.kuboard.cn/name: kubectl
  name: kubectl
  namespace: jenkins
  resourceVersion: '31857'
spec:
  progressDeadlineSeconds: 600
  replicas: 0
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      k8s.kuboard.cn/name: kubectl
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      annotations:
        kubectl.kubernetes.io/restartedAt: '2023-06-18T13:42:43+08:00'
      creationTimestamp: null
      labels:
        k8s.kuboard.cn/name: kubectl
    spec:
      automountServiceAccountToken: true
      containers:
        - command:
            - tail
            - '-f'
            - /etc/hosts
          image: 'win7/kubectl:v1.20.15'
          imagePullPolicy: Always
          name: c1
          resources: {}
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      serviceAccount: sa-jenkins-release
      serviceAccountName: sa-jenkins-release
      terminationGracePeriodSeconds: 30

这里我指定了 serviceAccount: sa-jenkins-release,这样在 pod 中执行 kubectl 命令时,就会使用 sa-jenkins-release 这个账号,而不是默认的 default 账号

六、在 kubeclt pod 中执行命令

kubectl get pod -n stable
kubectl -n stable set image deployment/app1 nginx=nginx:1.23.0 && kubectl -n stable rollout status deployment/app1