From 435e431c81b44eeca34592e135a56f7867ed71d9 Mon Sep 17 00:00:00 2001 From: "buu.nguyen" Date: Thu, 12 Dec 2024 21:06:44 +0700 Subject: [PATCH 1/4] Add helm chart --- Makefile | 1 + .../doris-resource-operator/.helmignore | 23 +++ .../doris-resource-operator/Chart.yaml | 21 ++ helm-charts/doris-resource-operator/README.md | 40 ++++ .../crds/mysql.nakamasato.com_mysqldbs.yaml | 107 ++++++++++ .../crds/mysql.nakamasato.com_mysqls.yaml | 138 +++++++++++++ .../crds/mysql.nakamasato.com_mysqlusers.yaml | 192 ++++++++++++++++++ .../templates/_helpers.tpl | 57 ++++++ .../templates/deployment.yaml | 124 +++++++++++ .../templates/leader-election-rbac.yaml | 53 +++++ .../templates/manager-config.yaml | 23 +++ .../templates/manager-rbac.yaml | 120 +++++++++++ .../templates/metrics-reader-rbac.yaml | 11 + .../templates/metrics-service.yaml | 14 ++ .../templates/proxy-rbac.yaml | 34 ++++ .../doris-resource-operator/values.yaml | 45 ++++ 16 files changed, 1003 insertions(+) create mode 100755 helm-charts/doris-resource-operator/.helmignore create mode 100755 helm-charts/doris-resource-operator/Chart.yaml create mode 100644 helm-charts/doris-resource-operator/README.md create mode 100644 helm-charts/doris-resource-operator/crds/mysql.nakamasato.com_mysqldbs.yaml create mode 100644 helm-charts/doris-resource-operator/crds/mysql.nakamasato.com_mysqls.yaml create mode 100644 helm-charts/doris-resource-operator/crds/mysql.nakamasato.com_mysqlusers.yaml create mode 100755 helm-charts/doris-resource-operator/templates/_helpers.tpl create mode 100644 helm-charts/doris-resource-operator/templates/deployment.yaml create mode 100644 helm-charts/doris-resource-operator/templates/leader-election-rbac.yaml create mode 100644 helm-charts/doris-resource-operator/templates/manager-config.yaml create mode 100644 helm-charts/doris-resource-operator/templates/manager-rbac.yaml create mode 100644 helm-charts/doris-resource-operator/templates/metrics-reader-rbac.yaml create mode 100644 helm-charts/doris-resource-operator/templates/metrics-service.yaml create mode 100644 helm-charts/doris-resource-operator/templates/proxy-rbac.yaml create mode 100644 helm-charts/doris-resource-operator/values.yaml diff --git a/Makefile b/Makefile index 7d5aa7e7..29c0e133 100644 --- a/Makefile +++ b/Makefile @@ -47,6 +47,7 @@ help: ## Display this help. .PHONY: manifests manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. $(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases + $(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=helm-charts/doris-resource-operator/crds .PHONY: generate generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. diff --git a/helm-charts/doris-resource-operator/.helmignore b/helm-charts/doris-resource-operator/.helmignore new file mode 100755 index 00000000..0e8a0eb3 --- /dev/null +++ b/helm-charts/doris-resource-operator/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/helm-charts/doris-resource-operator/Chart.yaml b/helm-charts/doris-resource-operator/Chart.yaml new file mode 100755 index 00000000..fd3d0380 --- /dev/null +++ b/helm-charts/doris-resource-operator/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: doris-manager +description: A Helm chart for Kubernetes +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: "0.0.1" +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "0.0.1" diff --git a/helm-charts/doris-resource-operator/README.md b/helm-charts/doris-resource-operator/README.md new file mode 100644 index 00000000..bcacee72 --- /dev/null +++ b/helm-charts/doris-resource-operator/README.md @@ -0,0 +1,40 @@ +# [mysql-operator](https://github.com/nakamasato/mysql-operator) + +## Values + +1. **adminUserSecretType**: `raw`, `gcp` or `k8s` . With `raw`, you need to give root user password in `MySQL` custom resource. With `gcp`, you can securely store root user password in GCP SecretManager. This root user password is used to manage (create/edit/update) MySQL users, databases, etc. With k8s you need to create (in the same namespace where this operator is installed) two kubernetes secrets one for the root username and another one for root password. +1. **gcpServiceAccount**: Only for `adminUserSecretType=gcp`. GCP service account for Pod `SA_NAME@PROJECT.iam.gserviceaccount.com` + 1. This service account needs the following roles: + 1. `roles/secretmanager.secretAccessor` to allow to get root password from SecretManager +1. **gcpProjectId**: Only for `adminUserSecretType=gcp` +1. **adminUserSecretNamespace**: Only for `adminUserSecretType=k8s`. Kubernetes Namespace of Secret for MySQL admin user credentials. +1. **cloudSQL.instanceConnectionName**: `InstanceConnectionName` for [Google Cloud SQL](https://cloud.google.com/sql/) if you use Cloud SQL to manage with mysql-operator. `::` + + + +## Usage + +### Dryrun + +You can check the final yaml with `--dry-run`: + +``` +helm install mysql-operator ./charts/mysql-operator \ + --dry-run \ + --set adminUserSecretType=gcp \ + --set gcpServiceAccount=${SA_NAME}@${PROJECT}.iam.gserviceaccount.com \ + --set gcpProjectId=$PROJECT \ + --set cloudSQL.instanceConnectionName=$PROJECT:$REGION:$INSTANCE_NAME \ + --namespace mysql-operator +``` + +### Install + +``` +helm install mysql-operator ./charts/mysql-operator \ + --set adminUserSecretType=gcp \ + --set gcpServiceAccount=${SA_NAME}@${PROJECT}.iam.gserviceaccount.com \ + --set gcpProjectId=$PROJECT \ + --set cloudSQL.instanceConnectionName=$PROJECT:$REGION:$INSTANCE_NAME \ + --namespace mysql-operator +``` diff --git a/helm-charts/doris-resource-operator/crds/mysql.nakamasato.com_mysqldbs.yaml b/helm-charts/doris-resource-operator/crds/mysql.nakamasato.com_mysqldbs.yaml new file mode 100644 index 00000000..00a55b8c --- /dev/null +++ b/helm-charts/doris-resource-operator/crds/mysql.nakamasato.com_mysqldbs.yaml @@ -0,0 +1,107 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: mysqldbs.mysql.nakamasato.com +spec: + group: mysql.nakamasato.com + names: + kind: MySQLDB + listKind: MySQLDBList + plural: mysqldbs + singular: mysqldb + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The phase of MySQLDB + jsonPath: .status.phase + name: Phase + type: string + - description: The reason for the current phase of this MySQLDB + jsonPath: .status.reason + name: Reason + type: string + - description: schema_migration table if schema migration is enabled. + jsonPath: .status.schemaMigration + name: SchemaMigration + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: MySQLDB is the Schema for the mysqldbs API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: MySQLDBSpec defines the desired state of MySQLDB + properties: + dbName: + description: MySQL Database name + type: string + mysqlName: + description: MySQL (CRD) name to reference to, which decides the destination + MySQL server + type: string + schemaMigrationFromGitHub: + description: MySQL Database Schema Migrations from GitHub + properties: + owner: + type: string + path: + type: string + ref: + type: string + repo: + type: string + required: + - owner + - path + - repo + type: object + required: + - dbName + - mysqlName + type: object + status: + description: MySQLDBStatus defines the observed state of MySQLDB + properties: + phase: + description: The phase of database creation + type: string + reason: + description: The reason for the current phase + type: string + schemaMigration: + description: Schema Migration status + properties: + dirty: + type: boolean + version: + type: integer + required: + - dirty + - version + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/helm-charts/doris-resource-operator/crds/mysql.nakamasato.com_mysqls.yaml b/helm-charts/doris-resource-operator/crds/mysql.nakamasato.com_mysqls.yaml new file mode 100644 index 00000000..38355228 --- /dev/null +++ b/helm-charts/doris-resource-operator/crds/mysql.nakamasato.com_mysqls.yaml @@ -0,0 +1,138 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: mysqls.mysql.nakamasato.com +spec: + group: mysql.nakamasato.com + names: + kind: MySQL + listKind: MySQLList + plural: mysqls + singular: mysql + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.host + name: Host + type: string + - jsonPath: .spec.adminUser.name + name: AdminUser + type: string + - jsonPath: .status.connected + name: Connected + type: boolean + - description: The number of MySQLUsers that belongs to the MySQL + jsonPath: .status.userCount + name: UserCount + type: integer + - description: The number of MySQLDBs that belongs to the MySQL + jsonPath: .status.dbCount + name: DBCount + type: integer + - jsonPath: .status.reason + name: Reason + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: MySQL is the Schema for the mysqls API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: MySQLSpec holds the connection information for the target + MySQL cluster. + properties: + adminPassword: + description: AdminPassword is MySQL password to connect target MySQL + cluster. + properties: + name: + description: Secret Name + type: string + type: + description: Secret Type (e.g. gcp, raw, k8s) + enum: + - raw + - gcp + - k8s + type: string + required: + - name + - type + type: object + adminUser: + description: AdminUser is MySQL user to connect target MySQL cluster. + properties: + name: + description: Secret Name + type: string + type: + description: Secret Type (e.g. gcp, raw, k8s) + enum: + - raw + - gcp + - k8s + type: string + required: + - name + - type + type: object + host: + description: Host is MySQL host of target MySQL cluster. + type: string + port: + default: 3306 + description: Port is MySQL port of target MySQL cluster. + type: integer + required: + - adminPassword + - adminUser + - host + type: object + status: + description: MySQLStatus defines the observed state of MySQL + properties: + connected: + description: true if successfully connected to the MySQL cluster + type: boolean + dbCount: + default: 0 + description: The number of database in this MySQL + format: int32 + type: integer + reason: + description: Reason for connection failure + type: string + userCount: + default: 0 + description: The number of users in this MySQL + format: int32 + type: integer + required: + - dbCount + - userCount + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/helm-charts/doris-resource-operator/crds/mysql.nakamasato.com_mysqlusers.yaml b/helm-charts/doris-resource-operator/crds/mysql.nakamasato.com_mysqlusers.yaml new file mode 100644 index 00000000..6be6cc8c --- /dev/null +++ b/helm-charts/doris-resource-operator/crds/mysql.nakamasato.com_mysqlusers.yaml @@ -0,0 +1,192 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: mysqlusers.mysql.nakamasato.com +spec: + group: mysql.nakamasato.com + names: + kind: MySQLUser + listKind: MySQLUserList + plural: mysqlusers + singular: mysqluser + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: true if MySQL user is created + jsonPath: .status.mysqlUserCreated + name: MySQLUser + type: boolean + - description: true if Secret is created + jsonPath: .status.secretCreated + name: Secret + type: boolean + - description: true if Grants are updated + jsonPath: .status.grantsUpdated + name: Grants + type: boolean + - description: The phase of this MySQLUser + jsonPath: .status.phase + name: Phase + type: string + - description: The reason for the current phase of this MySQLUser + jsonPath: .status.reason + name: Reason + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: MySQLUser is the Schema for the mysqlusers API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: MySQLUserSpec defines the desired state of MySQLUser + properties: + grants: + description: Grants of database user + items: + description: Grant defines the privileges and the resource for a + MySQL user + properties: + privileges: + description: Privileges for the MySQL user + items: + type: string + type: array + target: + description: Resource on which the privileges are applied + type: string + required: + - privileges + - target + type: object + type: array + host: + default: '%' + description: Host address where the client connects, default to '%' + type: string + mysqlName: + description: MySQL (CRD) name to reference to, which decides the destination + MySQL server + type: string + required: + - mysqlName + type: object + status: + description: MySQLUserStatus defines the observed state of MySQLUser + properties: + conditions: + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + grantsUpdated: + default: false + description: true if Grants are updated + type: boolean + mysqlUserCreated: + default: false + description: true if User is created + type: boolean + phase: + type: string + reason: + type: string + secretCreated: + default: false + description: true if Secret is created + type: boolean + userIdentity: + description: User identity in format 'username'@'host' + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/helm-charts/doris-resource-operator/templates/_helpers.tpl b/helm-charts/doris-resource-operator/templates/_helpers.tpl new file mode 100755 index 00000000..0a1dd23d --- /dev/null +++ b/helm-charts/doris-resource-operator/templates/_helpers.tpl @@ -0,0 +1,57 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "chart.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "chart.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "chart.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} +{{/* +Common labels +*/}} +{{- define "chart.labels" -}} +helm.sh/chart: {{ include "chart.chart" . }} +{{ include "chart.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} +{{/* +Selector labels +*/}} +{{- define "chart.selectorLabels" -}} +app.kubernetes.io/name: {{ include "chart.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} +{{/* +Create the name of the service account to use +*/}} +{{- define "chart.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "chart.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/helm-charts/doris-resource-operator/templates/deployment.yaml b/helm-charts/doris-resource-operator/templates/deployment.yaml new file mode 100644 index 00000000..050f2885 --- /dev/null +++ b/helm-charts/doris-resource-operator/templates/deployment.yaml @@ -0,0 +1,124 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "chart.fullname" . }}-controller-manager + labels: + {{- include "chart.labels" . | nindent 4 }} + {{- if .Values.gcpServiceAccount }} + annotations: + iam.gke.io/gcp-service-account: {{ .Values.gcpServiceAccount }} + {{- end }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "chart.fullname" . }}-controller-manager + labels: + control-plane: controller-manager + {{- include "chart.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.controllerManager.replicas }} + selector: + matchLabels: + control-plane: controller-manager + {{- include "chart.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + control-plane: controller-manager + {{- include "chart.selectorLabels" . | nindent 8 }} + spec: + containers: + - args: + - --leader-elect + - --admin-user-secret-type={{ .Values.adminUserSecretType | default "raw" }} + {{- if eq .Values.adminUserSecretType "k8s" }} + - --k8s-secret-namespace={{ .Values.k8sSecretNamespace | default "default" }} + {{- end }} + command: + - /manager + image: {{ .Values.controllerManager.manager.image.repository }}:{{ .Values.controllerManager.manager.image.tag | default .Chart.AppVersion }} + imagePullPolicy: {{ .Values.controllerManager.manager.image.pullPolicy }} + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + name: manager + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + {{- if .Values.controllerManager.manager.resources }} + resources: + {{- toYaml .Values.controllerManager.manager.resources | nindent 10 }} + {{- end }} + {{- if .Values.controllerManager.manager.securityContext }} + securityContext: + {{- toYaml .Values.controllerManager.manager.securityContext | nindent 10 }} + {{- end }} + {{- if eq .Values.adminUserSecretType "gcp" }} + {{- if .Values.gcpServiceAccount }} + env: + - name: PROJECT_ID + value: {{ .Values.gcpProjectId }} + {{- else }} + volumeMounts: + - name: gcp-sa-private-key + mountPath: /var/secrets/google + env: + - name: GOOGLE_APPLICATION_CREDENTIALS + value: /var/secrets/google/sa-private-key.json + - name: PROJECT_ID + value: {{ .Values.gcpProjectId }} + {{- end }} + {{- end }} + + # https://cloud.google.com/sql/docs/mysql/connect-instance-kubernetes#deploy_the_sample_app + {{- with .Values.cloudSQL }} + # If you are using the Go Connector (recommended), you can + # remove cloud-sql-proxy (everything below this line) + - name: cloud-sql-proxy + # This uses the latest version of the Cloud SQL Proxy + # It is recommended to use a specific version for production environments. + # See: https://github.com/GoogleCloudPlatform/cloudsql-proxy + image: gcr.io/cloud-sql-connectors/cloud-sql-proxy:latest + args: + # If connecting from a VPC-native GKE cluster, you can use the + # following flag to have the proxy connect over private IP + {{- if .usePrivateIp }} + # - "--private-ip" + {{- end }} + + # If you are not connecting with Automatic IAM, you can delete + # the following flag. + {{- if .enableIamAuth }} + - "--auto-iam-authn" + {{- end }} + + # tcp should be set to the port the proxy should listen on + # and should match the DB_PORT value set above. + # Defaults: MySQL: 3306, Postgres: 5432, SQLServer: 1433 + - "--port=3306" + - {{ .instanceConnectionName }} + securityContext: + # The default Cloud SQL proxy image runs as the + # "nonroot" user and group (uid: 65532) by default. + runAsNonRoot: true + {{- end }} + + {{- if .Values.controllerManager.podSecurityContext }} + securityContext: + {{- toYaml .Values.controllerManager.podSecurityContext | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "chart.fullname" . }}-controller-manager + terminationGracePeriodSeconds: 10 + {{- if and (eq .Values.adminUserSecretType "gcp") (empty .Values.gcpServiceAccount) }} + volumes: + - name: gcp-sa-private-key + secret: + secretName: gcp-sa-private-key + {{- end }} diff --git a/helm-charts/doris-resource-operator/templates/leader-election-rbac.yaml b/helm-charts/doris-resource-operator/templates/leader-election-rbac.yaml new file mode 100644 index 00000000..d0e738e4 --- /dev/null +++ b/helm-charts/doris-resource-operator/templates/leader-election-rbac.yaml @@ -0,0 +1,53 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "chart.fullname" . }}-leader-election-role + labels: + {{- include "chart.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "chart.fullname" . }}-leader-election-rolebinding + labels: + {{- include "chart.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: '{{ include "chart.fullname" . }}-leader-election-role' +subjects: +- kind: ServiceAccount + name: '{{ include "chart.fullname" . }}-controller-manager' + namespace: '{{ .Release.Namespace }}' diff --git a/helm-charts/doris-resource-operator/templates/manager-config.yaml b/helm-charts/doris-resource-operator/templates/manager-config.yaml new file mode 100644 index 00000000..af5eaf38 --- /dev/null +++ b/helm-charts/doris-resource-operator/templates/manager-config.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "chart.fullname" . }}-manager-config + labels: + {{- include "chart.labels" . | nindent 4 }} +data: + controller_manager_config.yaml: | + apiVersion: controller-runtime.sigs.k8s.io/v1alpha1 + health: + healthProbeBindAddress: {{ .Values.managerConfig.controllerManagerConfigYaml.health.healthProbeBindAddress + | quote }} + kind: ControllerManagerConfig + leaderElection: + leaderElect: {{ .Values.managerConfig.controllerManagerConfigYaml.leaderElection.leaderElect + }} + resourceName: {{ .Values.managerConfig.controllerManagerConfigYaml.leaderElection.resourceName + | quote }} + metrics: + bindAddress: {{ .Values.managerConfig.controllerManagerConfigYaml.metrics.bindAddress + | quote }} + webhook: + port: {{ .Values.managerConfig.controllerManagerConfigYaml.webhook.port }} diff --git a/helm-charts/doris-resource-operator/templates/manager-rbac.yaml b/helm-charts/doris-resource-operator/templates/manager-rbac.yaml new file mode 100644 index 00000000..919f157b --- /dev/null +++ b/helm-charts/doris-resource-operator/templates/manager-rbac.yaml @@ -0,0 +1,120 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "chart.fullname" . }}-manager-role + labels: + {{- include "chart.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - secrets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch + - update +- apiGroups: + - mysql.nakamasato.com + resources: + - mysqldbs + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - mysql.nakamasato.com + resources: + - mysqldbs/finalizers + verbs: + - update +- apiGroups: + - mysql.nakamasato.com + resources: + - mysqldbs/status + verbs: + - get + - patch + - update +- apiGroups: + - mysql.nakamasato.com + resources: + - mysqls + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - mysql.nakamasato.com + resources: + - mysqls/finalizers + verbs: + - update +- apiGroups: + - mysql.nakamasato.com + resources: + - mysqls/status + verbs: + - get + - patch + - update +- apiGroups: + - mysql.nakamasato.com + resources: + - mysqlusers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - mysql.nakamasato.com + resources: + - mysqlusers/finalizers + verbs: + - update +- apiGroups: + - mysql.nakamasato.com + resources: + - mysqlusers/status + verbs: + - get + - patch + - update +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "chart.fullname" . }}-manager-rolebinding + labels: + {{- include "chart.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: '{{ include "chart.fullname" . }}-manager-role' +subjects: +- kind: ServiceAccount + name: '{{ include "chart.fullname" . }}-controller-manager' + namespace: '{{ .Release.Namespace }}' diff --git a/helm-charts/doris-resource-operator/templates/metrics-reader-rbac.yaml b/helm-charts/doris-resource-operator/templates/metrics-reader-rbac.yaml new file mode 100644 index 00000000..ce5d8b5a --- /dev/null +++ b/helm-charts/doris-resource-operator/templates/metrics-reader-rbac.yaml @@ -0,0 +1,11 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "chart.fullname" . }}-metrics-reader + labels: + {{- include "chart.labels" . | nindent 4 }} +rules: +- nonResourceURLs: + - /metrics + verbs: + - get diff --git a/helm-charts/doris-resource-operator/templates/metrics-service.yaml b/helm-charts/doris-resource-operator/templates/metrics-service.yaml new file mode 100644 index 00000000..2fbef6b7 --- /dev/null +++ b/helm-charts/doris-resource-operator/templates/metrics-service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "chart.fullname" . }}-controller-manager-metrics-service + labels: + control-plane: controller-manager + {{- include "chart.labels" . | nindent 4 }} +spec: + type: {{ .Values.metricsService.type }} + selector: + control-plane: controller-manager + {{- include "chart.selectorLabels" . | nindent 4 }} + ports: + {{- .Values.metricsService.ports | toYaml | nindent 2 -}} diff --git a/helm-charts/doris-resource-operator/templates/proxy-rbac.yaml b/helm-charts/doris-resource-operator/templates/proxy-rbac.yaml new file mode 100644 index 00000000..d40fc07d --- /dev/null +++ b/helm-charts/doris-resource-operator/templates/proxy-rbac.yaml @@ -0,0 +1,34 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "chart.fullname" . }}-proxy-role + labels: + {{- include "chart.labels" . | nindent 4 }} +rules: +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "chart.fullname" . }}-proxy-rolebinding + labels: + {{- include "chart.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: '{{ include "chart.fullname" . }}-proxy-role' +subjects: +- kind: ServiceAccount + name: '{{ include "chart.fullname" . }}-controller-manager' + namespace: '{{ .Release.Namespace }}' diff --git a/helm-charts/doris-resource-operator/values.yaml b/helm-charts/doris-resource-operator/values.yaml new file mode 100644 index 00000000..5aa85eb3 --- /dev/null +++ b/helm-charts/doris-resource-operator/values.yaml @@ -0,0 +1,45 @@ +# set gcp if you use GCP SecretManager +# set k8s if you use Kubernetes secrets +adminUserSecretType: raw # set gcp if you use GCP SecretManager +# gcpServiceAccount: GSA_NAME@GSA_PROJECT.iam.gserviceaccount.com +# gcpProjectId: +# cloudSQL: +# instanceConnectionName: +# enableIamAuth: false +# usePrivateIp: false +k8sSecretNamespace: default +controllerManager: + manager: + image: + repository: ghcr.io/nakamasato/mysql-operator + pullPolicy: IfNotPresent + resources: + limits: + cpu: 200m + memory: 100Mi + requests: + cpu: 100m + memory: 20Mi + securityContext: + allowPrivilegeEscalation: false + podSecurityContext: + runAsNonRoot: true + replicas: 1 +managerConfig: + controllerManagerConfigYaml: + health: + healthProbeBindAddress: :8081 + leaderElection: + leaderElect: true + resourceName: dfc6d3c2.nakamasato.com + metrics: + bindAddress: 127.0.0.1:8080 + webhook: + port: 9443 +metricsService: + ports: + - name: https + port: 8443 + protocol: TCP + targetPort: https + type: ClusterIP From 2cb7d5fb347d15648148a5ce422476cec096d2fc Mon Sep 17 00:00:00 2001 From: "buu.nguyen" Date: Thu, 12 Dec 2024 21:11:06 +0700 Subject: [PATCH 2/4] Update crds --- .../crds/mysql.nakamasato.com_mysqldbs.yaml | 12 ++-- .../crds/mysql.nakamasato.com_mysqlusers.yaml | 55 ++++++++++++++----- 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/helm-charts/doris-resource-operator/crds/mysql.nakamasato.com_mysqldbs.yaml b/helm-charts/doris-resource-operator/crds/mysql.nakamasato.com_mysqldbs.yaml index 00a55b8c..6b4ad1ee 100644 --- a/helm-charts/doris-resource-operator/crds/mysql.nakamasato.com_mysqldbs.yaml +++ b/helm-charts/doris-resource-operator/crds/mysql.nakamasato.com_mysqldbs.yaml @@ -52,13 +52,15 @@ spec: spec: description: MySQLDBSpec defines the desired state of MySQLDB properties: + clusterName: + description: Cluster name to reference to, which decides the destination + type: string + x-kubernetes-validations: + - message: Cluster name is immutable + rule: self == oldSelf dbName: description: MySQL Database name type: string - mysqlName: - description: MySQL (CRD) name to reference to, which decides the destination - MySQL server - type: string schemaMigrationFromGitHub: description: MySQL Database Schema Migrations from GitHub properties: @@ -76,8 +78,8 @@ spec: - repo type: object required: + - clusterName - dbName - - mysqlName type: object status: description: MySQLDBStatus defines the observed state of MySQLDB diff --git a/helm-charts/doris-resource-operator/crds/mysql.nakamasato.com_mysqlusers.yaml b/helm-charts/doris-resource-operator/crds/mysql.nakamasato.com_mysqlusers.yaml index 6be6cc8c..1955632e 100644 --- a/helm-charts/doris-resource-operator/crds/mysql.nakamasato.com_mysqlusers.yaml +++ b/helm-charts/doris-resource-operator/crds/mysql.nakamasato.com_mysqlusers.yaml @@ -16,7 +16,7 @@ spec: versions: - additionalPrinterColumns: - description: true if MySQL user is created - jsonPath: .status.mysqlUserCreated + jsonPath: .status.userCreated name: MySQLUser type: boolean - description: true if Secret is created @@ -60,6 +60,12 @@ spec: spec: description: MySQLUserSpec defines the desired state of MySQLUser properties: + clusterName: + description: Cluster name to reference to, which decides the destination + type: string + x-kubernetes-validations: + - message: Cluster name is immutable + rule: self == oldSelf grants: description: Grants of database user items: @@ -67,12 +73,12 @@ spec: MySQL user properties: privileges: - description: Privileges for the MySQL user + description: Privileges to grant to the user items: type: string type: array target: - description: Resource on which the privileges are applied + description: Target on which the privileges are applied type: string required: - privileges @@ -82,13 +88,37 @@ spec: host: default: '%' description: Host address where the client connects, default to '%' + pattern: ^(\*|%|[a-zA-Z0-9._-]+|\d{1,3}(\.\d{1,3}){3})$ type: string - mysqlName: - description: MySQL (CRD) name to reference to, which decides the destination - MySQL server + x-kubernetes-validations: + - message: Host is immutable + rule: self == oldSelf + secretRef: + description: SecretRef is a reference to a Secret containing the password + properties: + key: + description: Key in the Secret that contains the password + type: string + name: + description: Name of the Secret containing the password + type: string + required: + - key + - name + type: object + username: + description: Username + maxLength: 64 + pattern: ^[a-zA-Z][a-zA-Z0-9_]*$ type: string + x-kubernetes-validations: + - message: Username is immutable + rule: self == oldSelf required: - - mysqlName + - clusterName + - host + - secretRef + - username type: object status: description: MySQLUserStatus defines the observed state of MySQLUser @@ -169,21 +199,18 @@ spec: default: false description: true if Grants are updated type: boolean - mysqlUserCreated: + passwordUpdated: default: false - description: true if User is created + description: true if User's password is updated type: boolean phase: type: string reason: type: string - secretCreated: + userCreated: default: false - description: true if Secret is created + description: true if User is created type: boolean - userIdentity: - description: User identity in format 'username'@'host' - type: string type: object type: object served: true From b2807ebd7aced847d0d537bd3b571af387f986e7 Mon Sep 17 00:00:00 2001 From: "buu.nguyen" Date: Thu, 12 Dec 2024 21:13:12 +0700 Subject: [PATCH 3/4] Add CI --- .github/workflows/docker-release.yaml | 16 ++++++++++++++++ .github/workflows/helm-release.yaml | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 .github/workflows/docker-release.yaml create mode 100644 .github/workflows/helm-release.yaml diff --git a/.github/workflows/docker-release.yaml b/.github/workflows/docker-release.yaml new file mode 100644 index 00000000..6e64ba05 --- /dev/null +++ b/.github/workflows/docker-release.yaml @@ -0,0 +1,16 @@ +name: Release Docker Image + +on: + workflow_dispatch: # for manual testing + push: + branches: + - main + +jobs: + call-docker-release: + permissions: + contents: write + packages: write + uses: thealtoclef/modular-automations/.github/workflows/docker-release.yaml@main + with: + no_push: false diff --git a/.github/workflows/helm-release.yaml b/.github/workflows/helm-release.yaml new file mode 100644 index 00000000..3931d9cd --- /dev/null +++ b/.github/workflows/helm-release.yaml @@ -0,0 +1,16 @@ +name: Release Helm Chart + +on: + workflow_dispatch: # for manual testing + push: + branches: + - main + paths: + - "charts/**/*" + +jobs: + call-helm-release: + permissions: + contents: write + packages: write + uses: thealtoclef/modular-automations/.github/workflows/helm-release.yaml@main From fd20d799c7155071020281ca517d5cb0f1ae9e1c Mon Sep 17 00:00:00 2001 From: "buu.nguyen" Date: Thu, 12 Dec 2024 21:17:24 +0700 Subject: [PATCH 4/4] feat: update release workflows for Docker and Helm Change the trigger for Docker and Helm release workflows to use semantic versioning tags instead of branch pushes. This allows for more controlled releases based on versioning, improving the release process and ensuring that only tagged versions are published. --- .github/workflows/docker-release.yaml | 9 +++------ .github/workflows/helm-release.yaml | 6 ++---- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/.github/workflows/docker-release.yaml b/.github/workflows/docker-release.yaml index 6e64ba05..e85a3c3f 100644 --- a/.github/workflows/docker-release.yaml +++ b/.github/workflows/docker-release.yaml @@ -3,14 +3,11 @@ name: Release Docker Image on: workflow_dispatch: # for manual testing push: - branches: - - main + # Publish semver tags as releases: + tags: ["v*.*.*"] jobs: call-docker-release: permissions: - contents: write packages: write - uses: thealtoclef/modular-automations/.github/workflows/docker-release.yaml@main - with: - no_push: false + uses: thealtoclef/modular-automations/.github/workflows/docker-release-forked-repo.yaml@main diff --git a/.github/workflows/helm-release.yaml b/.github/workflows/helm-release.yaml index 3931d9cd..16274079 100644 --- a/.github/workflows/helm-release.yaml +++ b/.github/workflows/helm-release.yaml @@ -3,10 +3,8 @@ name: Release Helm Chart on: workflow_dispatch: # for manual testing push: - branches: - - main - paths: - - "charts/**/*" + # Publish semver tags as releases: + tags: ["helm-v*.*.*"] jobs: call-helm-release: