From 11f4fa6312723a2500f94ccd281e33bf6db81771 Mon Sep 17 00:00:00 2001 From: Terence Lim Date: Tue, 25 Apr 2023 17:55:10 +0800 Subject: [PATCH] Deprecate XP helm charts (#72) * Deprecate XP helm charts * Add helm installation instructions to README --- .github/workflows/helm-chart.yml | 35 ---- .pre-commit-config.yaml | 15 -- CONTRIBUTING.md | 2 +- README.md | 4 + docs/infra/treatment-service.md | 85 ++------- infra/charts/management-service/Chart.yaml | 5 - infra/charts/management-service/README.md | 104 ---------- .../management-service/README.md.gotmpl | 57 ------ .../charts/postgresql-10.16.2.tgz | Bin 53913 -> 0 bytes .../management-service/requirements.lock | 6 - .../management-service/requirements.yaml | 6 - .../management-service/templates/_helpers.tpl | 96 ---------- .../templates/deployment.yaml | 130 ------------- .../management-service/templates/ingress.yaml | 33 ---- .../management-service/templates/secrets.yaml | 12 -- .../templates/service-swagger.yaml | 23 --- .../templates/service-xp.yaml | 23 --- .../templates/serviceaccount.yaml | 12 -- infra/charts/management-service/values.yaml | 177 ------------------ infra/charts/treatment-service/Chart.yaml | 5 - infra/charts/treatment-service/README.md | 97 ---------- .../charts/treatment-service/README.md.gotmpl | 57 ------ .../treatment-service/templates/_helpers.tpl | 54 ------ .../templates/deployment.yaml | 136 -------------- .../treatment-service/templates/hpa.yaml | 32 ---- .../treatment-service/templates/ingress.yaml | 33 ---- .../treatment-service/templates/secrets.yaml | 8 - .../templates/service-swagger.yaml | 25 --- .../templates/service-xp.yaml | 23 --- infra/charts/treatment-service/values.yaml | 98 ---------- 30 files changed, 18 insertions(+), 1375 deletions(-) delete mode 100644 .github/workflows/helm-chart.yml delete mode 100644 infra/charts/management-service/Chart.yaml delete mode 100644 infra/charts/management-service/README.md delete mode 100644 infra/charts/management-service/README.md.gotmpl delete mode 100644 infra/charts/management-service/charts/postgresql-10.16.2.tgz delete mode 100644 infra/charts/management-service/requirements.lock delete mode 100644 infra/charts/management-service/requirements.yaml delete mode 100644 infra/charts/management-service/templates/_helpers.tpl delete mode 100644 infra/charts/management-service/templates/deployment.yaml delete mode 100644 infra/charts/management-service/templates/ingress.yaml delete mode 100644 infra/charts/management-service/templates/secrets.yaml delete mode 100644 infra/charts/management-service/templates/service-swagger.yaml delete mode 100644 infra/charts/management-service/templates/service-xp.yaml delete mode 100644 infra/charts/management-service/templates/serviceaccount.yaml delete mode 100644 infra/charts/management-service/values.yaml delete mode 100644 infra/charts/treatment-service/Chart.yaml delete mode 100644 infra/charts/treatment-service/README.md delete mode 100644 infra/charts/treatment-service/README.md.gotmpl delete mode 100644 infra/charts/treatment-service/templates/_helpers.tpl delete mode 100644 infra/charts/treatment-service/templates/deployment.yaml delete mode 100644 infra/charts/treatment-service/templates/hpa.yaml delete mode 100644 infra/charts/treatment-service/templates/ingress.yaml delete mode 100644 infra/charts/treatment-service/templates/secrets.yaml delete mode 100644 infra/charts/treatment-service/templates/service-swagger.yaml delete mode 100644 infra/charts/treatment-service/templates/service-xp.yaml delete mode 100644 infra/charts/treatment-service/values.yaml diff --git a/.github/workflows/helm-chart.yml b/.github/workflows/helm-chart.yml deleted file mode 100644 index 1855e9cd..00000000 --- a/.github/workflows/helm-chart.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: helm-chart - -on: - push: - paths: - - ".github/workflows/helm-chart.yml" - - "infra/charts/**" - branches: - - main - workflow_dispatch: - inputs: - owner: - description: The GitHub user or org that owns this repository - type: string - required: true - repository: - description: The GitHub repository - type: string - required: true - default: "charts" - -jobs: - release: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Run chart-releaser - uses: stefanprodan/helm-gh-pages@v1.4.1 - with: - token: "${{ secrets.GH_PAGES_TOKEN }}" - charts_dir: infra/charts - owner: "${{ github.event.inputs.owner || 'turing-ml' }}" - repository: "${{ github.event.inputs.repository || 'charts' }}" - commit_username: ${{ github.actor }} - commit_email: "${{ github.actor }}@users.noreply.github.com" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 526f20cf..d617df81 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,19 +1,4 @@ repos: - - repo: https://github.com/norwoodj/helm-docs - rev: v1.11.0 - hooks: - - id: helm-docs-built - name: 'Helm Docs for XP Management Service Chart' - files: '^infra/charts/management-service/' - args: - - --chart-search-root=infra/charts/management-service - - --template-files=./README.md.gotmpl - - id: helm-docs-built - name: 'Helm Docs for XP Treatment Service Chart' - files: '^infra/charts/treatment-service/' - args: - - --chart-search-root=infra/charts/treatment-service - - --template-files=./README.md.gotmpl - repo: local hooks: - id: format diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cab47e8e..0517b018 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -63,7 +63,7 @@ Setup [`pre-commit`](https://pre-commit.com/) to automatically lint and format t make setup ``` -3. On push, the pre-commit hook will run. This runs `make format`, `make lint`, `UI linting` and `generation of helm docs`. +3. On push, the pre-commit hook will run. This runs `make format`, `make lint` and `UI linting`. ## XP Management/Treatment Service using Go diff --git a/README.md b/README.md index 462e5377..194c54d9 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,10 @@ To test authorization for Management Service locally, make the following changes To use the XP Go modules as API dependencies, simply import the XP Go modules directly i.e. `import "github.com/caraml-dev/xp/..."` +#### d. XP Helm installation + +For running a helm installation of XP, you may refer to the [xp-management](https://github.com/caraml-dev/helm-charts/tree/main/charts/xp-management) and [xp-treatment](https://github.com/caraml-dev/helm-charts/tree/main/charts/xp-treatment) charts. + ## Contributing XP is still under active development. Please have a look at our contributing and development guides if you want to contribute to the project: diff --git a/docs/infra/treatment-service.md b/docs/infra/treatment-service.md index 3c5c2a1a..60115dd3 100644 --- a/docs/infra/treatment-service.md +++ b/docs/infra/treatment-service.md @@ -63,49 +63,7 @@ In short, the service account configured would minimally need these roles/permis #### As a Helm Release -*Some of these steps have been adapted from https://github.com/caraml-dev/xp/tree/main/infra/charts/treatment-service* - -##### 1. Add the Helm Repository - -```shell -$ helm repo add xp https://turing-ml.github.io/charts -``` - -##### 2. Install the Helm Chart - -This command will install XP Treatment Service release named `xp-treatment` in the `default` namespace. -Default chart values will be used for the installation: -```shell -$ helm install xp-treatment xp/xp-treatment -``` - -You can (and most likely, should) override the default configuration with Helm chart values suitable for your -installation. Refer to [Configuration](https://github.com/caraml-dev/xp/tree/main/infra/charts/treatment-service#configuration) section for the detailed description of available configuration keys. - -You can also refer to [values.yaml](https://github.com/caraml-dev/xp/tree/main/infra/charts/treatment-service/values.yaml) -for a minimal configuration that needs to be provided for XP Treatment Service installation. - -```shell -$ helm install xp-treatment xp/xp-treatment \ - --values=path/to/helm/chart/values/file.yaml -``` - -Notice that you can specify the *Treatment Service configuration* [values](#configuration) under the `xpTreatment` -field in the Helm chart values file like below: - -```yaml -xpTreatment: - config: - Port: 8080 - ManagementService: - URL: https://caraml-dev.io/api/xp/v1 - AuthorizationEnabled: true - # ... -``` - -These configuration values would be saved in a `.yaml` file within a -[secret](https://kubernetes.io/docs/concepts/configuration/secret/) that gets mounted automatically onto the -Treatment Service pod, where it will be read by the Treatment Service. +*Follow the installation steps from https://github.com/caraml-dev/helm-charts/tree/main/charts/xp-treatment* ##### 2.1 Configure the Standalone Treatment Service to use a Google Cloud Provider (GCP) Service Account (Optional) @@ -182,36 +140,26 @@ is configured as a plugin for. #### Configuration -Unlike for the standalone Treatment Service whereby the configuration values are placed in a file solely dedicated -for Treatment Service configurations, the Treatment Service Plugin configuration values need to be placed under -the experiment engines section, within the -[Helm chart values](https://github.com/caraml-dev/turing/blob/477ac2392c590d3dd6453a5834657dc773fe0e56/infra/charts/turing/values.yaml#L104) +Unlike for the standalone Treatment Service whereby the configuration values are placed in a file solely dedicated for Treatment Service configurations, the Treatment Service Plugin configuration values need to be placed under the experiment engines section, within the +[Helm chart values](https://github.com/caraml-dev/helm-charts/blob/ce4026287443c9d5f2c3fb69d2dd33f3d90f89e3/charts/turing/values.yaml#L118) of a Turing API server deployment. -Note that not all the configuration values used in a standalone Treatment Service need to be specified for the -Treatment Service Plugin, since some of those values will be retrieved directly via the Management Service (e.g. Pub/Sub -configuration or segmenter configuration). See [below](#1-prepare-the-turing-api-server-helm-chart-values-file) for +Note that not all the configuration values used in a standalone Treatment Service need to be specified for the Treatment Service Plugin, since some of those values will be retrieved directly via the Management Service (e.g. Pub/Sub configuration or segmenter configuration). See [below](#1-prepare-the-turing-api-server-helm-chart-values-file) for an example of the configuration values that need to be specified. -When the Turing API server deploys a router, the plugin manager will automatically retrieve the aforementioned -configurations from the Management Service, as well as the experiment engine configuration -(shown in the code block above) from the Turing API server. +When the Turing API server deploys a router, the plugin manager will automatically retrieve the aforementioned configurations from the Management Service, as well as the experiment engine configuration (shown in the code block above) from the Turing API server. -The plugin manager then creates a new plugin configuration object that will subsequently be passed to the API and then -to the Treatment Service plugin runner, which will be configured with those values passed to it. +The plugin manager then creates a new plugin configuration object that will subsequently be passed to the API and then to the Treatment Service plugin runner, which will be configured with those values passed to it. ![treatment_service_plugin_configuration.png](treatment_service_plugin_configuration.png) #### Google Cloud Provider (GCP) Service Account -Just as in the standalone Treatment Service, a GCP Service Account with the following roles is needed for the -Treatment Service Plugin to communicate with the Management Service via a +Just as in the standalone Treatment Service, a GCP Service Account with the following roles is needed for the Treatment Service Plugin to communicate with the Management Service via a [Google Cloud Pub/Sub](https://cloud.google.com/pubsub/docs/overview) subscription and for logging treatment responses to a table in [Google BigQuery](https://cloud.google.com/bigquery): -- [roles/pubsub.subscriber](https://cloud.google.com/pubsub/docs/access-control#roles), minimally, for the topic - that the Management Service will publish updates to -- [roles/bigquery.dataEditor](https://cloud.google.com/bigquery/docs/access-control#bigquery.dataEditor), minimally, - for the table that will contain the logs (if logging to BigQuery is configured) +- [roles/pubsub.subscriber](https://cloud.google.com/pubsub/docs/access-control#roles), minimally, for the topic that the Management Service will publish updates to +- [roles/bigquery.dataEditor](https://cloud.google.com/bigquery/docs/access-control#bigquery.dataEditor), minimally, for the table that will contain the logs (if logging to BigQuery is configured) ### Deploying the Treatment Service Plugin @@ -261,14 +209,13 @@ turing: As mentioned [earlier](#configuration), the Treatment Service Plugin configuration values must also be provided. Place those values within the `turing.experimentEngines.*.options.treatment_service_config` field of the Turing API's -[Helm chart values file](https://github.com/caraml-dev/turing/blob/477ac2392c590d3dd6453a5834657dc773fe0e56/infra/charts/turing/values.yaml#L104). +[Helm chart values file](https://github.com/caraml-dev/helm-charts/blob/ce4026287443c9d5f2c3fb69d2dd33f3d90f89e3/charts/turing/values.yaml#L118). #### 1.1 Configure the Treatment Service Plugin to use a Google Cloud Provider (GCP) Service Account (Optional) The service account token file has to be made accessible to the Turing API server such that it is available for it to be mounted within a Turing Router. The Turing API server looks for this service account token file via the filepath stored in the `turing.expermentEngines.*.serviceAccountKeyFilePath` field of the Turing API -server -[Helm chart values file](https://github.com/caraml-dev/turing/blob/477ac2392c590d3dd6453a5834657dc773fe0e56/infra/charts/turing/values.yaml#L104): +server [Helm chart values file](https://github.com/caraml-dev/helm-charts/blob/ce4026287443c9d5f2c3fb69d2dd33f3d90f89e3/charts/turing/values.yaml#L118): ```yaml turing: @@ -284,11 +231,7 @@ How this service account token file has to be made accessible to the Turing API deploying the Turing API server and is out of scope of this guide. However, one recommended way to do so is to use the -[Helm chart installation of Turing](https://github.com/caraml-dev/turing/tree/477ac2392c590d3dd6453a5834657dc773fe0e56/infra/charts/turing), -which allows the service account token file (assumed to already exist within the same cluster as the Turing API -server deployment as a [secret](https://kubernetes.io/docs/concepts/configuration/secret/)) to be mounted as a volume into the -Turing API server container, through the use of `extraVolumes` and `extraVolumeMounts` in the Turing API's -[Helm chart values file](https://github.com/caraml-dev/turing/blob/477ac2392c590d3dd6453a5834657dc773fe0e56/infra/charts/turing/values.yaml#L104): +[Helm chart installation of Turing](https://github.com/caraml-dev/helm-charts/blob/ce4026287443c9d5f2c3fb69d2dd33f3d90f89e3/charts/turing), which allows the service account token file (assumed to already exist within the same cluster as the Turing API server deployment as a [secret](https://kubernetes.io/docs/concepts/configuration/secret/)) to be mounted as a volume into the Turing API server container, through the use of `extraVolumes` and `extraVolumeMounts` in the Turing API's [Helm chart values file](https://github.com/caraml-dev/helm-charts/blob/ce4026287443c9d5f2c3fb69d2dd33f3d90f89e3/charts/turing/values.yaml#L118): ```yaml turing: @@ -316,9 +259,7 @@ to access the mounted service account token. Last but not least, specify the `turing.experimentEngines.*.options.treatment_service_config.deployment_config.google_application_credentials_env_var` -field as follows to allow the Treatment Service Plugin to retrieve the filepath of the GCP service account secret -token from the Turing Router container correctly (the Turing API automatically injects the filepath of the mounted -service account token as the `GOOGLE_APPLICATION_CREDENTIALS_EXPERIMENT_ENGINE` env var within the Turing Router): +field as follows to allow the Treatment Service Plugin to retrieve the filepath of the GCP service account secret token from the Turing Router container correctly (the Turing API automatically injects the filepath of the mounted service account token as the `GOOGLE_APPLICATION_CREDENTIALS_EXPERIMENT_ENGINE` env var within the Turing Router): ```yaml turing: diff --git a/infra/charts/management-service/Chart.yaml b/infra/charts/management-service/Chart.yaml deleted file mode 100644 index b674d186..00000000 --- a/infra/charts/management-service/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: v0.9.0 -description: A Helm chart for Kubernetes Deployment of the XP Management Service -name: xp-management -version: 0.1.2 diff --git a/infra/charts/management-service/README.md b/infra/charts/management-service/README.md deleted file mode 100644 index 5767e01c..00000000 --- a/infra/charts/management-service/README.md +++ /dev/null @@ -1,104 +0,0 @@ -# xp-management - ---- -![Version: 0.1.2](https://img.shields.io/badge/Version-0.1.2-informational?style=flat-square) -![AppVersion: v0.9.0](https://img.shields.io/badge/AppVersion-v0.9.0-informational?style=flat-square) - -A Helm chart for Kubernetes Deployment of the XP Management Service - -## Introduction - -This Helm chart installs [Management Service](https://github.com/caraml-dev/xp/management-service) and all its dependencies in a Kubernetes cluster. - -## Prerequisites - -To use the charts here, [Helm](https://helm.sh/) must be configured for your -Kubernetes cluster. Setting up Kubernetes and Helm is outside the scope of -this README. Please refer to the Kubernetes and Helm documentation. - -- **Helm 3.0+** – This chart was tested with Helm v3.7.1, but it is also expected to work with earlier Helm versions -- **Kubernetes 1.18+** – This chart was tested with GKE v1.20.x, but it's possible it works with earlier k8s versions too. - -## Installation - -### Add Helm repository - -```sh -$ helm repo add xp https://turing-ml.github.io/charts -``` - -### Installing the chart - -This command will install XP Management Service release named `management-service` in the `default` namespace. -Default chart values will be used for the installation: -```shell -$ helm install xp xp/management-service -``` - -You can (and most likely, should) override the default configuration with values suitable for your installation. -Refer to [Configuration](#configuration) section for the detailed description of available configuration keys. - -You can also refer to [values.minimal.yaml](./values.minimal.yaml) to check a minimal configuration that needs -to be provided for XP Management Service installation. - -### Uninstalling the chart - -To uninstall `management-service` release: -```shell -$ helm uninstall management-service -``` - -The command removes all the Kubernetes components associated with the chart and deletes the release, -except for postgresql PVC, those will have to be removed manually. - -## Configuration - -The following table lists the configurable parameters of the XP Management Service chart and their default values. - -| Key | Type | Default | Description | -|-----|------|---------|-------------| -| global.mlp.encryption.key | string | `nil` | Global MLP Encryption Key to be used by all MLP components | -| global.sentry.dsn | string | `nil` | Global Sentry DSN value | -| postgresql | object | `{"containerPorts":{"postgresql":5432},"metrics":{"enabled":false,"replication":{"applicationName":"xp","enabled":false,"numSynchronousReplicas":2,"password":"repl_password","slaveReplicas":2,"synchronousCommit":"on","user":"repl_user"},"serviceMonitor":{"enabled":false}},"persistence":{"enabled":true,"size":"10Gi"},"postgresqlDatabase":"xp","postgresqlPassword":"xp","postgresqlUsername":"xp","resources":{"requests":{"cpu":"500m","memory":"256Mi"}},"tls":{"enabled":false}}` | Postgresql configuration to be applied to XP Management Service's postgresql database deployment Reference: https://artifacthub.io/packages/helm/bitnami/postgresql/10.16.2#parameters | -| postgresql.persistence.enabled | bool | `true` | Persist Postgresql data in a Persistent Volume Claim | -| postgresql.postgresqlPassword | string | `"xp"` | Password for XP Management Service Postgresql database | -| postgresql.resources | object | `{"requests":{"cpu":"500m","memory":"256Mi"}}` | Resources requests and limits for XP Management Service database. This should be set according to your cluster capacity and service level objectives. Reference: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ | -| swaggerUi.apiServer | string | `"http://127.0.0.1/v1"` | URL of API server | -| swaggerUi.image | object | `{"tag":"v3.47.1"}` | Docker tag for Swagger UI https://hub.docker.com/r/swaggerapi/swagger-ui | -| swaggerUi.service.externalPort | int | `8080` | Swagger UI Kubernetes service port number | -| swaggerUi.service.internalPort | int | `8081` | Swagger UI container port number | -| tags.db | bool | `true` | Specifies if Postgresql database needs to be installed together with XP Management Service | -| xpManagement.apiConfig | object | `{}` | XP Management Service server configuration. | -| xpManagement.extraArgs | list | `[]` | List of string containing additional XP Management Service server arguments. For example, multiple "-config" can be specified to use multiple config files | -| xpManagement.extraEnvs | list | `[]` | List of extra environment variables to add to XP Management Service server container | -| xpManagement.extraLabels | object | `{}` | List of extra labels to add to XP Management Service K8s resources | -| xpManagement.extraVolumeMounts | list | `[]` | Extra volume mounts to attach to XP Management Service server container. For example to mount the extra volume containing secrets | -| xpManagement.extraVolumes | list | `[]` | Extra volumes to attach to the Pod. For example, you can mount additional secrets to these volumes | -| xpManagement.image.pullPolicy | string | `"IfNotPresent"` | Docker image pull policy | -| xpManagement.image.registry | string | `"ghcr.io"` | Docker registry for XP Management Service image | -| xpManagement.image.repository | string | `"caraml-dev/xp/xp-management"` | Docker image repository for XP Management Service | -| xpManagement.image.tag | string | `"v0.9.0"` | Docker image tag for XP Management Service | -| xpManagement.ingress.class | string | `""` | Ingress class annotation to add to this Ingress rule, useful when there are multiple ingress controllers installed | -| xpManagement.ingress.enabled | bool | `false` | Enable ingress to provision Ingress resource for external access to XP Management Service | -| xpManagement.ingress.host | string | `""` | Set host value to enable name based virtual hosting. This allows routing HTTP traffic to multiple host names at the same IP address. If no host is specified, the ingress rule applies to all inbound HTTP traffic through the IP address specified. https://kubernetes.io/docs/concepts/services-networking/ingress/#name-based-virtual-hosting | -| xpManagement.labels | object | `{}` | | -| xpManagement.livenessProbe.initialDelaySeconds | int | `60` | Liveness probe delay and thresholds | -| xpManagement.livenessProbe.path | string | `"/v1/internal/live"` | HTTP path for liveness check | -| xpManagement.livenessProbe.periodSeconds | int | `10` | | -| xpManagement.livenessProbe.successThreshold | int | `1` | | -| xpManagement.livenessProbe.timeoutSeconds | int | `5` | | -| xpManagement.readinessProbe.initialDelaySeconds | int | `60` | Liveness probe delay and thresholds | -| xpManagement.readinessProbe.path | string | `"/v1/internal/ready"` | HTTP path for readiness check | -| xpManagement.readinessProbe.periodSeconds | int | `10` | | -| xpManagement.readinessProbe.successThreshold | int | `1` | | -| xpManagement.readinessProbe.timeoutSeconds | int | `5` | | -| xpManagement.replicaCount | int | `1` | | -| xpManagement.resources | object | `{}` | Resources requests and limits for XP Management Service. This should be set according to your cluster capacity and service level objectives. Reference: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ | -| xpManagement.sentry.dsn | string | `""` | Sentry DSN value used by both XP Management Service and XP UI | -| xpManagement.sentry.enabled | bool | `false` | | -| xpManagement.service.externalPort | int | `8080` | XP Management Service Kubernetes service port number | -| xpManagement.service.internalPort | int | `8080` | XP Management Service container port number | -| xpManagement.serviceAccount.annotations | object | `{}` | | -| xpManagement.serviceAccount.create | bool | `true` | | -| xpManagement.serviceAccount.name | string | `""` | | -| xpManagement.uiConfig | object | `{"apiConfig":{"mlpApiUrl":"/api/v1","xpApiUrl":"/api/xp/v1"},"appConfig":{"docsUrl":[{"href":"https://github.com/caraml-dev/xp/tree/main/docs","label":"XP User Guide"}]},"authConfig":{"oauthClientId":""},"sentryConfig":{}}` | XP UI configuration. | diff --git a/infra/charts/management-service/README.md.gotmpl b/infra/charts/management-service/README.md.gotmpl deleted file mode 100644 index 19371d65..00000000 --- a/infra/charts/management-service/README.md.gotmpl +++ /dev/null @@ -1,57 +0,0 @@ -{{ template "chart.header" . }} ---- -{{ template "chart.versionBadge" . }} -{{ template "chart.appVersionBadge" . }} - -{{ template "chart.description" . }} - -## Introduction - -This Helm chart installs [Management Service](https://github.com/caraml-dev/xp/management-service) and all its dependencies in a Kubernetes cluster. - -## Prerequisites - -To use the charts here, [Helm](https://helm.sh/) must be configured for your -Kubernetes cluster. Setting up Kubernetes and Helm is outside the scope of -this README. Please refer to the Kubernetes and Helm documentation. - -- **Helm 3.0+** – This chart was tested with Helm v3.7.1, but it is also expected to work with earlier Helm versions -- **Kubernetes 1.18+** – This chart was tested with GKE v1.20.x, but it's possible it works with earlier k8s versions too. - -## Installation - -### Add Helm repository - -```sh -$ helm repo add xp https://turing-ml.github.io/charts -``` - -### Installing the chart - -This command will install XP Management Service release named `management-service` in the `default` namespace. -Default chart values will be used for the installation: -```shell -$ helm install xp xp/management-service -``` - -You can (and most likely, should) override the default configuration with values suitable for your installation. -Refer to [Configuration](#configuration) section for the detailed description of available configuration keys. - -You can also refer to [values.minimal.yaml](./values.minimal.yaml) to check a minimal configuration that needs -to be provided for XP Management Service installation. - -### Uninstalling the chart - -To uninstall `management-service` release: -```shell -$ helm uninstall management-service -``` - -The command removes all the Kubernetes components associated with the chart and deletes the release, -except for postgresql PVC, those will have to be removed manually. - -## Configuration - -The following table lists the configurable parameters of the XP Management Service chart and their default values. - -{{ template "chart.valuesTable" . }} diff --git a/infra/charts/management-service/charts/postgresql-10.16.2.tgz b/infra/charts/management-service/charts/postgresql-10.16.2.tgz deleted file mode 100644 index d3a6d0f8f51e3f5ef0fdfa10b3205e922b5fcea8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53913 zcmV)UK(N0biwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PMZ{d)v0MDB7R(S70kyCw7mihvPV1x;y)B#dcGFwHq!qul8kq!U1_NL)7z}1&!uXUT_Iubpm_f=r z3pfwIyWgkR>-F~c_T<04UN8S|fA9J8@A`ZFm%GpVyZx8D-}U;>pTB(Z9q8RN9i>mg zIHce8?u;wnxNqcvQA9Z8m_%&Q0>FnHO$l8Lz#-&t3>j*{7{5o9VG<3%&29_Ear$S! z-|6pldaVG(C<;*IW5fn64@7W|2EZrtIf+^TP!tn}xdc1oJZ6J#*B670b;g)SaE?1Z znRoT?763OXg3iaz$5w!tPjSrUD>+KRgivs{R@1C0=CfpMH%GU$%PB(LIb148J#1e7r$uoK=mGFrcW71~1r+=L86YOW%^~GD>P%=_ z!THcq?<~R@NvN+zSPj4Rzg|H6YeYS#;ilT{?QJLf&>?i%ZDoV5*Xi$fc3WS1YCg(S zkpCg^ukRVh68YbI{(P?>|Mzz{^8YcO2Nd1?Ugvo$z*EHd0I(U{eX&14KTP_;i+@7& zL;pn&qW#`K|2f$WUhcwwqUX@xodkZ*|6vmRu>a5TZojv?yN`m&OaEmbp-I2LyZ^j3 zMG>NqqhJ8qyS?4M*WdM?_b+#QgWm37Z?E&u=ld^rf7sjI`@ikK#{|CPW6l2?7$%54 zfC5-M|NFap{k{GC{NLZ(%>PGuo;(5n$&fFWd+;VCV;F)MQaDE(QPz6$#JoI|t0};9 zI7PV<=OKa&?SP1I1o#Ycz-O3&TO5Xf+#pJEAl{=wDRP_�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 diff --git a/infra/charts/management-service/requirements.lock b/infra/charts/management-service/requirements.lock deleted file mode 100644 index 68a42bf8..00000000 --- a/infra/charts/management-service/requirements.lock +++ /dev/null @@ -1,6 +0,0 @@ -dependencies: -- name: postgresql - repository: https://charts.bitnami.com/bitnami - version: 10.16.2 -digest: sha256:cddad872d58f7f052d938e50fbcd18c844380eb21e17c78b0f297a34f4304be8 -generated: "2022-07-18T12:20:25.553187+08:00" diff --git a/infra/charts/management-service/requirements.yaml b/infra/charts/management-service/requirements.yaml deleted file mode 100644 index 566de37f..00000000 --- a/infra/charts/management-service/requirements.yaml +++ /dev/null @@ -1,6 +0,0 @@ -dependencies: - - name: postgresql - repository: https://charts.bitnami.com/bitnami - version: 10.16.2 - tags: - - db diff --git a/infra/charts/management-service/templates/_helpers.tpl b/infra/charts/management-service/templates/_helpers.tpl deleted file mode 100644 index 47c9dbe4..00000000 --- a/infra/charts/management-service/templates/_helpers.tpl +++ /dev/null @@ -1,96 +0,0 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "xp.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "xp.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "xp.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{- define "xp.environment" -}} -{{- .Values.global.environment | default .Values.xpManagement.environment | default "dev" -}} -{{- end -}} - -{{/* -Common labels -*/}} -{{- define "xp.labels" -}} -helm.sh/chart: {{ include "xp.chart" . }} -{{- with (.Values.xpManagement).extraLabels }} -{{- toYaml . | nindent 0 }} -{{- end }} -{{ include "xp.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "xp.selectorLabels" -}} -app.kubernetes.io/name: {{ include "xp.fullname" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - -{{/* -Create the name of the service account to use -*/}} -{{- define "xp.serviceAccountName" -}} -{{- if .Values.xpManagement.serviceAccount.create }} -{{- default (include "xp.fullname" .) .Values.xpManagement.serviceAccount.name }} -{{- else }} -{{- default "default" .Values.xpManagement.serviceAccount.name }} -{{- end }} -{{- end }} - -{{- define "xp.sentry.enabled" -}} -{{ eq ((.Values.xpManagement.apiConfig.sentryConfig).enabled | toString) "true" }} -{{- end -}} - -{{- define "xp.sentry.dsn" -}} -{{- .Values.global.sentry.dsn | default .Values.xpManagement.sentry.dsn -}} -{{- end -}} - -{{- define "xp.ui.defaultConfig" -}} -{{- if .Values.xpManagement.uiConfig -}} -appConfig: - environment: {{ .Values.xpManagement.uiConfig.appConfig.environment | default (include "xp.environment" .) }} -authConfig: - oauthClientId: {{ .Values.global.oauthClientId | default .Values.xpManagement.uiConfig.authConfig.oauthClientId | quote }} -{{- if (include "xp.sentry.enabled" .) }} -sentryConfig: - environment: {{ .Values.xpManagement.uiConfig.sentryConfig.environment | default (include "xp.environment" .) }} - dsn: {{ .Values.xpManagement.uiConfig.sentryConfig.dsn | default (include "xp.sentry.dsn" .) | quote }} -{{- end -}} -{{- end -}} -{{- end -}} - -{{- define "xp.ui.config" -}} -{{- $defaultConfig := include "xp.ui.defaultConfig" . | fromYaml -}} -{{ .Values.xpManagement.uiConfig | merge $defaultConfig | toPrettyJson }} -{{- end -}} diff --git a/infra/charts/management-service/templates/deployment.yaml b/infra/charts/management-service/templates/deployment.yaml deleted file mode 100644 index 665ad10f..00000000 --- a/infra/charts/management-service/templates/deployment.yaml +++ /dev/null @@ -1,130 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "xp.fullname" . }} - labels: - {{- include "xp.labels" . | nindent 4 }} -spec: - replicas: {{ .Values.xpManagement.replicaCount }} - selector: - matchLabels: - app: {{ template "xp.name" .}} - release: {{ .Release.Name }} - strategy: - type: RollingUpdate - rollingUpdate: - maxUnavailable: 0 - template: - metadata: - labels: - app: {{ template "xp.name" .}} - release: {{ .Release.Name }} - {{- include "xp.labels" . | nindent 8 }} - spec: - {{- with .Values.xpManagement.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - serviceAccountName: {{ include "xp.serviceAccountName" . }} - containers: - - name: api - image: "{{ .Values.xpManagement.image.registry }}{{ .Values.xpManagement.image.repository }}:{{ .Values.xpManagement.image.tag | default .Chart.AppVersion }}" - imagePullPolicy: {{ .Values.xpManagement.image.pullPolicy }} - env: - {{- with .Values.xpManagement.extraEnvs }} - {{- toYaml . | nindent 12 }} - {{- end }} - ports: - - name: http - containerPort: 8080 - protocol: TCP - livenessProbe: - httpGet: - path: {{ .Values.xpManagement.livenessProbe.path }} - port: {{ .Values.xpManagement.service.internalPort }} - scheme: HTTP - initialDelaySeconds: {{ .Values.xpManagement.livenessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.xpManagement.livenessProbe.periodSeconds }} - successThreshold: {{ .Values.xpManagement.livenessProbe.successThreshold }} - timeoutSeconds: {{ .Values.xpManagement.livenessProbe.timeoutSeconds }} - readinessProbe: - httpGet: - path: {{ .Values.xpManagement.readinessProbe.path }} - port: {{ .Values.xpManagement.service.internalPort }} - scheme: HTTP - initialDelaySeconds: {{ .Values.xpManagement.readinessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.xpManagement.readinessProbe.periodSeconds }} - successThreshold: {{ .Values.xpManagement.readinessProbe.successThreshold }} - timeoutSeconds: {{ .Values.xpManagement.readinessProbe.timeoutSeconds }} - resources: - {{- toYaml .Values.xpManagement.resources | nindent 12 }} - # Give time for running pods to terminate existing connection before letting - # Kubernetes terminate the pods. - # https://blog.sebastian-daschner.com/entries/zero-downtime-updates-kubernetes - lifecycle: - preStop: - exec: - command: ["/bin/bash", "-c", "sleep 15"] - args: - - serve - - --config=/etc/xp/config.yaml - {{- if .Values.xpManagement.uiConfig }} - - -ui-config - - /etc/xp/ui.config.json - {{- end }} - {{- with .Values.xpManagement.extraArgs }} - {{- toYaml . | nindent 8 }} - {{- end }} - volumeMounts: - - name: config - mountPath: /etc/xp - {{- with .Values.xpManagement.extraVolumeMounts }} - {{- toYaml . | nindent 8 }} - {{- end }} - - name: swagger-ui - image: "swaggerapi/swagger-ui:{{ .Values.swaggerUi.image.tag }}" - imagePullPolicy: IfNotPresent - ports: - - containerPort: {{ .Values.swaggerUi.service.internalPort }} - resources: - requests: - cpu: 100m - memory: 64Mi - limits: - cpu: 500m - memory: 128Mi - env: - - name: LAYOUT - value: "BaseLayout" - - name: SWAGGER_JSON - value: "/app/experiments.yaml" - - name: PORT - value: "{{ .Values.swaggerUi.service.internalPort }}" - - name: API_SERVER - value: "{{ .Values.swaggerUi.apiServer }}" - command: ["sh", "-c"] - args: - - | - mkdir /app - export LOCAL_API_SERVER="http://127.0.0.1:{{ .Values.xpManagement.service.internalPort }}" - echo "Fetching swagger configuration from ${LOCAL_API_SERVER}/experiments.yaml..." - until $$(wget -O $${SWAGGER_JSON} --tries 1 --timeout 1 ${LOCAL_API_SERVER}/experiments.yaml); do - printf '.' - sleep 10 - done - echo "Fetching swagger configuration from ${LOCAL_API_SERVER}/schema.yaml..." - until $$(wget -O /app/schema.yaml --tries 1 --timeout 1 ${LOCAL_API_SERVER}/schema.yaml); do - printf '.' - sleep 10 - done - echo "Update Swagger config..." - sed -r -i 's%^((\s*)-(\s*)url\s*:).*$$%\1 "'$${API_SERVER}'"%' $${SWAGGER_JSON} - echo "Running Swagger UI..." - /usr/share/nginx/run.sh - volumes: - - name: config - secret: - secretName: {{ template "xp.fullname" .}}-api-config - {{- with .Values.xpManagement.extraVolumes }} - {{- toYaml . | nindent 6 }} - {{- end }} diff --git a/infra/charts/management-service/templates/ingress.yaml b/infra/charts/management-service/templates/ingress.yaml deleted file mode 100644 index abdf5112..00000000 --- a/infra/charts/management-service/templates/ingress.yaml +++ /dev/null @@ -1,33 +0,0 @@ -{{- if .Values.xpManagement.ingress.enabled }} -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: {{ template "xp.fullname" .}} - namespace: {{ .Release.Namespace }} - annotations: - {{- with .Values.xpManagement.ingress.class }} - ingress.class: {{ . }} - {{- end }} - labels: - app: {{ include "xp.fullname" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} - helm.sh/chart: {{ include "xp.chart" . }} - app.kubernetes.io/name: {{ include "xp.fullname" . }} - app.kubernetes.io/instance: {{ .Release.Name }} - app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- if .Values.xpManagement.labels }} -{{ toYaml .Values.xpManagement.labels | indent 4 }} -{{- end }} -spec: - rules: - - {{- with .Values.xpManagement.ingress.host }} - host: {{ . }} - {{- end }} - http: - paths: - - path: / - backend: - serviceName: {{ template "xp.fullname" .}} - servicePort: {{ .Values.xpManagement.service.externalPort }} -{{- end }} diff --git a/infra/charts/management-service/templates/secrets.yaml b/infra/charts/management-service/templates/secrets.yaml deleted file mode 100644 index 1ab09eda..00000000 --- a/infra/charts/management-service/templates/secrets.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - namespace: {{ .Release.Namespace }} - name: {{ template "xp.fullname" .}}-api-config -stringData: - config.yaml: | - {{- toYaml .Values.xpManagement.apiConfig | nindent 4 -}} - {{- if .Values.xpManagement.uiConfig }} - ui.config.json: | - {{- include "xp.ui.config" . | nindent 4 -}} - {{- end }} diff --git a/infra/charts/management-service/templates/service-swagger.yaml b/infra/charts/management-service/templates/service-swagger.yaml deleted file mode 100644 index b6572137..00000000 --- a/infra/charts/management-service/templates/service-swagger.yaml +++ /dev/null @@ -1,23 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ template "xp.fullname" .}}-swagger - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "xp.fullname" .}} - chart: {{ template "xp.chart" .}} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -{{ if .Values.xpManagement.labels -}} -{{ toYaml .Values.xpManagement.labels | indent 4 -}} -{{- end }} -spec: - type: ClusterIP - ports: - - name: http - port: {{ .Values.swaggerUi.service.externalPort }} - targetPort: {{ .Values.swaggerUi.service.internalPort }} - protocol: TCP - selector: - app: {{ template "xp.fullname" .}} - release: {{ .Release.Name }} diff --git a/infra/charts/management-service/templates/service-xp.yaml b/infra/charts/management-service/templates/service-xp.yaml deleted file mode 100644 index d0af6037..00000000 --- a/infra/charts/management-service/templates/service-xp.yaml +++ /dev/null @@ -1,23 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ template "xp.fullname" .}} - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "xp.fullname" .}} - chart: {{ template "xp.chart" .}} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -{{ if .Values.xpManagement.labels -}} -{{ toYaml .Values.xpManagement.labels | indent 4 -}} -{{- end }} -spec: - type: ClusterIP - ports: - - name: http - port: {{ .Values.xpManagement.service.externalPort }} - targetPort: {{ .Values.xpManagement.service.internalPort }} - protocol: TCP - selector: - app: {{ template "xp.name" .}} - release: {{ .Release.Name }} diff --git a/infra/charts/management-service/templates/serviceaccount.yaml b/infra/charts/management-service/templates/serviceaccount.yaml deleted file mode 100644 index 6e88baa9..00000000 --- a/infra/charts/management-service/templates/serviceaccount.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- if .Values.xpManagement.serviceAccount.create -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "xp.serviceAccountName" . }} - labels: - {{- include "xp.labels" . | nindent 4 }} - {{- with .Values.xpManagement.serviceAccount.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -{{- end }} diff --git a/infra/charts/management-service/values.yaml b/infra/charts/management-service/values.yaml deleted file mode 100644 index 2feff8f9..00000000 --- a/infra/charts/management-service/values.yaml +++ /dev/null @@ -1,177 +0,0 @@ -xpManagement: - image: - # -- Docker registry for XP Management Service image - registry: ghcr.io - # -- Docker image repository for XP Management Service - repository: caraml-dev/xp/xp-management - # -- Docker image tag for XP Management Service - tag: v0.9.0 - # -- Docker image pull policy - pullPolicy: IfNotPresent - - labels: {} - replicaCount: 1 - - # -- Resources requests and limits for XP Management Service. This should be set - # according to your cluster capacity and service level objectives. - # Reference: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - resources: {} - - livenessProbe: - # -- HTTP path for liveness check - path: "/v1/internal/live" - # -- Liveness probe delay and thresholds - initialDelaySeconds: 60 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 5 - - readinessProbe: - # -- HTTP path for readiness check - path: "/v1/internal/ready" - # -- Liveness probe delay and thresholds - initialDelaySeconds: 60 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 5 - - service: - # -- XP Management Service Kubernetes service port number - externalPort: 8080 - # -- XP Management Service container port number - internalPort: 8080 - - ingress: - # -- Enable ingress to provision Ingress resource for external access to XP Management Service - enabled: false - # -- Set host value to enable name based virtual hosting. This allows routing - # HTTP traffic to multiple host names at the same IP address. If no host is - # specified, the ingress rule applies to all inbound HTTP traffic through - # the IP address specified. - # https://kubernetes.io/docs/concepts/services-networking/ingress/#name-based-virtual-hosting - host: "" - # -- Ingress class annotation to add to this Ingress rule, - # useful when there are multiple ingress controllers installed - class: "" - - # -- XP Management Service server configuration. - apiConfig: {} - - # -- XP UI configuration. - uiConfig: - apiConfig: - xpApiUrl: /api/xp/v1 - mlpApiUrl: /api/v1 - appConfig: - docsUrl: - - label: XP User Guide - href: https://github.com/caraml-dev/xp/tree/main/docs - authConfig: - oauthClientId: "" - sentryConfig: { } - - # -- List of string containing additional XP Management Service server arguments. For - # example, multiple "-config" can be specified to use multiple config files - extraArgs: [] - # Example - # - --config=/etc/secrets/experiment.yaml - # - --config=/etc/secrets/database.yaml - - # -- List of extra environment variables to add to XP Management Service server container - extraEnvs: [] - # # Example - # - name: DEMO_GREETING - # value: "Hello from the environment" - - # -- List of extra labels to add to XP Management Service K8s resources - extraLabels: {} - - # -- Extra volumes to attach to the Pod. For example, you can mount - # additional secrets to these volumes - extraVolumes: [] - # # Example - # - name: varlog - # emptyDir: {} - - # -- Extra volume mounts to attach to XP Management Service server container. For example - # to mount the extra volume containing secrets - extraVolumeMounts: [] - # # Example - # - name: varlog - # mountPath: /var/log - - serviceAccount: - # Specifies whether a service account should be created - create: true - # Annotations to add to the service account - annotations: {} - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - name: "" - - sentry: - enabled: false - # -- Sentry DSN value used by both XP Management Service and XP UI - dsn: "" - -# -- Postgresql configuration to be applied to XP Management Service's postgresql database deployment -# Reference: https://artifacthub.io/packages/helm/bitnami/postgresql/10.16.2#parameters -postgresql: - # -- Resources requests and limits for XP Management Service database. This should be set - # according to your cluster capacity and service level objectives. - # Reference: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - resources: - requests: - memory: 256Mi - cpu: 500m - persistence: - # -- Persist Postgresql data in a Persistent Volume Claim - enabled: true - size: 10Gi - postgresqlDatabase: xp - postgresqlUsername: xp - # -- Password for XP Management Service Postgresql database - postgresqlPassword: xp - tls: - enabled: false - containerPorts: - postgresql: 5432 - metrics: - enabled: false - serviceMonitor: - enabled: false - replication: - enabled: false - user: repl_user - password: repl_password - slaveReplicas: 2 - synchronousCommit: "on" - numSynchronousReplicas: 2 - applicationName: xp - -global: - sentry: - # -- (string) Global Sentry DSN value - dsn: - - mlp: - encryption: - # -- (string) Global MLP Encryption Key to be used by all MLP components - key: - -swaggerUi: - # -- Docker tag for Swagger UI https://hub.docker.com/r/swaggerapi/swagger-ui - image: - tag: v3.47.1 - # -- URL of API server - apiServer: http://127.0.0.1/v1 - service: - # -- Swagger UI container port number - internalPort: 8081 - # -- Swagger UI Kubernetes service port number - externalPort: 8080 - -# Tags are used to include/exclude chart dependencies -tags: - # -- Specifies if Postgresql database needs to be installed together with XP Management Service - db: true diff --git a/infra/charts/treatment-service/Chart.yaml b/infra/charts/treatment-service/Chart.yaml deleted file mode 100644 index 02de962f..00000000 --- a/infra/charts/treatment-service/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: v0.9.0 -name: xp-treatment -description: A Helm chart for Kubernetes Deployment of the XP Treatment Service -version: 0.1.2 diff --git a/infra/charts/treatment-service/README.md b/infra/charts/treatment-service/README.md deleted file mode 100644 index 60c2b95a..00000000 --- a/infra/charts/treatment-service/README.md +++ /dev/null @@ -1,97 +0,0 @@ -# xp-treatment - ---- -![Version: 0.1.2](https://img.shields.io/badge/Version-0.1.2-informational?style=flat-square) -![AppVersion: v0.9.0](https://img.shields.io/badge/AppVersion-v0.9.0-informational?style=flat-square) - -A Helm chart for Kubernetes Deployment of the XP Treatment Service - -## Introduction - -This Helm chart installs [Treatment Service](https://github.com/caraml-dev/xp/treatment-service) and all its dependencies in a Kubernetes cluster. - -## Prerequisites - -To use the charts here, [Helm](https://helm.sh/) must be configured for your -Kubernetes cluster. Setting up Kubernetes and Helm is outside the scope of -this README. Please refer to the Kubernetes and Helm documentation. - -- **Helm 3.0+** – This chart was tested with Helm v3.7.1, but it is also expected to work with earlier Helm versions -- **Kubernetes 1.18+** – This chart was tested with GKE v1.20.x, but it's possible it works with earlier k8s versions too. - -## Installation - -### Add Helm repository - -```sh -$ helm repo add xp https://turing-ml.github.io/charts -``` - -### Installing the chart - -This command will install XP Treatment Service release named `xp-treatment` in the `default` namespace. -Default chart values will be used for the installation: -```shell -$ helm install xp-treatment xp/xp-treatment -``` - -You can (and most likely, should) override the default configuration with values suitable for your installation. -Refer to [Configuration](#configuration) section for the detailed description of available configuration keys. - -You can also refer to [values.yaml](./values.yaml) to check a minimal configuration that needs -to be provided for XP Treatment Service installation. - -### Uninstalling the chart - -To uninstall the `xp-treatment` release: -```shell -$ helm uninstall xp-treatment -``` - -The command removes all the Kubernetes components associated with the chart and deletes the release, -except for postgresql PVC, those will have to be removed manually. - -## Configuration - -The following table lists the configurable parameters of the XP Treatment Service chart and their default values. - -| Key | Type | Default | Description | -|-----|------|---------|-------------| -| swaggerUi.apiServer | string | `"http://127.0.0.1/v1"` | URL of API server | -| swaggerUi.enabled | bool | `false` | | -| swaggerUi.image | object | `{"tag":"v3.47.1"}` | Docker tag for Swagger UI https://hub.docker.com/r/swaggerapi/swagger-ui | -| swaggerUi.service.externalPort | int | `8080` | Swagger UI Kubernetes service port number | -| swaggerUi.service.internalPort | int | `8081` | Swagger UI container port number | -| xpTreatment.autoscaling.enabled | bool | `false` | | -| xpTreatment.autoscaling.maxReplicas | int | `2` | | -| xpTreatment.autoscaling.minReplicas | int | `1` | | -| xpTreatment.autoscaling.targetCPUUtilizationPercentage | int | `80` | | -| xpTreatment.autoscaling.targetMemoryUtilizationPercentage | int | `80` | | -| xpTreatment.extraEnvs | list | `[]` | List of extra environment variables to add to XP Treatment Service server container | -| xpTreatment.extraLabels | object | `{}` | List of extra labels to add to XP Treatment Service K8s resources | -| xpTreatment.extraVolumeMounts | list | `[]` | Extra volume mounts to attach to XP Treatment Service server container. For example to mount the extra volume containing secrets | -| xpTreatment.extraVolumes | list | `[]` | Extra volumes to attach to the Pod. For example, you can mount additional secrets to these volumes | -| xpTreatment.image.pullPolicy | string | `"IfNotPresent"` | Docker image pull policy | -| xpTreatment.image.registry | string | `"ghcr.io"` | Docker registry for XP Treatment Service image | -| xpTreatment.image.repository | string | `"caraml-dev/xp/xp-treatment"` | Docker image repository for XP Treatment Service | -| xpTreatment.image.tag | string | `"v0.9.0"` | Docker image tag for XP Treatment Service | -| xpTreatment.ingress.class | string | `""` | Ingress class annotation to add to this Ingress rule, useful when there are multiple ingress controllers installed | -| xpTreatment.ingress.enabled | bool | `false` | Enable ingress to provision Ingress resource for external access to XP Treatment Service | -| xpTreatment.ingress.host | string | `""` | Set host value to enable name based virtual hosting. This allows routing HTTP traffic to multiple host names at the same IP address. If no host is specified, the ingress rule applies to all inbound HTTP traffic through the IP address specified. https://kubernetes.io/docs/concepts/services-networking/ingress/#name-based-virtual-hosting | -| xpTreatment.labels | object | `{}` | | -| xpTreatment.livenessProbe.initialDelaySeconds | int | `60` | Liveness probe delay and thresholds | -| xpTreatment.livenessProbe.path | string | `"/v1/internal/health/live"` | HTTP path for liveness check | -| xpTreatment.livenessProbe.periodSeconds | int | `10` | | -| xpTreatment.livenessProbe.successThreshold | int | `1` | | -| xpTreatment.livenessProbe.timeoutSeconds | int | `5` | | -| xpTreatment.nodeSelector | object | `{}` | | -| xpTreatment.readinessProbe.initialDelaySeconds | int | `60` | Liveness probe delay and thresholds | -| xpTreatment.readinessProbe.path | string | `"/v1/internal/health/ready"` | HTTP path for readiness check | -| xpTreatment.readinessProbe.periodSeconds | int | `10` | | -| xpTreatment.readinessProbe.successThreshold | int | `1` | | -| xpTreatment.readinessProbe.timeoutSeconds | int | `5` | | -| xpTreatment.replicaCount | int | `1` | | -| xpTreatment.resources | object | `{}` | Resources requests and limits for XP Treatment Service. This should be set according to your cluster capacity and service level objectives. Reference: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ | -| xpTreatment.service.externalPort | int | `8080` | XP Treatment Service Kubernetes service port number | -| xpTreatment.service.internalPort | int | `8080` | XP Treatment Service container port number | -| xpTreatment.service.type | string | `"ClusterIP"` | | diff --git a/infra/charts/treatment-service/README.md.gotmpl b/infra/charts/treatment-service/README.md.gotmpl deleted file mode 100644 index c2719d81..00000000 --- a/infra/charts/treatment-service/README.md.gotmpl +++ /dev/null @@ -1,57 +0,0 @@ -{{ template "chart.header" . }} ---- -{{ template "chart.versionBadge" . }} -{{ template "chart.appVersionBadge" . }} - -{{ template "chart.description" . }} - -## Introduction - -This Helm chart installs [Treatment Service](https://github.com/caraml-dev/xp/treatment-service) and all its dependencies in a Kubernetes cluster. - -## Prerequisites - -To use the charts here, [Helm](https://helm.sh/) must be configured for your -Kubernetes cluster. Setting up Kubernetes and Helm is outside the scope of -this README. Please refer to the Kubernetes and Helm documentation. - -- **Helm 3.0+** – This chart was tested with Helm v3.7.1, but it is also expected to work with earlier Helm versions -- **Kubernetes 1.18+** – This chart was tested with GKE v1.20.x, but it's possible it works with earlier k8s versions too. - -## Installation - -### Add Helm repository - -```sh -$ helm repo add xp https://turing-ml.github.io/charts -``` - -### Installing the chart - -This command will install XP Treatment Service release named `xp-treatment` in the `default` namespace. -Default chart values will be used for the installation: -```shell -$ helm install xp-treatment xp/xp-treatment -``` - -You can (and most likely, should) override the default configuration with values suitable for your installation. -Refer to [Configuration](#configuration) section for the detailed description of available configuration keys. - -You can also refer to [values.yaml](./values.yaml) to check a minimal configuration that needs -to be provided for XP Treatment Service installation. - -### Uninstalling the chart - -To uninstall the `xp-treatment` release: -```shell -$ helm uninstall xp-treatment -``` - -The command removes all the Kubernetes components associated with the chart and deletes the release, -except for postgresql PVC, those will have to be removed manually. - -## Configuration - -The following table lists the configurable parameters of the XP Treatment Service chart and their default values. - -{{ template "chart.valuesTable" . }} diff --git a/infra/charts/treatment-service/templates/_helpers.tpl b/infra/charts/treatment-service/templates/_helpers.tpl deleted file mode 100644 index 53cfdfe6..00000000 --- a/infra/charts/treatment-service/templates/_helpers.tpl +++ /dev/null @@ -1,54 +0,0 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "xp.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "xp.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "xp.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "xp.labels" -}} -helm.sh/chart: {{ include "xp.chart" . }} -{{- with (.Values.xpTreatment).extraLabels }} -{{- toYaml . | nindent 0 }} -{{- end }} -{{ include "xp.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "xp.selectorLabels" -}} -app.kubernetes.io/name: {{ include "xp.fullname" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} diff --git a/infra/charts/treatment-service/templates/deployment.yaml b/infra/charts/treatment-service/templates/deployment.yaml deleted file mode 100644 index f6d16697..00000000 --- a/infra/charts/treatment-service/templates/deployment.yaml +++ /dev/null @@ -1,136 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "xp.fullname" . }} - labels: - {{- include "xp.labels" . | nindent 4 }} -spec: - replicas: {{ .Values.xpTreatment.replicaCount }} - selector: - matchLabels: - app: {{ template "xp.name" . }} - release: {{ .Release.Name }} - strategy: - type: RollingUpdate - rollingUpdate: - maxUnavailable: 0 - template: - metadata: - labels: - app: {{ template "xp.name" . }} - release: {{ .Release.Name }} - {{- include "xp.labels" . | nindent 8 }} - {{- with .Values.xpTreatment.annotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - spec: - {{- with .Values.xpTreatment.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - containers: - - name: api - image: "{{ .Values.xpTreatment.image.registry }}{{ .Values.xpTreatment.image.repository }}:{{ .Values.xpTreatment.image.tag | default .Chart.AppVersion }}" - imagePullPolicy: {{ .Values.xpTreatment.image.pullPolicy }} - env: - {{- with .Values.xpTreatment.extraEnvs }} - {{- toYaml . | nindent 12 }} - {{- end }} - ports: - - name: http - containerPort: 8080 - protocol: TCP - livenessProbe: - httpGet: - path: {{ .Values.xpTreatment.livenessProbe.path }} - port: {{ .Values.xpTreatment.service.internalPort }} - scheme: HTTP - initialDelaySeconds: {{ .Values.xpTreatment.livenessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.xpTreatment.livenessProbe.periodSeconds }} - successThreshold: {{ .Values.xpTreatment.livenessProbe.successThreshold }} - timeoutSeconds: {{ .Values.xpTreatment.livenessProbe.timeoutSeconds }} - readinessProbe: - httpGet: - path: {{ .Values.xpTreatment.readinessProbe.path }} - port: {{ .Values.xpTreatment.service.internalPort }} - scheme: HTTP - initialDelaySeconds: {{ .Values.xpTreatment.readinessProbe.initialDelaySeconds }} - periodSeconds: {{ .Values.xpTreatment.readinessProbe.periodSeconds }} - successThreshold: {{ .Values.xpTreatment.readinessProbe.successThreshold }} - timeoutSeconds: {{ .Values.xpTreatment.readinessProbe.timeoutSeconds }} - resources: - {{- toYaml .Values.xpTreatment.resources | nindent 12 }} - # Give time for running pods to terminate existing connection before letting - # Kubernetes terminate the pods. - # https://blog.sebastian-daschner.com/entries/zero-downtime-updates-kubernetes - lifecycle: - preStop: - exec: - command: ["/bin/bash", "-c", "sleep 15"] - args: - - serve - - --config=/etc/xp/config.yaml - {{- with .Values.xpTreatment.extraArgs }} - {{- toYaml . | nindent 8 }} - {{- end }} - volumeMounts: - - name: config - mountPath: /etc/xp - {{- with .Values.xpTreatment.extraVolumeMounts }} - {{- toYaml . | nindent 8 }} - {{- end }} - {{- if .Values.swaggerUi.enabled }} - - name: swagger-ui - image: "swaggerapi/swagger-ui:{{ .Values.swaggerUi.image.tag }}" - imagePullPolicy: IfNotPresent - ports: - - containerPort: {{ .Values.swaggerUi.service.internalPort }} - resources: - requests: - cpu: 100m - memory: 64Mi - limits: - cpu: 500m - memory: 128Mi - env: - - name: LAYOUT - value: "BaseLayout" - - name: SWAGGER_JSON - value: "/app/treatment.yaml" - - name: PORT - value: "{{ .Values.swaggerUi.service.internalPort }}" - - name: API_SERVER - value: "{{ .Values.swaggerUi.apiServer }}" - command: ["sh", "-c"] - args: - - | - mkdir /app - export LOCAL_API_SERVER="http://127.0.0.1:{{ .Values.xpTreatment.service.internalPort }}" - echo "Fetching swagger configuration from ${LOCAL_API_SERVER}/treatment.yaml..." - until $$(wget -O $${SWAGGER_JSON} --tries 1 --timeout 1 ${LOCAL_API_SERVER}/treatment.yaml); do - printf '.' - sleep 10 - done - echo "Fetching swagger configuration from ${LOCAL_API_SERVER}/schema.yaml..." - until $$(wget -O /app/schema.yaml --tries 1 --timeout 1 ${LOCAL_API_SERVER}/schema.yaml); do - printf '.' - sleep 10 - done - echo "Update Swagger config..." - sed -r -i 's%^((\s*)-(\s*)url\s*:).*$$%\1 "'$${API_SERVER}'"%' $${SWAGGER_JSON} - echo "Running Swagger UI..." - /usr/share/nginx/run.sh - {{- end }} - volumes: - - name: config - secret: - secretName: {{ template "xp.fullname" .}}-config - {{- with .Values.xpTreatment.extraVolumes }} - {{- toYaml . | nindent 6 }} - {{- end }} - -{{- if .Values.xpTreatment.nodeSelector }} - nodeSelector: -{{ toYaml .Values.xpTreatment.nodeSelector | nindent 8 }} -{{ end -}} diff --git a/infra/charts/treatment-service/templates/hpa.yaml b/infra/charts/treatment-service/templates/hpa.yaml deleted file mode 100644 index e002200b..00000000 --- a/infra/charts/treatment-service/templates/hpa.yaml +++ /dev/null @@ -1,32 +0,0 @@ -{{- if .Values.xpTreatment.autoscaling.enabled }} -apiVersion: autoscaling/v2beta2 -kind: HorizontalPodAutoscaler -metadata: - name: {{ include "xp.fullname" . }} - labels: - {{- include "xp.labels" . | nindent 4 }} -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: {{ include "xp.fullname" . }} - minReplicas: {{ .Values.xpTreatment.autoscaling.minReplicas }} - maxReplicas: {{ .Values.xpTreatment.autoscaling.maxReplicas }} - metrics: - {{- if .Values.xpTreatment.autoscaling.targetCPUUtilizationPercentage }} - - type: Resource - resource: - name: cpu - target: - type: Utilization - averageUtilization: {{ .Values.xpTreatment.autoscaling.targetCPUUtilizationPercentage }} - {{- end }} - {{- if .Values.xpTreatment.autoscaling.targetMemoryUtilizationPercentage }} - - type: Resource - resource: - name: memory - target: - type: Utilization - averageUtilization: {{ .Values.xpTreatment.autoscaling.targetMemoryUtilizationPercentage }} - {{- end }} -{{- end }} diff --git a/infra/charts/treatment-service/templates/ingress.yaml b/infra/charts/treatment-service/templates/ingress.yaml deleted file mode 100644 index d6db030b..00000000 --- a/infra/charts/treatment-service/templates/ingress.yaml +++ /dev/null @@ -1,33 +0,0 @@ -{{- if .Values.xpTreatment.ingress.enabled }} -apiVersion: extensions/v1beta1 -kind: Ingress -metadata: - name: {{ template "xp.fullname" .}} - namespace: {{ .Release.Namespace }} - annotations: - {{- with .Values.xpTreatment.ingress.class }} - ingress.class: {{ . }} - {{- end }} - labels: - app: {{ include "xp.fullname" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} - helm.sh/chart: {{ include "xp.chart" . }} - app.kubernetes.io/name: {{ include "xp.fullname" . }} - app.kubernetes.io/instance: {{ .Release.Name }} - app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- if .Values.xpTreatment.labels }} -{{ toYaml .Values.xpTreatment.labels | indent 4 }} -{{- end }} -spec: - rules: - - {{- with .Values.xpTreatment.ingress.host }} - host: {{ . }} - {{- end }} - http: - paths: - - path: / - backend: - serviceName: {{ template "xp.fullname" .}} - servicePort: {{ .Values.xpTreatment.service.externalPort }} -{{- end }} diff --git a/infra/charts/treatment-service/templates/secrets.yaml b/infra/charts/treatment-service/templates/secrets.yaml deleted file mode 100644 index e8745645..00000000 --- a/infra/charts/treatment-service/templates/secrets.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - namespace: {{ .Release.Namespace }} - name: {{ template "xp.fullname" .}}-config -stringData: - config.yaml: | - {{- toYaml .Values.xpTreatment.config | nindent 4 -}} diff --git a/infra/charts/treatment-service/templates/service-swagger.yaml b/infra/charts/treatment-service/templates/service-swagger.yaml deleted file mode 100644 index 0cce43f1..00000000 --- a/infra/charts/treatment-service/templates/service-swagger.yaml +++ /dev/null @@ -1,25 +0,0 @@ -{{- if .Values.swaggerUi.enabled }} -apiVersion: v1 -kind: Service -metadata: - name: {{ include "xp.fullname" . }}-swagger - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "xp.fullname" .}} - chart: {{ template "xp.chart" .}} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -{{ if .Values.xpTreatment.labels -}} -{{ toYaml .Values.xpTreatment.labels | indent 4 -}} -{{- end }} -spec: - type: {{ .Values.swaggerUi.service.type }} - ports: - - name: http - port: {{ .Values.swaggerUi.service.externalPort }} - targetPort: {{ .Values.swaggerUi.service.internalPort }} - protocol: TCP - selector: - app: {{ template "xp.fullname" .}} - release: {{ .Release.Name }} -{{- end }} diff --git a/infra/charts/treatment-service/templates/service-xp.yaml b/infra/charts/treatment-service/templates/service-xp.yaml deleted file mode 100644 index 7d514b01..00000000 --- a/infra/charts/treatment-service/templates/service-xp.yaml +++ /dev/null @@ -1,23 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ include "xp.fullname" . }} - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "xp.fullname" .}} - chart: {{ template "xp.chart" .}} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -{{ if .Values.xpTreatment.labels -}} -{{ toYaml .Values.xpTreatment.labels | indent 4 -}} -{{- end }} -spec: - type: {{ .Values.xpTreatment.service.type }} - ports: - - name: http - port: {{ .Values.xpTreatment.service.externalPort }} - targetPort: {{ .Values.xpTreatment.service.internalPort }} - protocol: TCP - selector: - app: {{ template "xp.name" .}} - release: {{ .Release.Name }} diff --git a/infra/charts/treatment-service/values.yaml b/infra/charts/treatment-service/values.yaml deleted file mode 100644 index bc145c48..00000000 --- a/infra/charts/treatment-service/values.yaml +++ /dev/null @@ -1,98 +0,0 @@ -xpTreatment: - image: - # -- Docker registry for XP Treatment Service image - registry: ghcr.io - # -- Docker image repository for XP Treatment Service - repository: caraml-dev/xp/xp-treatment - # -- Docker image tag for XP Treatment Service - tag: v0.9.0 - # -- Docker image pull policy - pullPolicy: IfNotPresent - - labels: {} - replicaCount: 1 - - # -- Resources requests and limits for XP Treatment Service. This should be set - # according to your cluster capacity and service level objectives. - # Reference: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - resources: {} - - livenessProbe: - # -- HTTP path for liveness check - path: "/v1/internal/health/live" - # -- Liveness probe delay and thresholds - initialDelaySeconds: 60 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 5 - - readinessProbe: - # -- HTTP path for readiness check - path: "/v1/internal/health/ready" - # -- Liveness probe delay and thresholds - initialDelaySeconds: 60 - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 5 - - service: - type: ClusterIP - # -- XP Treatment Service Kubernetes service port number - externalPort: 8080 - # -- XP Treatment Service container port number - internalPort: 8080 - - ingress: - # -- Enable ingress to provision Ingress resource for external access to XP Treatment Service - enabled: false - # -- Set host value to enable name based virtual hosting. This allows routing - # HTTP traffic to multiple host names at the same IP address. If no host is - # specified, the ingress rule applies to all inbound HTTP traffic through - # the IP address specified. - # https://kubernetes.io/docs/concepts/services-networking/ingress/#name-based-virtual-hosting - host: "" - # -- Ingress class annotation to add to this Ingress rule, - # useful when there are multiple ingress controllers installed - class: "" - - # -- List of extra environment variables to add to XP Treatment Service server container - extraEnvs: [] - - # -- List of extra labels to add to XP Treatment Service K8s resources - extraLabels: {} - - # -- Extra volumes to attach to the Pod. For example, you can mount - # additional secrets to these volumes - extraVolumes: [] - # # Example - # - name: varlog - # emptyDir: {} - - # -- Extra volume mounts to attach to XP Treatment Service server container. For example - # to mount the extra volume containing secrets - extraVolumeMounts: [] - # # Example - # - name: varlog - # mountPath: /var/log - - nodeSelector: {} - - autoscaling: - enabled: false - minReplicas: 1 - maxReplicas: 2 - targetCPUUtilizationPercentage: 80 - targetMemoryUtilizationPercentage: 80 - -swaggerUi: - enabled: false - # -- Docker tag for Swagger UI https://hub.docker.com/r/swaggerapi/swagger-ui - image: - tag: v3.47.1 - # -- URL of API server - apiServer: http://127.0.0.1/v1 - service: - # -- Swagger UI container port number - internalPort: 8081 - # -- Swagger UI Kubernetes service port number - externalPort: 8080