diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cc50cf8f..b537772b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -49,7 +49,7 @@ jobs: ref: 'main' - name: Update kustomization - run: IMG=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${GITHUB_REF:10} make release + run: IMG=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${GITHUB_REF:10} make update-version-to-install - name: Set env run: echo "RELEASE_VERSION=$(echo ${GITHUB_REF:10})" >> $GITHUB_ENV @@ -58,9 +58,38 @@ jobs: uses: peter-evans/create-pull-request@v5 with: token: ${{ secrets.GITHUB_TOKEN }} - title: "chore: update kustomization for install to ${{ env.RELEASE_VERSION }}" + title: "chore: bump version to ${{ env.RELEASE_VERSION }} in install/kustomization.yaml" body: | # Why - New version [${{ env.RELEASE_VERSION }}](${{ github.server_url }}/${{ github.repository }}/releases/tag/${{ env.RELEASE_VERSION }}) was released. # What - Update kustomization for installation + + create-pr-for-helm-charts: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + ref: main + repository: nakamasato/helm-charts + + - name: Set env + run: echo "RELEASE_VERSION=$(echo ${GITHUB_REF:10})" >> $GITHUB_ENV + + - name: Update app version + run: | + yq e -i ".version = \"${{ env.RELEASE_VERSION }}\"" charts/mysql-operator/Chart.yaml + yq e -i ".appVersion = \"${{ env.RELEASE_VERSION }}\"" charts/mysql-operator/Chart.yaml + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v5 + with: + token: ${{ secrets.PAT_TO_UPDATE_HELM_CHARTS_REPO }} # when expired, need to update in https://github.com/settings/tokens + title: "chore: bump mysql-operator version to ${{ env.RELEASE_VERSION }}" + branch: bump-mysql-operator-chart + body: | + # Why + - New version [${{ env.RELEASE_VERSION }}](${{ github.server_url }}/${{ github.repository }}/releases/tag/${{ env.RELEASE_VERSION }}) was released. + # What + - bump mysql-operator chart version to [${{ env.RELEASE_VERSION }}](${{ github.server_url }}/${{ github.repository }}/releases/tag/${{ env.RELEASE_VERSION }}) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b9ea9d36..e1773fff 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,4 +8,5 @@ repos: - id: end-of-file-fixer - id: check-yaml args: [--allow-multiple-documents] + exclude: ^chart/templates/ - id: check-added-large-files diff --git a/Makefile b/Makefile index f1c291fd..9fac17e0 100644 --- a/Makefile +++ b/Makefile @@ -279,5 +279,15 @@ e2e-with-kuttl: e2e-with-ginkgo: ginkgo $(GINKGO) e2e -release: kustomize +update-version-to-install: kustomize cd config/install && $(KUSTOMIZE) edit set image controller=${IMG} + +HELMIFY ?= $(LOCALBIN)/helmify + +.PHONY: helmify +helmify: $(HELMIFY) ## Download helmify locally if necessary. +$(HELMIFY): $(LOCALBIN) + test -s $(LOCALBIN)/helmify || GOBIN=$(LOCALBIN) go install github.com/arttor/helmify/cmd/helmify@latest + +helm: manifests kustomize helmify + $(KUSTOMIZE) build config/install | $(HELMIFY) diff --git a/README.md b/README.md index 8099305d..6609983a 100644 --- a/README.md +++ b/README.md @@ -22,10 +22,18 @@ This is a go-based Kubernetes operator built with [operator-sdk](https://sdk.ope ## Getting Started -1. Install CRD +1. Install (Create CRD and operator objects) + With kustomize: ``` kubectl apply -k https://github.com/nakamasato/mysql-operator/config/install ``` + With Helm: + ``` + helm repo add nakamasato https://nakamasato.github.io/helm-charts + helm repo update + helm install mysql-operator nakamasato/mysql-operator + ``` + 1. (Optional) prepare MySQL. ``` kubectl apply -k https://github.com/nakamasato/mysql-operator/config/mysql @@ -128,6 +136,44 @@ This is a go-based Kubernetes operator built with [operator-sdk](https://sdk.ope Instead of writing raw password in `MySQL.Spec.AdminPassword`, you can get the password for root user from an external secret manager (e.g. GCP) (ref: [Authenticate to Google Cloud using a service account](https://cloud.google.com/kubernetes-engine/docs/tutorials/authenticating-to-cloud-platform)) +1. Create `SecretManager` + ``` + echo -n "password" | gcloud secrets create mysql-password --data-file=- + echo -n "root" | gcloud secrets create mysql-user --data-file=- + ``` +1. Create a `Secret` for credentials json for **service account** with `roles/secretm +anager.secretAccessor` permission + ``` + kubectl create secret generic gcp-sa-private-key --from-file=sa-private-key.json + ``` +1. Install mysql-operator with `--set cloudSecretManagerType=gcp --set gcpProjectId=$PROJECT_ID` + ``` + helm repo add nakamasato https://nakamasato.github.io/helm-charts + helm repo update + helm install mysql-operator nakamasato/mysql-operator --set cloudSecretManagerType=gcp --set gcpProjectId=$PROJECT_ID + ``` +1. You can specify `type: gcp` for `admin_user` and `admin_password`. + + ```yaml + apiVersion: mysql.nakamasato.com/v1alpha1 + kind: MySQL + metadata: + name: mysql-sample + spec: + host: mysql.default # need to include namespace if you use Kubernetes Service as an endpoint. + admin_user: + name: mysql-user # secret name in SecretManager + type: gcp + admin_password: + name: mysql-password # secret name in SecretManager + type: gcp + ``` + + Example: (you need to run `kubectl apply -k config/mysql`) + ``` + kubectl apply -k config/samples-on-k8s-with-gcp-secretmanager + ``` + [Read credentials from GCP SecretManager](docs/usage/gcp-secretmanager.md) ## Exposed Metrics diff --git a/config/samples-on-k8s-with-gcp-secretmanager/kustomization.yaml b/config/samples-on-k8s-with-gcp-secretmanager/kustomization.yaml new file mode 100644 index 00000000..5c4a1842 --- /dev/null +++ b/config/samples-on-k8s-with-gcp-secretmanager/kustomization.yaml @@ -0,0 +1,6 @@ +## Append samples you want in your CSV to this file as resources ## +resources: +- mysql_v1alpha1_mysqluser.yaml +- mysql_v1alpha1_mysql.yaml +- mysql_v1alpha1_mysqldb.yaml +#+kubebuilder:scaffold:manifestskustomizesamples diff --git a/config/samples-on-k8s-with-gcp-secretmanager/mysql_v1alpha1_mysql.yaml b/config/samples-on-k8s-with-gcp-secretmanager/mysql_v1alpha1_mysql.yaml new file mode 100644 index 00000000..e4e3093f --- /dev/null +++ b/config/samples-on-k8s-with-gcp-secretmanager/mysql_v1alpha1_mysql.yaml @@ -0,0 +1,12 @@ +apiVersion: mysql.nakamasato.com/v1alpha1 +kind: MySQL +metadata: + name: mysql-sample +spec: + host: mysql.default # need to include namespace if you use Kubernetes Service as an endpoint. + admin_user: + name: root + type: raw + admin_password: # echo -n "password" | gcloud secrets create mysql-password --data-file=- + name: mysql-password + type: gcp diff --git a/config/samples-on-k8s-with-gcp-secretmanager/mysql_v1alpha1_mysqldb.yaml b/config/samples-on-k8s-with-gcp-secretmanager/mysql_v1alpha1_mysqldb.yaml new file mode 100644 index 00000000..c4a56bec --- /dev/null +++ b/config/samples-on-k8s-with-gcp-secretmanager/mysql_v1alpha1_mysqldb.yaml @@ -0,0 +1,7 @@ +apiVersion: mysql.nakamasato.com/v1alpha1 +kind: MySQLDB +metadata: + name: sample-db # this is not a name for MySQL database but just a Kubernetes object name +spec: + dbName: sample_db # this is MySQL database name + mysqlName: mysql-sample diff --git a/config/samples-on-k8s-with-gcp-secretmanager/mysql_v1alpha1_mysqluser.yaml b/config/samples-on-k8s-with-gcp-secretmanager/mysql_v1alpha1_mysqluser.yaml new file mode 100644 index 00000000..3a385728 --- /dev/null +++ b/config/samples-on-k8s-with-gcp-secretmanager/mysql_v1alpha1_mysqluser.yaml @@ -0,0 +1,6 @@ +apiVersion: mysql.nakamasato.com/v1alpha1 +kind: MySQLUser +metadata: + name: nakamasato +spec: + mysqlName: mysql-sample diff --git a/config/samples-wtih-gcp-secretmanager/mysql_v1alpha1_mysqldb.yaml b/config/samples-wtih-gcp-secretmanager/mysql_v1alpha1_mysqldb.yaml index d8b7d532..c4a56bec 100644 --- a/config/samples-wtih-gcp-secretmanager/mysql_v1alpha1_mysqldb.yaml +++ b/config/samples-wtih-gcp-secretmanager/mysql_v1alpha1_mysqldb.yaml @@ -1,12 +1,6 @@ apiVersion: mysql.nakamasato.com/v1alpha1 kind: MySQLDB metadata: - labels: - app.kubernetes.io/name: mysqldb - app.kubernetes.io/instance: mysqldb-sample - app.kubernetes.io/part-of: mysql-operator - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/created-by: mysql-operator name: sample-db # this is not a name for MySQL database but just a Kubernetes object name spec: dbName: sample_db # this is MySQL database name diff --git a/docs/developer-guide/helm.md b/docs/developer-guide/helm.md new file mode 100644 index 00000000..9caf6bf1 --- /dev/null +++ b/docs/developer-guide/helm.md @@ -0,0 +1,118 @@ +# helm + +## Create Helm chart + +With [helmify](https://github.com/arttor/helmify), you can create a helm chart + +1. Update Makefile + ``` + HELMIFY ?= $(LOCALBIN)/helmify + + .PHONY: helmify + helmify: $(HELMIFY) ## Download helmify locally if necessary. + $(HELMIFY): $(LOCALBIN) + test -s $(LOCALBIN)/helmify || GOBIN=$(LOCALBIN) go install github.com/arttor/helmify/cmd/helmify@latest + + helm: manifests kustomize helmify + $(KUSTOMIZE) build config/install | $(HELMIFY) + ``` +1. Run + ``` + make helm + ``` +1. Check generated files + ``` + chart + ├── Chart.yaml + ├── templates + │ ├── _helpers.tpl + │ ├── deployment.yaml + │ ├── leader-election-rbac.yaml + │ ├── manager-config.yaml + │ ├── manager-rbac.yaml + │ ├── metrics-reader-rbac.yaml + │ ├── metrics-service.yaml + │ ├── mysql-crd.yaml + │ ├── mysqldb-crd.yaml + │ ├── mysqluser-crd.yaml + │ └── proxy-rbac.yaml + └── values.yaml + + 1 directory, 13 files + ``` +1. Update name in `chart/Chart.yaml` + ```yaml + name: mysql-operator + ``` +1. Update `chart/templates/deployment.yaml` for your purpose + What we do here is basically to enable to change `Deployment` from `Values`. (ref: [#199](https://github.com/nakamasato/mysql-operator/pull/199/commits/cc245343a9a24eee35425ef7d665c9d17996c7a8)) +1. Package + ``` + helm package chart --app-version v0.2.0 + ``` + The command will generate `mysql-operator-0.1.0.tgz` +## Publish package to Helm chart repo. + +https://github.com/nakamasato/helm-charts is used for repo. +All we need to do is to update the chart source file under [charts/mysql-operator](https://github.com/nakamasato/helm-charts/tree/main/charts/mysql-operator) in the repo. + +We use GitHub Actions to update the repo. + +## Install mysql-operator with the Helm chart (from local source file) + +1. Install mysql-operator with helm + + ``` + helm install mysql-operator-0.1.0.tgz --generate-name + ``` + + Optionally, you can add `--set cloudSecretManagerType=gcp --set gcpProjectId=$PROJECT_ID` to use GCP SecretManager to get AdminUser and/or AdminPassword. + +
+ + ``` + NAME: mysql-operator-0-1680907162 + LAST DEPLOYED: Sat Apr 8 07:13:58 2023 + NAMESPACE: default + STATUS: deployed + REVISION: 1 + TEST SUITE: None + ``` + +
+ +1. List + + ``` + helm list + ``` + + ``` + NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION + mysql-operator-0-1680907162 default 1 2023-04-08 07:39:22.416055 +0900 JST deployed mysql-operator-0.1.0 v0.2.0 + ``` +1. Check operator is running + ``` + kubectl get po + NAME READY STATUS RESTARTS AGE + mysql-operator-0-1680907162-controller-manager-f9d855dc9-d4psm 0/1 Running 0 13s + ``` +1. (Optional) upgrade an existing release + ``` + helm upgrade mysql-operator-0-1680913123 $HELM_PATH --set cloudSecretManagerType=gcp --set gcpProjectId=$PROJECT_ID + ``` +1. Uninstall + ``` + helm uninstall mysql-operator-0-1680907162 + ``` + +## Usage + +[Install with Helm](../usage/install-with-helm.md) + +## Development Tips + +1. Check resulting yaml file + ``` + helm template chart + ``` diff --git a/docs/developer-guide/versions.md b/docs/developer-guide/versions.md index 473b6275..09c50cfa 100644 --- a/docs/developer-guide/versions.md +++ b/docs/developer-guide/versions.md @@ -37,6 +37,19 @@ Steps: ``` GINKGO = $(LOCALBIN)/ginkgo ginkgo: - test -s $(LOCALBIN)/ginkgo && $(LOCALBIN)/ginkgo --version | grep -q $(GINKGO_VERSION) || \ + test -s $(LOCALBIN)/ginkgo && $(LOCALBIN)/ginkgo version | grep -q $(GINKGO_VERSION) || \ GOBIN=$(LOCALBIN) go install github.com/onsi/ginkgo/v2/ginkgo@$(GINKGO_VERSION) ``` + 1. helmify + + ``` + HELMIFY ?= $(LOCALBIN)/helmify + + .PHONY: helmify + helmify: $(HELMIFY) ## Download helmify locally if necessary. + $(HELMIFY): $(LOCALBIN) + test -s $(LOCALBIN)/helmify || GOBIN=$(LOCALBIN) go install github.com/arttor/helmify/cmd/helmify@latest + + helm: manifests kustomize helmify + $(KUSTOMIZE) build config/default | $(HELMIFY) + ``` diff --git a/docs/usage/gcp-secretmanager.md b/docs/usage/gcp-secretmanager.md index c921f569..d600bdea 100644 --- a/docs/usage/gcp-secretmanager.md +++ b/docs/usage/gcp-secretmanager.md @@ -24,9 +24,39 @@ mysql-operator can get the credentials of the MySQL user (which is used to acces ``` 1. Generate service account key json. ``` - gcloud iam service-accounts keys create config/default/sa-private-key.json --iam-account=mysql-operator@${PROJECT_ID}.iam.gserviceaccount.com + gcloud iam service-accounts keys create sa-private-key.json --iam-account=mysql-operator@${PROJECT_ID}.iam.gserviceaccount.com ``` + + +## Create Secret for service account key + +``` +kubectl create secret generic gcp-sa-private-key --from-file=sa-private-key.json +``` + +## Prepara mysql-operator yaml + +1. `containers[].args`: Add `"--cloud-secret-manager=gcp"` +1. `containers[]`: Add the following codes + ```yaml + volumeMounts: + - name: gcp-sa-private-key + mountPath: /var/secrets/google + env: + - name: GOOGLE_APPLICATION_CREDENTIALS + value: /var/secrets/google/sa-private-key.json + ``` +1. `volumes`: + ```yaml + volumes: + - name: gcp-sa-private-key + secret: + secretName: gcp-sa-private-key + ``` +1. + + ## Prepare mysql-operator yaml 1. Uncomment the following piece of codes in `config/default/kustomization.yaml` diff --git a/docs/usage/install-with-helm.md b/docs/usage/install-with-helm.md new file mode 100644 index 00000000..e2d09042 --- /dev/null +++ b/docs/usage/install-with-helm.md @@ -0,0 +1,65 @@ +# Install with Helm + +## 1. Preparation + +``` +helm repo add nakamasato https://nakamasato.github.io/helm-charts +helm repo update +``` + +## 2. Install + +### 2.1. Install without GCP SecretManager + +``` +helm install mysql-operator nakamasato/mysql-operator +``` + +### 2.2. Install with GCP credentials json + +1. Check the yaml to be applied with the `template` command + + ``` + helm template mysql-operator nakamasato/mysql-operator --set cloudSecretManagerType=gcp --set gcpProjectId=$PROJECT_ID + ``` + + Check point: + - [ ] secret is mounted + - [ ] env var `GOOGLE_APPLICATION_CREDENTIALS` is set + - [ ] env var `PROJECT_ID` is set + +1. Install + + ``` + helm install mysql-operator nakamasato/mysql-operator --set cloudSecretManagerType=gcp --set gcpProjectId=$PROJECT_ID --generate-name + ``` + +### 2.3. Install without GCP credentials json (e.g. Run on GCP resource) + +TODO + +## 3. Upgrade + +When you want to modify helm release (start operator with new settings or arguments), you can upgrade an existing release. + +1. Get target release + ``` + helm list + ``` +1. Upgrade + ``` + helm upgrade mysql-operator nakamasato/mysql-operator --set cloudSecretManagerType=gcp --set gcpProjectId=$PROJECT_ID + ``` + +## 4. Uninstall + +1. Check helm release to uninstall + ``` + helm list + NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION + mysql-operator default 2 2023-04-08 12:38:58.65552 +0900 JST deployed mysql-operator-0.1.0 v0.2.0 + ``` +1. Uninstall + ``` + helm uninstall mysql-operator + ```