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

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

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

1
2
3
## 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
1
$ helm repo add bitpoke https://helm-charts.bitpoke.io
  • 安装 mysql-operator

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$ 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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ 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,详细信息可以从官网获取,这里不进行解释。

1
2
3
4
5
6
7
8
9
$ 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 依赖的其他资源

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ 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 安装时的内容如下:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# 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;
  • 同时还有一些启动参数
1
2
3
4
5
- --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 安装时的内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 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 访问数据库的账号密码。

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
$ 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 安装时的内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 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解析出原文

1
2
3
4
5
$ echo 'b3JjaGVzdHJhdG9y' | base64 -d
orchestrator

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

helm install 安装时的内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# 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 安装时的内容如下:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# 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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
$ 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

1
2
3
4
5
6
7
8
9
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql-operator
spec:
  template:
    spec:
      serviceAccountName: mysql-operator
      # ... ...

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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

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

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

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

这里不得不夸赞下k8s

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

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