目录

bitpoke/mysql-operator 技术解读系列 - 部署

警告
本文最后更新于 2023-03-12,文中内容可能已过时。

安装 mysql-operator 的操作命令在官方仓库官网都有说明,具体安装命令如下:

## For Helm v3
helm repo add bitpoke https://helm-charts.bitpoke.io
helm install mysql-operator bitpoke/mysql-operator

在安装的chart包中,values.yaml文件有些内容可以自定义配置。

  • 如果想要在一个k8s集群里面启动多个mysql-operator,不想让不用operator互相干扰,就可以指定watchNamespace参数
  • 如果k8s集群使用的storageClass不支持动态迁移,那么operator的replicaCount就得设置为3,否则节点挂掉后无法拉起新的pod
  • 因为mysql高可用是基于orchestrator实现的,orchestrator又需要一个元数据库,元数据库的账号密码可以通过 orchestrator.topologyUser 和 orchestrator.topologyPassword 指定。topologyUser默认值是 orchestrator,如果密码不指定会随机生成
  • (其他参数以后用到再说明)… …
  • 添加 repo
$ helm repo add bitpoke https://helm-charts.bitpoke.io
  • 安装 mysql-operator

安装之前先创建一个namespace,然后将mysql-operator安装到这个ns中

$ kubectl create namespace mysql
namespace/mysql created

$ helm install mysql-operator bitpoke/mysql-operator -n mysql
NAME: mysql-operator
LAST DEPLOYED: Fri Mar 17 18:53:26 2023
NAMESPACE: mysql
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
You can create a new cluster by issuing:

cat <<EOF | kubectl apply -f-
apiVersion: mysql.presslabs.org/v1alpha1
kind: MysqlCluster
metadata:
  name: my-cluster
spec:
  replicas: 1
  secretName: my-cluster-secret
---
apiVersion: v1
kind: Secret
metadata:
  name: my-cluster-secret
type: Opaque
data:
  ROOT_PASSWORD: $(echo -n "not-so-secure" | base64)
EOF

执行成功后,可以用kubectl工具查询pod状态,直到Running

$ kubectl get all -n mysql
NAME                   READY   STATUS    RESTARTS   AGE
pod/mysql-operator-0   2/2     Running   1          3m11s

NAME                         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)            AGE
service/mysql-operator       ClusterIP   10.102.117.142   <none>        80/TCP,9125/TCP    9m1s
service/mysql-operator-orc   ClusterIP   None             <none>        80/TCP,10008/TCP   9m1s

NAME                              READY   AGE
statefulset.apps/mysql-operator   1/1     9m1s

至此 mysql-operator 就算安装完成了。

上述的安装流程步骤很简单,但是运行起来的mysql-operator对我们来说就是一个黑盒,下面通过执行 helm template 对其被安装的内容进行梳理。

CRD 全程叫做 CustomResourceDefinition,详细信息可以从官网获取,这里不进行解释。

$ helm template mysql-operator bitpoke/mysql-operator -n mysql --include-crds | grep -A 20 CustomResourceDefinition | grep -e kind
kind: CustomResourceDefinition
    kind: MysqlBackup
kind: CustomResourceDefinition
    kind: MysqlCluster
kind: CustomResourceDefinition
    kind: MysqlDatabase
kind: CustomResourceDefinition
    kind: MysqlUser

从上面可以看到,安装mysql-operator的时候会创建4个CRD资源。从名称可以看出是分别是关于backup、cluster、database、user 相关的,也是本系列在后续篇章中要重点讲解的内容。

查看 mysql-operator 依赖的其他资源

$ helm template mysql-operator bitpoke/mysql-operator -n mysql | grep -e ^kind -e name | grep -A 1 ^kind
kind: ServiceAccount
  name: mysql-operator
--
kind: Secret
  name: mysql-operator-orc
--
kind: ConfigMap
  name: mysql-operator-orc
--
kind: ClusterRole
  name: mysql-operator
--
kind: ClusterRoleBinding
  name: mysql-operator
--
kind: Service
  name: mysql-operator-orc
--
kind: Service
  name: mysql-operator
--
kind: StatefulSet
  name: mysql-operator

从上可以看出,计算资源由StatefulSet管理,有2个Service资源,1个ConfigMap,1个Secret。其余3个是跟权限管理相关的配置。

接下来详细聊聊每个资源的作用。

helm install 安装时的内容如下:

# Source: mysql-operator/templates/statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql-operator
  labels:
    helm.sh/chart: mysql-operator-0.6.2
    app.kubernetes.io/name: mysql-operator
    app.kubernetes.io/instance: mysql-operator
    app.kubernetes.io/version: "v0.6.2"
    app.kubernetes.io/managed-by: Helm
spec:
  replicas: 1
  serviceName: mysql-operator-orc
  podManagementPolicy: Parallel
  selector:
    matchLabels:
      app.kubernetes.io/name: mysql-operator
      app.kubernetes.io/instance: mysql-operator
  template:
    metadata:
      annotations:
        checksum/orchestrator-config: 301f994fcecde72ab6be4371173a860c68b440504210a400a8105c833311443b
        checksum/orchestrator-secret: 20304c64003f30460df7e5cdcc078d3bc55b882af412ed1d43ced6a765f1c160
      labels:
        app.kubernetes.io/name: mysql-operator
        app.kubernetes.io/instance: mysql-operator
    spec:
      serviceAccountName: mysql-operator
      securityContext:
        fsGroup: 65532
        runAsGroup: 65532
        runAsNonRoot: true
        runAsUser: 65532
      containers:
        - name: operator
          securityContext:
            {}
          image: "docker.io/bitpoke/mysql-operator:v0.6.2"
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 8080
              name: prometheus
              protocol: TCP
          env:
            - name: ORC_TOPOLOGY_USER
              valueFrom:
                secretKeyRef:
                  name: mysql-operator-orc
                  key: TOPOLOGY_USER
            - name: ORC_TOPOLOGY_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-operator-orc
                  key: TOPOLOGY_PASSWORD
          args:
            - --leader-election-namespace=mysql
            - --orchestrator-uri=http://mysql-operator.mysql/api
            - --sidecar-image=docker.io/bitpoke/mysql-operator-sidecar-5.7:v0.6.2
            - --sidecar-mysql8-image=docker.io/bitpoke/mysql-operator-sidecar-8.0:v0.6.2
            - --failover-before-shutdown=true
          livenessProbe:
            httpGet:
              path: /healthz
              port: 8081
          readinessProbe:
            httpGet:
              path: /readyz
              port: 8081
          resources:
            {}
        - name: orchestrator
          securityContext:
            {}
          image: docker.io/bitpoke/mysql-operator-orchestrator:v0.6.2
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 3000
              name: http
              protocol: TCP
            - containerPort: 10008
              name: raft
              protocol: TCP
          env:
            - name: POD_IP
              valueFrom:
                fieldRef:
                  fieldPath: status.podIP
          envFrom:
            - prefix: ORC_
              secretRef:
                name: mysql-operator-orc
          volumeMounts:
            - name: data
              mountPath: /var/lib/orchestrator
            - name: config
              mountPath: /usr/local/share/orchestrator/templates
          livenessProbe:
            timeoutSeconds: 10
            initialDelaySeconds: 200
            httpGet:
              path: /api/lb-check
              port: 3000
          # https://github.com/github/orchestrator/blob/master/docs/raft.md#proxy-healthy-raft-nodes
          readinessProbe:
            timeoutSeconds: 10
            httpGet:
              path: /api/raft-health
              port: 3000
          resources:
            {}
      volumes:
        - name: config
          configMap:
            name: mysql-operator-orc
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: [ ReadWriteOnce ]
        resources:
          requests:
            storage: 1Gi

从描述中可以看到,一个pod里面会有两个container,分别启动 orchestrator 和 operator。

  • 使用名字为 mysql-operator 的 serviceAccount 来做事件处理
  • 声明 8080 的 prometheus 端口
  • 在 livenessProbe 和 readinessProbe 里面出现了 8081 端口,但没有声明,所以只能 locahost 使用。
  • 需要从 mysql-operator-orc secret 获取两个值当做自己的环境变量 ORC_TOPOLOGY_USER 和 ORC_TOPOLOGY_PASSWORD;
  • 同时还有一些启动参数
- --leader-election-namespace=mysql                                             # 如果安装时pod不是单副本,需要选主,这里是指定选主的ns
- --orchestrator-uri=http://mysql-operator.mysql/api                            # operator 为了和 orchestrator 通信
- --sidecar-image=docker.io/bitpoke/mysql-operator-sidecar-5.7:v0.6.2           # 5.7 版本的 mysql sidecar 镜像
- --sidecar-mysql8-image=docker.io/bitpoke/mysql-operator-sidecar-8.0:v0.6.2    # 8.0 版本的 mysql sidecar 镜像。因为 mysql 版本差异导致备份恢复的 xtrabackup 软件版本不同。
- --failover-before-shutdown=true
  • 声明 3000 的 http 服务端口
  • 声明 10008 的 raft 消息同步端口
  • 也需要从 mysql-operator-orc secret 获取值当做自己的环境变量
  • 声明一个 volume 并挂载到 /var/lib/orchestrator(这里是为了存储 orchestrator 管理的元数据)
  • 从 mysql-operator-orc configmap 获取配置并挂载到 /usr/local/share/orchestrator/templates(orchestrator启动的配置文件)

helm install 安装时的内容如下:

# Source: mysql-operator/templates/orchestrator-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-operator-orc
  labels:
    helm.sh/chart: mysql-operator-0.6.2
    app.kubernetes.io/name: mysql-operator
    app.kubernetes.io/instance: mysql-operator
    app.kubernetes.io/version: "v0.6.2"
    app.kubernetes.io/managed-by: Helm
data:
  orchestrator.conf.json: "{..........}"
  orc-topology.cnf: |
    [client]
    user = {{ .Env.ORC_TOPOLOGY_USER }}
    password = {{ .Env.ORC_TOPOLOGY_PASSWORD }}

在 StatefulSet 部分已经解释

  • orchestrator.conf.json 是 orchestrator 启动需要使用的配置文件。
  • orc-topology.cnf 是 orchestrator 访问数据库的账号密码。

配置信息如下(相关描述可以从官网查阅):

$ cat /usr/local/share/orchestrator/templates/orchestrator.conf.json
{
  "ApplyMySQLPromotionAfterMasterFailover": true,
  "BackendDB": "sqlite",
  "Debug": false,
  "DetachLostReplicasAfterMasterFailover": true,
  "DetectClusterAliasQuery": "SELECT CONCAT(SUBSTRING(@@hostname, 1, LENGTH(@@hostname) - 1 - LENGTH(SUBSTRING_INDEX(@@hostname,'-',-2))),'.',SUBSTRING_INDEX(@@report_host,'.',-1))",
  "DetectInstanceAliasQuery": "SELECT @@hostname",
  "DiscoverByShowSlaveHosts": false,
  "FailMasterPromotionIfSQLThreadNotUpToDate": true,
  "HTTPAdvertise": "http://{{ .Env.HOSTNAME }}.mysql-operator-orc:3000",
  "HostnameResolveMethod": "none",
  "InstancePollSeconds": 5,
  "ListenAddress": ":3000",
  "MasterFailoverLostInstancesDowntimeMinutes": 10,
  "MySQLHostnameResolveMethod": "@@report_host",
  "MySQLTopologyCredentialsConfigFile": "/etc/orchestrator/orc-topology.cnf",
  "OnFailureDetectionProcesses": [
    "/usr/local/bin/orc-helper event -w '{failureClusterAlias}' 'OrcFailureDetection' 'Failure: {failureType}, failed host: {failedHost}, lost replcas: {lostReplicas}' || true",
    "/usr/local/bin/orc-helper failover-in-progress '{failureClusterAlias}' '{failureDescription}' || true"
  ],
  "PostIntermediateMasterFailoverProcesses": [
    "/usr/local/bin/orc-helper event '{failureClusterAlias}' 'OrcPostIntermediateMasterFailover' 'Failure type: {failureType}, failed hosts: {failedHost}, slaves: {countSlaves}' || true"
  ],
  "PostMasterFailoverProcesses": [
    "/usr/local/bin/orc-helper event '{failureClusterAlias}' 'OrcPostMasterFailover' 'Failure type: {failureType}, new master: {successorHost}, slaves: {slaveHosts}' || true"
  ],
  "PostUnsuccessfulFailoverProcesses": [
    "/usr/local/bin/orc-helper event -w '{failureClusterAlias}' 'OrcPostUnsuccessfulFailover' 'Failure: {failureType}, failed host: {failedHost} with {countSlaves} slaves' || true"
  ],
  "PreFailoverProcesses": [
    "/usr/local/bin/orc-helper failover-in-progress '{failureClusterAlias}' '{failureDescription}' || true"
  ],
  "ProcessesShellCommand": "sh",
  "RaftAdvertise": "{{ .Env.HOSTNAME }}.mysql-operator-orc",
  "RaftBind": "{{ .Env.HOSTNAME }}",
  "RaftDataDir": "/var/lib/orchestrator",
  "RaftEnabled": true,
  "RaftNodes": [],
  "RecoverIntermediateMasterClusterFilters": [
    ".*"
  ],
  "RecoverMasterClusterFilters": [
    ".*"
  ],
  "RecoveryIgnoreHostnameFilters": [],
  "RecoveryPeriodBlockSeconds": 300,
  "RemoveTextFromHostnameDisplay": ":3306",
  "SQLite3DataFile": "/var/lib/orchestrator/orc.db",
  "SlaveLagQuery": "SELECT TIMESTAMPDIFF(SECOND,ts,UTC_TIMESTAMP()) as drift FROM sys_operator.heartbeat ORDER BY drift ASC LIMIT 1",
  "UnseenInstanceForgetHours": 1
}

helm install 安装时的内容如下:

# Source: mysql-operator/templates/orchestrator-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: mysql-operator-orc
  labels:
    helm.sh/chart: mysql-operator-0.6.2
    app.kubernetes.io/name: mysql-operator
    app.kubernetes.io/instance: mysql-operator
    app.kubernetes.io/version: "v0.6.2"
    app.kubernetes.io/managed-by: Helm
data:
  TOPOLOGY_USER: "b3JjaGVzdHJhdG9y"
  TOPOLOGY_PASSWORD: "aVdZZndhMzJHZw=="

从 key 可以看出这就是 orchestrator 需要的元数据账号密码信息,使用base64解析出原文

$ echo 'b3JjaGVzdHJhdG9y' | base64 -d
orchestrator

$ echo 'aVdZZndhMzJHZw==' | base64 -d
iWYfwa32Gg

helm install 安装时的内容如下:

# Source: mysql-operator/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: mysql-operator
  labels:
    helm.sh/chart: mysql-operator-0.6.2
    app.kubernetes.io/name: mysql-operator
    app.kubernetes.io/instance: mysql-operator
    app.kubernetes.io/version: "v0.6.2"
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: operator
spec:
  type: ClusterIP
  ports:
    - port: 80
      name: http
      protocol: TCP
      targetPort: http
    - port: 9125
      name: prometheus
      protocol: TCP
      targetPort: prometheus
  selector:
    app.kubernetes.io/name: mysql-operator
    app.kubernetes.io/instance: mysql-operator
---
# Source: mysql-operator/templates/orchestrator-raft-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: mysql-operator-orc
  labels:
    app.kubernetes.io/component: orchestrator-raft
    helm.sh/chart: mysql-operator-0.6.2
    app.kubernetes.io/name: mysql-operator
    app.kubernetes.io/instance: mysql-operator
    app.kubernetes.io/version: "v0.6.2"
    app.kubernetes.io/managed-by: Helm
spec:
  type: ClusterIP
  clusterIP: None
  publishNotReadyAddresses: true
  ports:
    - name: http
      port: 80
      targetPort: 3000
    - name: raft
      port: 10008
      targetPort: 10008
  selector:
    app.kubernetes.io/name: mysql-operator
    app.kubernetes.io/instance: mysql-operator

以上有2个service,虽然 type 都是 ClusterIP,但是 mysql-operator-orc 还有个 clusterIP: None,这个配置表示该 service 是个 Headless Service,不需要额外的 ip。

  • mysql-operator-orc 有两个端口
  • mysql-operator 也有两个端口
    • 80:targetPort 是 http,查询发现还是 orchestrator 的 3000 端口
    • 9125:targetPort 是 prometheus,prometheus 在 StatefulSet中被定义到了 operator 容器的 8080 端口,通过 curl http://127.0.0.1:8080/metrics 可以查看到 operator 的指标数据

helm install 安装时的内容如下:

# Source: mysql-operator/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: mysql-operator
  labels:
    helm.sh/chart: mysql-operator-0.6.2
    app.kubernetes.io/name: mysql-operator
    app.kubernetes.io/instance: mysql-operator
    app.kubernetes.io/version: "v0.6.2"
    app.kubernetes.io/managed-by: Helm
---
# Source: mysql-operator/templates/clusterrole.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: mysql-operator
  labels:
    helm.sh/chart: mysql-operator-0.6.2
    app.kubernetes.io/name: mysql-operator
    app.kubernetes.io/instance: mysql-operator
    app.kubernetes.io/version: "v0.6.2"
    app.kubernetes.io/managed-by: Helm
rules:
- apiGroups:
    - apps
  resources:
    - statefulsets
  verbs:
    - create
    - delete
    - get
    - list
    - patch
    - update
    - watch
- apiGroups:
    - batch
  resources:
    - jobs
  verbs:
    - create
    - delete
    - get
    - list
    - patch
    - update
    - watch
- apiGroups:
    - coordination.k8s.io
  resources:
    - leases
  verbs:
    - create
    - delete
    - get
    - list
    - patch
    - update
    - watch
- apiGroups:
    - ""
  resources:
    - configmaps
    - events
    - jobs
    - persistentvolumeclaims
    - pods
    - secrets
    - services
  verbs:
    - create
    - delete
    - get
    - list
    - patch
    - update
    - watch
- apiGroups:
    - ""
  resources:
    - pods/status
  verbs:
    - create
    - delete
    - get
    - list
    - patch
    - update
    - watch
- apiGroups:
    - mysql.presslabs.org
  resources:
    - mysqlbackups
  verbs:
    - create
    - delete
    - get
    - list
    - patch
    - update
    - watch
- apiGroups:
    - mysql.presslabs.org
  resources:
    - mysqlclusters
    - mysqlclusters/status
  verbs:
    - create
    - delete
    - get
    - list
    - patch
    - update
    - watch
- apiGroups:
    - mysql.presslabs.org
  resources:
    - mysqldatabases
    - mysqldatabases/status
  verbs:
    - create
    - delete
    - get
    - list
    - patch
    - update
    - watch
- apiGroups:
    - mysql.presslabs.org
  resources:
    - mysqlusers
    - mysqlusers/status
  verbs:
    - create
    - delete
    - get
    - list
    - patch
    - update
    - watch
- apiGroups:
    - policy
  resources:
    - poddisruptionbudgets
  verbs:
    - create
    - delete
    - get
    - list
    - patch
    - update
    - watch
---
# Source: mysql-operator/templates/clusterrolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: mysql-operator
  labels:
    helm.sh/chart: mysql-operator-0.6.2
    app.kubernetes.io/name: mysql-operator
    app.kubernetes.io/instance: mysql-operator
    app.kubernetes.io/version: "v0.6.2"
    app.kubernetes.io/managed-by: Helm
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: mysql-operator
subjects:
  - name: mysql-operator
    namespace: "mysql"
    kind: ServiceAccount

在这里要引入k8s一个重要的概念 RBAC(Role Base Access Control),是一种权限控制机制,用于实现账户和权限的组合管理

  • 通过 ClusterRole 来声明都能操作那些api;
  • 通过 ServiceAccount 创建一个账户;
  • 最后通过 ClusterRoleBinding 将两者绑定。

另外每次创建一个 sa 的时候都会生成一个对应的 token secret:

$ kubectl create namespace sa-test
namespace/sa-test created

$ kubectl create serviceaccount test
serviceaccount/test created

$ kubectl get secret -n sa-test
NAME                  TYPE                                  DATA   AGE
default-token-6mdbt   kubernetes.io/service-account-token   3      31s

$ kubectl get secret -n sa-test -o yaml
apiVersion: v1
items:
- apiVersion: v1
  data:
    ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM1ekNDQWMrZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJek1ETXhOekF5TlRrek1sb1hEVE16TURNeE5EQXlOVGt6TWxvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBT3lKCm1ScE51Q21tVGM5dXNKbVJGMEo0Umw1bElQeE1iM0psQ0dONGF5Ry9IZXFEcmJlZnFLMzZJWmFYZVhNbi9Zb0wKMkM3Mktmd1Z3UnJuUldmZkt6L3k0UFR1bkRVUHpNa1BOMloybVRmbENuRG1ENEVjdGk4SVVNeS81ZWtVZ0kvLwppaEh6MllrKzVLb1RISmozc1VrTFRyV2llc0E3WVV6WkZnTGRmZkU2Yjh1WVExSzZtTW1yeWtjSVdyTVJqNEMyCkZ1SjM2a1VqNEJWK1luRVRMNnAxb1FxZWJqa1I2dFZWajZvb25ZNmNHejBUc0JldE03M3FrRTBBUnBFVm1kb3cKSWY1MmVJN0U0WFBuNWtHQk9RZ3k1OE5tNHdzQmEvYTlIbEtCSUFMUm9vaDdyamhHbmpCT1ZtNnFMcDRjdUVkUwpqellONE9WdWtaQ2M1cGRLRVdNQ0F3RUFBYU5DTUVBd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZFME5mWDRsdnEyRjF3MXlVVElYSE5QNVRGSFVNQTBHQ1NxR1NJYjMKRFFFQkN3VUFBNElCQVFCcFQreWwxcVE0Rm5wRjBOait6aVIxR2dZNnRkOXFkMkVaVmdqZ0t3bE1RcDdXSnJQaAo0cnZYTEg5SnhzTmc5Vkx3dGd0YklBall1a1J6dmo0b0ZNWGZGSmZTWlFONDBZTVhIdUl6dXQvNDRKeGp1MTNWClVqWDgrYWNmVG82TzZmc2JYdFpDR1g4UzFxZWRLUDZnbEFhOEh3dTNNbmJiRHdHYjdrcW51Uk81bTN0Z1B1Rm8KVnZRbnhkYjdzNmNIMUo5SjV1bURjMjVONk9BOGVrRzFROVM5Mk9pZDF6aitGZXQrOE55ZFE1ZFBVbWFUazhzdQpMaERjQTJ2TURuR0FrbnFGWWZkWjc5ejJnNlhlY1BCNE1LV2Frd25kZ1NxU2dtOXJKenBNTDFkU0ZTWHpjaEJYCitNc1FPNm5yNkZBMytsbkhrS1BrTWhsYnl5WE91OWNOSkNIQQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
    namespace: c2EtdGVzdA==
    token: ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWkNJNklrcERWMGRFWmtZeFNGbGhPRTFLTkVwSVNsQm9ZVlZ0YXpaeVZYaE5TamRvY0RScE1qQnFTMWcwTlVraWZRLmV5SnBjM01pT2lKcmRXSmxjbTVsZEdWekwzTmxjblpwWTJWaFkyTnZkVzUwSWl3aWEzVmlaWEp1WlhSbGN5NXBieTl6WlhKMmFXTmxZV05qYjNWdWRDOXVZVzFsYzNCaFkyVWlPaUp6WVMxMFpYTjBJaXdpYTNWaVpYSnVaWFJsY3k1cGJ5OXpaWEoyYVdObFlXTmpiM1Z1ZEM5elpXTnlaWFF1Ym1GdFpTSTZJbVJsWm1GMWJIUXRkRzlyWlc0dE5tMWtZblFpTENKcmRXSmxjbTVsZEdWekxtbHZMM05sY25acFkyVmhZMk52ZFc1MEwzTmxjblpwWTJVdFlXTmpiM1Z1ZEM1dVlXMWxJam9pWkdWbVlYVnNkQ0lzSW10MVltVnlibVYwWlhNdWFXOHZjMlZ5ZG1salpXRmpZMjkxYm5RdmMyVnlkbWxqWlMxaFkyTnZkVzUwTG5WcFpDSTZJamMwTkdVeFpqRTJMVFU1TldRdE5HVTNOaTA0TldVMUxUUXlZamRoWm1aak1tSXhNQ0lzSW5OMVlpSTZJbk41YzNSbGJUcHpaWEoyYVdObFlXTmpiM1Z1ZERwellTMTBaWE4wT21SbFptRjFiSFFpZlEuYVhqcXFpMGItUS1nTFJnSC1TUTY2T2hWMS1MWjhVZjlTeGplcUpVY0paVDQyUTBtcVl3MUY0cTl0cEtqQmVDSEhadnJiUENzaUZTMkRPbEtXM3I0aDFYZmpYemg0eTIwUnBvT1ZnT2tYOGhUWnZ5Q1BnUnZXWHBvTjBVZWYtNFotQUF4aFRWRnVWRWdqX1MzZGpiMUhSSVlsVHR3T3pnaVVnRWxZVFJWVFRFcDFySFBqQngtQUp5RGd4WlNqeEZQNWtJbGNRRzVTemZKQ3BzUXN6OWN3OFFwX1JPUlJwcExGVmExZGJNcFZjcXMzZDNCYWw0UXhfbEg2MnF5cXo4M1Z5a2RoUjVwN1JSSm8yZEpnNVZlVF9UVTZLdmpON21Qa2ctdjJPd3hQNkdHX1BrVm9xWHhpR2M4VkloLTZWeDNCdkF5Q1Y4LTRMTnZVVWt1TS1udkpR
  kind: Secret
  metadata:
    annotations:
      kubernetes.io/service-account.name: default
      kubernetes.io/service-account.uid: 744e1f16-595d-4e76-85e5-42b7affc2b10
    creationTimestamp: "2023-03-18T03:38:19Z"
    name: default-token-6mdbt
    namespace: sa-test
    resourceVersion: "49219"
    uid: 2bb22dc9-ee0f-48f9-922e-11001d96b2d7
  type: kubernetes.io/service-account-token
kind: List
metadata:
  resourceVersion: ""
  selfLink: ""

使用时就是上面的 StatefulSet 用法,指定好 serviceAccountName

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql-operator
spec:
  template:
    spec:
      serviceAccountName: mysql-operator
      # ... ...

在运行起来后,查看pod描述,每个container都会有多一个volumeMount,并且可以看到 volume 的声明

spec:
  containers:
  - name: operator
    # ... ...
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: kube-api-access-s5f2h
      readOnly: true
    # ... ...
  volumes:
  - name: kube-api-access-s5f2h
    projected:
      defaultMode: 420
      sources:
      - serviceAccountToken:
          expirationSeconds: 3607
          path: token
      - configMap:
          items:
          - key: ca.crt
            path: ca.crt
          name: kube-root-ca.crt
      - downwardAPI:
          items:
          - fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
            path: namespace

登录容器内部可以看到配置已经挂载

$ ls /var/run/secrets/kubernetes.io/serviceaccount
ca.crt     namespace  token

operator 启动时会从这个位置读取配置然后初始化k8s-client。

这里不得不夸赞下k8s

  • sa的获取的保存不用我们操心
  • sa的存储路径不用我们管理
  • sa配置载入的逻辑不用我们自己写

至此,通过安装mysql-operator和分析chart初步了解了资源组成,后续文章我们进入到mysql-operator内部,看看原理是如何实现的。