├── .dockerignore ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── issue.md ├── actions │ ├── dbtest │ │ └── action.yaml │ ├── e2e │ │ └── action.yaml │ ├── setup-aqua │ │ └── action.yaml │ └── upgrade │ │ └── action.yaml └── workflows │ ├── build-fluent-bit-container.yaml │ ├── build-mysql-container.yaml │ ├── build-mysqld-exporter-container.yaml │ ├── ci-e2e.yaml │ ├── ci.yaml │ ├── helm-release.yaml │ ├── helm.yaml │ ├── mdbook.yaml │ └── release.yaml ├── .gitignore ├── .goreleaser.yaml ├── .krew.yaml ├── CHANGELOG.md ├── DEVELOP.md ├── Dockerfile ├── LICENSE ├── Makefile ├── PROJECT ├── README.md ├── RELEASE.md ├── api └── v1beta2 │ ├── backuppolicy_types.go │ ├── backuppolicy_webhook.go │ ├── backuppolicy_webhook_test.go │ ├── conversion.go │ ├── groupversion_info.go │ ├── job_types.go │ ├── mysqlcluster_types.go │ ├── mysqlcluster_webhook.go │ ├── mysqlcluster_webhook_test.go │ ├── statefulset_webhhok.go │ ├── statefulset_webhhok_test.go │ ├── webhook_suite_test.go │ └── zz_generated.deepcopy.go ├── aqua-checksums.json ├── aqua.yaml ├── backup ├── backup.go ├── backup_test.go ├── bkop.go ├── bytecounter.go ├── bytecounter_test.go ├── integration_test.go ├── key.go ├── mock_test.go ├── restore.go ├── restore_test.go └── suite_test.go ├── charts └── moco │ ├── .helmignore │ ├── CHANGELOG.md │ ├── Chart.yaml │ ├── MIGRATION.md │ ├── README.md │ ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── certificate.yaml │ ├── deployment.yaml │ ├── generated │ │ ├── crds │ │ │ └── moco_crds.yaml │ │ └── generated.yaml │ └── issuer.yaml │ └── values.yaml ├── clustering ├── agent.go ├── log.go ├── manager.go ├── manager_test.go ├── metrics_test.go ├── mock_test.go ├── operations.go ├── process.go ├── status.go ├── status_test.go └── suite_test.go ├── cmd ├── kubectl-moco │ ├── cmd │ │ ├── common.go │ │ ├── completion.go │ │ ├── credential.go │ │ ├── mysql.go │ │ ├── root.go │ │ ├── start.go │ │ ├── stop.go │ │ └── switchover.go │ └── main.go ├── moco-backup │ ├── cmd │ │ ├── backup.go │ │ ├── restore.go │ │ └── root.go │ └── main.go └── moco-controller │ ├── cmd │ ├── root.go │ └── run.go │ └── main.go ├── config ├── certmanager │ ├── certificate.yaml │ ├── grpc.yaml │ ├── kustomization.yaml │ └── kustomizeconfig.yaml ├── crd │ ├── bases │ │ ├── moco.cybozu.com_backuppolicies.yaml │ │ └── moco.cybozu.com_mysqlclusters.yaml │ ├── kustomization.yaml │ ├── kustomizeconfig.yaml │ ├── patches │ │ ├── backuppolicy.yaml │ │ ├── cainjection_in_backuppolicies.yaml │ │ ├── cainjection_in_mysqlclusters.yaml │ │ ├── mysqlcluster.yaml │ │ ├── webhook_in_backuppolicies.yaml │ │ └── webhook_in_mysqlclusters.yaml │ └── tests │ │ ├── apiextensions.k8s.io_v1_customresourcedefinition_backuppolicies.moco.cybozu.com.yaml │ │ ├── apiextensions.k8s.io_v1_customresourcedefinition_mysqlclusters.moco.cybozu.com.yaml │ │ └── third │ │ └── cert-manager.crds.yaml ├── default │ ├── kustomization.yaml │ ├── manager_webhook_patch.yaml │ └── webhookcainjection_patch.yaml ├── kustomize-to-helm │ └── overlays │ │ ├── crds │ │ ├── conversion-patch.yaml │ │ ├── kustomization.yaml │ │ └── label-transformer.yaml │ │ └── templates │ │ ├── kustomization.yaml │ │ ├── label-transformer.yaml │ │ └── webhookcainjection-patch.yaml ├── manager │ ├── kustomization.yaml │ └── manager.yaml ├── rbac │ ├── backuppolicy_editor_role.yaml │ ├── backuppolicy_viewer_role.yaml │ ├── kustomization.yaml │ ├── leader_election_role.yaml │ ├── leader_election_role_binding.yaml │ ├── mysqlcluster_editor_role.yaml │ ├── mysqlcluster_viewer_role.yaml │ ├── role.yaml │ ├── role_binding.yaml │ └── service_account.yaml └── webhook │ ├── kustomization.yaml │ ├── kustomizeconfig.yaml │ ├── manifests.yaml │ ├── service.yaml │ └── validate_preventdelete.yaml ├── containers ├── fluent-bit │ ├── .dockerignore │ ├── Dockerfile │ ├── README.md │ └── TAG ├── mysql │ ├── 8.0.18 │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── TAG │ │ └── container-structure-test.yaml │ ├── 8.0.25 │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── TAG │ │ └── container-structure-test.yaml │ ├── 8.0.26 │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── TAG │ │ └── container-structure-test.yaml │ ├── 8.0.27 │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── TAG │ │ └── container-structure-test.yaml │ ├── 8.0.28 │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── TAG │ │ └── container-structure-test.yaml │ ├── 8.0.30 │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── TAG │ │ └── container-structure-test.yaml │ ├── 8.0.31 │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── TAG │ │ └── container-structure-test.yaml │ ├── 8.0.32 │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── TAG │ │ └── container-structure-test.yaml │ ├── 8.0.33 │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── TAG │ │ └── container-structure-test.yaml │ ├── 8.0.34 │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── TAG │ │ └── container-structure-test.yaml │ ├── 8.0.35 │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── TAG │ │ └── container-structure-test.yaml │ ├── 8.0.36 │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── TAG │ │ └── container-structure-test.yaml │ ├── 8.0.37 │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── TAG │ │ └── container-structure-test.yaml │ ├── 8.0.39 │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── TAG │ │ └── container-structure-test.yaml │ ├── 8.0.40 │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── TAG │ │ └── container-structure-test.yaml │ ├── 8.0.41 │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── TAG │ │ └── container-structure-test.yaml │ ├── 8.0.42 │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── TAG │ │ └── container-structure-test.yaml │ ├── 8.4.0 │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── TAG │ │ └── container-structure-test.yaml │ ├── 8.4.2 │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── TAG │ │ └── container-structure-test.yaml │ ├── 8.4.3 │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── TAG │ │ └── container-structure-test.yaml │ ├── 8.4.4 │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── TAG │ │ └── container-structure-test.yaml │ ├── 8.4.5 │ │ ├── .dockerignore │ │ ├── Dockerfile │ │ ├── TAG │ │ └── container-structure-test.yaml │ └── README.md ├── mysqld_exporter │ ├── .dockerignore │ ├── Dockerfile │ ├── README.md │ └── TAG └── tag_exists ├── controllers ├── certificate.go ├── certificate_tmpl.yaml ├── mock_test.go ├── mysql_container.go ├── mysqlcluster_controller.go ├── mysqlcluster_controller_test.go ├── partition_controller.go ├── partition_controller_test.go ├── pod_watcher.go ├── pod_watcher_test.go ├── pvc.go ├── pvc_test.go └── suite_test.go ├── ct.yaml ├── docs ├── .gitignore ├── README.md ├── SUMMARY.md ├── advanced.md ├── backup.md ├── book.toml ├── change-pvc-template.md ├── clustering.md ├── commands.md ├── crd.md ├── crd_backuppolicy_v1beta2.md ├── crd_mysqlcluster_v1beta2.md ├── custom-mysqld.md ├── customize-system-container.md ├── design.md ├── designdoc │ ├── allow_customize_containers.md │ ├── clustering_stop.md │ ├── object_storage_type.md │ ├── safe_statefulset_rolling_update.md │ ├── support_apply_pvc_template_changes.md │ └── support_reduce_volume_size.md ├── getting_started.md ├── helm.md ├── install-plugin.md ├── known_issues.md ├── kubectl-moco.md ├── links.csv ├── logo.svg ├── metrics.md ├── moco-backup.md ├── moco-controller.md ├── notes.md ├── reconcile.md ├── rolling-update-strategy.md ├── security.md ├── setup.md ├── upgrading.md └── usage.md ├── e2e ├── .gitignore ├── Makefile ├── README.md ├── backup_gcs_test.go ├── backup_test.go ├── backup_tls_test.go ├── backup_with_env_test.go ├── env_test.go ├── failover_test.go ├── failure_test.go ├── fake-gcs-server.yaml ├── kind-config.yaml ├── kind-config_actions.yaml ├── kustomization.yaml ├── lifecycle_test.go ├── manager_patch.yaml ├── minio-tls.yaml ├── minio.yaml ├── offline_test.go ├── partition_test.go ├── prevent_delete_test.go ├── pvc_test.go ├── replication_test.go ├── run_test.go ├── stop_test.go ├── suite_test.go ├── testdata │ ├── backup.yaml │ ├── backup_gcs.yaml │ ├── backup_tls.yaml │ ├── backup_with_env.yaml │ ├── client.yaml │ ├── donor.yaml │ ├── failover.yaml │ ├── failure.yaml │ ├── makebucket.yaml │ ├── makebucket_tls.yaml │ ├── makebucket_with_env.yaml │ ├── offline_test.yaml │ ├── offline_test_changed.yaml │ ├── partition.yaml │ ├── partition_changed.yaml │ ├── partition_force_rollingupdate.yaml │ ├── partition_image_pull_backoff.yaml │ ├── partition_volume_template.yaml │ ├── prevent_delete.yaml │ ├── pvc_test.yaml │ ├── pvc_test_changed.yaml │ ├── replication.yaml │ ├── restore1.yaml │ ├── restore2.yaml │ ├── restore_gcs.yaml │ ├── restore_tls.yaml │ ├── restore_with_env.yaml │ ├── single.yaml │ ├── stop.yaml │ ├── stop_changed.yaml │ └── upgrade.yaml └── upgrade_test.go ├── examples ├── anti-affinity-backuppolicy.yaml ├── anti-affinity.yaml ├── collect-metrics.yaml ├── custom-mycnf.yaml ├── custom-probe.yaml ├── guaranteed.yaml └── loadbalancer.yaml ├── go.mod ├── go.sum ├── hack └── boilerplate.go.txt ├── kustomization.yaml ├── pkg ├── bkop │ ├── backup.go │ ├── binlog.go │ ├── binlog_test.go │ ├── gtid.go │ ├── operator.go │ ├── operator_test.go │ ├── restore.go │ ├── status.go │ ├── suite_test.go │ └── types.go ├── bucket │ ├── gcs.go │ ├── gcs_test.go │ ├── interface.go │ ├── s3.go │ ├── s3_test.go │ └── suite_test.go ├── cert │ └── cert.go ├── constants │ ├── backup.go │ ├── constants.go │ ├── container.go │ ├── meta.go │ ├── ports.go │ └── users.go ├── dbop │ ├── driver.go │ ├── errors.go │ ├── gtid.go │ ├── gtid_test.go │ ├── kill.go │ ├── kill_test.go │ ├── nop.go │ ├── operator.go │ ├── replication.go │ ├── replication_test.go │ ├── status.go │ ├── status_test.go │ ├── suite_test.go │ ├── test_util.go │ └── types.go ├── event │ └── event.go ├── metrics │ └── metrics.go ├── mycnf │ ├── generator.go │ ├── generator_test.go │ └── testdata │ │ ├── bufsize.cnf │ │ ├── loose.cnf │ │ ├── nil.cnf │ │ ├── normalize.cnf │ │ └── opaque.cnf └── password │ └── password.go └── version.go /.dockerignore: -------------------------------------------------------------------------------- 1 | /bin 2 | /testbin 3 | /config 4 | /docs 5 | /e2e 6 | /hack 7 | /dist 8 | /.git 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **Environments** 14 | - Version: 15 | - OS: 16 | 17 | **To Reproduce** 18 | Steps to reproduce the behavior: 19 | 1. Go to '...' 20 | 2. Click on '....' 21 | 3. Scroll down to '....' 22 | 4. See error 23 | 24 | **Expected behavior** 25 | A clear and concise description of what you expected to happen. 26 | 27 | **Additional context** 28 | Add any other context about the problem here. 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Task 3 | about: Describe this issue 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## What 11 | 12 | Describe what this issue should address. 13 | 14 | ## How 15 | 16 | Describe how to address the issue. 17 | 18 | ## Checklist 19 | 20 | - [ ] Finish implementation of the issue 21 | - [ ] Test all functions 22 | - [ ] Have enough logs to trace activities 23 | - [ ] Notify developers of necessary actions 24 | -------------------------------------------------------------------------------- /.github/actions/dbtest/action.yaml: -------------------------------------------------------------------------------- 1 | name: Integration tests with MySQL 2 | description: 'An action to run integration tests with MySQL' 3 | 4 | inputs: 5 | mysql-version: 6 | description: 'MySQL version' 7 | required: true 8 | 9 | runs: 10 | using: "composite" 11 | steps: 12 | - uses: actions/setup-go@v5 13 | with: 14 | go-version-file: go.mod 15 | cache: true 16 | - name: Setup Aqua 17 | uses: ./.github/actions/setup-aqua 18 | - run: make setup 19 | shell: bash 20 | - run: make test-bkop MYSQL_VERSION=${{ inputs.mysql-version }} 21 | shell: bash 22 | - run: make test-dbop MYSQL_VERSION=${{ inputs.mysql-version }} 23 | shell: bash 24 | -------------------------------------------------------------------------------- /.github/actions/e2e/action.yaml: -------------------------------------------------------------------------------- 1 | name: End-to-End Tests 2 | description: 'An action to run End-to-End Tests' 3 | 4 | inputs: 5 | mysql-version: 6 | description: 'MySQL version' 7 | required: true 8 | k8s-version: 9 | description: 'K8s version' 10 | required: true 11 | name: 12 | description: 'Name of the action' 13 | required: true 14 | runs: 15 | using: "composite" 16 | steps: 17 | - uses: actions/setup-go@v5 18 | with: 19 | go-version-file: go.mod 20 | cache: true 21 | - name: Setup Aqua 22 | uses: ./.github/actions/setup-aqua 23 | - run: | 24 | swapon > swapon.txt 25 | sudo swapoff -a 26 | cat swapon.txt | tail -n+2 | awk '$2=="file" {print $1}' | sudo xargs --no-run-if-empty rm 27 | shell: bash 28 | - run: sudo mkdir /mnt/local-path-provisioner0 /mnt/local-path-provisioner1 /mnt/local-path-provisioner2 29 | shell: bash 30 | - name: Setup test cluster 31 | run: make start KUBERNETES_VERSION=${{ inputs.k8s-version }} MYSQL_VERSION=${{ inputs.mysql-version }} KIND_CONFIG=kind-config_actions.yaml 32 | working-directory: e2e 33 | shell: bash 34 | - run: make test MYSQL_VERSION=${{ inputs.mysql-version }} 35 | working-directory: e2e 36 | shell: bash 37 | - run: make logs 38 | working-directory: e2e 39 | if: always() 40 | shell: bash 41 | - uses: actions/upload-artifact@v4 42 | if: always() 43 | with: 44 | name: logs-${{inputs.name}}-${{ inputs.k8s-version }}-${{ inputs.mysql-version }}.tar.gz 45 | path: e2e/logs.tar.gz 46 | -------------------------------------------------------------------------------- /.github/actions/setup-aqua/action.yaml: -------------------------------------------------------------------------------- 1 | name: Setup Aqua 2 | description: Install Aqua CLI 3 | runs: 4 | using: composite 5 | steps: 6 | - name: Restore aqua cache 7 | uses: actions/cache/restore@v4 8 | with: 9 | path: ~/.local/share/aquaproj-aqua 10 | key: v1-aqua-installer-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('aqua.yaml') }} 11 | restore-keys: | 12 | v1-aqua-installer-${{ runner.os }}-${{ runner.arch }}- 13 | 14 | - name: Install aqua 15 | uses: aquaproj/aqua-installer@e2d0136abcf70b7a2f6f505720640750557c4b33 # v3.1.1 16 | with: 17 | aqua_version: v2.48.1 18 | working_directory: ${{ inputs.working_directory }} 19 | # aqua-installer runs aqua with -l option by default, so packages that aren't run in the workflow aren't cached. 20 | aqua_opts: "" 21 | 22 | - name: Save aqua cache 23 | if: github.ref_name == 'main' 24 | uses: actions/cache/save@v4 25 | with: 26 | path: ~/.local/share/aquaproj-aqua 27 | key: v1-aqua-installer-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('aqua.yaml') }} 28 | -------------------------------------------------------------------------------- /.github/actions/upgrade/action.yaml: -------------------------------------------------------------------------------- 1 | name: Upgrade Tests 2 | description: 'An action to run Upgrade Tests' 3 | 4 | runs: 5 | using: "composite" 6 | steps: 7 | - uses: actions/setup-go@v5 8 | with: 9 | go-version-file: go.mod 10 | cache: true 11 | - name: Setup Aqua 12 | uses: ./.github/actions/setup-aqua 13 | - run: | 14 | swapon > swapon.txt 15 | sudo swapoff -a 16 | cat swapon.txt | tail -n+2 | awk '$2=="file" {print $1}' | sudo xargs --no-run-if-empty rm 17 | shell: bash 18 | - run: sudo mkdir /mnt/local-path-provisioner0 /mnt/local-path-provisioner1 /mnt/local-path-provisioner2 19 | shell: bash 20 | - run: make start KIND_CONFIG=kind-config_actions.yaml 21 | working-directory: e2e 22 | shell: bash 23 | - run: make test-upgrade 24 | working-directory: e2e 25 | shell: bash 26 | - run: make logs 27 | working-directory: e2e 28 | if: always() 29 | shell: bash 30 | - uses: actions/upload-artifact@v4 31 | if: always() 32 | with: 33 | name: logs-upgrade.tar.gz 34 | path: e2e/logs.tar.gz 35 | -------------------------------------------------------------------------------- /.github/workflows/build-fluent-bit-container.yaml: -------------------------------------------------------------------------------- 1 | name: "Build Fluent Bit container" 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - "containers/fluent-bit/**" 7 | - ".github/workflows/build-fluent-bit-container.yaml" 8 | - "!**.md" 9 | push: 10 | branches: 11 | - 'main' 12 | paths: 13 | - "containers/fluent-bit/**" 14 | - ".github/workflows/build-fluent-bit-container.yaml" 15 | - "!**.md" 16 | 17 | jobs: 18 | build: 19 | runs-on: ${{ vars.IMAGE_BUILD_RUNNER || 'ubuntu-22.04' }} 20 | steps: 21 | - uses: actions/checkout@v4 22 | - uses: docker/setup-qemu-action@v3 23 | - uses: docker/setup-buildx-action@v3 24 | - name: Login to GitHub Container Registry 25 | uses: docker/login-action@v3 26 | with: 27 | registry: ghcr.io 28 | username: ${{ github.actor }} 29 | password: ${{ secrets.GITHUB_TOKEN }} 30 | 31 | - name: Check TAG file 32 | working-directory: containers 33 | run: | 34 | result="$(./tag_exists moco/fluent-bit fluent-bit)" 35 | if [ "$result" = ok ]; then 36 | exit 0 37 | fi 38 | echo "TAG=$(cat ./fluent-bit/TAG)" >> $GITHUB_ENV 39 | 40 | - uses: docker/build-push-action@v5 41 | if: env.TAG != null 42 | with: 43 | context: containers/fluent-bit/. 44 | platforms: linux/amd64,linux/arm64 45 | push: ${{ github.ref == 'refs/heads/main' }} 46 | tags: ghcr.io/cybozu-go/moco/fluent-bit:${{ env.TAG }} 47 | cache-from: type=gha 48 | cache-to: type=gha,mode=max 49 | -------------------------------------------------------------------------------- /.github/workflows/build-mysqld-exporter-container.yaml: -------------------------------------------------------------------------------- 1 | name: "Build mysqld exporter container" 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - "containers/mysqld_exporter/**" 7 | - ".github/workflows/build-mysqld-exporter-container.yaml" 8 | - "!**.md" 9 | push: 10 | branches: 11 | - 'main' 12 | paths: 13 | - "containers/mysqld_exporter/**" 14 | - ".github/workflows/build-mysqld-exporter-container.yaml" 15 | - "!**.md" 16 | 17 | jobs: 18 | build: 19 | runs-on: ${{ vars.IMAGE_BUILD_RUNNER || 'ubuntu-22.04' }} 20 | steps: 21 | - uses: actions/checkout@v4 22 | - uses: docker/setup-qemu-action@v3 23 | - uses: docker/setup-buildx-action@v3 24 | - name: Login to GitHub Container Registry 25 | uses: docker/login-action@v3 26 | with: 27 | registry: ghcr.io 28 | username: ${{ github.actor }} 29 | password: ${{ secrets.GITHUB_TOKEN }} 30 | 31 | - name: Check TAG file 32 | working-directory: containers 33 | run: | 34 | result="$(./tag_exists moco/mysqld_exporter mysqld_exporter)" 35 | if [ "$result" = ok ]; then 36 | exit 0 37 | fi 38 | echo "TAG=$(cat ./mysqld_exporter/TAG)" >> $GITHUB_ENV 39 | 40 | - uses: docker/build-push-action@v5 41 | if: env.TAG != null 42 | with: 43 | context: containers/mysqld_exporter/. 44 | platforms: linux/amd64,linux/arm64 45 | push: ${{ github.ref == 'refs/heads/main' }} 46 | tags: ghcr.io/cybozu-go/moco/mysqld_exporter:${{ env.TAG }} 47 | cache-from: type=gha 48 | cache-to: type=gha,mode=max 49 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - 'main' 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.ref }} 11 | cancel-in-progress: true 12 | 13 | env: 14 | cache-version: 1 15 | 16 | jobs: 17 | build: 18 | name: Build binaries 19 | runs-on: ubuntu-22.04 20 | steps: 21 | - uses: actions/checkout@v4 22 | - uses: actions/setup-go@v5 23 | with: 24 | go-version-file: go.mod 25 | cache: true 26 | - name: Setup Aqua 27 | uses: ./.github/actions/setup-aqua 28 | - run: make release-build 29 | 30 | test: 31 | name: Small tests 32 | runs-on: ubuntu-22.04 33 | steps: 34 | - uses: actions/checkout@v4 35 | - uses: actions/setup-go@v5 36 | with: 37 | go-version-file: go.mod 38 | cache: true 39 | - name: Setup Aqua 40 | uses: ./.github/actions/setup-aqua 41 | - run: make test 42 | - run: make check-generate 43 | - run: make envtest 44 | -------------------------------------------------------------------------------- /.github/workflows/helm-release.yaml: -------------------------------------------------------------------------------- 1 | name: Release Charts 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'chart-v*' 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-22.04 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v4 14 | with: 15 | fetch-depth: 0 16 | 17 | - name: Set up Helm 18 | uses: azure/setup-helm@v4 19 | with: 20 | version: v3.10.2 21 | 22 | - name: Check chart version 23 | run: | 24 | tag_version=${GITHUB_REF##*/chart-v} 25 | chart_version=$(cat charts/moco/Chart.yaml | grep 'version:' | sed 's/version:\s//') 26 | if [ "$tag_version" != "$chart_version" ]; then 27 | echo "Different versions: tag \"$tag_version\", chart \"$chart_version\"" 28 | exit 1 29 | fi 30 | - name: Packaging the chart 31 | run: helm package ./charts/moco/ 32 | 33 | - uses: actions/upload-artifact@v4 34 | with: 35 | name: helm-charts 36 | path: ./moco-*.tgz 37 | retention-days: 1 38 | 39 | publish: 40 | name: Publish charts on GitHub Pages 41 | runs-on: ubuntu-22.04 42 | needs: build 43 | steps: 44 | - uses: actions/checkout@v4 45 | with: 46 | ref: gh-pages 47 | 48 | - name: Set up Helm 49 | uses: azure/setup-helm@v4 50 | with: 51 | version: v3.15.0 52 | 53 | - uses: actions/download-artifact@v4 54 | with: 55 | name: helm-charts 56 | 57 | - name: Update charts index 58 | run: helm repo index --url https://cybozu-go.github.io/moco/ --merge index.yaml . 59 | 60 | - run: git add . 61 | 62 | - name: Check diffs 63 | run: | 64 | diffs=$(git status -s) 65 | if [ "$diffs" = "" ]; then 66 | echo "NO_DIFF=1" >> $GITHUB_ENV 67 | else 68 | printf "%s\n" "$diffs" 69 | fi 70 | - name: Commit changes 71 | if: env.NO_DIFF != '1' 72 | run: | 73 | git config --global user.name 'Cybozu Neco' 74 | git config --global user.email 'cybozu-neco@users.noreply.github.com' 75 | git commit -m 'update' 76 | - name: Push to gh-pages 77 | if: env.NO_DIFF != '1' 78 | run: git push origin gh-pages 79 | -------------------------------------------------------------------------------- /.github/workflows/helm.yaml: -------------------------------------------------------------------------------- 1 | name: Lint and Test Charts 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - "charts/**" 7 | - '!**.md' 8 | 9 | jobs: 10 | lint-test: 11 | runs-on: ubuntu-22.04 12 | 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v4 16 | with: 17 | fetch-depth: 0 18 | 19 | - uses: actions/setup-python@v5 20 | with: 21 | python-version: 3.8 22 | 23 | - name: Set up chart-testing 24 | uses: helm/chart-testing-action@0d28d3144d3a25ea2cc349d6e59901c4ff469b3b # v2.7.0 25 | 26 | - name: Run chart-testing (list-changed) 27 | id: list-changed 28 | run: | 29 | changed=$(ct list-changed --config ct.yaml) 30 | if [[ -n "$changed" ]]; then 31 | echo "changed=true" >> $GITHUB_OUTPUT 32 | fi 33 | - name: Run chart-testing (lint) 34 | run: ct lint --config ct.yaml 35 | 36 | - name: Create kind cluster 37 | uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0 38 | if: steps.list-changed.outputs.changed == 'true' 39 | with: 40 | version: v0.23.0 41 | node_image: kindest/node:v1.32.0 42 | kubectl_version: v1.32.0 43 | config: e2e/kind-config.yaml 44 | 45 | - name: Apply cert-manager 46 | run: | 47 | kubectl apply -f https://github.com/jetstack/cert-manager/releases/latest/download/cert-manager.yaml 48 | kubectl -n cert-manager wait --for=condition=available --timeout=180s --all deployments 49 | - name: Run chart-testing (install) 50 | run: ct install --config ct.yaml 51 | -------------------------------------------------------------------------------- /.github/workflows/mdbook.yaml: -------------------------------------------------------------------------------- 1 | name: Book 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - 'main' 7 | jobs: 8 | build: 9 | name: Build book 10 | runs-on: ubuntu-22.04 11 | steps: 12 | - uses: actions/checkout@v4 13 | - name: Setup Aqua 14 | uses: ./.github/actions/setup-aqua 15 | - run: make book 16 | - uses: actions/upload-artifact@v4 17 | with: 18 | name: book 19 | path: docs/book 20 | retention-days: 1 21 | publish: 22 | name: Publish book on GitHub Pages 23 | runs-on: ubuntu-22.04 24 | needs: build 25 | steps: 26 | - uses: actions/checkout@v4 27 | with: 28 | ref: gh-pages 29 | # ignore helm chart index file and chart archive file. 30 | - run: ls | grep -v -E 'index.yaml|moco-.*\.tgz' | xargs rm -rf 31 | - uses: actions/download-artifact@v4 32 | with: 33 | name: book 34 | - run: ls -R 35 | - run: git add . 36 | - name: Check diff 37 | run: | 38 | diffs=$(git status -s) 39 | if [ "$diffs" = "" ]; then 40 | echo "NO_DIFF=1" >> $GITHUB_ENV 41 | else 42 | printf "%s\n" "$diffs" 43 | fi 44 | - name: Commit changes 45 | if: env.NO_DIFF != '1' 46 | run: | 47 | git config --global user.name 'Cybozu Neco' 48 | git config --global user.email 'cybozu-neco@users.noreply.github.com' 49 | git commit -m 'update' 50 | - name: Push to gh-pages 51 | if: github.ref == 'refs/heads/main' && env.NO_DIFF != '1' 52 | run: git push origin gh-pages 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Test binary, build with `go test -c` 2 | *.test 3 | 4 | # Output of the go coverage tool, specifically when used with LiteIDE 5 | *.out 6 | 7 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 8 | .glide/ 9 | 10 | # Editors 11 | *~ 12 | .*.swp 13 | .#* 14 | \#*# 15 | /.vscode 16 | /.idea 17 | 18 | # ignore binaries 19 | /bin 20 | /build 21 | /testbin 22 | /dist 23 | -------------------------------------------------------------------------------- /.goreleaser.yaml: -------------------------------------------------------------------------------- 1 | before: 2 | hooks: 3 | - make release-manifests-build 4 | 5 | builds: 6 | - id: kubectl-moco 7 | main: ./cmd/kubectl-moco 8 | binary: kubectl-moco 9 | goos: 10 | - windows 11 | - darwin 12 | - linux 13 | goarch: 14 | - amd64 15 | - arm64 16 | env: 17 | - CGO_ENABLED=0 18 | ignore: # ref: https://goreleaser.com/deprecations/#builds-for-windowsarm64 19 | - goos: windows 20 | goarch: arm64 21 | 22 | archives: 23 | - builds: 24 | - kubectl-moco 25 | name_template: "kubectl-{{ .ProjectName }}_{{ .Tag }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" 26 | wrap_in_directory: false 27 | format: tar.gz 28 | files: 29 | - LICENSE 30 | rlcp: true 31 | 32 | checksum: 33 | name_template: checksums.txt 34 | 35 | changelog: 36 | skip: true 37 | 38 | release: 39 | github: 40 | owner: cybozu-go 41 | name: moco 42 | prerelease: auto 43 | name_template: "Release {{ .Tag }}" 44 | footer: | 45 | See [CHANGELOG.md](./CHANGELOG.md) for details. 46 | extra_files: 47 | - glob: build/moco.yaml 48 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Build the moco-controller binary 2 | FROM --platform=$BUILDPLATFORM ghcr.io/cybozu/golang:1.23-jammy as builder 3 | 4 | ARG TARGETARCH 5 | 6 | # Copy the go source 7 | COPY ./ . 8 | 9 | # Build 10 | RUN GOARCH=${TARGETARCH} CGO_ENABLED=0 go build -ldflags="-w -s" -o moco-controller ./cmd/moco-controller 11 | RUN GOARCH=${TARGETARCH} go build -ldflags="-w -s" -o moco-backup ./cmd/moco-backup 12 | 13 | # the controller image 14 | FROM --platform=$TARGETPLATFORM scratch as controller 15 | LABEL org.opencontainers.image.source https://github.com/cybozu-go/moco 16 | 17 | COPY --from=builder /work/moco-controller ./ 18 | USER 10000:10000 19 | 20 | ENTRYPOINT ["/moco-controller"] 21 | 22 | # For MySQL binaries 23 | FROM --platform=$TARGETPLATFORM ghcr.io/cybozu-go/moco/mysql:8.4.5.1 as mysql 24 | 25 | # the backup image 26 | FROM --platform=$TARGETPLATFORM ghcr.io/cybozu/ubuntu:22.04 27 | LABEL org.opencontainers.image.source https://github.com/cybozu-go/moco 28 | 29 | ARG MYSQLSH_VERSION=8.4.5 30 | ARG MYSQLSH_GLIBC_VERSION=2.28 31 | ARG TARGETARCH 32 | 33 | COPY --from=builder /work/moco-backup /moco-backup 34 | 35 | COPY --from=mysql /usr/local/mysql/LICENSE /usr/local/mysql/LICENSE 36 | COPY --from=mysql /usr/local/mysql/bin/mysqlbinlog /usr/local/mysql/bin/mysqlbinlog 37 | COPY --from=mysql /usr/local/mysql/bin/mysql /usr/local/mysql/bin/mysql 38 | 39 | RUN apt-get update \ 40 | && apt-get install -y --no-install-recommends libjemalloc2 zstd python3 libpython3.10 s3cmd \ 41 | && rm -rf /var/lib/apt/lists/* \ 42 | && if [ "${TARGETARCH}" = 'amd64' ]; then MYSQLSH_ARCH='x86-64'; fi \ 43 | && if [ "${TARGETARCH}" = 'arm64' ]; then MYSQLSH_ARCH='arm-64'; fi \ 44 | && curl -o /tmp/mysqlsh.tar.gz -fsL "https://cdn.mysql.com/Downloads/MySQL-Shell/mysql-shell-${MYSQLSH_VERSION}-linux-glibc${MYSQLSH_GLIBC_VERSION}-${MYSQLSH_ARCH:-unknown}bit.tar.gz" \ 45 | && mkdir /usr/local/mysql-shell \ 46 | && tar -xf /tmp/mysqlsh.tar.gz -C /usr/local/mysql-shell --strip-components=1 \ 47 | && rm -f /tmp/mysqlsh.tar.gz 48 | 49 | ENV PATH=/usr/local/mysql/bin:/usr/local/mysql-shell/bin:"$PATH" 50 | USER 10000:10000 51 | ENTRYPOINT ["/moco-backup"] 52 | -------------------------------------------------------------------------------- /PROJECT: -------------------------------------------------------------------------------- 1 | domain: cybozu.com 2 | layout: 3 | - go.kubebuilder.io/v3 4 | projectName: moco 5 | repo: github.com/cybozu-go/moco 6 | resources: 7 | - api: 8 | crdVersion: v1 9 | namespaced: true 10 | controller: true 11 | domain: cybozu.com 12 | group: moco 13 | kind: MySQLCluster 14 | path: github.com/cybozu-go/moco/api/v1beta2 15 | version: v1beta2 16 | webhooks: 17 | validation: true 18 | webhookVersion: v1 19 | - api: 20 | crdVersion: v1 21 | namespaced: true 22 | controller: true 23 | domain: cybozu.com 24 | group: moco 25 | kind: BackupPolicy 26 | path: github.com/cybozu-go/moco/api/v1beta2 27 | version: v1beta2 28 | webhooks: 29 | validation: true 30 | webhookVersion: v1 31 | version: "3" 32 | -------------------------------------------------------------------------------- /api/v1beta2/conversion.go: -------------------------------------------------------------------------------- 1 | package v1beta2 2 | 3 | // Hub marks this type as a conversion hub. 4 | func (*MySQLCluster) Hub() {} 5 | 6 | // Hub marks this type as a conversion hub. 7 | func (*BackupPolicy) Hub() {} 8 | -------------------------------------------------------------------------------- /api/v1beta2/groupversion_info.go: -------------------------------------------------------------------------------- 1 | // Package v1beta2 contains API Schema definitions for the moco.cybozu.com v1beta2 API group 2 | // +kubebuilder:object:generate=true 3 | // +groupName=moco.cybozu.com 4 | package v1beta2 5 | 6 | import ( 7 | "k8s.io/apimachinery/pkg/runtime/schema" 8 | "sigs.k8s.io/controller-runtime/pkg/scheme" 9 | ) 10 | 11 | var ( 12 | // GroupVersion is group version used to register these objects 13 | GroupVersion = schema.GroupVersion{Group: "moco.cybozu.com", Version: "v1beta2"} 14 | 15 | // SchemeBuilder is used to add go types to the GroupVersionKind scheme 16 | SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} 17 | 18 | // AddToScheme adds the types in this group-version to the given scheme. 19 | AddToScheme = SchemeBuilder.AddToScheme 20 | ) 21 | -------------------------------------------------------------------------------- /aqua.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # yaml-language-server: $schema=https://raw.githubusercontent.com/aquaproj/aqua/main/json-schema/aqua-yaml.json 3 | # aqua - Declarative CLI Version Manager 4 | # https://aquaproj.github.io/ 5 | checksum: 6 | enabled: true 7 | require_checksum: true 8 | # supported_envs: 9 | # - all 10 | registries: 11 | - type: standard 12 | ref: v4.350.0 # renovate: depName=aquaproj/aqua-registry 13 | packages: 14 | - name: kubernetes-sigs/kind@v0.23.0 15 | - name: kubernetes/kubectl@v1.32.0 16 | - name: kubernetes-sigs/kustomize@kustomize/v5.4.3 17 | - name: helm/helm@v3.15.4 18 | - name: goreleaser/goreleaser@v1.26.2 19 | - name: mikefarah/yq@v4.44.3 20 | - name: kubernetes-sigs/controller-tools/controller-gen@v0.17.0 21 | - name: clamoriniere/crd-to-markdown@v0.0.3 22 | - name: dominikh/go-tools/staticcheck@2025.1.1 23 | - name: rust-lang/mdBook@v0.4.40 24 | - name: kubernetes-sigs/controller-runtime/setup-envtest@v0.20.4 25 | -------------------------------------------------------------------------------- /backup/bkop.go: -------------------------------------------------------------------------------- 1 | package backup 2 | 3 | import "github.com/cybozu-go/moco/pkg/bkop" 4 | 5 | // to mock in test 6 | var newOperator = bkop.NewOperator 7 | -------------------------------------------------------------------------------- /backup/bytecounter.go: -------------------------------------------------------------------------------- 1 | package backup 2 | 3 | import ( 4 | "io" 5 | "sync/atomic" 6 | ) 7 | 8 | // ByteCountWriter counts the written data in bytes 9 | type ByteCountWriter struct { 10 | written int64 11 | } 12 | 13 | var _ io.Writer = &ByteCountWriter{} 14 | 15 | // Write implements io.Writer interface. 16 | func (w *ByteCountWriter) Write(data []byte) (int, error) { 17 | atomic.AddInt64(&w.written, int64(len(data))) 18 | return len(data), nil 19 | } 20 | 21 | // Written returns the number of written bytes. 22 | func (w *ByteCountWriter) Written() int64 { 23 | return atomic.LoadInt64(&w.written) 24 | } 25 | -------------------------------------------------------------------------------- /backup/bytecounter_test.go: -------------------------------------------------------------------------------- 1 | package backup 2 | 3 | import ( 4 | "io" 5 | "strings" 6 | "testing" 7 | ) 8 | 9 | func TestByteCountWriter(t *testing.T) { 10 | r := strings.NewReader("abcdefg") 11 | 12 | bcw := &ByteCountWriter{} 13 | tr := io.TeeReader(r, bcw) 14 | 15 | n, err := io.Copy(io.Discard, tr) 16 | if err != nil { 17 | t.Fatal(err) 18 | } 19 | 20 | written := bcw.Written() 21 | if written != int64(n) { 22 | t.Errorf("unexpected written bytes: %d (n=%d)", written, n) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /backup/key.go: -------------------------------------------------------------------------------- 1 | package backup 2 | 3 | import ( 4 | "path" 5 | "time" 6 | 7 | "github.com/cybozu-go/moco/pkg/constants" 8 | ) 9 | 10 | const prefix = "moco" 11 | 12 | func calcKey(clusterNS, clusterName, filename string, dt time.Time) string { 13 | return path.Join(prefix, clusterNS, clusterName, dt.UTC().Format(constants.BackupTimeFormat), filename) 14 | } 15 | 16 | func calcPrefix(clusterNS, clusterName string) string { 17 | return path.Join(prefix, clusterNS, clusterName) + "/" 18 | } 19 | -------------------------------------------------------------------------------- /charts/moco/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /charts/moco/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: moco 3 | description: MySQL operator on Kubernetes using GTID-based semi-synchronous replication. 4 | 5 | # A chart can be either an 'application' or a 'library' chart. 6 | # 7 | # Application charts are a collection of templates that can be packaged into versioned archives 8 | # to be deployed. 9 | # 10 | # Library charts provide useful utilities or functions for the chart developer. They're included as 11 | # a dependency of application charts to inject those utilities and functions into the rendering 12 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 13 | type: application 14 | 15 | # This is the chart version. This version number should be incremented each time you make changes 16 | # to the chart and its templates, including the app version. 17 | # Versions are expected to follow Semantic Versioning (https://semver.org/) 18 | version: 0.17.1 19 | 20 | # This is the version number of the application being deployed. This version number should be 21 | # incremented each time you make changes to the application. Versions are not expected to 22 | # follow Semantic Versioning. They should reflect the version the application is using. 23 | # It is recommended to use it with quotes. 24 | appVersion: 0.27.1 25 | 26 | # This version does not necessarily match the supported version. This version number 27 | # will be updated when there is an obviously uninstallable version. If there are no 28 | # problems, update only moco/README.md#supported-software for the corresponding kubernetes version. 29 | kubeVersion: ">= 1.22.0-0" 30 | -------------------------------------------------------------------------------- /charts/moco/templates/NOTES.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cybozu-go/moco/cfc68f26ae7be73b993da180b1da3589eb57f7d7/charts/moco/templates/NOTES.txt -------------------------------------------------------------------------------- /charts/moco/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "moco.name" -}} 5 | {{- default .Chart.Name | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create chart name and version as used by the chart label. 10 | */}} 11 | {{- define "moco.chart" -}} 12 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 13 | {{- end }} 14 | 15 | {{/* 16 | Common labels 17 | */}} 18 | {{- define "moco.labels" -}} 19 | helm.sh/chart: {{ include "moco.chart" . }} 20 | app.kubernetes.io/name: {{ include "moco.name" . }} 21 | {{- if .Chart.AppVersion }} 22 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 23 | {{- end }} 24 | app.kubernetes.io/managed-by: {{ .Release.Service }} 25 | {{- end }} 26 | -------------------------------------------------------------------------------- /charts/moco/templates/certificate.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cert-manager.io/v1 2 | kind: Certificate 3 | metadata: 4 | name: moco-controller-grpc 5 | namespace: {{ .Release.Namespace }} 6 | labels: 7 | {{- include "moco.labels" . | nindent 4 }} 8 | spec: 9 | commonName: moco-controller 10 | issuerRef: 11 | kind: Issuer 12 | name: moco-grpc-issuer 13 | secretName: moco-controller-grpc 14 | usages: 15 | - digital signature 16 | - key encipherment 17 | - client auth 18 | --- 19 | apiVersion: cert-manager.io/v1 20 | kind: Certificate 21 | metadata: 22 | name: moco-grpc-ca 23 | namespace: {{ .Release.Namespace }} 24 | labels: 25 | {{- include "moco.labels" . | nindent 4 }} 26 | spec: 27 | commonName: MOCO gRPC CA 28 | duration: 87600h0m0s 29 | isCA: true 30 | issuerRef: 31 | kind: Issuer 32 | name: moco-selfsigned-issuer 33 | renewBefore: 720h0m0s 34 | secretName: moco-grpc-ca 35 | --- 36 | apiVersion: cert-manager.io/v1 37 | kind: Certificate 38 | metadata: 39 | name: moco-serving-cert 40 | namespace: {{ .Release.Namespace }} 41 | labels: 42 | {{- include "moco.labels" . | nindent 4 }} 43 | spec: 44 | dnsNames: 45 | - moco-webhook-service.{{ .Release.Namespace }}.svc 46 | - moco-webhook-service.{{ .Release.Namespace }}.svc.cluster.local 47 | issuerRef: 48 | kind: Issuer 49 | name: moco-selfsigned-issuer 50 | secretName: moco-controller-cert 51 | -------------------------------------------------------------------------------- /charts/moco/templates/issuer.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cert-manager.io/v1 2 | kind: Issuer 3 | metadata: 4 | name: moco-grpc-issuer 5 | namespace: {{ .Release.Namespace }} 6 | labels: 7 | {{- include "moco.labels" . | nindent 4 }} 8 | spec: 9 | ca: 10 | secretName: moco-grpc-ca 11 | --- 12 | apiVersion: cert-manager.io/v1 13 | kind: Issuer 14 | metadata: 15 | name: moco-selfsigned-issuer 16 | namespace: {{ .Release.Namespace }} 17 | labels: 18 | {{- include "moco.labels" . | nindent 4 }} 19 | spec: 20 | selfSigned: {} 21 | -------------------------------------------------------------------------------- /charts/moco/values.yaml: -------------------------------------------------------------------------------- 1 | # replicaCount -- Number of controller replicas. 2 | replicaCount: 2 3 | 4 | image: 5 | # image.repository -- MOCO image repository to use. 6 | repository: ghcr.io/cybozu-go/moco 7 | 8 | # image.pullPolicy -- MOCO image pulling policy. 9 | pullPolicy: IfNotPresent 10 | 11 | # image.tag -- MOCO image tag to use. 12 | # @default -- `{{ .Chart.AppVersion }}` 13 | tag: # 0.27.1 14 | 15 | # imagePullSecrets -- Secrets for pulling MOCO image from private repository. 16 | imagePullSecrets: [] 17 | 18 | # resources -- resources used by moco-controller. 19 | resources: 20 | requests: 21 | cpu: 100m 22 | memory: 20Mi 23 | 24 | crds: 25 | # crds.enabled -- Install and update CRDs as part of the Helm chart. 26 | enabled: true 27 | 28 | # extraArgs -- Additional command line flags to pass to moco-controller binary. 29 | extraArgs: [] 30 | 31 | # nodeSelector -- nodeSelector used by moco-controller. 32 | nodeSelector: {} 33 | 34 | # affinity -- affinity used by moco-controller. 35 | affinity: {} 36 | 37 | # tolerations -- tolerations used by moco-controller. 38 | tolerations: [] 39 | 40 | # topologySpreadConstraints -- topologySpreadConstraints used by moco-controller. 41 | topologySpreadConstraints: [] 42 | 43 | # priorityClassName -- PriorityClass used by moco-controller. 44 | priorityClassName: "" 45 | -------------------------------------------------------------------------------- /clustering/agent.go: -------------------------------------------------------------------------------- 1 | package clustering 2 | 3 | import ( 4 | "context" 5 | "io" 6 | "net" 7 | "strconv" 8 | "time" 9 | 10 | agent "github.com/cybozu-go/moco-agent/proto" 11 | mocov1beta2 "github.com/cybozu-go/moco/api/v1beta2" 12 | "github.com/cybozu-go/moco/pkg/cert" 13 | "github.com/cybozu-go/moco/pkg/constants" 14 | "github.com/cybozu-go/moco/pkg/dbop" 15 | "google.golang.org/grpc" 16 | "google.golang.org/grpc/credentials" 17 | "google.golang.org/grpc/keepalive" 18 | ) 19 | 20 | // AgentConn represents a gRPC connection to a moco-agent 21 | type AgentConn interface { 22 | agent.AgentClient 23 | io.Closer 24 | } 25 | 26 | type agentConn struct { 27 | agent.AgentClient 28 | *grpc.ClientConn 29 | } 30 | 31 | var _ AgentConn = agentConn{} 32 | 33 | // AgentFactory represents the interface of a factory to create AgentConn 34 | type AgentFactory interface { 35 | New(ctx context.Context, cluster *mocov1beta2.MySQLCluster, index int) (AgentConn, error) 36 | } 37 | 38 | // NewAgentFactory returns a new AgentFactory. 39 | func NewAgentFactory(r dbop.Resolver, reloader *cert.Reloader) AgentFactory { 40 | return defaultAgentFactory{resolver: r, reloader: reloader} 41 | } 42 | 43 | type defaultAgentFactory struct { 44 | resolver dbop.Resolver 45 | reloader *cert.Reloader 46 | } 47 | 48 | var _ AgentFactory = defaultAgentFactory{} 49 | 50 | func (f defaultAgentFactory) New(ctx context.Context, cluster *mocov1beta2.MySQLCluster, index int) (AgentConn, error) { 51 | ctx, cancel := context.WithTimeout(ctx, 5*time.Second) 52 | defer cancel() 53 | 54 | ip, err := f.resolver.Resolve(ctx, cluster, index) 55 | if err != nil { 56 | return nil, err 57 | } 58 | addr := net.JoinHostPort(ip, strconv.Itoa(constants.AgentPort)) 59 | kp := keepalive.ClientParameters{ 60 | Time: 1 * time.Minute, 61 | } 62 | cred := credentials.NewTLS(f.reloader.TLSClientConfig()) 63 | conn, err := grpc.NewClient(addr, 64 | grpc.WithAuthority(cluster.PodHostname(index)), 65 | grpc.WithTransportCredentials(cred), 66 | grpc.WithKeepaliveParams(kp)) 67 | if err != nil { 68 | return agentConn{}, err 69 | } 70 | return agentConn{ 71 | AgentClient: agent.NewAgentClient(conn), 72 | ClientConn: conn, 73 | }, nil 74 | } 75 | -------------------------------------------------------------------------------- /clustering/log.go: -------------------------------------------------------------------------------- 1 | package clustering 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/go-logr/logr" 7 | ) 8 | 9 | var defaultLog logr.Logger 10 | 11 | // SetDefaultLogger sets the default logger used by the clustering package. 12 | // The default logger is not normally used. It is used when another 13 | // logger is not set in context due to testing or programming errors. 14 | func SetDefaultLogger(log logr.Logger) { 15 | defaultLog = log 16 | } 17 | 18 | func logFromContext(ctx context.Context) logr.Logger { 19 | if log, err := logr.FromContext(ctx); err == nil { 20 | return log 21 | } 22 | return defaultLog 23 | } 24 | -------------------------------------------------------------------------------- /clustering/metrics_test.go: -------------------------------------------------------------------------------- 1 | package clustering 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | 7 | "github.com/onsi/gomega/types" 8 | "github.com/prometheus/client_golang/prometheus" 9 | "github.com/prometheus/client_golang/prometheus/testutil" 10 | ) 11 | 12 | type opMetrics struct { 13 | op string 14 | val float64 15 | } 16 | 17 | func MetricsIs(op string, val float64) *opMetrics { 18 | return &opMetrics{op: op, val: val} 19 | } 20 | 21 | var _ types.GomegaMatcher = &opMetrics{} 22 | 23 | func (m *opMetrics) Match(actual interface{}) (success bool, err error) { 24 | c, ok := actual.(prometheus.Collector) 25 | if !ok { 26 | return false, errors.New("not a collector") 27 | } 28 | val := testutil.ToFloat64(c) 29 | switch m.op { 30 | case "==": 31 | return val == m.val, nil 32 | case ">": 33 | return val > m.val, nil 34 | case ">=": 35 | return val >= m.val, nil 36 | case "<": 37 | return val < m.val, nil 38 | case "<=": 39 | return val <= m.val, nil 40 | } 41 | return false, fmt.Errorf("unsupported operator %s", m.op) 42 | } 43 | 44 | func (m *opMetrics) FailureMessage(actual interface{}) (message string) { 45 | return fmt.Sprintf("given metrics is not %s %f", m.op, m.val) 46 | } 47 | 48 | func (m *opMetrics) NegatedFailureMessage(actual interface{}) (message string) { 49 | return fmt.Sprintf("given metrics is %s %f", m.op, m.val) 50 | } 51 | -------------------------------------------------------------------------------- /cmd/kubectl-moco/cmd/common.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | 8 | mocov1beta2 "github.com/cybozu-go/moco/api/v1beta2" 9 | "github.com/cybozu-go/moco/pkg/constants" 10 | "github.com/cybozu-go/moco/pkg/password" 11 | corev1 "k8s.io/api/core/v1" 12 | "k8s.io/apimachinery/pkg/types" 13 | ) 14 | 15 | func getPassword(ctx context.Context, clusterName, user string) (string, error) { 16 | cluster := &mocov1beta2.MySQLCluster{} 17 | cluster.Name = clusterName 18 | cluster.Namespace = namespace 19 | name := cluster.UserSecretName() 20 | secret := &corev1.Secret{} 21 | if err := kubeClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: name}, secret); err != nil { 22 | return "", err 23 | } 24 | 25 | passwd, err := password.NewMySQLPasswordFromSecret(secret) 26 | if err != nil { 27 | return "", err 28 | } 29 | 30 | switch user { 31 | case constants.AdminUser: 32 | return passwd.Admin(), nil 33 | case constants.ReadOnlyUser: 34 | return passwd.ReadOnly(), nil 35 | case constants.WritableUser: 36 | return passwd.Writable(), nil 37 | } 38 | 39 | return "", fmt.Errorf("invalid user: %s", user) 40 | } 41 | 42 | func getPodName(ctx context.Context, cluster *mocov1beta2.MySQLCluster, index int) (string, error) { 43 | if index >= int(cluster.Spec.Replicas) { 44 | return "", errors.New("index should be smaller than replicas") 45 | } 46 | if index < 0 { 47 | index = cluster.Status.CurrentPrimaryIndex 48 | } 49 | 50 | return cluster.PodName(index), nil 51 | } 52 | -------------------------------------------------------------------------------- /cmd/kubectl-moco/cmd/completion.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "context" 5 | "strings" 6 | 7 | mocov1beta2 "github.com/cybozu-go/moco/api/v1beta2" 8 | "github.com/spf13/cobra" 9 | "sigs.k8s.io/controller-runtime/pkg/client" 10 | ) 11 | 12 | func mysqlClusterCandidates(ctx context.Context, cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { 13 | if len(args) != 0 { 14 | return nil, cobra.ShellCompDirectiveNoFileComp 15 | } 16 | 17 | var namespace string 18 | 19 | if cmd.Flags().Changed("namespace") { 20 | ns, err := cmd.Flags().GetString("namespace") 21 | if err != nil { 22 | return nil, cobra.ShellCompDirectiveError 23 | } 24 | namespace = ns 25 | } else { 26 | ns, _, err := kubeConfigFlags.ToRawKubeConfigLoader().Namespace() 27 | if err != nil { 28 | return nil, cobra.ShellCompDirectiveError 29 | } 30 | namespace = ns 31 | } 32 | 33 | clusters := &mocov1beta2.MySQLClusterList{} 34 | if err := kubeClient.List(ctx, clusters, &client.ListOptions{ 35 | Namespace: namespace, 36 | }); err != nil { 37 | return nil, cobra.ShellCompDirectiveError 38 | } 39 | 40 | var candidates []string 41 | for _, c := range clusters.Items { 42 | if !strings.HasPrefix(c.Name, toComplete) { 43 | continue 44 | } 45 | candidates = append(candidates, c.Name) 46 | } 47 | 48 | return candidates, cobra.ShellCompDirectiveNoFileComp 49 | } 50 | -------------------------------------------------------------------------------- /cmd/kubectl-moco/cmd/credential.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/cybozu-go/moco/pkg/constants" 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | var credentialConfig struct { 12 | user string 13 | format string 14 | } 15 | 16 | // credentialCmd represents the credential command 17 | var credentialCmd = &cobra.Command{ 18 | Use: "credential CLUSTER_NAME", 19 | Short: "Fetch the credential of a specified user", 20 | Long: "Fetch the credential of a specified user.", 21 | Args: cobra.ExactArgs(1), 22 | RunE: func(cmd *cobra.Command, args []string) error { 23 | return fetchCredential(cmd.Context(), args[0]) 24 | }, 25 | ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { 26 | return mysqlClusterCandidates(cmd.Context(), cmd, args, toComplete) 27 | }, 28 | } 29 | 30 | func fetchCredential(ctx context.Context, clusterName string) error { 31 | password, err := getPassword(ctx, clusterName, credentialConfig.user) 32 | if err != nil { 33 | return err 34 | } 35 | switch credentialConfig.format { 36 | case "plain": 37 | fmt.Println(password) 38 | case "mycnf": 39 | fmt.Printf(`[client] 40 | user=%s 41 | password="%s" 42 | `, credentialConfig.user, password) 43 | default: 44 | return fmt.Errorf("unknown format: %s", credentialConfig.format) 45 | } 46 | return nil 47 | } 48 | 49 | func init() { 50 | fs := credentialCmd.Flags() 51 | fs.StringVarP(&credentialConfig.user, "mysql-user", "u", constants.ReadOnlyUser, "User for login to mysql") 52 | fs.StringVar(&credentialConfig.format, "format", "plain", "The format of output [`plain` or `mycnf`]") 53 | 54 | _ = credentialCmd.RegisterFlagCompletionFunc("mysql-user", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { 55 | return []string{constants.ReadOnlyUser, constants.WritableUser, constants.AdminUser}, cobra.ShellCompDirectiveDefault 56 | }) 57 | _ = credentialCmd.RegisterFlagCompletionFunc("format", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { 58 | return []string{"plain", "mycnf"}, cobra.ShellCompDirectiveDefault 59 | }) 60 | 61 | rootCmd.AddCommand(credentialCmd) 62 | } 63 | -------------------------------------------------------------------------------- /cmd/kubectl-moco/cmd/root.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "flag" 5 | "os" 6 | 7 | // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) 8 | _ "k8s.io/client-go/plugin/pkg/client/auth" 9 | 10 | "github.com/cybozu-go/moco" 11 | mocov1beta2 "github.com/cybozu-go/moco/api/v1beta2" 12 | "github.com/spf13/cobra" 13 | "github.com/spf13/pflag" 14 | "k8s.io/apimachinery/pkg/runtime" 15 | "k8s.io/cli-runtime/pkg/genericclioptions" 16 | clientgoscheme "k8s.io/client-go/kubernetes/scheme" 17 | "k8s.io/klog/v2" 18 | "k8s.io/kubectl/pkg/cmd/util" 19 | "sigs.k8s.io/controller-runtime/pkg/client" 20 | ) 21 | 22 | var ( 23 | kubeConfigFlags *genericclioptions.ConfigFlags 24 | kubeClient client.Client 25 | factory util.Factory 26 | namespace string 27 | ) 28 | 29 | func init() { 30 | klog.InitFlags(nil) 31 | pflag.CommandLine.AddGoFlagSet(flag.CommandLine) 32 | kubeConfigFlags = genericclioptions.NewConfigFlags(true) 33 | kubeConfigFlags.AddFlags(rootCmd.PersistentFlags()) 34 | } 35 | 36 | // rootCmd represents the base command when called without any subcommands 37 | var rootCmd = &cobra.Command{ 38 | Use: "kubectl-moco", 39 | Version: moco.Version, 40 | Short: "the utility command for MOCO", 41 | Long: "the utility command for MOCO.", 42 | PersistentPreRunE: func(cmd *cobra.Command, args []string) error { 43 | cmd.SilenceUsage = true 44 | 45 | factory = util.NewFactory(util.NewMatchVersionFlags(kubeConfigFlags)) 46 | restConfig, err := factory.ToRESTConfig() 47 | if err != nil { 48 | return err 49 | } 50 | 51 | scheme := runtime.NewScheme() 52 | err = clientgoscheme.AddToScheme(scheme) 53 | if err != nil { 54 | return err 55 | } 56 | 57 | err = mocov1beta2.AddToScheme(scheme) 58 | if err != nil { 59 | return err 60 | } 61 | 62 | kubeClient, err = client.New(restConfig, client.Options{Scheme: scheme}) 63 | if err != nil { 64 | return err 65 | } 66 | 67 | namespace, _, err = kubeConfigFlags.ToRawKubeConfigLoader().Namespace() 68 | return err 69 | }, 70 | } 71 | 72 | // Execute adds all child commands to the root command and sets flags appropriately. 73 | // This is called by main.main(). It only needs to happen once to the rootCmd. 74 | func Execute() { 75 | defer klog.Flush() 76 | if err := rootCmd.Execute(); err != nil { 77 | os.Exit(1) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /cmd/kubectl-moco/cmd/switchover.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | 7 | mocov1beta2 "github.com/cybozu-go/moco/api/v1beta2" 8 | "github.com/cybozu-go/moco/pkg/constants" 9 | "github.com/spf13/cobra" 10 | corev1 "k8s.io/api/core/v1" 11 | "k8s.io/apimachinery/pkg/types" 12 | ) 13 | 14 | var switchoverCmd = &cobra.Command{ 15 | Use: "switchover CLUSTER_NAME", 16 | Short: "Switch the primary instance", 17 | Long: "Switch the primary instance to one of the replicas.", 18 | Args: cobra.ExactArgs(1), 19 | RunE: func(cmd *cobra.Command, args []string) error { 20 | return switchover(cmd.Context(), args[0]) 21 | }, 22 | ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { 23 | return mysqlClusterCandidates(cmd.Context(), cmd, args, toComplete) 24 | }, 25 | } 26 | 27 | func switchover(ctx context.Context, name string) error { 28 | cluster := &mocov1beta2.MySQLCluster{} 29 | if err := kubeClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: name}, cluster); err != nil { 30 | return err 31 | } 32 | 33 | if cluster.Spec.Offline { 34 | return errors.New("offline cluster is not able to switch") 35 | } 36 | 37 | if cluster.Spec.Replicas == 1 { 38 | return errors.New("single-instance cluster is not able to switch") 39 | } 40 | 41 | podName := cluster.PodName(cluster.Status.CurrentPrimaryIndex) 42 | pod := &corev1.Pod{} 43 | if err := kubeClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: podName}, pod); err != nil { 44 | return err 45 | } 46 | 47 | if pod.Annotations == nil { 48 | pod.Annotations = make(map[string]string) 49 | } 50 | pod.Annotations[constants.AnnDemote] = "true" 51 | 52 | return kubeClient.Update(ctx, pod) 53 | } 54 | 55 | func init() { 56 | rootCmd.AddCommand(switchoverCmd) 57 | } 58 | -------------------------------------------------------------------------------- /cmd/kubectl-moco/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/cybozu-go/moco/cmd/kubectl-moco/cmd" 4 | 5 | func main() { 6 | cmd.Execute() 7 | } 8 | -------------------------------------------------------------------------------- /cmd/moco-backup/cmd/backup.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/cybozu-go/moco/backup" 7 | "github.com/spf13/cobra" 8 | ctrl "sigs.k8s.io/controller-runtime" 9 | ) 10 | 11 | var backupCmd = &cobra.Command{ 12 | Use: "backup BUCKET NAMESPACE NAME", 13 | Short: "backup a MySQLCluster's data to an object storage bucket", 14 | Long: `Backup a MySQLCluster's data. 15 | 16 | BUCKET: The bucket name. 17 | NAMESPACE: The namespace of the MySQLCluster. 18 | NAME: The name of the MySQLCluster.`, 19 | Args: cobra.ExactArgs(3), 20 | RunE: func(cmd *cobra.Command, args []string) error { 21 | bucketName := args[0] 22 | namespace := args[1] 23 | name := args[2] 24 | 25 | b, err := makeBucket(bucketName) 26 | if err != nil { 27 | return fmt.Errorf("failed to create a bucket interface: %w", err) 28 | } 29 | 30 | cfg, err := ctrl.GetConfig() 31 | if err != nil { 32 | return fmt.Errorf("failed to get config for Kubernetes: %w", err) 33 | } 34 | 35 | bm, err := backup.NewBackupManager(cfg, b, commonArgs.workDir, namespace, name, mysqlPassword, commonArgs.threads) 36 | if err != nil { 37 | return fmt.Errorf("failed to create a backup manager: %w", err) 38 | } 39 | return bm.Backup(cmd.Context()) 40 | }, 41 | } 42 | 43 | func init() { 44 | rootCmd.AddCommand(backupCmd) 45 | } 46 | -------------------------------------------------------------------------------- /cmd/moco-backup/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/cybozu-go/moco/cmd/moco-backup/cmd" 5 | ) 6 | 7 | func main() { 8 | cmd.Execute() 9 | } 10 | -------------------------------------------------------------------------------- /cmd/moco-controller/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/cybozu-go/moco/cmd/moco-controller/cmd" 4 | 5 | func main() { 6 | cmd.Execute() 7 | } 8 | -------------------------------------------------------------------------------- /config/certmanager/certificate.yaml: -------------------------------------------------------------------------------- 1 | # The following manifests contain a self-signed issuer CR and a certificate CR. 2 | # More document can be found at https://docs.cert-manager.io 3 | # WARNING: Targets CertManager v1.0. Check https://cert-manager.io/docs/installation/upgrading/ for breaking changes. 4 | apiVersion: cert-manager.io/v1 5 | kind: Issuer 6 | metadata: 7 | name: selfsigned-issuer 8 | namespace: system 9 | spec: 10 | selfSigned: {} 11 | --- 12 | apiVersion: cert-manager.io/v1 13 | kind: Certificate 14 | metadata: 15 | name: serving-cert # this name should match the one appeared in kustomizeconfig.yaml 16 | namespace: system 17 | spec: 18 | # $(SERVICE_NAME) and $(SERVICE_NAMESPACE) will be substituted by kustomize 19 | dnsNames: 20 | - $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc 21 | - $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc.cluster.local 22 | issuerRef: 23 | kind: Issuer 24 | name: selfsigned-issuer 25 | secretName: moco-controller-cert 26 | -------------------------------------------------------------------------------- /config/certmanager/grpc.yaml: -------------------------------------------------------------------------------- 1 | # This file contains resources to create a CA for mTLS gRPC communication 2 | # and a certificate for moco-controller. 3 | apiVersion: cert-manager.io/v1 4 | kind: Certificate 5 | metadata: 6 | name: grpc-ca 7 | namespace: system 8 | spec: 9 | commonName: MOCO gRPC CA 10 | isCA: true 11 | duration: 87600h0m0s # 10 years 12 | renewBefore: 720h0m0s # 30 days 13 | issuerRef: 14 | kind: Issuer 15 | name: selfsigned-issuer 16 | secretName: moco-grpc-ca 17 | --- 18 | apiVersion: cert-manager.io/v1 19 | kind: Issuer 20 | metadata: 21 | name: grpc-issuer 22 | namespace: system 23 | spec: 24 | ca: 25 | secretName: moco-grpc-ca 26 | --- 27 | apiVersion: cert-manager.io/v1 28 | kind: Certificate 29 | metadata: 30 | name: controller-grpc 31 | namespace: system 32 | spec: 33 | commonName: moco-controller 34 | usages: 35 | - digital signature 36 | - key encipherment 37 | - client auth 38 | issuerRef: 39 | kind: Issuer 40 | name: grpc-issuer 41 | secretName: moco-controller-grpc 42 | -------------------------------------------------------------------------------- /config/certmanager/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - certificate.yaml 3 | - grpc.yaml 4 | 5 | configurations: 6 | - kustomizeconfig.yaml 7 | -------------------------------------------------------------------------------- /config/certmanager/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # This configuration is for teaching kustomize how to update name ref and var substitution 2 | nameReference: 3 | - kind: Issuer 4 | group: cert-manager.io 5 | fieldSpecs: 6 | - kind: Certificate 7 | group: cert-manager.io 8 | path: spec/issuerRef/name 9 | 10 | varReference: 11 | - kind: Certificate 12 | group: cert-manager.io 13 | path: spec/commonName 14 | - kind: Certificate 15 | group: cert-manager.io 16 | path: spec/dnsNames 17 | -------------------------------------------------------------------------------- /config/crd/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # This kustomization.yaml is not intended to be run by itself, 2 | # since it depends on service name and namespace that are out of this kustomize package. 3 | # It should be run by config/default 4 | resources: 5 | - bases/moco.cybozu.com_mysqlclusters.yaml 6 | - bases/moco.cybozu.com_backuppolicies.yaml 7 | #+kubebuilder:scaffold:crdkustomizeresource 8 | 9 | patchesStrategicMerge: 10 | - patches/mysqlcluster.yaml 11 | - patches/backuppolicy.yaml 12 | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. 13 | # patches here are for enabling the conversion webhook for each CRD 14 | # - patches/webhook_in_mysqlclusters.yaml 15 | #- patches/webhook_in_backuppolicies.yaml 16 | #+kubebuilder:scaffold:crdkustomizewebhookpatch 17 | 18 | # [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix. 19 | # patches here are for enabling the CA injection for each CRD 20 | - patches/cainjection_in_mysqlclusters.yaml 21 | #- patches/cainjection_in_backuppolicies.yaml 22 | #+kubebuilder:scaffold:crdkustomizecainjectionpatch 23 | 24 | # the following config is for teaching kustomize how to do kustomization for CRDs. 25 | configurations: 26 | - kustomizeconfig.yaml 27 | -------------------------------------------------------------------------------- /config/crd/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # This file is for teaching kustomize how to substitute name and namespace reference in CRD 2 | nameReference: 3 | - kind: Service 4 | version: v1 5 | fieldSpecs: 6 | - kind: CustomResourceDefinition 7 | version: v1 8 | group: apiextensions.k8s.io 9 | path: spec/conversion/webhook/clientConfig/service/name 10 | 11 | namespace: 12 | - kind: CustomResourceDefinition 13 | version: v1 14 | group: apiextensions.k8s.io 15 | path: spec/conversion/webhook/clientConfig/service/namespace 16 | create: false 17 | 18 | varReference: 19 | - path: metadata/annotations 20 | -------------------------------------------------------------------------------- /config/crd/patches/backuppolicy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | name: backuppolicies.moco.cybozu.com 5 | creationTimestamp: null 6 | status: null 7 | -------------------------------------------------------------------------------- /config/crd/patches/cainjection_in_backuppolicies.yaml: -------------------------------------------------------------------------------- 1 | # The following patch adds a directive for certmanager to inject CA into the CRD 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 7 | name: backuppolicies.moco.cybozu.com 8 | -------------------------------------------------------------------------------- /config/crd/patches/cainjection_in_mysqlclusters.yaml: -------------------------------------------------------------------------------- 1 | # The following patch adds a directive for certmanager to inject CA into the CRD 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 7 | name: mysqlclusters.moco.cybozu.com 8 | -------------------------------------------------------------------------------- /config/crd/patches/mysqlcluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | name: mysqlclusters.moco.cybozu.com 5 | creationTimestamp: null 6 | status: null 7 | -------------------------------------------------------------------------------- /config/crd/patches/webhook_in_backuppolicies.yaml: -------------------------------------------------------------------------------- 1 | # The following patch enables a conversion webhook for the CRD 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | name: backuppolicies.moco.cybozu.com 6 | spec: 7 | conversion: 8 | strategy: Webhook 9 | webhook: 10 | clientConfig: 11 | service: 12 | namespace: system 13 | name: webhook-service 14 | path: /convert 15 | -------------------------------------------------------------------------------- /config/crd/patches/webhook_in_mysqlclusters.yaml: -------------------------------------------------------------------------------- 1 | # The following patch enables a conversion webhook for the CRD 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | name: mysqlclusters.moco.cybozu.com 6 | spec: 7 | conversion: 8 | strategy: Webhook 9 | webhook: 10 | clientConfig: 11 | service: 12 | namespace: system 13 | name: webhook-service 14 | path: /convert 15 | conversionReviewVersions: 16 | - v1 17 | -------------------------------------------------------------------------------- /config/default/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # Adds namespace to all resources. 2 | namespace: moco-system 3 | 4 | # Value of this field is prepended to the 5 | # names of all resources, e.g. a deployment named 6 | # "wordpress" becomes "alices-wordpress". 7 | # Note that it should also match with the prefix (text before '-') of the namespace 8 | # field above. 9 | namePrefix: moco- 10 | 11 | # Labels to add to all resources and selectors. 12 | commonLabels: 13 | app.kubernetes.io/name: moco 14 | 15 | bases: 16 | - ../crd 17 | - ../rbac 18 | - ../manager 19 | - ../webhook 20 | - ../certmanager 21 | 22 | patchesStrategicMerge: 23 | - manager_webhook_patch.yaml 24 | - webhookcainjection_patch.yaml 25 | 26 | # the following config is for teaching kustomize how to do var substitution 27 | vars: 28 | - name: CERTIFICATE_NAMESPACE # namespace of the certificate CR 29 | objref: 30 | kind: Certificate 31 | group: cert-manager.io 32 | version: v1 33 | name: serving-cert # this name should match the one in certificate.yaml 34 | fieldref: 35 | fieldpath: metadata.namespace 36 | - name: CERTIFICATE_NAME 37 | objref: 38 | kind: Certificate 39 | group: cert-manager.io 40 | version: v1 41 | name: serving-cert # this name should match the one in certificate.yaml 42 | - name: SERVICE_NAMESPACE # namespace of the service 43 | objref: 44 | kind: Service 45 | version: v1 46 | name: webhook-service 47 | fieldref: 48 | fieldpath: metadata.namespace 49 | - name: SERVICE_NAME 50 | objref: 51 | kind: Service 52 | version: v1 53 | name: webhook-service 54 | -------------------------------------------------------------------------------- /config/default/manager_webhook_patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: controller 5 | namespace: system 6 | spec: 7 | template: 8 | spec: 9 | containers: 10 | - name: moco-controller 11 | ports: 12 | - containerPort: 9443 13 | name: webhook-server 14 | protocol: TCP 15 | volumeMounts: 16 | - mountPath: /tmp/k8s-webhook-server/serving-certs 17 | name: cert 18 | readOnly: true 19 | volumes: 20 | - name: cert 21 | secret: 22 | defaultMode: 420 23 | secretName: moco-controller-cert 24 | -------------------------------------------------------------------------------- /config/default/webhookcainjection_patch.yaml: -------------------------------------------------------------------------------- 1 | # This patch add annotation to admission webhook config and 2 | # the variables $(CERTIFICATE_NAMESPACE) and $(CERTIFICATE_NAME) will be substituted by kustomize. 3 | apiVersion: admissionregistration.k8s.io/v1 4 | kind: MutatingWebhookConfiguration 5 | metadata: 6 | name: mutating-webhook-configuration 7 | annotations: 8 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 9 | --- 10 | apiVersion: admissionregistration.k8s.io/v1 11 | kind: ValidatingWebhookConfiguration 12 | metadata: 13 | name: validating-webhook-configuration 14 | annotations: 15 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 16 | -------------------------------------------------------------------------------- /config/kustomize-to-helm/overlays/crds/conversion-patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | annotations: 5 | cert-manager.io/inject-ca-from: '{{ .Release.Namespace }}/moco-serving-cert' 6 | name: mysqlclusters.moco.cybozu.com 7 | spec: 8 | conversion: 9 | strategy: Webhook 10 | webhook: 11 | clientConfig: 12 | service: 13 | namespace: '{{ .Release.Namespace }}' 14 | name: 'moco-webhook-service' 15 | path: /convert 16 | conversionReviewVersions: 17 | - v1 18 | -------------------------------------------------------------------------------- /config/kustomize-to-helm/overlays/crds/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - ../../../crd 3 | 4 | patchesStrategicMerge: 5 | - conversion-patch.yaml 6 | 7 | commonLabels: 8 | app.kubernetes.io/name: moco 9 | 10 | commonAnnotations: 11 | helm.sh/resource-policy: keep 12 | 13 | transformers: 14 | - label-transformer.yaml 15 | -------------------------------------------------------------------------------- /config/kustomize-to-helm/overlays/crds/label-transformer.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: builtin 2 | kind: LabelTransformer 3 | metadata: 4 | name: helm-metadata-labels 5 | labels: 6 | helm.sh/chart: '{{ include "moco.chart" . }}' 7 | app.kubernetes.io/name: '{{ include "moco.name" . }}' 8 | app.kubernetes.io/version: '{{ .Chart.AppVersion }}' 9 | app.kubernetes.io/managed-by: '{{ .Release.Service }}' 10 | fieldSpecs: 11 | - path: metadata/labels 12 | create: true 13 | -------------------------------------------------------------------------------- /config/kustomize-to-helm/overlays/templates/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - ../../../rbac 3 | - ../../../webhook 4 | 5 | namespace: '{{ .Release.Namespace }}' 6 | 7 | namePrefix: 'moco-' 8 | 9 | commonLabels: 10 | app.kubernetes.io/name: '{{ include "moco.name" . }}' 11 | 12 | patchesStrategicMerge: 13 | - webhookcainjection-patch.yaml 14 | 15 | transformers: 16 | - label-transformer.yaml 17 | -------------------------------------------------------------------------------- /config/kustomize-to-helm/overlays/templates/label-transformer.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: builtin 2 | kind: LabelTransformer 3 | metadata: 4 | name: helm-metadata-labels 5 | labels: 6 | helm.sh/chart: '{{ include "moco.chart" . }}' 7 | app.kubernetes.io/name: '{{ include "moco.name" . }}' 8 | app.kubernetes.io/version: '{{ .Chart.AppVersion }}' 9 | app.kubernetes.io/managed-by: '{{ .Release.Service }}' 10 | fieldSpecs: 11 | - path: metadata/labels 12 | create: true 13 | -------------------------------------------------------------------------------- /config/kustomize-to-helm/overlays/templates/webhookcainjection-patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: admissionregistration.k8s.io/v1 2 | kind: MutatingWebhookConfiguration 3 | metadata: 4 | name: mutating-webhook-configuration 5 | annotations: 6 | cert-manager.io/inject-ca-from: '{{ .Release.Namespace }}/moco-serving-cert' 7 | --- 8 | apiVersion: admissionregistration.k8s.io/v1 9 | kind: ValidatingWebhookConfiguration 10 | metadata: 11 | name: validating-webhook-configuration 12 | annotations: 13 | cert-manager.io/inject-ca-from: '{{ .Release.Namespace }}/moco-serving-cert' 14 | -------------------------------------------------------------------------------- /config/manager/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - manager.yaml 3 | -------------------------------------------------------------------------------- /config/manager/manager.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: system 5 | --- 6 | apiVersion: apps/v1 7 | kind: Deployment 8 | metadata: 9 | name: controller 10 | namespace: system 11 | labels: 12 | app.kubernetes.io/component: moco-controller 13 | spec: 14 | selector: 15 | matchLabels: 16 | app.kubernetes.io/component: moco-controller 17 | replicas: 2 18 | template: 19 | metadata: 20 | annotations: 21 | kubectl.kubernetes.io/default-container: moco-controller 22 | labels: 23 | app.kubernetes.io/component: moco-controller 24 | spec: 25 | securityContext: 26 | runAsNonRoot: true 27 | containers: 28 | - name: moco-controller 29 | image: ghcr.io/cybozu-go/moco:latest 30 | env: 31 | - name: POD_NAMESPACE 32 | valueFrom: 33 | fieldRef: 34 | fieldPath: metadata.namespace 35 | securityContext: 36 | allowPrivilegeEscalation: false 37 | readOnlyRootFilesystem: true 38 | ports: 39 | - name: health 40 | containerPort: 8081 41 | protocol: TCP 42 | - name: metrics 43 | containerPort: 8080 44 | protocol: TCP 45 | livenessProbe: 46 | httpGet: 47 | path: /healthz 48 | port: health 49 | initialDelaySeconds: 15 50 | periodSeconds: 20 51 | readinessProbe: 52 | httpGet: 53 | path: /readyz 54 | port: health 55 | initialDelaySeconds: 5 56 | periodSeconds: 10 57 | resources: 58 | requests: 59 | cpu: 100m 60 | memory: 20Mi 61 | volumeMounts: 62 | - mountPath: /grpc-cert 63 | name: grpc-cert 64 | readOnly: true 65 | volumes: 66 | - name: grpc-cert 67 | secret: 68 | defaultMode: 420 69 | secretName: moco-controller-grpc 70 | serviceAccountName: controller-manager 71 | terminationGracePeriodSeconds: 10 72 | -------------------------------------------------------------------------------- /config/rbac/backuppolicy_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to edit backuppolicies. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: backuppolicy-editor-role 6 | labels: 7 | rbac.authorization.k8s.io/aggregate-to-admin: "true" 8 | rbac.authorization.k8s.io/aggregate-to-edit: "true" 9 | rules: 10 | - apiGroups: 11 | - moco.cybozu.com 12 | resources: 13 | - backuppolicies 14 | verbs: 15 | - create 16 | - delete 17 | - get 18 | - list 19 | - patch 20 | - update 21 | - watch 22 | - apiGroups: 23 | - moco.cybozu.com 24 | resources: 25 | - backuppolicies/status 26 | verbs: 27 | - get 28 | -------------------------------------------------------------------------------- /config/rbac/backuppolicy_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to view backuppolicies. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: backuppolicy-viewer-role 6 | labels: 7 | rbac.authorization.k8s.io/aggregate-to-view: "true" 8 | rules: 9 | - apiGroups: 10 | - moco.cybozu.com 11 | resources: 12 | - backuppolicies 13 | verbs: 14 | - get 15 | - list 16 | - watch 17 | - apiGroups: 18 | - moco.cybozu.com 19 | resources: 20 | - backuppolicies/status 21 | verbs: 22 | - get 23 | -------------------------------------------------------------------------------- /config/rbac/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - role.yaml 3 | - role_binding.yaml 4 | - leader_election_role.yaml 5 | - leader_election_role_binding.yaml 6 | - mysqlcluster_editor_role.yaml 7 | - mysqlcluster_viewer_role.yaml 8 | - backuppolicy_editor_role.yaml 9 | - backuppolicy_viewer_role.yaml 10 | - service_account.yaml 11 | -------------------------------------------------------------------------------- /config/rbac/leader_election_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions to do leader election. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | name: leader-election-role 6 | rules: 7 | - apiGroups: 8 | - "" 9 | - coordination.k8s.io 10 | resources: 11 | - configmaps 12 | - leases 13 | verbs: 14 | - get 15 | - list 16 | - watch 17 | - create 18 | - update 19 | - patch 20 | - delete 21 | - apiGroups: 22 | - "" 23 | resources: 24 | - events 25 | verbs: 26 | - create 27 | - patch 28 | -------------------------------------------------------------------------------- /config/rbac/leader_election_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | name: leader-election-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: Role 8 | name: leader-election-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: controller-manager 12 | namespace: system 13 | -------------------------------------------------------------------------------- /config/rbac/mysqlcluster_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to edit mysqlclusters. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: mysqlcluster-editor-role 6 | labels: 7 | rbac.authorization.k8s.io/aggregate-to-admin: "true" 8 | rbac.authorization.k8s.io/aggregate-to-edit: "true" 9 | rules: 10 | - apiGroups: 11 | - moco.cybozu.com 12 | resources: 13 | - mysqlclusters 14 | verbs: 15 | - create 16 | - delete 17 | - get 18 | - list 19 | - patch 20 | - update 21 | - watch 22 | - apiGroups: 23 | - moco.cybozu.com 24 | resources: 25 | - mysqlclusters/status 26 | verbs: 27 | - get 28 | -------------------------------------------------------------------------------- /config/rbac/mysqlcluster_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to view mysqlclusters. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: mysqlcluster-viewer-role 6 | labels: 7 | rbac.authorization.k8s.io/aggregate-to-view: "true" 8 | rules: 9 | - apiGroups: 10 | - moco.cybozu.com 11 | resources: 12 | - mysqlclusters 13 | verbs: 14 | - get 15 | - list 16 | - watch 17 | - apiGroups: 18 | - moco.cybozu.com 19 | resources: 20 | - mysqlclusters/status 21 | verbs: 22 | - get 23 | -------------------------------------------------------------------------------- /config/rbac/role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: manager-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: manager-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: controller-manager 12 | namespace: system 13 | -------------------------------------------------------------------------------- /config/rbac/service_account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: controller-manager 5 | namespace: system 6 | -------------------------------------------------------------------------------- /config/webhook/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - manifests.yaml 3 | - service.yaml 4 | - validate_preventdelete.yaml 5 | 6 | configurations: 7 | - kustomizeconfig.yaml 8 | -------------------------------------------------------------------------------- /config/webhook/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # the following config is for teaching kustomize where to look at when substituting vars. 2 | # It requires kustomize v2.1.0 or newer to work properly. 3 | nameReference: 4 | - kind: Service 5 | version: v1 6 | fieldSpecs: 7 | - kind: MutatingWebhookConfiguration 8 | group: admissionregistration.k8s.io 9 | path: webhooks/clientConfig/service/name 10 | - kind: ValidatingWebhookConfiguration 11 | group: admissionregistration.k8s.io 12 | path: webhooks/clientConfig/service/name 13 | 14 | namespace: 15 | - kind: MutatingWebhookConfiguration 16 | group: admissionregistration.k8s.io 17 | path: webhooks/clientConfig/service/namespace 18 | create: true 19 | - kind: ValidatingWebhookConfiguration 20 | group: admissionregistration.k8s.io 21 | path: webhooks/clientConfig/service/namespace 22 | create: true 23 | 24 | varReference: 25 | - path: metadata/annotations 26 | -------------------------------------------------------------------------------- /config/webhook/manifests.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: admissionregistration.k8s.io/v1 3 | kind: MutatingWebhookConfiguration 4 | metadata: 5 | name: mutating-webhook-configuration 6 | webhooks: 7 | - admissionReviewVersions: 8 | - v1 9 | clientConfig: 10 | service: 11 | name: webhook-service 12 | namespace: system 13 | path: /mutate-moco-cybozu-com-v1beta2-mysqlcluster 14 | failurePolicy: Fail 15 | matchPolicy: Equivalent 16 | name: mmysqlcluster.kb.io 17 | rules: 18 | - apiGroups: 19 | - moco.cybozu.com 20 | apiVersions: 21 | - v1beta2 22 | operations: 23 | - CREATE 24 | resources: 25 | - mysqlclusters 26 | sideEffects: None 27 | - admissionReviewVersions: 28 | - v1 29 | clientConfig: 30 | service: 31 | name: webhook-service 32 | namespace: system 33 | path: /mutate-apps-v1-statefulset 34 | failurePolicy: Fail 35 | name: statefulset.kb.io 36 | rules: 37 | - apiGroups: 38 | - apps 39 | apiVersions: 40 | - v1 41 | operations: 42 | - CREATE 43 | - UPDATE 44 | resources: 45 | - statefulsets 46 | sideEffects: None 47 | --- 48 | apiVersion: admissionregistration.k8s.io/v1 49 | kind: ValidatingWebhookConfiguration 50 | metadata: 51 | name: validating-webhook-configuration 52 | webhooks: 53 | - admissionReviewVersions: 54 | - v1 55 | clientConfig: 56 | service: 57 | name: webhook-service 58 | namespace: system 59 | path: /validate-moco-cybozu-com-v1beta2-backuppolicy 60 | failurePolicy: Fail 61 | matchPolicy: Equivalent 62 | name: vbackuppolicy.kb.io 63 | rules: 64 | - apiGroups: 65 | - moco.cybozu.com 66 | apiVersions: 67 | - v1beta2 68 | operations: 69 | - CREATE 70 | - UPDATE 71 | - DELETE 72 | resources: 73 | - backuppolicies 74 | sideEffects: None 75 | - admissionReviewVersions: 76 | - v1 77 | clientConfig: 78 | service: 79 | name: webhook-service 80 | namespace: system 81 | path: /validate-moco-cybozu-com-v1beta2-mysqlcluster 82 | failurePolicy: Fail 83 | matchPolicy: Equivalent 84 | name: vmysqlcluster.kb.io 85 | rules: 86 | - apiGroups: 87 | - moco.cybozu.com 88 | apiVersions: 89 | - v1beta2 90 | operations: 91 | - CREATE 92 | - UPDATE 93 | resources: 94 | - mysqlclusters 95 | sideEffects: None 96 | -------------------------------------------------------------------------------- /config/webhook/service.yaml: -------------------------------------------------------------------------------- 1 | 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: webhook-service 6 | namespace: system 7 | spec: 8 | ports: 9 | - port: 443 10 | targetPort: webhook-server 11 | selector: 12 | app.kubernetes.io/component: moco-controller 13 | -------------------------------------------------------------------------------- /config/webhook/validate_preventdelete.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: admissionregistration.k8s.io/v1 2 | kind: ValidatingAdmissionPolicy 3 | metadata: 4 | name: delete-validator 5 | spec: 6 | failurePolicy: Fail 7 | matchConstraints: 8 | resourceRules: 9 | - apiGroups: [""] 10 | apiVersions: ["*"] 11 | operations: ["DELETE"] 12 | resources: ["pods"] 13 | validations: 14 | - expression: | 15 | !has(oldObject.metadata.annotations) || 16 | !("moco.cybozu.com/prevent-delete" in oldObject.metadata.annotations) || 17 | !(oldObject.metadata.annotations["moco.cybozu.com/prevent-delete"] == "true") 18 | messageExpression: oldObject.metadata.name + ' is protected from deletion' 19 | --- 20 | apiVersion: admissionregistration.k8s.io/v1 21 | kind: ValidatingAdmissionPolicyBinding 22 | metadata: 23 | name: delete-validator 24 | spec: 25 | policyName: moco-delete-validator 26 | validationActions: 27 | - Deny 28 | -------------------------------------------------------------------------------- /containers/fluent-bit/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /containers/fluent-bit/README.md: -------------------------------------------------------------------------------- 1 | Fluent Bit container 2 | ==================== 3 | 4 | Build Docker container image for [Fluent Bit][], Log Processor and Forwarder. 5 | 6 | Docker images 7 | ------------- 8 | 9 | Docker images are available on [ghcr.io](https://github.com/cybozu-go/moco/pkgs/container/moco%2Ffluent-bit) 10 | 11 | [Fluent Bit]: https://fluentbit.io/ 12 | -------------------------------------------------------------------------------- /containers/fluent-bit/TAG: -------------------------------------------------------------------------------- 1 | 3.1.7.1 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.18/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.18/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/cybozu/ubuntu-dev:20.04 AS builder 2 | 3 | ARG MYSQL_VERSION=8.0.18 4 | 5 | RUN apt-get update && apt-get -y install --no-install-recommends \ 6 | cmake \ 7 | libncurses5-dev \ 8 | libjemalloc-dev \ 9 | libnuma-dev \ 10 | libaio-dev \ 11 | pkg-config 12 | 13 | RUN cd tmp/ \ 14 | && curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-${MYSQL_VERSION}.tar.gz \ 15 | && tar -x -z -f mysql-boost-${MYSQL_VERSION}.tar.gz \ 16 | && cd mysql-${MYSQL_VERSION} \ 17 | && mkdir bld \ 18 | && cd bld \ 19 | && cmake .. -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=Release -DWITH_BOOST=$(ls -d ../boost/boost_*) -DWITH_NUMA=1 -DWITH_JEMALLOC=1 -DWITH_PACKAGE_FLAGS=0 \ 20 | && make -j 20 \ 21 | && make install 22 | 23 | FROM ghcr.io/cybozu/ubuntu:20.04 24 | 25 | COPY --from=builder /usr/local/mysql/LICENSE /usr/local/mysql/LICENSE 26 | COPY --from=builder /usr/local/mysql/bin /usr/local/mysql/bin 27 | COPY --from=builder /usr/local/mysql/lib /usr/local/mysql/lib 28 | COPY --from=builder /usr/local/mysql/share /usr/local/mysql/share 29 | 30 | RUN apt-get update \ 31 | && apt-get install -y --no-install-recommends libjemalloc2 libnuma1 libaio1 \ 32 | && rm -rf /var/lib/apt/lists/* \ 33 | && mkdir -p /var/lib/mysql \ 34 | && chown -R 10000:10000 /var/lib/mysql 35 | 36 | ENV PATH=/usr/local/mysql/bin:"$PATH" 37 | VOLUME /var/lib/mysql 38 | ENTRYPOINT ["mysqld"] 39 | EXPOSE 3306 33060 33062 8080 40 | USER 10000:10000 41 | -------------------------------------------------------------------------------- /containers/mysql/8.0.18/TAG: -------------------------------------------------------------------------------- 1 | 8.0.18.12 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.18/container-structure-test.yaml: -------------------------------------------------------------------------------- 1 | schemaVersion: '2.0.0' 2 | fileExistenceTests: 3 | - name: 'mysqld' 4 | path: '/usr/local/mysql/bin/mysqld' 5 | shouldExist: true 6 | isExecutableBy: 'owner' 7 | - name: 'mysql lib' 8 | path: '/usr/local/mysql/lib' 9 | shouldExist: true 10 | - name: 'mysql share' 11 | path: '/usr/local/mysql/share' 12 | shouldExist: true 13 | - name: 'mysql LICENSE' 14 | path: '/usr/local/mysql/LICENSE' 15 | shouldExist: true 16 | -------------------------------------------------------------------------------- /containers/mysql/8.0.25/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.25/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/cybozu/ubuntu-dev:20.04 AS builder 2 | 3 | ARG MYSQL_VERSION=8.0.25 4 | 5 | RUN apt-get update && apt-get -y install --no-install-recommends \ 6 | cmake \ 7 | libncurses5-dev \ 8 | libjemalloc-dev \ 9 | libnuma-dev \ 10 | libaio-dev \ 11 | pkg-config 12 | 13 | RUN cd tmp/ \ 14 | && curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-${MYSQL_VERSION}.tar.gz \ 15 | && tar -x -z -f mysql-boost-${MYSQL_VERSION}.tar.gz \ 16 | && cd mysql-${MYSQL_VERSION} \ 17 | && mkdir bld \ 18 | && cd bld \ 19 | && cmake .. -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=Release -DWITH_BOOST=$(ls -d ../boost/boost_*) -DWITH_NUMA=1 -DWITH_JEMALLOC=1 -DWITH_PACKAGE_FLAGS=0 \ 20 | && make -j 20 \ 21 | && make install 22 | 23 | FROM ghcr.io/cybozu/ubuntu:20.04 24 | 25 | COPY --from=builder /usr/local/mysql/LICENSE /usr/local/mysql/LICENSE 26 | COPY --from=builder /usr/local/mysql/bin /usr/local/mysql/bin 27 | COPY --from=builder /usr/local/mysql/lib /usr/local/mysql/lib 28 | COPY --from=builder /usr/local/mysql/share /usr/local/mysql/share 29 | 30 | RUN apt-get update \ 31 | && apt-get install -y --no-install-recommends libjemalloc2 libnuma1 libaio1 \ 32 | && rm -rf /var/lib/apt/lists/* \ 33 | && mkdir -p /var/lib/mysql \ 34 | && chown -R 10000:10000 /var/lib/mysql 35 | 36 | ENV PATH=/usr/local/mysql/bin:"$PATH" 37 | VOLUME /var/lib/mysql 38 | ENTRYPOINT ["mysqld"] 39 | EXPOSE 3306 33060 33062 8080 40 | USER 10000:10000 41 | -------------------------------------------------------------------------------- /containers/mysql/8.0.25/TAG: -------------------------------------------------------------------------------- 1 | 8.0.25.12 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.25/container-structure-test.yaml: -------------------------------------------------------------------------------- 1 | schemaVersion: '2.0.0' 2 | fileExistenceTests: 3 | - name: 'mysqld' 4 | path: '/usr/local/mysql/bin/mysqld' 5 | shouldExist: true 6 | isExecutableBy: 'owner' 7 | - name: 'mysql lib' 8 | path: '/usr/local/mysql/lib' 9 | shouldExist: true 10 | - name: 'mysql share' 11 | path: '/usr/local/mysql/share' 12 | shouldExist: true 13 | - name: 'mysql LICENSE' 14 | path: '/usr/local/mysql/LICENSE' 15 | shouldExist: true 16 | -------------------------------------------------------------------------------- /containers/mysql/8.0.26/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.26/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/cybozu/ubuntu-dev:20.04 AS builder 2 | 3 | ARG MYSQL_VERSION=8.0.26 4 | 5 | RUN apt-get update && apt-get -y install --no-install-recommends \ 6 | cmake \ 7 | libncurses5-dev \ 8 | libjemalloc-dev \ 9 | libnuma-dev \ 10 | libaio-dev \ 11 | pkg-config 12 | 13 | RUN cd tmp/ \ 14 | && curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-${MYSQL_VERSION}.tar.gz \ 15 | && tar -x -z -f mysql-boost-${MYSQL_VERSION}.tar.gz \ 16 | && cd mysql-${MYSQL_VERSION} \ 17 | && mkdir bld \ 18 | && cd bld \ 19 | && cmake .. -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=Release -DWITH_BOOST=$(ls -d ../boost/boost_*) -DWITH_NUMA=1 -DWITH_JEMALLOC=1 -DWITH_PACKAGE_FLAGS=0 \ 20 | && make -j 20 \ 21 | && make install 22 | 23 | FROM ghcr.io/cybozu/ubuntu:20.04 24 | 25 | COPY --from=builder /usr/local/mysql/LICENSE /usr/local/mysql/LICENSE 26 | COPY --from=builder /usr/local/mysql/bin /usr/local/mysql/bin 27 | COPY --from=builder /usr/local/mysql/lib /usr/local/mysql/lib 28 | COPY --from=builder /usr/local/mysql/share /usr/local/mysql/share 29 | 30 | RUN apt-get update \ 31 | && apt-get install -y --no-install-recommends libjemalloc2 libnuma1 libaio1 \ 32 | && rm -rf /var/lib/apt/lists/* \ 33 | && mkdir -p /var/lib/mysql \ 34 | && chown -R 10000:10000 /var/lib/mysql 35 | 36 | ENV PATH=/usr/local/mysql/bin:"$PATH" 37 | VOLUME /var/lib/mysql 38 | ENTRYPOINT ["mysqld"] 39 | EXPOSE 3306 33060 33062 8080 40 | USER 10000:10000 41 | -------------------------------------------------------------------------------- /containers/mysql/8.0.26/TAG: -------------------------------------------------------------------------------- 1 | 8.0.26.13 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.26/container-structure-test.yaml: -------------------------------------------------------------------------------- 1 | schemaVersion: '2.0.0' 2 | fileExistenceTests: 3 | - name: 'mysqld' 4 | path: '/usr/local/mysql/bin/mysqld' 5 | shouldExist: true 6 | isExecutableBy: 'owner' 7 | - name: 'mysql lib' 8 | path: '/usr/local/mysql/lib' 9 | shouldExist: true 10 | - name: 'mysql share' 11 | path: '/usr/local/mysql/share' 12 | shouldExist: true 13 | - name: 'mysql LICENSE' 14 | path: '/usr/local/mysql/LICENSE' 15 | shouldExist: true 16 | -------------------------------------------------------------------------------- /containers/mysql/8.0.27/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.27/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/cybozu/ubuntu-dev:20.04 AS builder 2 | 3 | ARG MYSQL_VERSION=8.0.27 4 | 5 | RUN apt-get update && apt-get -y install --no-install-recommends \ 6 | cmake \ 7 | libncurses5-dev \ 8 | libjemalloc-dev \ 9 | libnuma-dev \ 10 | libaio-dev \ 11 | pkg-config 12 | 13 | RUN cd tmp/ \ 14 | && curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-${MYSQL_VERSION}.tar.gz \ 15 | && tar -x -z -f mysql-boost-${MYSQL_VERSION}.tar.gz \ 16 | && cd mysql-${MYSQL_VERSION} \ 17 | && mkdir bld \ 18 | && cd bld \ 19 | && cmake .. -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=Release -DWITH_BOOST=$(ls -d ../boost/boost_*) -DWITH_NUMA=1 -DWITH_JEMALLOC=1 -DWITH_PACKAGE_FLAGS=0 \ 20 | && make -j 20 \ 21 | && make install 22 | 23 | FROM ghcr.io/cybozu/ubuntu:20.04 24 | 25 | COPY --from=builder /usr/local/mysql/LICENSE /usr/local/mysql/LICENSE 26 | COPY --from=builder /usr/local/mysql/bin /usr/local/mysql/bin 27 | COPY --from=builder /usr/local/mysql/lib /usr/local/mysql/lib 28 | COPY --from=builder /usr/local/mysql/share /usr/local/mysql/share 29 | 30 | RUN apt-get update \ 31 | && apt-get install -y --no-install-recommends libjemalloc2 libnuma1 libaio1 \ 32 | && rm -rf /var/lib/apt/lists/* \ 33 | && mkdir -p /var/lib/mysql \ 34 | && chown -R 10000:10000 /var/lib/mysql 35 | 36 | ENV PATH=/usr/local/mysql/bin:"$PATH" 37 | VOLUME /var/lib/mysql 38 | ENTRYPOINT ["mysqld"] 39 | EXPOSE 3306 33060 33062 8080 40 | USER 10000:10000 41 | -------------------------------------------------------------------------------- /containers/mysql/8.0.27/TAG: -------------------------------------------------------------------------------- 1 | 8.0.27.11 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.27/container-structure-test.yaml: -------------------------------------------------------------------------------- 1 | schemaVersion: '2.0.0' 2 | fileExistenceTests: 3 | - name: 'mysqld' 4 | path: '/usr/local/mysql/bin/mysqld' 5 | shouldExist: true 6 | isExecutableBy: 'owner' 7 | - name: 'mysql lib' 8 | path: '/usr/local/mysql/lib' 9 | shouldExist: true 10 | - name: 'mysql share' 11 | path: '/usr/local/mysql/share' 12 | shouldExist: true 13 | - name: 'mysql LICENSE' 14 | path: '/usr/local/mysql/LICENSE' 15 | shouldExist: true 16 | -------------------------------------------------------------------------------- /containers/mysql/8.0.28/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.28/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/cybozu/ubuntu-dev:20.04 AS builder 2 | 3 | ARG MYSQL_VERSION=8.0.28 4 | 5 | RUN apt-get update && apt-get -y install --no-install-recommends \ 6 | cmake \ 7 | libncurses5-dev \ 8 | libjemalloc-dev \ 9 | libnuma-dev \ 10 | libaio-dev \ 11 | pkg-config 12 | 13 | RUN cd tmp/ \ 14 | && curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-${MYSQL_VERSION}.tar.gz \ 15 | && tar -x -z -f mysql-boost-${MYSQL_VERSION}.tar.gz \ 16 | && cd mysql-${MYSQL_VERSION} \ 17 | && mkdir bld \ 18 | && cd bld \ 19 | && cmake .. -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=Release -DWITH_BOOST=$(ls -d ../boost/boost_*) -DWITH_NUMA=1 -DWITH_JEMALLOC=1 -DWITH_PACKAGE_FLAGS=0 \ 20 | && make -j 20 \ 21 | && make install 22 | 23 | FROM ghcr.io/cybozu/ubuntu:20.04 24 | 25 | COPY --from=builder /usr/local/mysql/LICENSE /usr/local/mysql/LICENSE 26 | COPY --from=builder /usr/local/mysql/bin /usr/local/mysql/bin 27 | COPY --from=builder /usr/local/mysql/lib /usr/local/mysql/lib 28 | COPY --from=builder /usr/local/mysql/share /usr/local/mysql/share 29 | 30 | RUN apt-get update \ 31 | && apt-get install -y --no-install-recommends libjemalloc2 libnuma1 libaio1 \ 32 | && rm -rf /var/lib/apt/lists/* \ 33 | && mkdir -p /var/lib/mysql \ 34 | && chown -R 10000:10000 /var/lib/mysql 35 | 36 | ENV PATH=/usr/local/mysql/bin:"$PATH" 37 | VOLUME /var/lib/mysql 38 | ENTRYPOINT ["mysqld"] 39 | EXPOSE 3306 33060 33062 8080 40 | USER 10000:10000 41 | -------------------------------------------------------------------------------- /containers/mysql/8.0.28/TAG: -------------------------------------------------------------------------------- 1 | 8.0.28.14 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.28/container-structure-test.yaml: -------------------------------------------------------------------------------- 1 | schemaVersion: '2.0.0' 2 | fileExistenceTests: 3 | - name: 'mysqld' 4 | path: '/usr/local/mysql/bin/mysqld' 5 | shouldExist: true 6 | isExecutableBy: 'owner' 7 | - name: 'mysql lib' 8 | path: '/usr/local/mysql/lib' 9 | shouldExist: true 10 | - name: 'mysql share' 11 | path: '/usr/local/mysql/share' 12 | shouldExist: true 13 | - name: 'mysql LICENSE' 14 | path: '/usr/local/mysql/LICENSE' 15 | shouldExist: true 16 | -------------------------------------------------------------------------------- /containers/mysql/8.0.30/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.30/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/cybozu/ubuntu-dev:20.04 AS builder 2 | 3 | ARG MYSQL_VERSION=8.0.30 4 | 5 | RUN apt-get update && apt-get -y install --no-install-recommends \ 6 | cmake \ 7 | libncurses5-dev \ 8 | libjemalloc-dev \ 9 | libnuma-dev \ 10 | libaio-dev \ 11 | pkg-config 12 | 13 | RUN cd tmp/ \ 14 | && curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-${MYSQL_VERSION}.tar.gz \ 15 | && tar -x -z -f mysql-boost-${MYSQL_VERSION}.tar.gz \ 16 | && cd mysql-${MYSQL_VERSION} \ 17 | && mkdir bld \ 18 | && cd bld \ 19 | && cmake .. -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=Release -DWITH_BOOST=$(ls -d ../boost/boost_*) -DWITH_NUMA=1 -DWITH_JEMALLOC=1 -DWITH_PACKAGE_FLAGS=0 \ 20 | && make -j 20 \ 21 | && make install 22 | 23 | FROM ghcr.io/cybozu/ubuntu:20.04 24 | 25 | COPY --from=builder /usr/local/mysql/LICENSE /usr/local/mysql/LICENSE 26 | COPY --from=builder /usr/local/mysql/bin /usr/local/mysql/bin 27 | COPY --from=builder /usr/local/mysql/lib /usr/local/mysql/lib 28 | COPY --from=builder /usr/local/mysql/share /usr/local/mysql/share 29 | 30 | RUN apt-get update \ 31 | && apt-get install -y --no-install-recommends libjemalloc2 libnuma1 libaio1 \ 32 | && rm -rf /var/lib/apt/lists/* \ 33 | && mkdir -p /var/lib/mysql \ 34 | && chown -R 10000:10000 /var/lib/mysql 35 | 36 | ENV PATH=/usr/local/mysql/bin:"$PATH" 37 | VOLUME /var/lib/mysql 38 | ENTRYPOINT ["mysqld"] 39 | EXPOSE 3306 33060 33062 8080 40 | USER 10000:10000 41 | -------------------------------------------------------------------------------- /containers/mysql/8.0.30/TAG: -------------------------------------------------------------------------------- 1 | 8.0.30.11 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.30/container-structure-test.yaml: -------------------------------------------------------------------------------- 1 | schemaVersion: '2.0.0' 2 | fileExistenceTests: 3 | - name: 'mysqld' 4 | path: '/usr/local/mysql/bin/mysqld' 5 | shouldExist: true 6 | isExecutableBy: 'owner' 7 | - name: 'mysql lib' 8 | path: '/usr/local/mysql/lib' 9 | shouldExist: true 10 | - name: 'mysql share' 11 | path: '/usr/local/mysql/share' 12 | shouldExist: true 13 | - name: 'mysql LICENSE' 14 | path: '/usr/local/mysql/LICENSE' 15 | shouldExist: true 16 | -------------------------------------------------------------------------------- /containers/mysql/8.0.31/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.31/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/cybozu/ubuntu-dev:20.04 AS builder 2 | 3 | ARG MYSQL_VERSION=8.0.31 4 | 5 | RUN apt-get update && apt-get -y install --no-install-recommends \ 6 | cmake \ 7 | libncurses5-dev \ 8 | libjemalloc-dev \ 9 | libnuma-dev \ 10 | libaio-dev \ 11 | pkg-config 12 | 13 | RUN cd tmp/ \ 14 | && curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-${MYSQL_VERSION}.tar.gz \ 15 | && tar -x -z -f mysql-boost-${MYSQL_VERSION}.tar.gz \ 16 | && cd mysql-${MYSQL_VERSION} \ 17 | && mkdir bld \ 18 | && cd bld \ 19 | && cmake .. -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=Release -DWITH_BOOST=$(ls -d ../boost/boost_*) -DWITH_NUMA=1 -DWITH_JEMALLOC=1 -DWITH_PACKAGE_FLAGS=0 \ 20 | && make -j 20 \ 21 | && make install 22 | 23 | FROM ghcr.io/cybozu/ubuntu:20.04 24 | 25 | COPY --from=builder /usr/local/mysql/LICENSE /usr/local/mysql/LICENSE 26 | COPY --from=builder /usr/local/mysql/bin /usr/local/mysql/bin 27 | COPY --from=builder /usr/local/mysql/lib /usr/local/mysql/lib 28 | COPY --from=builder /usr/local/mysql/share /usr/local/mysql/share 29 | 30 | RUN apt-get update \ 31 | && apt-get install -y --no-install-recommends libjemalloc2 libnuma1 libaio1 \ 32 | && rm -rf /var/lib/apt/lists/* \ 33 | && mkdir -p /var/lib/mysql \ 34 | && chown -R 10000:10000 /var/lib/mysql 35 | 36 | ENV PATH=/usr/local/mysql/bin:"$PATH" 37 | VOLUME /var/lib/mysql 38 | ENTRYPOINT ["mysqld"] 39 | EXPOSE 3306 33060 33062 8080 40 | USER 10000:10000 41 | -------------------------------------------------------------------------------- /containers/mysql/8.0.31/TAG: -------------------------------------------------------------------------------- 1 | 8.0.31.10 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.31/container-structure-test.yaml: -------------------------------------------------------------------------------- 1 | schemaVersion: '2.0.0' 2 | fileExistenceTests: 3 | - name: 'mysqld' 4 | path: '/usr/local/mysql/bin/mysqld' 5 | shouldExist: true 6 | isExecutableBy: 'owner' 7 | - name: 'mysql lib' 8 | path: '/usr/local/mysql/lib' 9 | shouldExist: true 10 | - name: 'mysql share' 11 | path: '/usr/local/mysql/share' 12 | shouldExist: true 13 | - name: 'mysql LICENSE' 14 | path: '/usr/local/mysql/LICENSE' 15 | shouldExist: true 16 | -------------------------------------------------------------------------------- /containers/mysql/8.0.32/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.32/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/cybozu/ubuntu-dev:20.04 AS builder 2 | 3 | ARG MYSQL_VERSION=8.0.32 4 | 5 | RUN apt-get update && apt-get -y install --no-install-recommends \ 6 | cmake \ 7 | libncurses5-dev \ 8 | libjemalloc-dev \ 9 | libnuma-dev \ 10 | libaio-dev \ 11 | pkg-config 12 | 13 | RUN cd tmp/ \ 14 | && curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-${MYSQL_VERSION}.tar.gz \ 15 | && tar -x -z -f mysql-boost-${MYSQL_VERSION}.tar.gz \ 16 | && cd mysql-${MYSQL_VERSION} \ 17 | && mkdir bld \ 18 | && cd bld \ 19 | && cmake .. -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=Release -DWITH_BOOST=$(ls -d ../boost/boost_*) -DWITH_NUMA=1 -DWITH_JEMALLOC=1 -DWITH_PACKAGE_FLAGS=0 \ 20 | && make -j 20 \ 21 | && make install 22 | 23 | FROM ghcr.io/cybozu/ubuntu:20.04 24 | 25 | COPY --from=builder /usr/local/mysql/LICENSE /usr/local/mysql/LICENSE 26 | COPY --from=builder /usr/local/mysql/bin /usr/local/mysql/bin 27 | COPY --from=builder /usr/local/mysql/lib /usr/local/mysql/lib 28 | COPY --from=builder /usr/local/mysql/share /usr/local/mysql/share 29 | 30 | RUN apt-get update \ 31 | && apt-get install -y --no-install-recommends libjemalloc2 libnuma1 libaio1 \ 32 | && rm -rf /var/lib/apt/lists/* \ 33 | && mkdir -p /var/lib/mysql \ 34 | && chown -R 10000:10000 /var/lib/mysql 35 | 36 | ENV PATH=/usr/local/mysql/bin:"$PATH" 37 | VOLUME /var/lib/mysql 38 | ENTRYPOINT ["mysqld"] 39 | EXPOSE 3306 33060 33062 8080 40 | USER 10000:10000 41 | -------------------------------------------------------------------------------- /containers/mysql/8.0.32/TAG: -------------------------------------------------------------------------------- 1 | 8.0.32.5 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.32/container-structure-test.yaml: -------------------------------------------------------------------------------- 1 | schemaVersion: '2.0.0' 2 | fileExistenceTests: 3 | - name: 'mysqld' 4 | path: '/usr/local/mysql/bin/mysqld' 5 | shouldExist: true 6 | isExecutableBy: 'owner' 7 | - name: 'mysql lib' 8 | path: '/usr/local/mysql/lib' 9 | shouldExist: true 10 | - name: 'mysql share' 11 | path: '/usr/local/mysql/share' 12 | shouldExist: true 13 | - name: 'mysql LICENSE' 14 | path: '/usr/local/mysql/LICENSE' 15 | shouldExist: true 16 | -------------------------------------------------------------------------------- /containers/mysql/8.0.33/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.33/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/cybozu/ubuntu-dev:22.04 AS builder 2 | 3 | ARG MYSQL_VERSION=8.0.33 4 | 5 | RUN apt-get update && apt-get -y install --no-install-recommends \ 6 | cmake \ 7 | libncurses5-dev \ 8 | libjemalloc-dev \ 9 | libnuma-dev \ 10 | libaio-dev \ 11 | pkg-config 12 | 13 | RUN cd tmp/ \ 14 | && curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-${MYSQL_VERSION}.tar.gz \ 15 | && tar -x -z -f mysql-boost-${MYSQL_VERSION}.tar.gz \ 16 | && cd mysql-${MYSQL_VERSION} \ 17 | && mkdir bld \ 18 | && cd bld \ 19 | && cmake .. -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=Release -DWITH_BOOST=$(ls -d ../boost/boost_*) -DWITH_NUMA=1 -DWITH_JEMALLOC=1 -DWITH_PACKAGE_FLAGS=0 \ 20 | && make -j 20 \ 21 | && make install 22 | 23 | FROM ghcr.io/cybozu/ubuntu:22.04 24 | 25 | COPY --from=builder /usr/local/mysql/LICENSE /usr/local/mysql/LICENSE 26 | COPY --from=builder /usr/local/mysql/bin /usr/local/mysql/bin 27 | COPY --from=builder /usr/local/mysql/lib /usr/local/mysql/lib 28 | COPY --from=builder /usr/local/mysql/share /usr/local/mysql/share 29 | 30 | RUN apt-get update \ 31 | && apt-get install -y --no-install-recommends libjemalloc2 libnuma1 libaio1 \ 32 | && rm -rf /var/lib/apt/lists/* \ 33 | && mkdir -p /var/lib/mysql \ 34 | && chown -R 10000:10000 /var/lib/mysql 35 | 36 | ENV PATH=/usr/local/mysql/bin:"$PATH" 37 | VOLUME /var/lib/mysql 38 | ENTRYPOINT ["mysqld"] 39 | EXPOSE 3306 33060 33062 8080 40 | USER 10000:10000 41 | -------------------------------------------------------------------------------- /containers/mysql/8.0.33/TAG: -------------------------------------------------------------------------------- 1 | 8.0.33.4 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.33/container-structure-test.yaml: -------------------------------------------------------------------------------- 1 | schemaVersion: '2.0.0' 2 | fileExistenceTests: 3 | - name: 'mysqld' 4 | path: '/usr/local/mysql/bin/mysqld' 5 | shouldExist: true 6 | isExecutableBy: 'owner' 7 | - name: 'mysql lib' 8 | path: '/usr/local/mysql/lib' 9 | shouldExist: true 10 | - name: 'mysql share' 11 | path: '/usr/local/mysql/share' 12 | shouldExist: true 13 | - name: 'mysql LICENSE' 14 | path: '/usr/local/mysql/LICENSE' 15 | shouldExist: true 16 | -------------------------------------------------------------------------------- /containers/mysql/8.0.34/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.34/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/cybozu/ubuntu-dev:22.04 AS builder 2 | 3 | ARG MYSQL_VERSION=8.0.34 4 | 5 | RUN apt-get update && apt-get -y install --no-install-recommends \ 6 | cmake \ 7 | libncurses5-dev \ 8 | libjemalloc-dev \ 9 | libnuma-dev \ 10 | libaio-dev \ 11 | pkg-config 12 | 13 | RUN cd tmp/ \ 14 | && curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-${MYSQL_VERSION}.tar.gz \ 15 | && tar -x -z -f mysql-boost-${MYSQL_VERSION}.tar.gz \ 16 | && cd mysql-${MYSQL_VERSION} \ 17 | && mkdir bld \ 18 | && cd bld \ 19 | && cmake .. -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=Release -DWITH_BOOST=$(ls -d ../boost/boost_*) -DWITH_NUMA=1 -DWITH_JEMALLOC=1 -DWITH_PACKAGE_FLAGS=0 \ 20 | && make -j 20 \ 21 | && make install 22 | 23 | FROM ghcr.io/cybozu/ubuntu:22.04 24 | 25 | COPY --from=builder /usr/local/mysql/LICENSE /usr/local/mysql/LICENSE 26 | COPY --from=builder /usr/local/mysql/bin /usr/local/mysql/bin 27 | COPY --from=builder /usr/local/mysql/lib /usr/local/mysql/lib 28 | COPY --from=builder /usr/local/mysql/share /usr/local/mysql/share 29 | 30 | RUN apt-get update \ 31 | && apt-get install -y --no-install-recommends libjemalloc2 libnuma1 libaio1 \ 32 | && rm -rf /var/lib/apt/lists/* \ 33 | && mkdir -p /var/lib/mysql \ 34 | && chown -R 10000:10000 /var/lib/mysql 35 | 36 | ENV PATH=/usr/local/mysql/bin:"$PATH" 37 | VOLUME /var/lib/mysql 38 | ENTRYPOINT ["mysqld"] 39 | EXPOSE 3306 33060 33062 8080 40 | USER 10000:10000 41 | -------------------------------------------------------------------------------- /containers/mysql/8.0.34/TAG: -------------------------------------------------------------------------------- 1 | 8.0.34.4 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.34/container-structure-test.yaml: -------------------------------------------------------------------------------- 1 | schemaVersion: '2.0.0' 2 | fileExistenceTests: 3 | - name: 'mysqld' 4 | path: '/usr/local/mysql/bin/mysqld' 5 | shouldExist: true 6 | isExecutableBy: 'owner' 7 | - name: 'mysql lib' 8 | path: '/usr/local/mysql/lib' 9 | shouldExist: true 10 | - name: 'mysql share' 11 | path: '/usr/local/mysql/share' 12 | shouldExist: true 13 | - name: 'mysql LICENSE' 14 | path: '/usr/local/mysql/LICENSE' 15 | shouldExist: true 16 | -------------------------------------------------------------------------------- /containers/mysql/8.0.35/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.35/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/cybozu/ubuntu-dev:22.04 AS builder 2 | 3 | ARG MYSQL_VERSION=8.0.35 4 | 5 | RUN apt-get update && apt-get -y install --no-install-recommends \ 6 | cmake \ 7 | libncurses5-dev \ 8 | libjemalloc-dev \ 9 | libnuma-dev \ 10 | libaio-dev \ 11 | pkg-config 12 | 13 | RUN cd tmp/ \ 14 | && curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-${MYSQL_VERSION}.tar.gz \ 15 | && tar -x -z -f mysql-boost-${MYSQL_VERSION}.tar.gz \ 16 | && cd mysql-${MYSQL_VERSION} \ 17 | && mkdir bld \ 18 | && cd bld \ 19 | && cmake .. -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=Release -DWITH_BOOST=$(ls -d ../boost/boost_*) -DWITH_NUMA=1 -DWITH_JEMALLOC=1 -DWITH_PACKAGE_FLAGS=0 \ 20 | && make -j 20 \ 21 | && make install 22 | 23 | FROM ghcr.io/cybozu/ubuntu:22.04 24 | 25 | COPY --from=builder /usr/local/mysql/LICENSE /usr/local/mysql/LICENSE 26 | COPY --from=builder /usr/local/mysql/bin /usr/local/mysql/bin 27 | COPY --from=builder /usr/local/mysql/lib /usr/local/mysql/lib 28 | COPY --from=builder /usr/local/mysql/share /usr/local/mysql/share 29 | 30 | RUN apt-get update \ 31 | && apt-get install -y --no-install-recommends libjemalloc2 libnuma1 libaio1 \ 32 | && rm -rf /var/lib/apt/lists/* \ 33 | && mkdir -p /var/lib/mysql \ 34 | && chown -R 10000:10000 /var/lib/mysql 35 | 36 | ENV PATH=/usr/local/mysql/bin:"$PATH" 37 | VOLUME /var/lib/mysql 38 | ENTRYPOINT ["mysqld"] 39 | EXPOSE 3306 33060 33062 8080 40 | USER 10000:10000 41 | -------------------------------------------------------------------------------- /containers/mysql/8.0.35/TAG: -------------------------------------------------------------------------------- 1 | 8.0.35.3 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.35/container-structure-test.yaml: -------------------------------------------------------------------------------- 1 | schemaVersion: '2.0.0' 2 | fileExistenceTests: 3 | - name: 'mysqld' 4 | path: '/usr/local/mysql/bin/mysqld' 5 | shouldExist: true 6 | isExecutableBy: 'owner' 7 | - name: 'mysql lib' 8 | path: '/usr/local/mysql/lib' 9 | shouldExist: true 10 | - name: 'mysql share' 11 | path: '/usr/local/mysql/share' 12 | shouldExist: true 13 | - name: 'mysql LICENSE' 14 | path: '/usr/local/mysql/LICENSE' 15 | shouldExist: true 16 | -------------------------------------------------------------------------------- /containers/mysql/8.0.36/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.36/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/cybozu/ubuntu-dev:22.04 AS builder 2 | 3 | ARG MYSQL_VERSION=8.0.36 4 | 5 | RUN apt-get update && apt-get -y install --no-install-recommends \ 6 | cmake \ 7 | libncurses5-dev \ 8 | libjemalloc-dev \ 9 | libnuma-dev \ 10 | libaio-dev \ 11 | pkg-config 12 | 13 | RUN cd tmp/ \ 14 | && curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-${MYSQL_VERSION}.tar.gz \ 15 | && tar -x -z -f mysql-boost-${MYSQL_VERSION}.tar.gz \ 16 | && cd mysql-${MYSQL_VERSION} \ 17 | && mkdir bld \ 18 | && cd bld \ 19 | && cmake .. -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=Release -DWITH_BOOST=$(ls -d ../boost/boost_*) -DWITH_NUMA=1 -DWITH_JEMALLOC=1 -DWITH_PACKAGE_FLAGS=0 \ 20 | && make -j 20 \ 21 | && make install 22 | 23 | FROM ghcr.io/cybozu/ubuntu:22.04 24 | 25 | COPY --from=builder /usr/local/mysql/LICENSE /usr/local/mysql/LICENSE 26 | COPY --from=builder /usr/local/mysql/bin /usr/local/mysql/bin 27 | COPY --from=builder /usr/local/mysql/lib /usr/local/mysql/lib 28 | COPY --from=builder /usr/local/mysql/share /usr/local/mysql/share 29 | 30 | RUN apt-get update \ 31 | && apt-get install -y --no-install-recommends libjemalloc2 libnuma1 libaio1 \ 32 | && rm -rf /var/lib/apt/lists/* \ 33 | && mkdir -p /var/lib/mysql \ 34 | && chown -R 10000:10000 /var/lib/mysql 35 | 36 | ENV PATH=/usr/local/mysql/bin:"$PATH" 37 | VOLUME /var/lib/mysql 38 | ENTRYPOINT ["mysqld"] 39 | EXPOSE 3306 33060 33062 8080 40 | USER 10000:10000 41 | -------------------------------------------------------------------------------- /containers/mysql/8.0.36/TAG: -------------------------------------------------------------------------------- 1 | 8.0.36.3 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.36/container-structure-test.yaml: -------------------------------------------------------------------------------- 1 | schemaVersion: '2.0.0' 2 | fileExistenceTests: 3 | - name: 'mysqld' 4 | path: '/usr/local/mysql/bin/mysqld' 5 | shouldExist: true 6 | isExecutableBy: 'owner' 7 | - name: 'mysql lib' 8 | path: '/usr/local/mysql/lib' 9 | shouldExist: true 10 | - name: 'mysql share' 11 | path: '/usr/local/mysql/share' 12 | shouldExist: true 13 | - name: 'mysql LICENSE' 14 | path: '/usr/local/mysql/LICENSE' 15 | shouldExist: true 16 | -------------------------------------------------------------------------------- /containers/mysql/8.0.37/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.37/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/cybozu/ubuntu-dev:22.04 AS builder 2 | 3 | ARG MYSQL_VERSION=8.0.37 4 | 5 | RUN apt-get update && apt-get -y install --no-install-recommends \ 6 | cmake \ 7 | libncurses5-dev \ 8 | libjemalloc-dev \ 9 | libnuma-dev \ 10 | libaio-dev \ 11 | pkg-config 12 | 13 | RUN cd tmp/ \ 14 | && curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-${MYSQL_VERSION}.tar.gz \ 15 | && tar -x -z -f mysql-boost-${MYSQL_VERSION}.tar.gz \ 16 | && cd mysql-${MYSQL_VERSION} \ 17 | && mkdir bld \ 18 | && cd bld \ 19 | && cmake .. -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=Release -DWITH_BOOST=$(ls -d ../boost/boost_*) -DWITH_NUMA=1 -DWITH_JEMALLOC=1 -DWITH_PACKAGE_FLAGS=0 \ 20 | && make -j 20 \ 21 | && make install 22 | 23 | FROM ghcr.io/cybozu/ubuntu:22.04 24 | 25 | COPY --from=builder /usr/local/mysql/LICENSE /usr/local/mysql/LICENSE 26 | COPY --from=builder /usr/local/mysql/bin /usr/local/mysql/bin 27 | COPY --from=builder /usr/local/mysql/lib /usr/local/mysql/lib 28 | COPY --from=builder /usr/local/mysql/share /usr/local/mysql/share 29 | 30 | RUN apt-get update \ 31 | && apt-get install -y --no-install-recommends libjemalloc2 libnuma1 libaio1 \ 32 | && rm -rf /var/lib/apt/lists/* \ 33 | && mkdir -p /var/lib/mysql \ 34 | && chown -R 10000:10000 /var/lib/mysql 35 | 36 | ENV PATH=/usr/local/mysql/bin:"$PATH" 37 | VOLUME /var/lib/mysql 38 | ENTRYPOINT ["mysqld"] 39 | EXPOSE 3306 33060 33062 8080 40 | USER 10000:10000 41 | -------------------------------------------------------------------------------- /containers/mysql/8.0.37/TAG: -------------------------------------------------------------------------------- 1 | 8.0.37.2 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.37/container-structure-test.yaml: -------------------------------------------------------------------------------- 1 | schemaVersion: '2.0.0' 2 | fileExistenceTests: 3 | - name: 'mysqld' 4 | path: '/usr/local/mysql/bin/mysqld' 5 | shouldExist: true 6 | isExecutableBy: 'owner' 7 | - name: 'mysql lib' 8 | path: '/usr/local/mysql/lib' 9 | shouldExist: true 10 | - name: 'mysql share' 11 | path: '/usr/local/mysql/share' 12 | shouldExist: true 13 | - name: 'mysql LICENSE' 14 | path: '/usr/local/mysql/LICENSE' 15 | shouldExist: true 16 | -------------------------------------------------------------------------------- /containers/mysql/8.0.39/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.39/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/cybozu/ubuntu-dev:22.04 AS builder 2 | 3 | ARG MYSQL_VERSION=8.0.39 4 | 5 | RUN apt-get update && apt-get -y install --no-install-recommends \ 6 | cmake \ 7 | libncurses5-dev \ 8 | libjemalloc-dev \ 9 | libnuma-dev \ 10 | libaio-dev \ 11 | pkg-config 12 | 13 | RUN cd tmp/ \ 14 | && curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-${MYSQL_VERSION}.tar.gz \ 15 | && tar -x -z -f mysql-boost-${MYSQL_VERSION}.tar.gz \ 16 | && cd mysql-${MYSQL_VERSION} \ 17 | && mkdir bld \ 18 | && cd bld \ 19 | && cmake .. -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=Release -DWITH_BOOST=$(ls -d ../boost/boost_*) -DWITH_NUMA=1 -DWITH_JEMALLOC=1 -DWITH_PACKAGE_FLAGS=0 \ 20 | && make -j 20 \ 21 | && make install 22 | 23 | FROM ghcr.io/cybozu/ubuntu:22.04 24 | 25 | COPY --from=builder /usr/local/mysql/LICENSE /usr/local/mysql/LICENSE 26 | COPY --from=builder /usr/local/mysql/bin /usr/local/mysql/bin 27 | COPY --from=builder /usr/local/mysql/lib /usr/local/mysql/lib 28 | COPY --from=builder /usr/local/mysql/share /usr/local/mysql/share 29 | 30 | RUN apt-get update \ 31 | && apt-get install -y --no-install-recommends libjemalloc2 libnuma1 libaio1 \ 32 | && rm -rf /var/lib/apt/lists/* \ 33 | && mkdir -p /var/lib/mysql \ 34 | && chown -R 10000:10000 /var/lib/mysql 35 | 36 | ENV PATH=/usr/local/mysql/bin:"$PATH" 37 | VOLUME /var/lib/mysql 38 | ENTRYPOINT ["mysqld"] 39 | EXPOSE 3306 33060 33062 8080 40 | USER 10000:10000 41 | -------------------------------------------------------------------------------- /containers/mysql/8.0.39/TAG: -------------------------------------------------------------------------------- 1 | 8.0.39.1 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.39/container-structure-test.yaml: -------------------------------------------------------------------------------- 1 | schemaVersion: '2.0.0' 2 | fileExistenceTests: 3 | - name: 'mysqld' 4 | path: '/usr/local/mysql/bin/mysqld' 5 | shouldExist: true 6 | isExecutableBy: 'owner' 7 | - name: 'mysql lib' 8 | path: '/usr/local/mysql/lib' 9 | shouldExist: true 10 | - name: 'mysql share' 11 | path: '/usr/local/mysql/share' 12 | shouldExist: true 13 | - name: 'mysql LICENSE' 14 | path: '/usr/local/mysql/LICENSE' 15 | shouldExist: true 16 | -------------------------------------------------------------------------------- /containers/mysql/8.0.40/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.40/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/cybozu/ubuntu-dev:22.04 AS builder 2 | 3 | ARG MYSQL_VERSION=8.0.40 4 | 5 | RUN apt-get update && apt-get -y install --no-install-recommends \ 6 | cmake \ 7 | libncurses5-dev \ 8 | libjemalloc-dev \ 9 | libnuma-dev \ 10 | libaio-dev \ 11 | pkg-config 12 | 13 | RUN cd tmp/ \ 14 | && curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-${MYSQL_VERSION}.tar.gz \ 15 | && tar -x -z -f mysql-boost-${MYSQL_VERSION}.tar.gz \ 16 | && cd mysql-${MYSQL_VERSION} \ 17 | && mkdir bld \ 18 | && cd bld \ 19 | && cmake .. -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=Release -DWITH_BOOST=$(ls -d ../boost/boost_*) -DWITH_NUMA=1 -DWITH_JEMALLOC=1 -DWITH_PACKAGE_FLAGS=0 \ 20 | && make -j 20 \ 21 | && make install 22 | 23 | FROM ghcr.io/cybozu/ubuntu:22.04 24 | 25 | COPY --from=builder /usr/local/mysql/LICENSE /usr/local/mysql/LICENSE 26 | COPY --from=builder /usr/local/mysql/bin /usr/local/mysql/bin 27 | COPY --from=builder /usr/local/mysql/lib /usr/local/mysql/lib 28 | COPY --from=builder /usr/local/mysql/share /usr/local/mysql/share 29 | 30 | RUN apt-get update \ 31 | && apt-get install -y --no-install-recommends libjemalloc2 libnuma1 libaio1 \ 32 | && rm -rf /var/lib/apt/lists/* \ 33 | && mkdir -p /var/lib/mysql \ 34 | && chown -R 10000:10000 /var/lib/mysql 35 | 36 | ENV PATH=/usr/local/mysql/bin:"$PATH" 37 | VOLUME /var/lib/mysql 38 | ENTRYPOINT ["mysqld"] 39 | EXPOSE 3306 33060 33062 8080 40 | USER 10000:10000 41 | -------------------------------------------------------------------------------- /containers/mysql/8.0.40/TAG: -------------------------------------------------------------------------------- 1 | 8.0.40.2 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.40/container-structure-test.yaml: -------------------------------------------------------------------------------- 1 | schemaVersion: '2.0.0' 2 | fileExistenceTests: 3 | - name: 'mysqld' 4 | path: '/usr/local/mysql/bin/mysqld' 5 | shouldExist: true 6 | isExecutableBy: 'owner' 7 | - name: 'mysql lib' 8 | path: '/usr/local/mysql/lib' 9 | shouldExist: true 10 | - name: 'mysql share' 11 | path: '/usr/local/mysql/share' 12 | shouldExist: true 13 | - name: 'mysql LICENSE' 14 | path: '/usr/local/mysql/LICENSE' 15 | shouldExist: true 16 | -------------------------------------------------------------------------------- /containers/mysql/8.0.41/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.41/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/cybozu/ubuntu-dev:22.04 AS builder 2 | 3 | ARG MYSQL_VERSION=8.0.41 4 | 5 | RUN apt-get update && apt-get -y install --no-install-recommends \ 6 | cmake \ 7 | libncurses5-dev \ 8 | libjemalloc-dev \ 9 | libnuma-dev \ 10 | libaio-dev \ 11 | pkg-config 12 | 13 | RUN cd tmp/ \ 14 | && curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-${MYSQL_VERSION}.tar.gz \ 15 | && tar -x -z -f mysql-boost-${MYSQL_VERSION}.tar.gz \ 16 | && cd mysql-${MYSQL_VERSION} \ 17 | && mkdir bld \ 18 | && cd bld \ 19 | && cmake .. -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=Release -DWITH_BOOST=$(ls -d ../boost/boost_*) -DWITH_NUMA=1 -DWITH_JEMALLOC=1 -DWITH_PACKAGE_FLAGS=0 \ 20 | && make -j 20 \ 21 | && make install 22 | 23 | FROM ghcr.io/cybozu/ubuntu:22.04 24 | 25 | COPY --from=builder /usr/local/mysql/LICENSE /usr/local/mysql/LICENSE 26 | COPY --from=builder /usr/local/mysql/bin /usr/local/mysql/bin 27 | COPY --from=builder /usr/local/mysql/lib /usr/local/mysql/lib 28 | COPY --from=builder /usr/local/mysql/share /usr/local/mysql/share 29 | 30 | RUN apt-get update \ 31 | && apt-get install -y --no-install-recommends libjemalloc2 libnuma1 libaio1 \ 32 | && rm -rf /var/lib/apt/lists/* \ 33 | && mkdir -p /var/lib/mysql \ 34 | && chown -R 10000:10000 /var/lib/mysql 35 | 36 | ENV PATH=/usr/local/mysql/bin:"$PATH" 37 | VOLUME /var/lib/mysql 38 | ENTRYPOINT ["mysqld"] 39 | EXPOSE 3306 33060 33062 8080 40 | USER 10000:10000 41 | -------------------------------------------------------------------------------- /containers/mysql/8.0.41/TAG: -------------------------------------------------------------------------------- 1 | 8.0.41.2 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.41/container-structure-test.yaml: -------------------------------------------------------------------------------- 1 | schemaVersion: '2.0.0' 2 | fileExistenceTests: 3 | - name: 'mysqld' 4 | path: '/usr/local/mysql/bin/mysqld' 5 | shouldExist: true 6 | isExecutableBy: 'owner' 7 | - name: 'mysql lib' 8 | path: '/usr/local/mysql/lib' 9 | shouldExist: true 10 | - name: 'mysql share' 11 | path: '/usr/local/mysql/share' 12 | shouldExist: true 13 | - name: 'mysql LICENSE' 14 | path: '/usr/local/mysql/LICENSE' 15 | shouldExist: true 16 | -------------------------------------------------------------------------------- /containers/mysql/8.0.42/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.42/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/cybozu/ubuntu-dev:22.04 AS builder 2 | 3 | ARG MYSQL_VERSION=8.0.42 4 | 5 | RUN apt-get update && apt-get -y install --no-install-recommends \ 6 | cmake \ 7 | libncurses5-dev \ 8 | libjemalloc-dev \ 9 | libnuma-dev \ 10 | libaio-dev \ 11 | pkg-config 12 | 13 | RUN cd tmp/ \ 14 | && curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-${MYSQL_VERSION}.tar.gz \ 15 | && tar -x -z -f mysql-boost-${MYSQL_VERSION}.tar.gz \ 16 | && cd mysql-${MYSQL_VERSION} \ 17 | && mkdir bld \ 18 | && cd bld \ 19 | && cmake .. -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=Release -DWITH_BOOST=$(ls -d ../boost/boost_*) -DWITH_NUMA=1 -DWITH_JEMALLOC=1 -DWITH_PACKAGE_FLAGS=0 \ 20 | && make -j 20 \ 21 | && make install 22 | 23 | FROM ghcr.io/cybozu/ubuntu:22.04 24 | 25 | COPY --from=builder /usr/local/mysql/LICENSE /usr/local/mysql/LICENSE 26 | COPY --from=builder /usr/local/mysql/bin /usr/local/mysql/bin 27 | COPY --from=builder /usr/local/mysql/lib /usr/local/mysql/lib 28 | COPY --from=builder /usr/local/mysql/share /usr/local/mysql/share 29 | 30 | RUN apt-get update \ 31 | && apt-get install -y --no-install-recommends libjemalloc2 libnuma1 libaio1 \ 32 | && rm -rf /var/lib/apt/lists/* \ 33 | && mkdir -p /var/lib/mysql \ 34 | && chown -R 10000:10000 /var/lib/mysql 35 | 36 | ENV PATH=/usr/local/mysql/bin:"$PATH" 37 | VOLUME /var/lib/mysql 38 | ENTRYPOINT ["mysqld"] 39 | EXPOSE 3306 33060 33062 8080 40 | USER 10000:10000 41 | -------------------------------------------------------------------------------- /containers/mysql/8.0.42/TAG: -------------------------------------------------------------------------------- 1 | 8.0.42.1 2 | -------------------------------------------------------------------------------- /containers/mysql/8.0.42/container-structure-test.yaml: -------------------------------------------------------------------------------- 1 | schemaVersion: '2.0.0' 2 | fileExistenceTests: 3 | - name: 'mysqld' 4 | path: '/usr/local/mysql/bin/mysqld' 5 | shouldExist: true 6 | isExecutableBy: 'owner' 7 | - name: 'mysql lib' 8 | path: '/usr/local/mysql/lib' 9 | shouldExist: true 10 | - name: 'mysql share' 11 | path: '/usr/local/mysql/share' 12 | shouldExist: true 13 | - name: 'mysql LICENSE' 14 | path: '/usr/local/mysql/LICENSE' 15 | shouldExist: true 16 | -------------------------------------------------------------------------------- /containers/mysql/8.4.0/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /containers/mysql/8.4.0/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/cybozu/ubuntu-dev:22.04 AS builder 2 | 3 | ARG MYSQL_VERSION=8.4.0 4 | 5 | RUN apt-get update && apt-get -y install --no-install-recommends \ 6 | cmake \ 7 | libncurses5-dev \ 8 | libjemalloc-dev \ 9 | libnuma-dev \ 10 | libaio-dev \ 11 | pkg-config 12 | 13 | RUN cd tmp/ \ 14 | && curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.4/mysql-${MYSQL_VERSION}.tar.gz \ 15 | && tar -x -z -f mysql-${MYSQL_VERSION}.tar.gz \ 16 | && cd mysql-${MYSQL_VERSION} \ 17 | && mkdir bld \ 18 | && cd bld \ 19 | && cmake .. -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=Release -DWITH_NUMA=1 -DWITH_JEMALLOC=1 -DWITH_PACKAGE_FLAGS=0 \ 20 | && make -j 20 \ 21 | && make install 22 | 23 | FROM ghcr.io/cybozu/ubuntu:22.04 24 | 25 | COPY --from=builder /usr/local/mysql/LICENSE /usr/local/mysql/LICENSE 26 | COPY --from=builder /usr/local/mysql/bin /usr/local/mysql/bin 27 | COPY --from=builder /usr/local/mysql/lib /usr/local/mysql/lib 28 | COPY --from=builder /usr/local/mysql/share /usr/local/mysql/share 29 | 30 | RUN apt-get update \ 31 | && apt-get install -y --no-install-recommends libjemalloc2 libnuma1 libaio1 \ 32 | && rm -rf /var/lib/apt/lists/* \ 33 | && mkdir -p /var/lib/mysql \ 34 | && chown -R 10000:10000 /var/lib/mysql 35 | 36 | ENV PATH=/usr/local/mysql/bin:"$PATH" 37 | VOLUME /var/lib/mysql 38 | ENTRYPOINT ["mysqld"] 39 | EXPOSE 3306 33060 33062 8080 40 | USER 10000:10000 41 | -------------------------------------------------------------------------------- /containers/mysql/8.4.0/TAG: -------------------------------------------------------------------------------- 1 | 8.4.0.2 2 | -------------------------------------------------------------------------------- /containers/mysql/8.4.0/container-structure-test.yaml: -------------------------------------------------------------------------------- 1 | schemaVersion: '2.0.0' 2 | fileExistenceTests: 3 | - name: 'mysqld' 4 | path: '/usr/local/mysql/bin/mysqld' 5 | shouldExist: true 6 | isExecutableBy: 'owner' 7 | - name: 'mysql lib' 8 | path: '/usr/local/mysql/lib' 9 | shouldExist: true 10 | - name: 'mysql share' 11 | path: '/usr/local/mysql/share' 12 | shouldExist: true 13 | - name: 'mysql LICENSE' 14 | path: '/usr/local/mysql/LICENSE' 15 | shouldExist: true 16 | -------------------------------------------------------------------------------- /containers/mysql/8.4.2/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /containers/mysql/8.4.2/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/cybozu/ubuntu-dev:22.04 AS builder 2 | 3 | ARG MYSQL_VERSION=8.4.2 4 | 5 | RUN apt-get update && apt-get -y install --no-install-recommends \ 6 | cmake \ 7 | libncurses5-dev \ 8 | libjemalloc-dev \ 9 | libnuma-dev \ 10 | libaio-dev \ 11 | pkg-config 12 | 13 | RUN cd tmp/ \ 14 | && curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.4/mysql-${MYSQL_VERSION}.tar.gz \ 15 | && tar -x -z -f mysql-${MYSQL_VERSION}.tar.gz \ 16 | && cd mysql-${MYSQL_VERSION} \ 17 | && mkdir bld \ 18 | && cd bld \ 19 | && cmake .. -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=Release -DWITH_NUMA=1 -DWITH_JEMALLOC=1 -DWITH_PACKAGE_FLAGS=0 \ 20 | && make -j 20 \ 21 | && make install 22 | 23 | FROM ghcr.io/cybozu/ubuntu:22.04 24 | 25 | COPY --from=builder /usr/local/mysql/LICENSE /usr/local/mysql/LICENSE 26 | COPY --from=builder /usr/local/mysql/bin /usr/local/mysql/bin 27 | COPY --from=builder /usr/local/mysql/lib /usr/local/mysql/lib 28 | COPY --from=builder /usr/local/mysql/share /usr/local/mysql/share 29 | 30 | RUN apt-get update \ 31 | && apt-get install -y --no-install-recommends libjemalloc2 libnuma1 libaio1 \ 32 | && rm -rf /var/lib/apt/lists/* \ 33 | && mkdir -p /var/lib/mysql \ 34 | && chown -R 10000:10000 /var/lib/mysql 35 | 36 | ENV PATH=/usr/local/mysql/bin:"$PATH" 37 | VOLUME /var/lib/mysql 38 | ENTRYPOINT ["mysqld"] 39 | EXPOSE 3306 33060 33062 8080 40 | USER 10000:10000 41 | -------------------------------------------------------------------------------- /containers/mysql/8.4.2/TAG: -------------------------------------------------------------------------------- 1 | 8.4.2.1 2 | -------------------------------------------------------------------------------- /containers/mysql/8.4.2/container-structure-test.yaml: -------------------------------------------------------------------------------- 1 | schemaVersion: '2.0.0' 2 | fileExistenceTests: 3 | - name: 'mysqld' 4 | path: '/usr/local/mysql/bin/mysqld' 5 | shouldExist: true 6 | isExecutableBy: 'owner' 7 | - name: 'mysql lib' 8 | path: '/usr/local/mysql/lib' 9 | shouldExist: true 10 | - name: 'mysql share' 11 | path: '/usr/local/mysql/share' 12 | shouldExist: true 13 | - name: 'mysql LICENSE' 14 | path: '/usr/local/mysql/LICENSE' 15 | shouldExist: true 16 | -------------------------------------------------------------------------------- /containers/mysql/8.4.3/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /containers/mysql/8.4.3/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/cybozu/ubuntu-dev:22.04 AS builder 2 | 3 | ARG MYSQL_VERSION=8.4.3 4 | 5 | RUN apt-get update && apt-get -y install --no-install-recommends \ 6 | cmake \ 7 | libncurses5-dev \ 8 | libjemalloc-dev \ 9 | libnuma-dev \ 10 | libaio-dev \ 11 | pkg-config 12 | 13 | RUN cd tmp/ \ 14 | && curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.4/mysql-${MYSQL_VERSION}.tar.gz \ 15 | && tar -x -z -f mysql-${MYSQL_VERSION}.tar.gz \ 16 | && cd mysql-${MYSQL_VERSION} \ 17 | && mkdir bld \ 18 | && cd bld \ 19 | && cmake .. -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=Release -DWITH_NUMA=1 -DWITH_JEMALLOC=1 -DWITH_PACKAGE_FLAGS=0 \ 20 | && make -j 20 \ 21 | && make install 22 | 23 | FROM ghcr.io/cybozu/ubuntu:22.04 24 | 25 | COPY --from=builder /usr/local/mysql/LICENSE /usr/local/mysql/LICENSE 26 | COPY --from=builder /usr/local/mysql/bin /usr/local/mysql/bin 27 | COPY --from=builder /usr/local/mysql/lib /usr/local/mysql/lib 28 | COPY --from=builder /usr/local/mysql/share /usr/local/mysql/share 29 | 30 | RUN apt-get update \ 31 | && apt-get install -y --no-install-recommends libjemalloc2 libnuma1 libaio1 \ 32 | && rm -rf /var/lib/apt/lists/* \ 33 | && mkdir -p /var/lib/mysql \ 34 | && chown -R 10000:10000 /var/lib/mysql 35 | 36 | ENV PATH=/usr/local/mysql/bin:"$PATH" 37 | VOLUME /var/lib/mysql 38 | ENTRYPOINT ["mysqld"] 39 | EXPOSE 3306 33060 33062 8080 40 | USER 10000:10000 41 | -------------------------------------------------------------------------------- /containers/mysql/8.4.3/TAG: -------------------------------------------------------------------------------- 1 | 8.4.3.1 2 | -------------------------------------------------------------------------------- /containers/mysql/8.4.3/container-structure-test.yaml: -------------------------------------------------------------------------------- 1 | schemaVersion: '2.0.0' 2 | fileExistenceTests: 3 | - name: 'mysqld' 4 | path: '/usr/local/mysql/bin/mysqld' 5 | shouldExist: true 6 | isExecutableBy: 'owner' 7 | - name: 'mysql lib' 8 | path: '/usr/local/mysql/lib' 9 | shouldExist: true 10 | - name: 'mysql share' 11 | path: '/usr/local/mysql/share' 12 | shouldExist: true 13 | - name: 'mysql LICENSE' 14 | path: '/usr/local/mysql/LICENSE' 15 | shouldExist: true 16 | -------------------------------------------------------------------------------- /containers/mysql/8.4.4/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /containers/mysql/8.4.4/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/cybozu/ubuntu-dev:22.04 AS builder 2 | 3 | ARG MYSQL_VERSION=8.4.4 4 | 5 | RUN apt-get update && apt-get -y install --no-install-recommends \ 6 | cmake \ 7 | libncurses5-dev \ 8 | libjemalloc-dev \ 9 | libnuma-dev \ 10 | libaio-dev \ 11 | pkg-config 12 | 13 | RUN cd tmp/ \ 14 | && curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.4/mysql-${MYSQL_VERSION}.tar.gz \ 15 | && tar -x -z -f mysql-${MYSQL_VERSION}.tar.gz \ 16 | && cd mysql-${MYSQL_VERSION} \ 17 | && mkdir bld \ 18 | && cd bld \ 19 | && cmake .. -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=Release -DWITH_NUMA=1 -DWITH_JEMALLOC=1 -DWITH_PACKAGE_FLAGS=0 \ 20 | && make -j 20 \ 21 | && make install 22 | 23 | FROM ghcr.io/cybozu/ubuntu:22.04 24 | 25 | COPY --from=builder /usr/local/mysql/LICENSE /usr/local/mysql/LICENSE 26 | COPY --from=builder /usr/local/mysql/bin /usr/local/mysql/bin 27 | COPY --from=builder /usr/local/mysql/lib /usr/local/mysql/lib 28 | COPY --from=builder /usr/local/mysql/share /usr/local/mysql/share 29 | 30 | RUN apt-get update \ 31 | && apt-get install -y --no-install-recommends libjemalloc2 libnuma1 libaio1 \ 32 | && rm -rf /var/lib/apt/lists/* \ 33 | && mkdir -p /var/lib/mysql \ 34 | && chown -R 10000:10000 /var/lib/mysql 35 | 36 | ENV PATH=/usr/local/mysql/bin:"$PATH" 37 | VOLUME /var/lib/mysql 38 | ENTRYPOINT ["mysqld"] 39 | EXPOSE 3306 33060 33062 8080 40 | USER 10000:10000 41 | -------------------------------------------------------------------------------- /containers/mysql/8.4.4/TAG: -------------------------------------------------------------------------------- 1 | 8.4.4.2 2 | -------------------------------------------------------------------------------- /containers/mysql/8.4.4/container-structure-test.yaml: -------------------------------------------------------------------------------- 1 | schemaVersion: '2.0.0' 2 | fileExistenceTests: 3 | - name: 'mysqld' 4 | path: '/usr/local/mysql/bin/mysqld' 5 | shouldExist: true 6 | isExecutableBy: 'owner' 7 | - name: 'mysql lib' 8 | path: '/usr/local/mysql/lib' 9 | shouldExist: true 10 | - name: 'mysql share' 11 | path: '/usr/local/mysql/share' 12 | shouldExist: true 13 | - name: 'mysql LICENSE' 14 | path: '/usr/local/mysql/LICENSE' 15 | shouldExist: true 16 | -------------------------------------------------------------------------------- /containers/mysql/8.4.5/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /containers/mysql/8.4.5/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/cybozu/ubuntu-dev:22.04 AS builder 2 | 3 | ARG MYSQL_VERSION=8.4.5 4 | 5 | RUN apt-get update && apt-get -y install --no-install-recommends \ 6 | cmake \ 7 | libncurses5-dev \ 8 | libjemalloc-dev \ 9 | libnuma-dev \ 10 | libaio-dev \ 11 | pkg-config 12 | 13 | RUN cd tmp/ \ 14 | && curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.4/mysql-${MYSQL_VERSION}.tar.gz \ 15 | && tar -x -z -f mysql-${MYSQL_VERSION}.tar.gz \ 16 | && cd mysql-${MYSQL_VERSION} \ 17 | && mkdir bld \ 18 | && cd bld \ 19 | && cmake .. -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=Release -DWITH_NUMA=1 -DWITH_JEMALLOC=1 -DWITH_PACKAGE_FLAGS=0 \ 20 | && make -j 20 \ 21 | && make install 22 | 23 | FROM ghcr.io/cybozu/ubuntu:22.04 24 | 25 | COPY --from=builder /usr/local/mysql/LICENSE /usr/local/mysql/LICENSE 26 | COPY --from=builder /usr/local/mysql/bin /usr/local/mysql/bin 27 | COPY --from=builder /usr/local/mysql/lib /usr/local/mysql/lib 28 | COPY --from=builder /usr/local/mysql/share /usr/local/mysql/share 29 | 30 | RUN apt-get update \ 31 | && apt-get install -y --no-install-recommends libjemalloc2 libnuma1 libaio1 \ 32 | && rm -rf /var/lib/apt/lists/* \ 33 | && mkdir -p /var/lib/mysql \ 34 | && chown -R 10000:10000 /var/lib/mysql 35 | 36 | ENV PATH=/usr/local/mysql/bin:"$PATH" 37 | VOLUME /var/lib/mysql 38 | ENTRYPOINT ["mysqld"] 39 | EXPOSE 3306 33060 33062 8080 40 | USER 10000:10000 41 | -------------------------------------------------------------------------------- /containers/mysql/8.4.5/TAG: -------------------------------------------------------------------------------- 1 | 8.4.5.1 2 | -------------------------------------------------------------------------------- /containers/mysql/8.4.5/container-structure-test.yaml: -------------------------------------------------------------------------------- 1 | schemaVersion: '2.0.0' 2 | fileExistenceTests: 3 | - name: 'mysqld' 4 | path: '/usr/local/mysql/bin/mysqld' 5 | shouldExist: true 6 | isExecutableBy: 'owner' 7 | - name: 'mysql lib' 8 | path: '/usr/local/mysql/lib' 9 | shouldExist: true 10 | - name: 'mysql share' 11 | path: '/usr/local/mysql/share' 12 | shouldExist: true 13 | - name: 'mysql LICENSE' 14 | path: '/usr/local/mysql/LICENSE' 15 | shouldExist: true 16 | -------------------------------------------------------------------------------- /containers/mysql/README.md: -------------------------------------------------------------------------------- 1 | # MySQL container 2 | 3 | This directory provides a Dockerfile to build a MySQL container for [MOCO](https://github.com/cybozu-go/moco). 4 | 5 | ## MOCO MySQL container 6 | 7 | ### Usage 8 | 9 | This container image is assumed to be used by [MOCO](https://github.com/cybozu-go/moco). 10 | 11 | ### Docker images 12 | 13 | Docker images are available on [ghcr.io](https://github.com/cybozu-go/moco/pkgs/container/moco%2Fmysql) 14 | -------------------------------------------------------------------------------- /containers/mysqld_exporter/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /containers/mysqld_exporter/Dockerfile: -------------------------------------------------------------------------------- 1 | # mysqld_exporter container 2 | 3 | # Stage1: build from source 4 | FROM ghcr.io/cybozu/golang:1.22-jammy AS build 5 | 6 | ARG MYSQLD_EXPORTER_VERSION=v0.16.0 7 | 8 | RUN git clone -b ${MYSQLD_EXPORTER_VERSION} --depth 1 https://github.com/prometheus/mysqld_exporter \ 9 | && make -C mysqld_exporter build 10 | 11 | # Stage2: setup runtime container 12 | FROM scratch 13 | 14 | COPY --from=build /work/mysqld_exporter/LICENSE /LICENSE 15 | COPY --from=build /work/mysqld_exporter/mysqld_exporter /mysqld_exporter 16 | 17 | USER 10000:10000 18 | EXPOSE 9104 19 | 20 | ENTRYPOINT ["/mysqld_exporter"] 21 | -------------------------------------------------------------------------------- /containers/mysqld_exporter/README.md: -------------------------------------------------------------------------------- 1 | # mysqld_exporter 2 | 3 | This directory provides a Dockerfile to build a Docker container that runs [mysqld_exporter](https://github.com/prometheus/mysqld_exporter). 4 | 5 | Docker images 6 | ------------- 7 | 8 | Docker images are available on [ghcr.io](https://github.com/cybozu-go/moco/pkgs/container/moco%2Fmysqld_exporter) 9 | -------------------------------------------------------------------------------- /containers/mysqld_exporter/TAG: -------------------------------------------------------------------------------- 1 | 0.16.0.1 2 | -------------------------------------------------------------------------------- /containers/tag_exists: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | if [ -z "$GITHUB_REPOSITORY_OWNER" ]; then 4 | GITHUB_REPOSITORY_OWNER="cybozu-go" 5 | fi 6 | 7 | if [ $# -eq 0 ]; then 8 | echo "Usage: tag_exists NAME" 9 | exit 1 10 | fi 11 | 12 | NAME="$1" 13 | if [ $# -eq 2 ]; then 14 | DIR="$2" 15 | else 16 | DIR="$NAME" 17 | fi 18 | TAG=$(cat "$DIR"/TAG) 19 | 20 | HTTP_STATUS=$(curl -sSL -w "%{http_code}" "https://ghcr.io/token?scope=repository%3A$GITHUB_REPOSITORY_OWNER%2F$NAME%3Apull&service=ghcr.io" -o /dev/null) 21 | # If a non-existent image is specified, 403 will be returned. 22 | # {"errors":[{"code":"DENIED","message":"requested access to the resource is denied"}]} 23 | if [ "$HTTP_STATUS" = "403" ]; then 24 | echo "ng" 25 | exit 0 26 | fi 27 | 28 | TOKEN=$(curl -sSfL "https://ghcr.io/token?scope=repository%3A$GITHUB_REPOSITORY_OWNER%2F$NAME%3Apull&service=ghcr.io" | jq -r .token) 29 | RESULT=$(curl -H "Authorization: Bearer $TOKEN" -sSfL "https://ghcr.io/v2/$GITHUB_REPOSITORY_OWNER/$NAME/tags/list" | jq --arg tag "$TAG" '.tags[] | select(. == $tag)') 30 | 31 | if [ -z "$RESULT" ]; then 32 | echo "ng" 33 | exit 0 34 | fi 35 | 36 | echo "ok" 37 | -------------------------------------------------------------------------------- /controllers/certificate_tmpl.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cert-manager.io/v1 2 | kind: Certificate 3 | metadata: 4 | name: "{{ .Name }}" 5 | namespace: "{{ .Namespace }}" 6 | spec: 7 | dnsNames: 8 | - "*.{{ .ServiceName }}.{{ .TargetNamespace }}.svc" 9 | secretName: "{{ .Name }}" 10 | usages: 11 | - digital signature 12 | - key encipherment 13 | - server auth 14 | issuerRef: 15 | kind: Issuer 16 | name: moco-grpc-issuer 17 | -------------------------------------------------------------------------------- /controllers/mock_test.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "sync" 5 | 6 | "github.com/cybozu-go/moco/clustering" 7 | "k8s.io/apimachinery/pkg/types" 8 | ) 9 | 10 | type mockManager struct { 11 | mu sync.Mutex 12 | clusters map[string]struct{} 13 | updated []types.NamespacedName 14 | } 15 | 16 | var _ clustering.ClusterManager = &mockManager{} 17 | 18 | func (m *mockManager) Update(key types.NamespacedName, origin string) { 19 | m.mu.Lock() 20 | defer m.mu.Unlock() 21 | 22 | m.clusters[key.String()] = struct{}{} 23 | } 24 | 25 | func (m *mockManager) UpdateNoStart(key types.NamespacedName, origin string) { 26 | m.mu.Lock() 27 | defer m.mu.Unlock() 28 | 29 | m.updated = append(m.updated, key) 30 | } 31 | 32 | func (m *mockManager) Stop(key types.NamespacedName) { 33 | m.mu.Lock() 34 | defer m.mu.Unlock() 35 | 36 | delete(m.clusters, key.String()) 37 | } 38 | 39 | func (m *mockManager) StopAll() {} 40 | 41 | func (m *mockManager) Pause(key types.NamespacedName) { 42 | m.mu.Lock() 43 | defer m.mu.Unlock() 44 | 45 | delete(m.clusters, key.String()) 46 | } 47 | 48 | func (m *mockManager) getKeys() map[string]bool { 49 | m.mu.Lock() 50 | defer m.mu.Unlock() 51 | 52 | keys := make(map[string]bool) 53 | for k := range m.clusters { 54 | keys[k] = true 55 | } 56 | return keys 57 | } 58 | 59 | func (m *mockManager) isUpdated(key types.NamespacedName) bool { 60 | m.mu.Lock() 61 | defer m.mu.Unlock() 62 | 63 | for _, k := range m.updated { 64 | if k.Namespace == key.Namespace && k.Name == key.Name { 65 | return true 66 | } 67 | } 68 | return false 69 | } 70 | -------------------------------------------------------------------------------- /ct.yaml: -------------------------------------------------------------------------------- 1 | # This file is the config file for helm/chart-testing 2 | target-branch: main 3 | validate-maintainers: false 4 | check-version-increment: false 5 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | /book 2 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # MOCO documentation 2 | 3 | moco logo 4 | 5 | This is the documentation site for [MOCO](https://github.com/cybozu-go/moco). 6 | MOCO is a Kubernetes operator for MySQL created and maintained by Cybozu. 7 | -------------------------------------------------------------------------------- /docs/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | [MOCO](README.md) 4 | 5 | # User manual 6 | 7 | - [Getting started](getting_started.md) 8 | - [Deploying MOCO](setup.md) 9 | - [Helm Chart](helm.md) 10 | - [Installing kubectl-moco](install-plugin.md) 11 | - [Usage](usage.md) 12 | - [Advanced topics](advanced.md) 13 | - [Building your own image](custom-mysqld.md) 14 | - [Customize system container](customize-system-container.md) 15 | - [Change volumeClaimTemplates](change-pvc-template.md) 16 | - [Rollout strategy](rolling-update-strategy.md) 17 | - [Known issues](known_issues.md) 18 | 19 | # References 20 | 21 | - [Custom resources](crd.md) 22 | - [MySQLCluster v1beta2](crd_mysqlcluster_v1beta2.md) 23 | - [BackupPolicy v1beta2](crd_backuppolicy_v1beta2.md) 24 | - [Commands](commands.md) 25 | - [kubectl-moco](kubectl-moco.md) 26 | - [moco-controller](moco-controller.md) 27 | - [moco-backup](moco-backup.md) 28 | - [Metrics](metrics.md) 29 | 30 | # Developer documents 31 | 32 | - [Design notes](notes.md) 33 | - [Goals](design.md) 34 | - [Reconciliation](reconcile.md) 35 | - [Clustering](clustering.md) 36 | - [Backup and restore](backup.md) 37 | - [Upgrading mysqld](upgrading.md) 38 | - [Security](security.md) 39 | -------------------------------------------------------------------------------- /docs/advanced.md: -------------------------------------------------------------------------------- 1 | # Advanced topics 2 | -------------------------------------------------------------------------------- /docs/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | language = "en" 3 | multilingual = false 4 | src = "." 5 | title = "MOCO Documentation" 6 | 7 | [output.html] 8 | git-repository-url = "https://github.com/cybozu-go/moco" 9 | edit-url-template = "https://github.com/cybozu-go/moco/edit/main/docs/{path}" 10 | site-url = "/moco/" 11 | -------------------------------------------------------------------------------- /docs/commands.md: -------------------------------------------------------------------------------- 1 | # Commands 2 | -------------------------------------------------------------------------------- /docs/crd.md: -------------------------------------------------------------------------------- 1 | # Custom resources 2 | -------------------------------------------------------------------------------- /docs/custom-mysqld.md: -------------------------------------------------------------------------------- 1 | # Building custom image of `mysqld` 2 | 3 | There are pre-built `mysqld` container images for MOCO on [`ghcr.io/cybozu-go/moco/mysql`](https://github.com/cybozu-go/moco/pkgs/container/moco%2Fmysql). 4 | Users can use one of these images to supply `mysqld` container in [MySQLCluster](crd_mysqlcluster.md) like: 5 | 6 | ```yaml 7 | apiVersion: moco.cybozu.com/v1beta2 8 | kind: MySQLCluster 9 | spec: 10 | podTemplate: 11 | spec: 12 | containers: 13 | - name: mysqld 14 | image: ghcr.io/cybozu-go/moco/mysql:8.4.5 15 | ``` 16 | 17 | If you want to build and use your own `mysqld`, read the rest of this document. 18 | 19 | ## Dockerfile 20 | 21 | The easiest way to build a custom `mysqld` for MOCO is to copy and edit our Dockerfile. 22 | You can find it under [`containers/mysql` directory in `github.com/cybozu-go/moco`](https://github.com/cybozu-go/moco/tree/main/containers/mysql). 23 | 24 | You should keep the following points: 25 | 26 | - `ENTRYPOINT` should be `["mysqld"]` 27 | - `USER` should be `10000:10000` 28 | - `sleep` command must exist in one of the `PATH` directories. 29 | 30 | ## How to build `mysqld` 31 | 32 | On Ubuntu 22.04, you can build the source code as follows: 33 | 34 | ```console 35 | $ sudo apt-get update 36 | $ sudo apt-get -y --no-install-recommends install build-essential libssl-dev \ 37 | cmake libncurses5-dev libjemalloc-dev libnuma-dev libaio-dev pkg-config 38 | $ curl -fsSL -O https://dev.mysql.com/get/Downloads/MySQL-8.4/mysql-8.4.5.tar.gz 39 | $ tar -x -z -f mysql-8.4.5.tar.gz 40 | $ cd mysql-8.4.5 41 | $ mkdir bld 42 | $ cd bld 43 | $ cmake .. -DBUILD_CONFIG=mysql_release -DCMAKE_BUILD_TYPE=Release \ 44 | -DWITH_NUMA=1 -DWITH_JEMALLOC=1 45 | $ make -j $(nproc) 46 | $ make install 47 | ``` 48 | -------------------------------------------------------------------------------- /docs/getting_started.md: -------------------------------------------------------------------------------- 1 | # Getting started 2 | -------------------------------------------------------------------------------- /docs/helm.md: -------------------------------------------------------------------------------- 1 | {{#include ../charts/moco/README.md}} 2 | -------------------------------------------------------------------------------- /docs/install-plugin.md: -------------------------------------------------------------------------------- 1 | # Installing kubectl-moco 2 | 3 | [kubectl-moco](kubectl-moco.md) is a plugin for `kubectl` to control MySQL clusters of MOCO. 4 | 5 | Pre-built binaries are available on [GitHub releases](https://github.com/cybozu-go/moco/releases) for Windows, Linux, and MacOS. 6 | 7 | ## Installing using Krew 8 | 9 | [Krew](https://krew.sigs.k8s.io/) is the plugin manager for kubectl command-line tool. 10 | 11 | See the [documentation](https://krew.sigs.k8s.io/docs/user-guide/setup/install/) for how to install Krew. 12 | 13 | ```console 14 | $ kubectl krew update 15 | $ kubectl krew install moco 16 | ``` 17 | 18 | ## Installing manually 19 | 20 | 1. Set `OS` to the operating system name 21 | 22 | OS is one of `linux`, `windows`, or `darwin` (MacOS). 23 | 24 | If Go is available, `OS` can be set automatically as follows: 25 | 26 | ```console 27 | $ OS=$(go env GOOS) 28 | ``` 29 | 30 | 2. Set `ARCH` to the architecture name 31 | 32 | ARCH is one of `amd64` or `arm64`. 33 | 34 | If Go is available, `ARCH` can be set automatically as follows: 35 | 36 | ```console 37 | $ ARCH=$(go env GOARCH) 38 | ``` 39 | 40 | 3. Set `VERSION` to the MOCO version 41 | 42 | See the MOCO release page: https://github.com/cybozu-go/moco/releases 43 | 44 | ```console 45 | $ VERSION=< The version you want to install > 46 | ``` 47 | 48 | 4. Download the binary and put it in a directory of your `PATH`. 49 | 50 | The following is an example to install the plugin in `/usr/local/bin`. 51 | 52 | ```console 53 | $ curl -L -sS https://github.com/cybozu-go/moco/releases/download/${VERSION}/kubectl-moco_${VERSION}_${OS}_${ARCH}.tar.gz \ 54 | | tar xz -C /usr/local/bin kubectl-moco 55 | ``` 56 | 57 | 5. Check the installation by running `kubectl moco -h`. 58 | 59 | ```console 60 | $ kubectl moco -h 61 | the utility command for MOCO. 62 | 63 | Usage: 64 | kubectl-moco [command] 65 | 66 | Available Commands: 67 | credential Fetch the credential of a specified user 68 | help Help about any command 69 | mysql Run mysql command in a specified MySQL instance 70 | switchover Switch the primary instance 71 | 72 | ... 73 | ``` 74 | -------------------------------------------------------------------------------- /docs/known_issues.md: -------------------------------------------------------------------------------- 1 | # Known issues 2 | 3 | This document lists the known issues of MOCO. 4 | 5 | - [Multi-threaded replication](#multi-threaded-replication) 6 | 7 | ## Multi-threaded replication 8 | 9 | _Status: Resolved_ 10 | 11 | If you use MOCO with MySQL version 8.0.25 or earlier, you should not configure the replicas with `replica_parallel_workers` > 1. 12 | Multi-threaded replication will cause the replica to fail to resume after the crash. 13 | 14 | Currently, MOCO does not support MySQL version 8.0.25 or earlier, so this issue does not occur. 15 | -------------------------------------------------------------------------------- /docs/moco-backup.md: -------------------------------------------------------------------------------- 1 | # `moco-backup` 2 | 3 | `moco-backup` command is used in `ghcr.io/cybozu-go/moco-backup` container. 4 | Normally, users need not take care of this command. 5 | 6 | ## Environment variables 7 | 8 | `moco-backup` takes configurations of S3 API from environment variables. 9 | For details, read documentation of [`EnvConfig` in github.com/aws/aws-sdk-go-v2/config][EnvConfig]. 10 | 11 | It also requires `MYSQL_PASSWORD` environment variable to be set. 12 | 13 | ## Global command-line flags 14 | 15 | ``` 16 | Global Flags: 17 | --endpoint string S3 API endpoint URL 18 | --region string AWS region 19 | --threads int The number of threads to be used (default 4) 20 | --use-path-style Use path-style S3 API 21 | --work-dir string The writable working directory (default "/work") 22 | --ca-cert string Path to SSL CA certificate file used in addition to system default 23 | ``` 24 | 25 | ## Subcommands 26 | 27 | ### `backup` subcommand 28 | 29 | Usage: `moco-backup backup BUCKET NAMESPACE NAME` 30 | 31 | - `BUCKET`: The bucket name. 32 | - `NAMESPACE`: The namespace of the MySQLCluster. 33 | - `NAME`: The name of the MySQLCluster. 34 | 35 | ### `restore subcommand 36 | 37 | Usage: `moco-backup restore BUCKET SOURCE_NAMESPACE SOURCE_NAME NAMESPACE NAME YYYYMMDD-hhmmss` 38 | 39 | - `BUCKET`: The bucket name. 40 | - `SOURCE_NAMESPACE`: The source MySQLCluster's namespace. 41 | - `SOURCE_NAME`: The source MySQLCluster's name. 42 | - `NAMESPACE`: The target MySQLCluster's namespace. 43 | - `NAME`: The target MySQLCluster's name. 44 | - `YYYYMMDD-hhmmss`: The point-in-time to restore data. e.g. `20210523-150423` 45 | 46 | [EnvConfig]: https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/config#EnvConfig 47 | -------------------------------------------------------------------------------- /docs/notes.md: -------------------------------------------------------------------------------- 1 | # Design notes 2 | -------------------------------------------------------------------------------- /docs/security.md: -------------------------------------------------------------------------------- 1 | # Security considerations 2 | 3 | ## gRPC API 4 | 5 | [moco-agent][], a sidecar container in mysqld Pod, provides gRPC API to 6 | execute `CLONE INSTANCE` and required operations after CLONE. 7 | More importantly, the request contains credentials to access the source 8 | database. 9 | 10 | To protect the credentials and prevent abuse of API, MOCO configures mTLS 11 | between moco-agent and moco-controller as follows: 12 | 13 | 1. Create an [Issuer][] resource in `moco-system` namespace as the Certificate Authority. 14 | 2. Create a [Certificate][] resource to issue the certificate for `moco-controller`. 15 | 3. `moco-controller` issues certificates for each MySQLCluster by creating [Certificate][] resources. 16 | 4. `moco-controller` copies Secret resources created by cert-manager to the namespaces of MySQLCluster. 17 | 5. Both moco-controller and moco-agent verifies the certificate with the CA certificate. 18 | - The CA certificate is embedded in the Secret resources. 19 | 6. moco-agent additionally verifies the certificate from `moco-controller` if it's Common Name is `moco-controller`. 20 | 21 | ## MySQL passwords 22 | 23 | MOCO generates its user passwords randomly with the OS random device. 24 | The passwords then stored as Secret resources. 25 | 26 | As to communication between moco-controller and mysqld, it is not (yet) over TLS. 27 | That said, the password is encrypted anyway thanks to [caching_sha2_password](https://dev.mysql.com/doc/refman/8.0/en/caching-sha2-pluggable-authentication.html) authentication. 28 | 29 | [moco-agent]: https://github.com/cybozu-go/moco-agent 30 | [Issuer]: https://cert-manager.io/docs/reference/api-docs/#cert-manager.io/v1.Issuer 31 | [Certificate]: https://cert-manager.io/docs/reference/api-docs/#cert-manager.io/v1.Certificate 32 | -------------------------------------------------------------------------------- /docs/setup.md: -------------------------------------------------------------------------------- 1 | Setup 2 | ===== 3 | 4 | ## Quick setup 5 | 6 | You can choose between two installation methods. 7 | 8 | MOCO depends on cert-manager. If cert-manager is not installed on your cluster, install it as follows: 9 | 10 | ```console 11 | $ curl -fsLO https://github.com/jetstack/cert-manager/releases/latest/download/cert-manager.yaml 12 | $ kubectl apply -f cert-manager.yaml 13 | ``` 14 | 15 | ### Install using raw manifests: 16 | 17 | ```console 18 | $ curl -fsLO https://github.com/cybozu-go/moco/releases/latest/download/moco.yaml 19 | $ kubectl apply -f moco.yaml 20 | ``` 21 | 22 | ### Install using Helm chart: 23 | 24 | ```console 25 | $ helm repo add moco https://cybozu-go.github.io/moco/ 26 | $ helm repo update 27 | $ helm install --create-namespace --namespace moco-system moco moco/moco 28 | ``` 29 | 30 | ## Customize manifests 31 | 32 | If you want to edit the manifest, [`config/`](https://github.com/cybozu-go/moco/tree/main/config) directory contains the source YAML for [kustomize](https://kustomize.io/). 33 | 34 | ## Next step 35 | 36 | Read [`usage.md`](usage.md) and create your first MySQL cluster! 37 | -------------------------------------------------------------------------------- /e2e/.gitignore: -------------------------------------------------------------------------------- 1 | /.kubeconfig 2 | /logs 3 | /logs.tar.gz 4 | -------------------------------------------------------------------------------- /e2e/README.md: -------------------------------------------------------------------------------- 1 | # End-to-end tests for MOCO 2 | 3 | This directory contains test suites that runs MOCO on a real Kubernetes using [kind][]. 4 | 5 | ## Strategy 6 | 7 | We adopt [Test Pyramid](https://martinfowler.com/bliki/TestPyramid.html) and [Test Sizes](https://testing.googleblog.com/2010/12/test-sizes.html). 8 | 9 | The end-to-end (e2e) tests are positioned at the top of the pyramid and "Large" ones. 10 | 11 | MOCO has small and medium tests in package directories, so all packages are ensured to work by themselves. 12 | Therefore, we include the following tests in the e2e suite. 13 | 14 | - Manifests. 15 | - MySQL cluster lifecycle (create, update, delete). 16 | - Access moco-agent over mTLS connections. 17 | - Access mysqld via Services. 18 | - Garbage collection after deleting MySQLCluster. 19 | - Slow logs from a sidecar container. 20 | - Metrics of `moco-controller`. 21 | - `kubectl-moco` plugin features. 22 | - Backup and restore features. 23 | 24 | ## How to run e2e tests 25 | 26 | 1. Prepare a Linux with Docker. 27 | 2. Install aqua by following the instructions at https://aquaproj.github.io/docs/install/. 28 | 3. Run the following commands in this directory. 29 | 30 | ```console 31 | $ make start 32 | $ make test 33 | $ make test-upgrade 34 | ``` 35 | 36 | 4. After the test, run the following command to stop `kind` cluster. 37 | 38 | ```console 39 | $ make stop 40 | ``` 41 | 42 | ## How to test with a development version of moco-agent 43 | 44 | 1. Prepare the source directory of moco-agent. 45 | 2. Run `make start AGENT_DIR=` with the directory path of moco-agent. 46 | 47 | [kind]: https://kind.sigs.k8s.io/ 48 | -------------------------------------------------------------------------------- /e2e/env_test.go: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | import "os" 4 | 5 | var ( 6 | runE2E = os.Getenv("RUN_E2E") != "" 7 | kubectlCmd = os.Getenv("KUBECTL") 8 | mysqlVersion = os.Getenv("MYSQL_VERSION") 9 | doUpgrade = os.Getenv("UPGRADE") != "" 10 | ) 11 | -------------------------------------------------------------------------------- /e2e/fake-gcs-server.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | namespace: default 5 | name: fake-gcs-server 6 | spec: 7 | ports: 8 | - name: fake-gcs-server 9 | port: 4443 10 | targetPort: fake-gcs-server 11 | protocol: TCP 12 | selector: 13 | name: fake-gcs-server 14 | --- 15 | apiVersion: v1 16 | kind: Pod 17 | metadata: 18 | namespace: default 19 | name: fake-gcs-server 20 | labels: 21 | name: fake-gcs-server 22 | spec: 23 | containers: 24 | - name: fake-gcs-server 25 | image: fsouza/fake-gcs-server 26 | args: 27 | - "-scheme=http" 28 | - "-port=4443" 29 | - "-public-host=fake-gcs-server.default.svc:4443" 30 | ports: 31 | - name: fake-gcs-server 32 | containerPort: 4443 33 | protocol: TCP 34 | volumeMounts: 35 | - name: bucket 36 | mountPath: /data/moco 37 | volumes: 38 | - name: bucket 39 | emptyDir: {} 40 | -------------------------------------------------------------------------------- /e2e/kind-config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kind.x-k8s.io/v1alpha4 2 | kind: Cluster 3 | nodes: 4 | - role: control-plane 5 | - role: worker 6 | - role: worker 7 | - role: worker 8 | -------------------------------------------------------------------------------- /e2e/kind-config_actions.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kind.x-k8s.io/v1alpha4 2 | kind: Cluster 3 | nodes: 4 | - role: control-plane 5 | - role: worker 6 | extraMounts: 7 | - hostPath: /mnt/local-path-provisioner0 8 | containerPath: /var/local-path-provisioner 9 | - role: worker 10 | extraMounts: 11 | - hostPath: /mnt/local-path-provisioner1 12 | containerPath: /var/local-path-provisioner 13 | - role: worker 14 | extraMounts: 15 | - hostPath: /mnt/local-path-provisioner2 16 | containerPath: /var/local-path-provisioner 17 | -------------------------------------------------------------------------------- /e2e/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - ../config/default 3 | 4 | patchesStrategicMerge: 5 | - manager_patch.yaml 6 | 7 | images: 8 | - name: ghcr.io/cybozu-go/moco 9 | newName: moco 10 | newTag: dev 11 | -------------------------------------------------------------------------------- /e2e/manager_patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: moco-controller 5 | namespace: moco-system 6 | spec: 7 | replicas: 1 8 | template: 9 | spec: 10 | containers: 11 | - name: moco-controller 12 | image: ghcr.io/cybozu-go/moco:latest 13 | args: 14 | - --check-interval=5s 15 | - --backup-image=moco-backup:dev 16 | env: 17 | - name: DEBUG_CONTROLLER 18 | value: "1" 19 | - name: TEST_NO_JOB_RESOURCE 20 | value: "1" 21 | -------------------------------------------------------------------------------- /e2e/minio-tls.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cert-manager.io/v1 2 | kind: Issuer 3 | metadata: 4 | namespace: default 5 | name: default-selfsigned-issuer 6 | spec: 7 | selfSigned: {} 8 | --- 9 | apiVersion: cert-manager.io/v1 10 | kind: Certificate 11 | metadata: 12 | namespace: default 13 | name: minio-cert 14 | spec: 15 | commonName: minio cert 16 | issuerRef: 17 | kind: Issuer 18 | name: default-selfsigned-issuer 19 | secretName: minio-cert 20 | dnsNames: 21 | - minio-tls.default.svc 22 | --- 23 | apiVersion: v1 24 | kind: Service 25 | metadata: 26 | namespace: default 27 | name: minio-tls 28 | spec: 29 | ports: 30 | - name: minio 31 | port: 9000 32 | targetPort: minio 33 | protocol: TCP 34 | selector: 35 | name: minio-tls 36 | --- 37 | apiVersion: v1 38 | kind: Pod 39 | metadata: 40 | namespace: default 41 | name: minio-tls 42 | labels: 43 | name: minio-tls 44 | spec: 45 | containers: 46 | - name: minio 47 | image: minio/minio 48 | args: 49 | - server 50 | - /data 51 | ports: 52 | - name: minio 53 | containerPort: 9000 54 | protocol: TCP 55 | volumeMounts: 56 | - name: data 57 | mountPath: /data 58 | - name: secret-volume 59 | mountPath: /root/.minio/certs 60 | volumes: 61 | - name: data 62 | emptyDir: {} 63 | - name: secret-volume 64 | secret: 65 | secretName: minio-cert 66 | items: 67 | - key: tls.crt 68 | path: public.crt 69 | - key: tls.key 70 | path: private.key 71 | -------------------------------------------------------------------------------- /e2e/minio.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | namespace: default 5 | name: minio 6 | spec: 7 | ports: 8 | - name: minio 9 | port: 9000 10 | targetPort: minio 11 | protocol: TCP 12 | selector: 13 | name: minio 14 | --- 15 | apiVersion: v1 16 | kind: Pod 17 | metadata: 18 | namespace: default 19 | name: minio 20 | labels: 21 | name: minio 22 | spec: 23 | containers: 24 | - name: minio 25 | image: minio/minio 26 | args: 27 | - server 28 | - /data 29 | ports: 30 | - name: minio 31 | containerPort: 9000 32 | protocol: TCP 33 | volumeMounts: 34 | - name: data 35 | mountPath: /data 36 | volumes: 37 | - name: data 38 | emptyDir: {} 39 | -------------------------------------------------------------------------------- /e2e/suite_test.go: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | import ( 4 | _ "embed" 5 | "testing" 6 | "time" 7 | 8 | . "github.com/onsi/ginkgo/v2" 9 | . "github.com/onsi/gomega" 10 | ) 11 | 12 | func TestE2e(t *testing.T) { 13 | if !runE2E { 14 | t.Skip("no RUN_E2E environment variable") 15 | } 16 | RegisterFailHandler(Fail) 17 | SetDefaultEventuallyTimeout(5 * time.Minute) 18 | SetDefaultEventuallyPollingInterval(100 * time.Millisecond) 19 | RunSpecs(t, "E2e Suite") 20 | } 21 | 22 | //go:embed testdata/client.yaml 23 | var clientYAML string 24 | 25 | var _ = SynchronizedBeforeSuite(func() { 26 | kubectlSafe(fillTemplate(clientYAML), "apply", "-f", "-") 27 | }, func() {}) 28 | -------------------------------------------------------------------------------- /e2e/testdata/backup.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: backup 5 | --- 6 | apiVersion: v1 7 | kind: ConfigMap 8 | metadata: 9 | namespace: backup 10 | name: mycnf 11 | data: 12 | innodb_log_file_size: "10M" 13 | --- 14 | apiVersion: v1 15 | kind: ServiceAccount 16 | metadata: 17 | namespace: backup 18 | name: backup-owner 19 | --- 20 | apiVersion: moco.cybozu.com/v1beta2 21 | kind: BackupPolicy 22 | metadata: 23 | namespace: backup 24 | name: daily 25 | spec: 26 | schedule: "@daily" 27 | jobConfig: 28 | serviceAccountName: backup-owner 29 | env: 30 | - name: AWS_ACCESS_KEY_ID 31 | value: minioadmin 32 | - name: AWS_SECRET_ACCESS_KEY 33 | value: minioadmin 34 | - name: AWS_REGION 35 | value: us-east-1 36 | bucketConfig: 37 | bucketName: moco 38 | endpointURL: http://minio.default.svc:9000 39 | usePathStyle: true 40 | workVolume: 41 | emptyDir: {} 42 | --- 43 | apiVersion: moco.cybozu.com/v1beta2 44 | kind: MySQLCluster 45 | metadata: 46 | namespace: backup 47 | name: source 48 | spec: 49 | mysqlConfigMapName: mycnf 50 | replicas: 3 51 | backupPolicyName: daily 52 | podTemplate: 53 | spec: 54 | containers: 55 | - name: mysqld 56 | image: ghcr.io/cybozu-go/moco/mysql:{{ . }} 57 | volumeClaimTemplates: 58 | - metadata: 59 | name: mysql-data 60 | spec: 61 | accessModes: ["ReadWriteOnce"] 62 | resources: 63 | requests: 64 | storage: 1Gi 65 | -------------------------------------------------------------------------------- /e2e/testdata/backup_gcs.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: backup-gcs 5 | --- 6 | apiVersion: v1 7 | kind: ConfigMap 8 | metadata: 9 | namespace: backup-gcs 10 | name: mycnf 11 | data: 12 | innodb_log_file_size: "10M" 13 | --- 14 | apiVersion: v1 15 | kind: ServiceAccount 16 | metadata: 17 | namespace: backup-gcs 18 | name: backup-owner 19 | --- 20 | apiVersion: moco.cybozu.com/v1beta2 21 | kind: BackupPolicy 22 | metadata: 23 | namespace: backup-gcs 24 | name: daily 25 | spec: 26 | schedule: "@daily" 27 | jobConfig: 28 | serviceAccountName: backup-owner 29 | env: 30 | - name: STORAGE_EMULATOR_HOST 31 | value: fake-gcs-server.default.svc:4443 32 | bucketConfig: 33 | bucketName: moco 34 | backendType: gcs 35 | workVolume: 36 | emptyDir: {} 37 | --- 38 | apiVersion: moco.cybozu.com/v1beta2 39 | kind: MySQLCluster 40 | metadata: 41 | namespace: backup-gcs 42 | name: source 43 | spec: 44 | mysqlConfigMapName: mycnf 45 | replicas: 3 46 | backupPolicyName: daily 47 | podTemplate: 48 | spec: 49 | containers: 50 | - name: mysqld 51 | image: ghcr.io/cybozu-go/moco/mysql:{{ . }} 52 | volumeClaimTemplates: 53 | - metadata: 54 | name: mysql-data 55 | spec: 56 | accessModes: [ "ReadWriteOnce" ] 57 | resources: 58 | requests: 59 | storage: 1Gi 60 | -------------------------------------------------------------------------------- /e2e/testdata/backup_tls.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: backup-tls 5 | --- 6 | apiVersion: v1 7 | kind: ConfigMap 8 | metadata: 9 | namespace: backup-tls 10 | name: mycnf 11 | data: 12 | innodb_log_file_size: "10M" 13 | --- 14 | apiVersion: v1 15 | kind: ServiceAccount 16 | metadata: 17 | namespace: backup-tls 18 | name: backup-owner 19 | --- 20 | apiVersion: moco.cybozu.com/v1beta2 21 | kind: BackupPolicy 22 | metadata: 23 | namespace: backup-tls 24 | name: daily 25 | spec: 26 | schedule: "@daily" 27 | jobConfig: 28 | serviceAccountName: backup-owner 29 | env: 30 | - name: AWS_ACCESS_KEY_ID 31 | value: minioadmin 32 | - name: AWS_SECRET_ACCESS_KEY 33 | value: minioadmin 34 | - name: AWS_REGION 35 | value: us-east-1 36 | volumeMounts: 37 | - mountPath: /minio-cert 38 | name: minio-cert 39 | volumes: 40 | - name: minio-cert 41 | secret: 42 | secretName: minio-cert 43 | bucketConfig: 44 | bucketName: moco 45 | endpointURL: https://minio-tls.default.svc:9000 46 | usePathStyle: true 47 | caCert: /minio-cert/ca.crt 48 | workVolume: 49 | emptyDir: {} 50 | --- 51 | apiVersion: moco.cybozu.com/v1beta2 52 | kind: MySQLCluster 53 | metadata: 54 | namespace: backup-tls 55 | name: source 56 | spec: 57 | mysqlConfigMapName: mycnf 58 | replicas: 3 59 | backupPolicyName: daily 60 | podTemplate: 61 | spec: 62 | containers: 63 | - name: mysqld 64 | image: ghcr.io/cybozu-go/moco/mysql:{{ . }} 65 | volumeClaimTemplates: 66 | - metadata: 67 | name: mysql-data 68 | spec: 69 | accessModes: ["ReadWriteOnce"] 70 | resources: 71 | requests: 72 | storage: 1Gi 73 | -------------------------------------------------------------------------------- /e2e/testdata/backup_with_env.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: backup-with-env 5 | --- 6 | apiVersion: v1 7 | kind: ConfigMap 8 | metadata: 9 | namespace: backup-with-env 10 | name: mycnf 11 | data: 12 | innodb_log_file_size: "10M" 13 | --- 14 | apiVersion: v1 15 | kind: ServiceAccount 16 | metadata: 17 | namespace: backup-with-env 18 | name: backup-owner 19 | --- 20 | apiVersion: moco.cybozu.com/v1beta2 21 | kind: BackupPolicy 22 | metadata: 23 | namespace: backup-with-env 24 | name: daily 25 | spec: 26 | schedule: "@daily" 27 | jobConfig: 28 | serviceAccountName: backup-owner 29 | env: 30 | - name: AWS_ACCESS_KEY_ID 31 | value: minioadmin 32 | - name: AWS_SECRET_ACCESS_KEY 33 | value: minioadmin 34 | - name: AWS_REGION 35 | value: us-east-1 36 | bucketConfig: 37 | bucketName: "$(BUCKET_NAME)" 38 | endpointURL: http://minio.default.svc:9000 39 | usePathStyle: true 40 | envFrom: 41 | - configMapRef: 42 | name: bucket-name 43 | workVolume: 44 | emptyDir: {} 45 | --- 46 | apiVersion: moco.cybozu.com/v1beta2 47 | kind: MySQLCluster 48 | metadata: 49 | namespace: backup-with-env 50 | name: source 51 | spec: 52 | mysqlConfigMapName: mycnf 53 | replicas: 3 54 | backupPolicyName: daily 55 | podTemplate: 56 | spec: 57 | containers: 58 | - name: mysqld 59 | image: ghcr.io/cybozu-go/moco/mysql:{{ . }} 60 | volumeClaimTemplates: 61 | - metadata: 62 | name: mysql-data 63 | spec: 64 | accessModes: ["ReadWriteOnce"] 65 | resources: 66 | requests: 67 | storage: 1Gi 68 | --- 69 | apiVersion: v1 70 | kind: ConfigMap 71 | metadata: 72 | namespace: backup-with-env 73 | name: bucket-name 74 | data: 75 | BUCKET_NAME: moco-with-env 76 | -------------------------------------------------------------------------------- /e2e/testdata/client.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | namespace: default 6 | name: client 7 | spec: 8 | containers: 9 | - name: pause 10 | image: ghcr.io/cybozu-go/moco/mysql:{{ . }} 11 | command: ["pause"] 12 | -------------------------------------------------------------------------------- /e2e/testdata/donor.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: donor 5 | --- 6 | apiVersion: v1 7 | kind: ConfigMap 8 | metadata: 9 | namespace: donor 10 | name: mycnf 11 | data: 12 | innodb_log_file_size: "10M" 13 | --- 14 | apiVersion: moco.cybozu.com/v1beta2 15 | kind: MySQLCluster 16 | metadata: 17 | namespace: donor 18 | name: single 19 | spec: 20 | mysqlConfigMapName: mycnf 21 | podTemplate: 22 | spec: 23 | containers: 24 | - name: mysqld 25 | image: ghcr.io/cybozu-go/moco/mysql:{{ . }} 26 | volumeClaimTemplates: 27 | - metadata: 28 | name: mysql-data 29 | spec: 30 | accessModes: [ "ReadWriteOnce" ] 31 | resources: 32 | requests: 33 | storage: 1Gi 34 | -------------------------------------------------------------------------------- /e2e/testdata/failover.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: failover 5 | --- 6 | apiVersion: moco.cybozu.com/v1beta2 7 | kind: MySQLCluster 8 | metadata: 9 | namespace: failover 10 | name: test 11 | spec: 12 | replicas: 3 13 | podTemplate: 14 | spec: 15 | containers: 16 | - name: mysqld 17 | image: ghcr.io/cybozu-go/moco/mysql:{{ . }} 18 | volumeClaimTemplates: 19 | - metadata: 20 | name: mysql-data 21 | spec: 22 | accessModes: [ "ReadWriteOnce" ] 23 | resources: 24 | requests: 25 | storage: 1Gi 26 | -------------------------------------------------------------------------------- /e2e/testdata/failure.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: failure 5 | --- 6 | apiVersion: moco.cybozu.com/v1beta2 7 | kind: MySQLCluster 8 | metadata: 9 | namespace: failure 10 | name: test 11 | spec: 12 | replicas: 3 13 | podTemplate: 14 | spec: 15 | containers: 16 | - name: mysqld 17 | image: ghcr.io/cybozu-go/moco/mysql:{{ . }} 18 | volumeClaimTemplates: 19 | - metadata: 20 | name: mysql-data 21 | spec: 22 | accessModes: [ "ReadWriteOnce" ] 23 | resources: 24 | requests: 25 | storage: 1Gi 26 | -------------------------------------------------------------------------------- /e2e/testdata/makebucket.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: make-bucket 5 | namespace: default 6 | spec: 7 | template: 8 | spec: 9 | restartPolicy: OnFailure 10 | containers: 11 | - command: 12 | - s3cmd 13 | - --host=minio.default.svc:9000 14 | - --host-bucket=minio.default.svc:9000 15 | - --access_key=minioadmin 16 | - --secret_key=minioadmin 17 | - --no-ssl 18 | - mb 19 | - s3://moco 20 | image: moco-backup:dev 21 | imagePullPolicy: IfNotPresent 22 | name: make-bucket 23 | -------------------------------------------------------------------------------- /e2e/testdata/makebucket_tls.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: make-bucket-tls 5 | namespace: default 6 | spec: 7 | template: 8 | spec: 9 | restartPolicy: OnFailure 10 | containers: 11 | - command: 12 | - s3cmd 13 | - --host=minio-tls.default.svc:9000 14 | - --host-bucket=minio-tls.default.svc:9000 15 | - --access_key=minioadmin 16 | - --secret_key=minioadmin 17 | - --ssl 18 | - --ca-certs=/minio-cert/ca.crt 19 | - mb 20 | - s3://moco 21 | image: moco-backup:dev 22 | imagePullPolicy: IfNotPresent 23 | name: make-bucket-tls 24 | volumeMounts: 25 | - name: minio-cert 26 | mountPath: /minio-cert 27 | volumes: 28 | - name: minio-cert 29 | secret: 30 | secretName: minio-cert 31 | items: 32 | - key: ca.crt 33 | path: ca.crt 34 | -------------------------------------------------------------------------------- /e2e/testdata/makebucket_with_env.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: make-bucket-with-env 5 | namespace: default 6 | spec: 7 | template: 8 | spec: 9 | restartPolicy: OnFailure 10 | containers: 11 | - command: 12 | - s3cmd 13 | - --host=minio.default.svc:9000 14 | - --host-bucket=minio.default.svc:9000 15 | - --access_key=minioadmin 16 | - --secret_key=minioadmin 17 | - --no-ssl 18 | - mb 19 | - s3://moco-with-env 20 | image: moco-backup:dev 21 | imagePullPolicy: IfNotPresent 22 | name: make-bucket 23 | -------------------------------------------------------------------------------- /e2e/testdata/offline_test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: offline 5 | --- 6 | apiVersion: moco.cybozu.com/v1beta2 7 | kind: MySQLCluster 8 | metadata: 9 | namespace: offline 10 | name: test 11 | spec: 12 | offline: false 13 | replicas: 1 14 | podTemplate: 15 | spec: 16 | containers: 17 | - name: mysqld 18 | image: ghcr.io/cybozu-go/moco/mysql:{{ . }} 19 | volumeClaimTemplates: 20 | - metadata: 21 | name: mysql-data 22 | spec: 23 | accessModes: [ "ReadWriteOnce" ] 24 | resources: 25 | requests: 26 | storage: 1Gi 27 | -------------------------------------------------------------------------------- /e2e/testdata/offline_test_changed.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: moco.cybozu.com/v1beta2 2 | kind: MySQLCluster 3 | metadata: 4 | namespace: offline 5 | name: test 6 | spec: 7 | offline: true 8 | replicas: 1 9 | podTemplate: 10 | spec: 11 | containers: 12 | - name: mysqld 13 | image: ghcr.io/cybozu-go/moco/mysql:{{ . }} 14 | volumeClaimTemplates: 15 | - metadata: 16 | name: mysql-data 17 | spec: 18 | accessModes: [ "ReadWriteOnce" ] 19 | resources: 20 | requests: 21 | storage: 1Gi 22 | -------------------------------------------------------------------------------- /e2e/testdata/partition.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: partition 5 | --- 6 | apiVersion: moco.cybozu.com/v1beta2 7 | kind: MySQLCluster 8 | metadata: 9 | namespace: partition 10 | name: test 11 | spec: 12 | replicas: 3 13 | podTemplate: 14 | spec: 15 | containers: 16 | - name: mysqld 17 | image: ghcr.io/cybozu-go/moco/mysql:{{ . }} 18 | resources: 19 | requests: 20 | cpu: 1m 21 | volumeClaimTemplates: 22 | - metadata: 23 | name: mysql-data 24 | spec: 25 | accessModes: [ "ReadWriteOnce" ] 26 | resources: 27 | requests: 28 | storage: 1Gi 29 | -------------------------------------------------------------------------------- /e2e/testdata/partition_changed.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: moco.cybozu.com/v1beta2 2 | kind: MySQLCluster 3 | metadata: 4 | namespace: partition 5 | name: test 6 | spec: 7 | replicas: 3 8 | podTemplate: 9 | spec: 10 | containers: 11 | - name: mysqld 12 | image: ghcr.io/cybozu-go/moco/mysql:{{ . }} 13 | resources: 14 | requests: 15 | cpu: 2m 16 | volumeClaimTemplates: 17 | - metadata: 18 | name: mysql-data 19 | spec: 20 | accessModes: [ "ReadWriteOnce" ] 21 | resources: 22 | requests: 23 | storage: 1Gi 24 | -------------------------------------------------------------------------------- /e2e/testdata/partition_force_rollingupdate.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: moco.cybozu.com/v1beta2 2 | kind: MySQLCluster 3 | metadata: 4 | namespace: partition 5 | name: test 6 | annotations: 7 | moco.cybozu.com/force-rolling-update: "true" 8 | spec: 9 | replicas: 3 10 | podTemplate: 11 | spec: 12 | containers: 13 | - name: mysqld 14 | image: ghcr.io/cybozu-go/moco/mysql:{{ . }} 15 | resources: 16 | requests: 17 | cpu: 3m 18 | volumeClaimTemplates: 19 | - metadata: 20 | name: mysql-data 21 | spec: 22 | accessModes: [ "ReadWriteOnce" ] 23 | resources: 24 | requests: 25 | storage: 1Gi 26 | -------------------------------------------------------------------------------- /e2e/testdata/partition_image_pull_backoff.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: moco.cybozu.com/v1beta2 2 | kind: MySQLCluster 3 | metadata: 4 | namespace: partition 5 | name: test 6 | spec: 7 | replicas: 3 8 | podTemplate: 9 | spec: 10 | containers: 11 | - name: mysqld 12 | image: ghcr.io/cybozu-go/moco/mysql:invalid-image 13 | resources: 14 | requests: 15 | cpu: 1m 16 | volumeClaimTemplates: 17 | - metadata: 18 | name: mysql-data 19 | spec: 20 | accessModes: [ "ReadWriteOnce" ] 21 | resources: 22 | requests: 23 | storage: 1Gi 24 | -------------------------------------------------------------------------------- /e2e/testdata/partition_volume_template.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: moco.cybozu.com/v1beta2 2 | kind: MySQLCluster 3 | metadata: 4 | namespace: partition 5 | name: test 6 | spec: 7 | replicas: 3 8 | podTemplate: 9 | metadata: 10 | labels: 11 | foo: bar 12 | spec: 13 | containers: 14 | - name: mysqld 15 | image: ghcr.io/cybozu-go/moco/mysql:{{ . }} 16 | resources: 17 | requests: 18 | cpu: 1m 19 | volumeClaimTemplates: 20 | - metadata: 21 | name: mysql-data 22 | labels: 23 | foo: bar 24 | spec: 25 | accessModes: [ "ReadWriteOnce" ] 26 | resources: 27 | requests: 28 | storage: 1Gi 29 | -------------------------------------------------------------------------------- /e2e/testdata/prevent_delete.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: prevent-delete 5 | --- 6 | apiVersion: v1 7 | kind: ConfigMap 8 | metadata: 9 | namespace: prevent-delete 10 | name: mycnf 11 | data: 12 | innodb_log_file_size: "10M" 13 | --- 14 | apiVersion: moco.cybozu.com/v1beta2 15 | kind: MySQLCluster 16 | metadata: 17 | namespace: prevent-delete 18 | name: test 19 | spec: 20 | mysqlConfigMapName: mycnf 21 | replicas: 3 22 | maxDelaySeconds: 0 23 | maxDelaySecondsForPodDeletion: 10 24 | podTemplate: 25 | spec: 26 | containers: 27 | - name: mysqld 28 | image: ghcr.io/cybozu-go/moco/mysql:{{ . }} 29 | volumeClaimTemplates: 30 | - metadata: 31 | name: mysql-data 32 | spec: 33 | accessModes: [ "ReadWriteOnce" ] 34 | resources: 35 | requests: 36 | storage: 1Gi 37 | -------------------------------------------------------------------------------- /e2e/testdata/pvc_test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: pvc 5 | --- 6 | apiVersion: v1 7 | kind: ConfigMap 8 | metadata: 9 | namespace: pvc 10 | name: mycnf 11 | data: 12 | innodb_log_file_size: "10M" 13 | --- 14 | apiVersion: storage.k8s.io/v1 15 | kind: StorageClass 16 | metadata: 17 | name: standard-allow-volume-expansion 18 | provisioner: rancher.io/local-path 19 | reclaimPolicy: Delete 20 | volumeBindingMode: WaitForFirstConsumer 21 | allowVolumeExpansion: true 22 | --- 23 | apiVersion: moco.cybozu.com/v1beta2 24 | kind: MySQLCluster 25 | metadata: 26 | namespace: pvc 27 | name: cluster 28 | spec: 29 | replicas: 3 30 | mysqlConfigMapName: mycnf 31 | podTemplate: 32 | spec: 33 | containers: 34 | - name: mysqld 35 | image: ghcr.io/cybozu-go/moco/mysql:{{ . }} 36 | volumeClaimTemplates: 37 | - metadata: 38 | name: mysql-data 39 | spec: 40 | storageClassName: standard-allow-volume-expansion 41 | accessModes: [ "ReadWriteOnce" ] 42 | resources: 43 | requests: 44 | storage: 500Mi 45 | -------------------------------------------------------------------------------- /e2e/testdata/pvc_test_changed.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: moco.cybozu.com/v1beta2 2 | kind: MySQLCluster 3 | metadata: 4 | namespace: pvc 5 | name: cluster 6 | spec: 7 | replicas: 3 8 | mysqlConfigMapName: mycnf 9 | podTemplate: 10 | spec: 11 | containers: 12 | - name: mysqld 13 | image: ghcr.io/cybozu-go/moco/mysql:{{ . }} 14 | volumeClaimTemplates: 15 | - metadata: 16 | name: mysql-data 17 | labels: 18 | foo: bar 19 | spec: 20 | storageClassName: standard-allow-volume-expansion 21 | accessModes: [ "ReadWriteOnce" ] 22 | resources: 23 | requests: 24 | storage: 1Gi 25 | -------------------------------------------------------------------------------- /e2e/testdata/replication.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: repl 5 | --- 6 | apiVersion: v1 7 | kind: ConfigMap 8 | metadata: 9 | namespace: repl 10 | name: mycnf 11 | data: 12 | innodb_log_file_size: "10M" 13 | --- 14 | apiVersion: moco.cybozu.com/v1beta2 15 | kind: MySQLCluster 16 | metadata: 17 | namespace: repl 18 | name: test 19 | spec: 20 | mysqlConfigMapName: mycnf 21 | replicas: 3 22 | replicationSourceSecretName: donor 23 | podTemplate: 24 | spec: 25 | containers: 26 | - name: mysqld 27 | image: ghcr.io/cybozu-go/moco/mysql:{{ . }} 28 | volumeClaimTemplates: 29 | - metadata: 30 | name: mysql-data 31 | spec: 32 | accessModes: [ "ReadWriteOnce" ] 33 | resources: 34 | requests: 35 | storage: 1Gi 36 | -------------------------------------------------------------------------------- /e2e/testdata/restore1.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: moco.cybozu.com/v1beta2 2 | kind: MySQLCluster 3 | metadata: 4 | namespace: backup 5 | name: target1 6 | spec: 7 | mysqlConfigMapName: mycnf 8 | replicas: 1 9 | restore: 10 | sourceName: source 11 | sourceNamespace: backup 12 | restorePoint: "{{ .RestorePoint }}" 13 | jobConfig: 14 | serviceAccountName: backup-owner 15 | env: 16 | - name: AWS_ACCESS_KEY_ID 17 | value: minioadmin 18 | - name: AWS_SECRET_ACCESS_KEY 19 | value: minioadmin 20 | - name: AWS_REGION 21 | value: us-east-1 22 | bucketConfig: 23 | bucketName: moco 24 | endpointURL: http://minio.default.svc:9000 25 | usePathStyle: true 26 | workVolume: 27 | emptyDir: {} 28 | podTemplate: 29 | spec: 30 | containers: 31 | - name: mysqld 32 | image: ghcr.io/cybozu-go/moco/mysql:{{ .MySQLVersion }} 33 | volumeClaimTemplates: 34 | - metadata: 35 | name: mysql-data 36 | spec: 37 | accessModes: ["ReadWriteOnce"] 38 | resources: 39 | requests: 40 | storage: 1Gi 41 | -------------------------------------------------------------------------------- /e2e/testdata/restore2.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: moco.cybozu.com/v1beta2 2 | kind: MySQLCluster 3 | metadata: 4 | namespace: backup 5 | name: target2 6 | spec: 7 | mysqlConfigMapName: mycnf 8 | replicas: 1 9 | restore: 10 | sourceName: source 11 | sourceNamespace: backup 12 | restorePoint: "{{ .RestorePoint }}" 13 | schema: "test2" 14 | jobConfig: 15 | serviceAccountName: backup-owner 16 | env: 17 | - name: AWS_ACCESS_KEY_ID 18 | value: minioadmin 19 | - name: AWS_SECRET_ACCESS_KEY 20 | value: minioadmin 21 | - name: AWS_REGION 22 | value: us-east-1 23 | bucketConfig: 24 | bucketName: moco 25 | endpointURL: http://minio.default.svc:9000 26 | usePathStyle: true 27 | workVolume: 28 | emptyDir: {} 29 | podTemplate: 30 | spec: 31 | containers: 32 | - name: mysqld 33 | image: ghcr.io/cybozu-go/moco/mysql:{{ .MySQLVersion }} 34 | volumeClaimTemplates: 35 | - metadata: 36 | name: mysql-data 37 | spec: 38 | accessModes: ["ReadWriteOnce"] 39 | resources: 40 | requests: 41 | storage: 1Gi 42 | -------------------------------------------------------------------------------- /e2e/testdata/restore_gcs.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: moco.cybozu.com/v1beta2 2 | kind: MySQLCluster 3 | metadata: 4 | namespace: backup-gcs 5 | name: target 6 | spec: 7 | mysqlConfigMapName: mycnf 8 | replicas: 1 9 | restore: 10 | sourceName: source 11 | sourceNamespace: backup-gcs 12 | restorePoint: "{{ .RestorePoint }}" 13 | jobConfig: 14 | serviceAccountName: backup-owner 15 | env: 16 | - name: STORAGE_EMULATOR_HOST 17 | value: fake-gcs-server.default.svc:4443 18 | bucketConfig: 19 | bucketName: moco 20 | backendType: gcs 21 | workVolume: 22 | emptyDir: {} 23 | podTemplate: 24 | spec: 25 | containers: 26 | - name: mysqld 27 | image: ghcr.io/cybozu-go/moco/mysql:{{ .MySQLVersion }} 28 | volumeClaimTemplates: 29 | - metadata: 30 | name: mysql-data 31 | spec: 32 | accessModes: [ "ReadWriteOnce" ] 33 | resources: 34 | requests: 35 | storage: 1Gi 36 | -------------------------------------------------------------------------------- /e2e/testdata/restore_tls.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: moco.cybozu.com/v1beta2 2 | kind: MySQLCluster 3 | metadata: 4 | namespace: backup-tls 5 | name: target 6 | spec: 7 | mysqlConfigMapName: mycnf 8 | replicas: 1 9 | restore: 10 | sourceName: source 11 | sourceNamespace: backup-tls 12 | restorePoint: "{{ .RestorePoint }}" 13 | jobConfig: 14 | serviceAccountName: backup-owner 15 | env: 16 | - name: AWS_ACCESS_KEY_ID 17 | value: minioadmin 18 | - name: AWS_SECRET_ACCESS_KEY 19 | value: minioadmin 20 | - name: AWS_REGION 21 | value: us-east-1 22 | volumeMounts: 23 | - mountPath: /minio-cert 24 | name: minio-cert 25 | volumes: 26 | - name: minio-cert 27 | secret: 28 | secretName: minio-cert 29 | bucketConfig: 30 | bucketName: moco 31 | endpointURL: https://minio-tls.default.svc:9000 32 | usePathStyle: true 33 | caCert: /minio-cert/ca.crt 34 | workVolume: 35 | emptyDir: {} 36 | podTemplate: 37 | spec: 38 | containers: 39 | - name: mysqld 40 | image: ghcr.io/cybozu-go/moco/mysql:{{ .MySQLVersion }} 41 | volumeClaimTemplates: 42 | - metadata: 43 | name: mysql-data 44 | spec: 45 | accessModes: ["ReadWriteOnce"] 46 | resources: 47 | requests: 48 | storage: 1Gi 49 | -------------------------------------------------------------------------------- /e2e/testdata/restore_with_env.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: moco.cybozu.com/v1beta2 2 | kind: MySQLCluster 3 | metadata: 4 | namespace: backup-with-env 5 | name: target 6 | spec: 7 | mysqlConfigMapName: mycnf 8 | replicas: 1 9 | restore: 10 | sourceName: source 11 | sourceNamespace: backup-with-env 12 | restorePoint: "{{ .RestorePoint }}" 13 | jobConfig: 14 | serviceAccountName: backup-owner 15 | env: 16 | - name: AWS_ACCESS_KEY_ID 17 | value: minioadmin 18 | - name: AWS_SECRET_ACCESS_KEY 19 | value: minioadmin 20 | - name: AWS_REGION 21 | value: us-east-1 22 | bucketConfig: 23 | bucketName: "$(BUCKET_NAME)" 24 | endpointURL: http://minio.default.svc:9000 25 | usePathStyle: true 26 | workVolume: 27 | emptyDir: {} 28 | envFrom: 29 | - configMapRef: 30 | name: bucket-name 31 | podTemplate: 32 | spec: 33 | containers: 34 | - name: mysqld 35 | image: ghcr.io/cybozu-go/moco/mysql:{{ .MySQLVersion }} 36 | volumeClaimTemplates: 37 | - metadata: 38 | name: mysql-data 39 | spec: 40 | accessModes: ["ReadWriteOnce"] 41 | resources: 42 | requests: 43 | storage: 1Gi 44 | --- 45 | apiVersion: v1 46 | kind: ConfigMap 47 | metadata: 48 | namespace: backup-with-env 49 | name: bucket-name 50 | data: 51 | BUCKET_NAME: moco-with-env 52 | -------------------------------------------------------------------------------- /e2e/testdata/single.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: foo 5 | --- 6 | apiVersion: v1 7 | kind: ConfigMap 8 | metadata: 9 | namespace: foo 10 | name: mycnf 11 | data: 12 | long_query_time: "0" 13 | innodb_log_file_size: "10M" 14 | --- 15 | apiVersion: moco.cybozu.com/v1beta2 16 | kind: MySQLCluster 17 | metadata: 18 | namespace: foo 19 | name: single 20 | spec: 21 | mysqlConfigMapName: mycnf 22 | podTemplate: 23 | spec: 24 | containers: 25 | - name: mysqld 26 | image: ghcr.io/cybozu-go/moco/mysql:{{ . }} 27 | resources: 28 | limits: 29 | cpu: "0.5" 30 | memory: 1Gi 31 | volumeClaimTemplates: 32 | - metadata: 33 | name: mysql-data 34 | spec: 35 | accessModes: [ "ReadWriteOnce" ] 36 | resources: 37 | requests: 38 | storage: 1Gi 39 | logRotationSchedule: "@every 10s" 40 | -------------------------------------------------------------------------------- /e2e/testdata/stop.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: stop 5 | --- 6 | apiVersion: moco.cybozu.com/v1beta2 7 | kind: MySQLCluster 8 | metadata: 9 | namespace: stop 10 | name: test 11 | spec: 12 | replicas: 3 13 | podTemplate: 14 | spec: 15 | containers: 16 | - name: mysqld 17 | image: ghcr.io/cybozu-go/moco/mysql:{{ . }} 18 | volumeClaimTemplates: 19 | - metadata: 20 | name: mysql-data 21 | spec: 22 | accessModes: [ "ReadWriteOnce" ] 23 | resources: 24 | requests: 25 | storage: 1Gi 26 | -------------------------------------------------------------------------------- /e2e/testdata/stop_changed.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: stop 5 | --- 6 | apiVersion: moco.cybozu.com/v1beta2 7 | kind: MySQLCluster 8 | metadata: 9 | namespace: stop 10 | name: test 11 | spec: 12 | replicas: 3 13 | podTemplate: 14 | metadata: 15 | labels: 16 | foo: bar 17 | spec: 18 | containers: 19 | - name: mysqld 20 | image: ghcr.io/cybozu-go/moco/mysql:{{ . }} 21 | volumeClaimTemplates: 22 | - metadata: 23 | name: mysql-data 24 | spec: 25 | accessModes: [ "ReadWriteOnce" ] 26 | resources: 27 | requests: 28 | storage: 1Gi 29 | -------------------------------------------------------------------------------- /e2e/testdata/upgrade.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: upgrade 5 | --- 6 | apiVersion: moco.cybozu.com/v1beta2 7 | kind: MySQLCluster 8 | metadata: 9 | namespace: upgrade 10 | name: test 11 | spec: 12 | replicas: 5 13 | podTemplate: 14 | spec: 15 | containers: 16 | - name: mysqld 17 | image: ghcr.io/cybozu-go/moco/mysql:{{ . }} 18 | volumeClaimTemplates: 19 | - metadata: 20 | name: mysql-data 21 | spec: 22 | accessModes: [ "ReadWriteOnce" ] 23 | resources: 24 | requests: 25 | storage: 1Gi 26 | -------------------------------------------------------------------------------- /examples/anti-affinity-backuppolicy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: moco.cybozu.com/v1beta2 2 | kind: BackupPolicy 3 | metadata: 4 | namespace: backup 5 | name: daily 6 | spec: 7 | # Backup schedule. Any CRON format is allowed. 8 | schedule: "@daily" 9 | 10 | jobConfig: 11 | affinity: 12 | podAntiAffinity: 13 | preferredDuringSchedulingIgnoredDuringExecution: 14 | - weight: 100 15 | podAffinityTerm: 16 | namespaceSelector: {} # to apply the anti-affinity across all namespaces 17 | labelSelector: 18 | matchExpressions: 19 | - key: app.kubernetes.io/name 20 | operator: In 21 | values: ["mysql-backup"] 22 | - key: app.kubernetes.io/created-by 23 | operator: In 24 | values: ["moco"] 25 | topologyKey: kubernetes.io/hostname 26 | -------------------------------------------------------------------------------- /examples/anti-affinity.yaml: -------------------------------------------------------------------------------- 1 | # This example shows how to schedule Pods on different Nodes. 2 | apiVersion: moco.cybozu.com/v1beta2 3 | kind: MySQLCluster 4 | metadata: 5 | namespace: default 6 | name: test 7 | spec: 8 | replicas: 3 9 | podTemplate: 10 | spec: 11 | affinity: 12 | # The anti-affinity for Pods 13 | # cf. https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity 14 | podAntiAffinity: 15 | requiredDuringSchedulingIgnoredDuringExecution: 16 | - labelSelector: 17 | matchExpressions: 18 | - key: app.kubernetes.io/name 19 | operator: In 20 | values: 21 | - mysql 22 | - key: app.kubernetes.io/instance 23 | operator: In 24 | values: 25 | - test 26 | topologyKey: "kubernetes.io/hostname" 27 | containers: 28 | - name: mysqld 29 | image: ghcr.io/cybozu-go/moco/mysql:8.4.5 30 | resources: 31 | requests: 32 | cpu: "10" 33 | memory: "10Gi" 34 | limits: 35 | cpu: "10" 36 | memory: "10Gi" 37 | volumeClaimTemplates: 38 | - metadata: 39 | name: mysql-data 40 | spec: 41 | accessModes: [ "ReadWriteOnce" ] 42 | resources: 43 | requests: 44 | storage: 1Gi 45 | -------------------------------------------------------------------------------- /examples/collect-metrics.yaml: -------------------------------------------------------------------------------- 1 | # This example shows how to collect and export mysqld metrics using mysqld_exporter. 2 | apiVersion: moco.cybozu.com/v1beta2 3 | kind: MySQLCluster 4 | metadata: 5 | namespace: default 6 | name: test 7 | spec: 8 | # collectors is a list of collector flag names. 9 | # See https://github.com/prometheus/mysqld_exporter/blob/master/README.md#collector-flags for all available collectors. 10 | collectors: 11 | - engine_innodb_status 12 | - info_schema.innodb_metrics 13 | podTemplate: 14 | spec: 15 | containers: 16 | - name: mysqld 17 | image: ghcr.io/cybozu-go/moco/mysql:8.4.5 18 | volumeClaimTemplates: 19 | - metadata: 20 | name: mysql-data 21 | spec: 22 | accessModes: [ "ReadWriteOnce" ] 23 | resources: 24 | requests: 25 | storage: 1Gi 26 | -------------------------------------------------------------------------------- /examples/custom-mycnf.yaml: -------------------------------------------------------------------------------- 1 | # This example shows how to set MySQL server system variables. 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | namespace: default 6 | name: mycnf 7 | data: 8 | # key-value in data field will become server system variable names and values. 9 | # https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html 10 | # https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html 11 | long_query_time: "5" 12 | innodb_buffer_pool_size: "70G" 13 | --- 14 | apiVersion: moco.cybozu.com/v1beta2 15 | kind: MySQLCluster 16 | metadata: 17 | namespace: default 18 | name: test 19 | spec: 20 | replicas: 3 21 | # ConfigMap name in the same namespace. 22 | mysqlConfigMapName: mycnf 23 | podTemplate: 24 | spec: 25 | containers: 26 | - name: mysqld 27 | image: ghcr.io/cybozu-go/moco/mysql:8.4.5 28 | volumeClaimTemplates: 29 | - metadata: 30 | name: mysql-data 31 | spec: 32 | accessModes: [ "ReadWriteOnce" ] 33 | resources: 34 | requests: 35 | storage: 1Gi 36 | -------------------------------------------------------------------------------- /examples/custom-probe.yaml: -------------------------------------------------------------------------------- 1 | # This example shows how to uses a user-defined probe 2 | apiVersion: moco.cybozu.com/v1beta2 3 | kind: MySQLCluster 4 | metadata: 5 | namespace: default 6 | name: test 7 | spec: 8 | replicas: 3 9 | podTemplate: 10 | spec: 11 | containers: 12 | - name: mysqld 13 | image: ghcr.io/cybozu-go/moco/mysql:8.4.5 14 | # If you want to override the default probes, you cannot override the httpGet. 15 | livenessProbe: 16 | failureThreshold: 3 17 | # Cannot be overwritten httpGet. 18 | # 19 | # httpGet: 20 | # path: /foo/healthz 21 | # port: health 22 | # scheme: HTTP 23 | periodSeconds: 10 24 | successThreshold: 1 25 | timeoutSeconds: 1 26 | terminationGracePeriodSeconds: 200 27 | # Default probes: 28 | # 29 | # startupProbe: 30 | # failureThreshold: 360 # .spec.startupWaitSeconds (default: 3600) / 10 31 | # httpGet: 32 | # path: /healthz 33 | # port: health 34 | # scheme: HTTP 35 | # periodSeconds: 10 36 | # successThreshold: 1 37 | # timeoutSeconds: 1 38 | # readinessProbe: 39 | # failureThreshold: 3 40 | # httpGet: 41 | # path: /readyz 42 | # port: health 43 | # scheme: HTTP 44 | # periodSeconds: 10 45 | # successThreshold: 1 46 | # timeoutSeconds: 1 47 | # livenessProbe: 48 | # failureThreshold: 3 49 | # httpGet: 50 | # path: /healthz 51 | # port: health 52 | # scheme: HTTP 53 | # periodSeconds: 10 54 | # successThreshold: 1 55 | # timeoutSeconds: 1 56 | volumeClaimTemplates: 57 | - metadata: 58 | name: mysql-data 59 | spec: 60 | accessModes: [ "ReadWriteOnce" ] 61 | resources: 62 | requests: 63 | storage: 1Gi 64 | -------------------------------------------------------------------------------- /examples/guaranteed.yaml: -------------------------------------------------------------------------------- 1 | # This example shows how to assign Guaranteed QoS class to Pods. 2 | apiVersion: moco.cybozu.com/v1beta2 3 | kind: MySQLCluster 4 | metadata: 5 | namespace: default 6 | name: test 7 | spec: 8 | replicas: 3 9 | podTemplate: 10 | spec: 11 | containers: 12 | - name: mysqld 13 | image: ghcr.io/cybozu-go/moco/mysql:8.4.5 14 | # By limiting CPU and memory, Pods will have Guaranteed QoS class. 15 | # requests can be omitted; it will be set to the same value as limits. 16 | resources: 17 | limits: 18 | cpu: "10" 19 | memory: "10Gi" 20 | volumeClaimTemplates: 21 | - metadata: 22 | name: mysql-data 23 | spec: 24 | accessModes: [ "ReadWriteOnce" ] 25 | resources: 26 | requests: 27 | storage: 1Gi 28 | -------------------------------------------------------------------------------- /examples/loadbalancer.yaml: -------------------------------------------------------------------------------- 1 | # This example shows how to change Service type to LoadBalancer 2 | apiVersion: moco.cybozu.com/v1beta2 3 | kind: MySQLCluster 4 | metadata: 5 | namespace: default 6 | name: test 7 | spec: 8 | replicas: 3 9 | # primaryServiceTemplate and replicaServiceTemplate allows you to specify annotations, labels, and spec 10 | # of Services to be generated for this MySQLCluster. 11 | primaryServiceTemplate: 12 | metadata: 13 | annotations: 14 | metallb.universe.tf/address-pool: production-public-ips 15 | spec: 16 | type: LoadBalancer 17 | podTemplate: 18 | spec: 19 | containers: 20 | - name: mysqld 21 | image: ghcr.io/cybozu-go/moco/mysql:8.4.5 22 | volumeClaimTemplates: 23 | - metadata: 24 | name: mysql-data 25 | spec: 26 | accessModes: [ "ReadWriteOnce" ] 27 | resources: 28 | requests: 29 | storage: 1Gi 30 | -------------------------------------------------------------------------------- /hack/boilerplate.go.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cybozu-go/moco/cfc68f26ae7be73b993da180b1da3589eb57f7d7/hack/boilerplate.go.txt -------------------------------------------------------------------------------- /kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - config/default 3 | 4 | images: 5 | - name: ghcr.io/cybozu-go/moco 6 | newTag: 0.27.1 7 | -------------------------------------------------------------------------------- /pkg/bkop/backup.go: -------------------------------------------------------------------------------- 1 | package bkop 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net" 7 | "os" 8 | "os/exec" 9 | "strings" 10 | 11 | "github.com/cybozu-go/moco/pkg/constants" 12 | ) 13 | 14 | func (o operator) DumpFull(ctx context.Context, dir string) error { 15 | args := []string{ 16 | fmt.Sprintf("mysql://%s@%s", o.user, net.JoinHostPort(o.host, fmt.Sprint(o.port))), 17 | "-p" + o.password, 18 | "--save-passwords=never", 19 | "-C", "False", 20 | "--", 21 | "util", 22 | "dump-instance", 23 | dir, 24 | "--excludeUsers=" + strings.Join(constants.MocoUsers, ","), 25 | "--threads=" + fmt.Sprint(o.threads), 26 | } 27 | 28 | cmd := exec.CommandContext(ctx, "mysqlsh", args...) 29 | cmd.Stdout = os.Stdout 30 | cmd.Stderr = os.Stderr 31 | return cmd.Run() 32 | } 33 | 34 | func (o operator) GetBinlogs(ctx context.Context) ([]string, error) { 35 | var binlogs []showBinaryLogs 36 | if err := o.db.SelectContext(ctx, &binlogs, `SHOW BINARY LOGS`); err != nil { 37 | return nil, fmt.Errorf("failed to show binary logs: %w", err) 38 | } 39 | 40 | r := make([]string, len(binlogs)) 41 | for i, row := range binlogs { 42 | r[i] = row.LogName 43 | } 44 | return r, nil 45 | } 46 | 47 | func (o operator) DumpBinlog(ctx context.Context, dir, binlogName, filterGTID string) error { 48 | args := []string{ 49 | "-h", o.host, 50 | "--port", fmt.Sprint(o.port), 51 | "--protocol=tcp", 52 | "-u", o.user, 53 | "-p" + o.password, 54 | "--get-server-public-key", 55 | "--read-from-remote-master=BINLOG-DUMP-GTIDS", 56 | "--exclude-gtids=" + filterGTID, 57 | "-t", 58 | "--raw", 59 | "--result-file=" + dir + "/", 60 | binlogName, 61 | } 62 | 63 | cmd := exec.CommandContext(ctx, "mysqlbinlog", args...) 64 | cmd.Stdout = os.Stdout 65 | cmd.Stderr = os.Stderr 66 | return cmd.Run() 67 | } 68 | -------------------------------------------------------------------------------- /pkg/bkop/binlog.go: -------------------------------------------------------------------------------- 1 | package bkop 2 | 3 | import ( 4 | "sort" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | // SortBinlogs sort binlog filenames according to its number. 10 | // `binlogs` should contains filenames such as `binlog.000001`. 11 | func SortBinlogs(binlogs []string) { 12 | sort.Slice(binlogs, func(i, j int) bool { 13 | log1 := binlogs[i] 14 | log2 := binlogs[j] 15 | var index1, index2 int64 16 | if fields := strings.Split(log1, "."); len(fields) == 2 { 17 | index1, _ = strconv.ParseInt(fields[1], 10, 64) 18 | } 19 | if fields := strings.Split(log2, "."); len(fields) == 2 { 20 | index2, _ = strconv.ParseInt(fields[1], 10, 64) 21 | } 22 | return index1 < index2 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /pkg/bkop/binlog_test.go: -------------------------------------------------------------------------------- 1 | package bkop 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/google/go-cmp/cmp" 7 | ) 8 | 9 | func TestSortBinlogs(t *testing.T) { 10 | binlogs := []string{ 11 | "binlog.01", 12 | "binlog.101", 13 | "binlog.02", 14 | "binlog.31", 15 | } 16 | SortBinlogs(binlogs) 17 | expected := []string{ 18 | "binlog.01", 19 | "binlog.02", 20 | "binlog.31", 21 | "binlog.101", 22 | } 23 | 24 | if !cmp.Equal(binlogs, expected) { 25 | t.Error("wrong sort result", cmp.Diff(binlogs, expected)) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /pkg/bkop/gtid.go: -------------------------------------------------------------------------------- 1 | package bkop 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "os" 7 | "path/filepath" 8 | ) 9 | 10 | // GetGTIDExecuted gets executed GTID set from the dump directory. 11 | func GetGTIDExecuted(dir string) (string, error) { 12 | fname := filepath.Join(dir, "@.json") 13 | data, err := os.ReadFile(fname) 14 | if err != nil { 15 | return "", fmt.Errorf("could not read %s: %w", fname, err) 16 | } 17 | 18 | var t struct { 19 | GTIDExecuted string `json:"gtidExecuted"` 20 | } 21 | if err := json.Unmarshal(data, &t); err != nil { 22 | return "", fmt.Errorf("failed to parse contents in @.json: %w", err) 23 | } 24 | 25 | return t.GTIDExecuted, nil 26 | } 27 | -------------------------------------------------------------------------------- /pkg/bkop/status.go: -------------------------------------------------------------------------------- 1 | package bkop 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | ) 7 | 8 | func (o operator) GetServerStatus(ctx context.Context, st *ServerStatus) error { 9 | bls := &showBinaryLogStatus{} 10 | var version string 11 | if err := o.db.GetContext(ctx, &version, `SELECT SUBSTRING_INDEX(VERSION(), '.', 2)`); err != nil { 12 | return fmt.Errorf("failed to get version: %w", err) 13 | } 14 | if version == "8.4" { 15 | if err := o.db.GetContext(ctx, bls, `SHOW BINARY LOG STATUS`); err != nil { 16 | return fmt.Errorf("failed to show binary log status: %w", err) 17 | } 18 | } else if version == "8.0" { 19 | if err := o.db.GetContext(ctx, bls, `SHOW MASTER STATUS`); err != nil { 20 | return fmt.Errorf("failed to show master status: %w", err) 21 | } 22 | } else { 23 | return fmt.Errorf("unsupported version: %s", version) 24 | } 25 | if err := o.db.GetContext(ctx, st, `SELECT @@super_read_only, @@server_uuid`); err != nil { 26 | return fmt.Errorf("failed to get global variables: %w", err) 27 | } 28 | 29 | st.CurrentBinlog = bls.File 30 | return nil 31 | } 32 | -------------------------------------------------------------------------------- /pkg/bkop/suite_test.go: -------------------------------------------------------------------------------- 1 | package bkop 2 | 3 | import ( 4 | "log" 5 | "os" 6 | "testing" 7 | 8 | "github.com/cybozu-go/moco/pkg/dbop" 9 | "github.com/go-logr/stdr" 10 | . "github.com/onsi/ginkgo/v2" 11 | . "github.com/onsi/gomega" 12 | ) 13 | 14 | func TestBKOp(t *testing.T) { 15 | if os.Getenv("TEST_MYSQL") != "1" { 16 | t.Skip("skip") 17 | } 18 | RegisterFailHandler(Fail) 19 | RunSpecs(t, "BKOp Suite") 20 | } 21 | 22 | var _ = BeforeSuite(func() { 23 | dbop.SetLogger(stdr.New(log.New(os.Stderr, "", log.LstdFlags))) 24 | }) 25 | -------------------------------------------------------------------------------- /pkg/bkop/types.go: -------------------------------------------------------------------------------- 1 | package bkop 2 | 3 | // ServerStatus defines a struct to retrieve the backup source server status. 4 | // These information will be used in the next backup to retrieve binary logs 5 | // since the last backup. 6 | type ServerStatus struct { 7 | SuperReadOnly bool `db:"@@super_read_only"` 8 | UUID string `db:"@@server_uuid"` 9 | CurrentBinlog string 10 | } 11 | 12 | type showBinaryLogStatus struct { 13 | File string `db:"File"` 14 | Position int64 `db:"Position"` 15 | BinlogDoDB string `db:"Binlog_Do_DB"` 16 | BinlogIgnoreDB string `db:"Binlog_Ignore_DB"` 17 | ExecutedGTIDSet string `db:"Executed_Gtid_Set"` 18 | } 19 | 20 | type showBinaryLogs struct { 21 | LogName string `db:"Log_name"` 22 | FileSize int64 `db:"File_size"` 23 | Encrypted string `db:"Encrypted"` 24 | } 25 | -------------------------------------------------------------------------------- /pkg/bucket/gcs.go: -------------------------------------------------------------------------------- 1 | package bucket 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "io" 7 | 8 | "cloud.google.com/go/storage" 9 | "google.golang.org/api/iterator" 10 | "google.golang.org/api/option" 11 | ) 12 | 13 | type gcsBucket struct { 14 | name string 15 | client *storage.Client 16 | } 17 | 18 | func NewGCSBucket(ctx context.Context, name string, opts ...option.ClientOption) (Bucket, error) { 19 | client, err := storage.NewClient(ctx, opts...) 20 | if err != nil { 21 | return nil, err 22 | } 23 | 24 | b := &gcsBucket{ 25 | name: name, 26 | client: client, 27 | } 28 | 29 | return b, nil 30 | } 31 | 32 | func (b *gcsBucket) Put(ctx context.Context, key string, data io.Reader, objectSize int64) error { 33 | bucket := b.client.Bucket(b.name) 34 | 35 | w := bucket.Object(key).NewWriter(ctx) 36 | 37 | // Chunk size is set to 16 MiB by default. 38 | // There is a trade-off between upload speed and memory space for the chunk size. 39 | // The default value is respected here. 40 | // https://cloud.google.com/storage/docs/resumable-uploads#go 41 | // w.ChunkSize = int(decidePartSize(objectSize)) 42 | 43 | if _, err := io.Copy(w, data); err != nil { 44 | return err 45 | } 46 | if err := w.Close(); err != nil { 47 | return err 48 | } 49 | return nil 50 | } 51 | 52 | func (b *gcsBucket) Get(ctx context.Context, key string) (io.ReadCloser, error) { 53 | rc, err := b.client.Bucket(b.name).Object(key).NewReader(ctx) 54 | if err != nil { 55 | return nil, err 56 | } 57 | return rc, nil 58 | } 59 | 60 | func (b *gcsBucket) List(ctx context.Context, prefix string) ([]string, error) { 61 | var keys []string 62 | it := b.client.Bucket(b.name).Objects(ctx, &storage.Query{Prefix: prefix}) 63 | for { 64 | obj, err := it.Next() 65 | if errors.Is(err, iterator.Done) { 66 | break 67 | } 68 | if err != nil { 69 | return nil, err 70 | } 71 | keys = append(keys, obj.Name) 72 | } 73 | return keys, nil 74 | } 75 | -------------------------------------------------------------------------------- /pkg/bucket/interface.go: -------------------------------------------------------------------------------- 1 | package bucket 2 | 3 | import ( 4 | "context" 5 | "io" 6 | ) 7 | 8 | // Bucket represents the interface to access an object storage bucket. 9 | type Bucket interface { 10 | // Put puts an object with `key`. The data is read from `data`. 11 | Put(ctx context.Context, key string, data io.Reader, objectSize int64) error 12 | 13 | // Get gets an object by `key`. 14 | Get(ctx context.Context, key string) (io.ReadCloser, error) 15 | 16 | // List lists the matching object keys that have `prefix`. 17 | // The prefix argument should end with /. (e.g. "foo/bar/"). 18 | // If / is not at the end, both ojbects xx-1/bar and xx-11/bar are taken. 19 | List(ctx context.Context, prefix string) ([]string, error) 20 | } 21 | -------------------------------------------------------------------------------- /pkg/bucket/suite_test.go: -------------------------------------------------------------------------------- 1 | package bucket 2 | 3 | import ( 4 | "testing" 5 | 6 | . "github.com/onsi/ginkgo/v2" 7 | . "github.com/onsi/gomega" 8 | ) 9 | 10 | func TestBucket(t *testing.T) { 11 | RegisterFailHandler(Fail) 12 | RunSpecs(t, "Bucket Suite") 13 | } 14 | -------------------------------------------------------------------------------- /pkg/constants/backup.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | // moco-backup related constants 4 | const ( 5 | BackupSubcommand = "backup" 6 | RestoreSubcommand = "restore" 7 | 8 | BackupTimeFormat = "20060102-150405" 9 | DumpFilename = "dump.tar" 10 | BinlogFilename = "binlog.tar.zst" 11 | ) 12 | 13 | const ( 14 | BackendTypeS3 = "s3" 15 | BackendTypeGCS = "gcs" 16 | ) 17 | -------------------------------------------------------------------------------- /pkg/constants/container.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | // container names 4 | const ( 5 | AgentContainerName = "agent" 6 | InitContainerName = "moco-init" 7 | CopyInitContainerName = "copy-moco-init" 8 | MysqldContainerName = "mysqld" 9 | SlowQueryLogAgentContainerName = "slow-log" 10 | ExporterContainerName = "mysqld-exporter" 11 | ) 12 | 13 | // container resources 14 | const ( 15 | AgentContainerCPURequest = "100m" 16 | AgentContainerCPULimit = "100m" 17 | AgentContainerMemRequest = "100Mi" 18 | AgentContainerMemLimit = "100Mi" 19 | 20 | InitContainerCPURequest = "100m" 21 | InitContainerCPULimit = "100m" 22 | InitContainerMemRequest = "300Mi" 23 | InitContainerMemLimit = "300Mi" 24 | 25 | SlowQueryLogAgentCPURequest = "100m" 26 | SlowQueryLogAgentCPULimit = "100m" 27 | SlowQueryLogAgentMemRequest = "20Mi" 28 | SlowQueryLogAgentMemLimit = "20Mi" 29 | 30 | ExporterContainerCPURequest = "200m" 31 | ExporterContainerCPULimit = "200m" 32 | ExporterContainerMemRequest = "100Mi" 33 | ExporterContainerMemLimit = "100Mi" 34 | ) 35 | 36 | // volume names 37 | const ( 38 | MySQLDataVolumeName = "mysql-data" 39 | MySQLConfVolumeName = "mysql-conf" 40 | MySQLInitConfVolumeName = "mysql-conf-d" 41 | MySQLConfSecretVolumeName = "my-cnf-secret" 42 | GRPCSecretVolumeName = "grpc-cert" 43 | RunVolumeName = "run" 44 | VarLogVolumeName = "var-log" 45 | TmpVolumeName = "tmp" 46 | SlowQueryLogAgentConfigVolumeName = "slow-fluent-bit-config" 47 | SharedVolumeName = "shared" 48 | ) 49 | 50 | // UID/GID 51 | const ( 52 | ContainerUID = 10000 53 | ContainerGID = 10000 54 | ) 55 | 56 | // command names 57 | const ( 58 | InitCommand = "moco-init" 59 | ) 60 | 61 | // PreStop sleep duration 62 | const PreStopSeconds = "20" 63 | -------------------------------------------------------------------------------- /pkg/constants/meta.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | // label keys and values 4 | const ( 5 | LabelAppInstance = "app.kubernetes.io/instance" 6 | LabelAppNamespace = "app.kubernetes.io/instance-namespace" 7 | LabelAppName = "app.kubernetes.io/name" 8 | AppNameMySQL = "mysql" 9 | AppNameBackup = "mysql-backup" 10 | LabelAppCreatedBy = "app.kubernetes.io/created-by" 11 | AppCreator = "moco" 12 | 13 | LabelMocoRole = "moco.cybozu.com/role" 14 | RolePrimary = "primary" 15 | RoleReplica = "replica" 16 | ) 17 | 18 | // annotation keys and values 19 | const ( 20 | AnnDemote = "moco.cybozu.com/demote" 21 | AnnSecretVersion = "moco.cybozu.com/secret-version" 22 | AnnClusteringStopped = "moco.cybozu.com/clustering-stopped" 23 | AnnReconciliationStopped = "moco.cybozu.com/reconciliation-stopped" 24 | AnnForceRollingUpdate = "moco.cybozu.com/force-rolling-update" 25 | AnnPreventDelete = "moco.cybozu.com/prevent-delete" 26 | ) 27 | 28 | // MySQLClusterFinalizer is the finalizer specifier for MySQLCluster. 29 | const MySQLClusterFinalizer = "moco.cybozu.com/mysqlcluster" 30 | -------------------------------------------------------------------------------- /pkg/constants/ports.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | const ( 4 | // MySQLPort is the port number for MySQL 5 | MySQLPort = 3306 6 | MySQLPortName = "mysql" 7 | 8 | // MySQLXPort is the port number for MySQL XProtocol 9 | MySQLXPort = 33060 10 | MySQLXPortName = "mysqlx" 11 | 12 | // MySQLAdminPort is the port number for MySQL Admin 13 | MySQLAdminPort = 33062 14 | MySQLAdminPortName = "mysql-admin" 15 | 16 | // MySQLHealthPort is the port number to check readiness and liveness of mysqld. 17 | MySQLHealthPort = 9081 18 | MySQLHealthPortName = "health" 19 | 20 | // AgentPort is the port number for agent container 21 | AgentPort = 9080 22 | AgentPortName = "agent" 23 | 24 | // AgentMetricsPort is the port number for agent container 25 | AgentMetricsPort = 8080 26 | AgentMetricsPortName = "agent-metrics" 27 | 28 | // ExporterPort is the port number for mysqld_exporter 29 | ExporterPort = 9104 30 | ExporterPortName = "mysqld-metrics" 31 | ) 32 | -------------------------------------------------------------------------------- /pkg/constants/users.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | // MySQL user names for MOCO 4 | const ( 5 | AdminUser = "moco-admin" 6 | AgentUser = "moco-agent" 7 | ReplicationUser = "moco-repl" 8 | CloneDonorUser = "moco-clone-donor" 9 | ExporterUser = "moco-exporter" 10 | BackupUser = "moco-backup" 11 | ReadOnlyUser = "moco-readonly" 12 | WritableUser = "moco-writable" 13 | ) 14 | 15 | // MocoSystemUsers is a map to hold system users. 16 | // This does not include moco-readonly and moco-writable as they are for end users. 17 | var MocoSystemUsers = map[string]bool{ 18 | AdminUser: true, 19 | AgentUser: true, 20 | ReplicationUser: true, 21 | CloneDonorUser: true, 22 | ExporterUser: true, 23 | BackupUser: true, 24 | } 25 | 26 | // MocoUsers is a list of all users created for MOCO. 27 | var MocoUsers = []string{ 28 | AdminUser, 29 | AgentUser, 30 | ReplicationUser, 31 | CloneDonorUser, 32 | ExporterUser, 33 | BackupUser, 34 | ReadOnlyUser, 35 | WritableUser, 36 | } 37 | 38 | // my.cnf filenames for different kind of users. 39 | const ( 40 | AdminMyCnf = AdminUser + "-my.cnf" 41 | ExporterMyCnf = ExporterUser + "-my.cnf" 42 | BackupMyCnf = BackupUser + "-my.cnf" 43 | ReadOnlyMyCnf = ReadOnlyUser + "-my.cnf" 44 | WritableMyCnf = WritableUser + "-my.cnf" 45 | ) 46 | -------------------------------------------------------------------------------- /pkg/dbop/driver.go: -------------------------------------------------------------------------------- 1 | package dbop 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/go-logr/logr" 7 | "github.com/go-sql-driver/mysql" 8 | ) 9 | 10 | type logger struct { 11 | log logr.Logger 12 | } 13 | 14 | var _ mysql.Logger = logger{} 15 | 16 | func (l logger) Print(v ...interface{}) { 17 | l.log.Info(fmt.Sprint(v...)) 18 | } 19 | 20 | // SetLogger configures MySQL driver logging to use `log`. 21 | func SetLogger(log logr.Logger) { 22 | mysql.SetLogger(logger{log: log}) 23 | } 24 | 25 | func init() { 26 | SetLogger(logr.Discard()) 27 | } 28 | -------------------------------------------------------------------------------- /pkg/dbop/errors.go: -------------------------------------------------------------------------------- 1 | package dbop 2 | 3 | import "errors" 4 | 5 | // Sentinel errors. To test these errors, use `errors.Is`. 6 | var ( 7 | ErrErrantTransactions = errors.New("detected errant transactions") 8 | ErrNoTopRunner = errors.New("unable to determine the top runner") 9 | ErrTimeout = errors.New("timeout") 10 | ) 11 | -------------------------------------------------------------------------------- /pkg/dbop/kill.go: -------------------------------------------------------------------------------- 1 | package dbop 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | 8 | "github.com/cybozu-go/moco/pkg/constants" 9 | "github.com/go-sql-driver/mysql" 10 | ) 11 | 12 | func (o *operator) KillConnections(ctx context.Context) error { 13 | var procs []Process 14 | 15 | if err := o.db.SelectContext(ctx, &procs, `SELECT ID, USER, HOST FROM information_schema.PROCESSLIST`); err != nil { 16 | return fmt.Errorf("failed to get process list: %w", err) 17 | } 18 | 19 | for _, p := range procs { 20 | if constants.MocoSystemUsers[p.User] { 21 | continue 22 | } 23 | if p.Host == "localhost" { 24 | continue 25 | } 26 | if p.User == "system user" { 27 | continue 28 | } 29 | 30 | if _, err := o.db.ExecContext(ctx, `KILL CONNECTION ?`, p.ID); err != nil && !isNoSuchThread(err) { 31 | return fmt.Errorf("failed to kill connection %d for %s from %s: %w", p.ID, p.User, p.Host, err) 32 | } 33 | } 34 | return nil 35 | } 36 | 37 | func isNoSuchThread(err error) bool { 38 | var merr *mysql.MySQLError 39 | // Error number 1094 is ER_NO_SUCH_THREAD. 40 | if errors.As(err, &merr) && merr.Number == 1094 { 41 | return true 42 | } 43 | return false 44 | } 45 | -------------------------------------------------------------------------------- /pkg/dbop/nop.go: -------------------------------------------------------------------------------- 1 | package dbop 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | ) 7 | 8 | // ErrNop is a sentinel error for NopOperator 9 | var ErrNop = errors.New("nop") 10 | 11 | // NopOperator is an implementation of Operator that always returns ErrNop. 12 | type NopOperator struct { 13 | name string 14 | } 15 | 16 | var _ Operator = NopOperator{} 17 | 18 | func (o NopOperator) Name() string { 19 | return o.name 20 | } 21 | 22 | func (o NopOperator) Close() error { 23 | return nil 24 | } 25 | 26 | func (o NopOperator) GetStatus(context.Context) (*MySQLInstanceStatus, error) { 27 | return nil, ErrNop 28 | } 29 | 30 | func (o NopOperator) SubtractGTID(ctx context.Context, set1, set2 string) (string, error) { 31 | return "", ErrNop 32 | } 33 | 34 | func (o NopOperator) IsSubsetGTID(ctx context.Context, set1, set2 string) (bool, error) { 35 | return false, ErrNop 36 | } 37 | 38 | func (o NopOperator) ConfigureReplica(ctx context.Context, source AccessInfo, semisync bool) error { 39 | return ErrNop 40 | } 41 | 42 | func (o NopOperator) ConfigurePrimary(ctx context.Context, waitForCount int) error { 43 | return ErrNop 44 | } 45 | 46 | func (o NopOperator) StopReplicaIOThread(context.Context) error { 47 | return ErrNop 48 | } 49 | 50 | func (o NopOperator) WaitForGTID(ctx context.Context, gtidSet string, timeoutSeconds int) error { 51 | return ErrNop 52 | } 53 | 54 | func (o NopOperator) SetReadOnly(context.Context, bool) error { 55 | return ErrNop 56 | } 57 | 58 | func (o NopOperator) KillConnections(context.Context) error { 59 | return ErrNop 60 | } 61 | -------------------------------------------------------------------------------- /pkg/dbop/suite_test.go: -------------------------------------------------------------------------------- 1 | package dbop 2 | 3 | import ( 4 | "log" 5 | "os" 6 | "testing" 7 | 8 | "github.com/go-logr/stdr" 9 | . "github.com/onsi/ginkgo/v2" 10 | . "github.com/onsi/gomega" 11 | ) 12 | 13 | func TestDBOp(t *testing.T) { 14 | if os.Getenv("TEST_MYSQL") != "1" { 15 | t.Skip("skip") 16 | } 17 | RegisterFailHandler(Fail) 18 | RunSpecs(t, "DBOp Suite") 19 | } 20 | 21 | var factory = NewTestFactory() 22 | 23 | var _ = BeforeSuite(func() { 24 | SetLogger(stdr.New(log.New(os.Stderr, "", log.LstdFlags))) 25 | }) 26 | 27 | var _ = AfterSuite(func() { 28 | factory.Cleanup() 29 | }) 30 | -------------------------------------------------------------------------------- /version.go: -------------------------------------------------------------------------------- 1 | package moco 2 | 3 | const ( 4 | // Version is the MOCO version 5 | Version = "0.27.1" 6 | 7 | // FluentBitImage is the image for slow-log sidecar container. 8 | FluentBitImage = "ghcr.io/cybozu-go/moco/fluent-bit:3.1.7.1" 9 | 10 | // ExporterImage is the image for mysqld_exporter sidecar container. 11 | ExporterImage = "ghcr.io/cybozu-go/moco/mysqld_exporter:0.16.0.1" 12 | ) 13 | --------------------------------------------------------------------------------