From 6c8c778eabed54db25102004a1d3261689f1aa60 Mon Sep 17 00:00:00 2001 From: Torsten Gippert <46532698+tgip-work@users.noreply.github.com> Date: Wed, 13 Apr 2022 16:51:45 +0200 Subject: [PATCH] Migrate epi 0.2.0 from old repo (#29) * checkin epi 0.2.0 * rename repo ph-ethadapter to pharmaledger-imi * helm chart testing * doc update --- charts/epi/.helmignore | 24 ++ charts/epi/Chart.yaml | 29 ++ charts/epi/README.md | 354 ++++++++++++++++++ charts/epi/README.md.gotmpl | 305 +++++++++++++++ charts/epi/templates/NOTES.txt | 22 ++ charts/epi/templates/_configmap-bdns.tpl | 24 ++ charts/epi/templates/_configmap-config.tpl | 94 +++++ charts/epi/templates/_configmap-domains.tpl | 56 +++ .../epi/templates/_configmap-environment.tpl | 89 +++++ charts/epi/templates/_helpers.tpl | 88 +++++ .../epi/templates/configmap-seedsbackup.yaml | 21 ++ charts/epi/templates/configmaps.yaml | 22 ++ charts/epi/templates/deployment.yaml | 183 +++++++++ charts/epi/templates/ingress.yaml | 61 +++ charts/epi/templates/job-cleanup.yaml | 163 ++++++++ charts/epi/templates/job-init.yaml | 315 ++++++++++++++++ charts/epi/templates/pvc.yaml | 34 ++ charts/epi/templates/service.yaml | 19 + charts/epi/templates/serviceaccount.yaml | 12 + .../epi/templates/tests/test-connection.yaml | 15 + charts/epi/values.yaml | 260 +++++++++++++ 21 files changed, 2190 insertions(+) create mode 100644 charts/epi/.helmignore create mode 100644 charts/epi/Chart.yaml create mode 100644 charts/epi/README.md create mode 100644 charts/epi/README.md.gotmpl create mode 100644 charts/epi/templates/NOTES.txt create mode 100644 charts/epi/templates/_configmap-bdns.tpl create mode 100644 charts/epi/templates/_configmap-config.tpl create mode 100644 charts/epi/templates/_configmap-domains.tpl create mode 100644 charts/epi/templates/_configmap-environment.tpl create mode 100644 charts/epi/templates/_helpers.tpl create mode 100644 charts/epi/templates/configmap-seedsbackup.yaml create mode 100644 charts/epi/templates/configmaps.yaml create mode 100644 charts/epi/templates/deployment.yaml create mode 100644 charts/epi/templates/ingress.yaml create mode 100644 charts/epi/templates/job-cleanup.yaml create mode 100644 charts/epi/templates/job-init.yaml create mode 100644 charts/epi/templates/pvc.yaml create mode 100644 charts/epi/templates/service.yaml create mode 100644 charts/epi/templates/serviceaccount.yaml create mode 100644 charts/epi/templates/tests/test-connection.yaml create mode 100644 charts/epi/values.yaml diff --git a/charts/epi/.helmignore b/charts/epi/.helmignore new file mode 100644 index 00000000..446ca364 --- /dev/null +++ b/charts/epi/.helmignore @@ -0,0 +1,24 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ +tests \ No newline at end of file diff --git a/charts/epi/Chart.yaml b/charts/epi/Chart.yaml new file mode 100644 index 00000000..779dc2b1 --- /dev/null +++ b/charts/epi/Chart.yaml @@ -0,0 +1,29 @@ +apiVersion: v2 +name: epi +description: A Helm chart for Pharma Ledger epi (electronic product information) application + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.2.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +appVersion: "poc.1.6" + +icon: https://avatars.githubusercontent.com/u/60230259?s=200&v=4 + +maintainers: + - name: tgip-work + url: https://github.com/tgip-work diff --git a/charts/epi/README.md b/charts/epi/README.md new file mode 100644 index 00000000..9d954316 --- /dev/null +++ b/charts/epi/README.md @@ -0,0 +1,354 @@ +# epi + +![Version: 0.2.0](https://img.shields.io/badge/Version-0.2.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: poc.1.6](https://img.shields.io/badge/AppVersion-poc.1.6-informational?style=flat-square) + +A Helm chart for Pharma Ledger epi (electronic product information) application + +## Requirements + +- [helm 3](https://helm.sh/docs/intro/install/) +- These mandatory configuration values: + - Domain - The Domain - e.g. `epipoc` + - Sub Domain - The Sub Domain - e.g. `epipoc.my-company` + - Vault Domain - The Vault Domain - e.g. `vault.my-company` + - ethadapterUrl - The Full URL of the Ethadapter including protocol and port - e.g. "https://ethadapter.my-company.com:3000" + - bdnsHosts - The Centrally managed and provided BDNS Hosts Config - + +## Usage + +- [Here](./README.md#values) is a full list of all configuration values. +- The [values.yaml file](./values.yaml) shows the raw view of all configuration values. + +## Changelog + +- From 0.1.x to 0.2.x - Technical release: Significant changes! Please uninstall old versions first! Upgrade from 0.1.x not tested and not guaranteed! + - Uses Helm hooks for Init and Cleanup + - Optimized Build process: SeedsBackup will only be created if the underlying Container image has changed, e.g. in case of an upgrade! + - Readiness probe implemented. Application container is considered as *ready* after build process has been finished. + - Value `config.ethadapterUrl` has changed from `https://ethadapter.my-company.com:3000` to `http://ethadapter.ethadapter:3000` in order to reflect changes in [ethadapter](https://github.com/PharmaLedger-IMI/helmchart-ethadapter/tree/epi-improve-build/charts/ethadapter). + - Value `persistence.storageClassName` has changed from `gp2` to empty string `""` in order to remove pre-defined setting for AWS and to be cloud-agnostic by default. + - Configurable sleep time between start of apihub and build process (`config.sleepTime`). + - Configuration options for PersistentVolumeClaim + - Configuration has been prepared for running as non-root user (commented out yet, see [values.yaml `podSecurityContext` and `securityContext`](./values.yaml)). + - Minor optimizations at Kubernetes resources, e.g. set sizeLimit of temporary shared volume, explictly set readOnly flags at volumeMounts. + +## Helm Lifecycle and Kubernetes Resources Lifetime + +This helm chart uses Helm [hooks](https://helm.sh/docs/topics/charts_hooks/) in order to install, upgrade and manage the application and its resources. + +```mermaid +sequenceDiagram + participant PIN as pre-install + participant PUP as pre-upgrade + participant I as install + participant U as uninstall + participant PUN as post-uninstall + Note over PIN,PUN: PersistentVolumeClaim + Note over PIN,PUN: ConfigMap SeedsBackup + Note over PIN:Init Job + Note over PIN:ConfigMaps Init + Note over PIN:ServiceAccount Init + Note over PIN:Role Init + Note over PIN:RoleBinding Init + note right of PIN: Note: The Init Job stores
Seeds in Configmap SeedsBackup and
is either executed by a) pre-install hook or
b)pre-upgrade hook + Note over PUP,U:Deployment + Note over PUP,U:ConfigMap build-info + Note over PUP,U:Configmaps for application + Note over PUP,U:Service + Note over PUP,U:Ingress + Note over PUP,U:ServiceAccount + Note over PUP:Init Job
and more
(see pre-install) + Note over PUN:Cleanup Job + Note over PUN:ServiceAccount Cleanup + Note over PUN:Role Cleanup + Note over PUN:RoleBinding Cleanup + note right of PUN: Note: The Cleanup job
1. deletes PersistentVolumeClaim (optional)
2. creates final backup of ConfigMap SeedsBackup
3. deletes ConfigMap SeedsBackup +``` + +## Init Job + +The Init Job is an important step and will be executed on helm [hooks](https://helm.sh/docs/topics/charts_hooks/) `pre-install` and `pre-upgrade`. +Its pod consists of three containers, two init containers and one main container. + +```mermaid +flowchart LR +A(Init Container 1:
Check necessity for build process) -->B(Init Container 2:
Run build process if necessary) +B --> C(Main Container:
Write/Update ConfigMap Seedsbackup) +``` + +### Init Job Details + +1. On `helm install` and `helm upgrade`, helm will deploy a Kubernete Job named *job-init* which schedules a pod consisting of two Init Containers and one Main Container. + +```mermaid +flowchart LR +A(Helm pre-install/pre-upgrade hook) -->|deploys| B(Init Job) +B -->|schedules| C(Init Pod) +``` + +2. The first Init Container runs `kubectl` command to check existance of ConfigMap `build-info` which contains information about latest successful build process. + 1. If ConfigMap `build-info` does not exist or latest build process does not match current epi application container image, then a *signal* file will be written to a shared volume between containers. + 2. Otherwise the build process has already been executed for current application container image. + +```mermaid +flowchart LR +D(Init Container
Kubectl) --> E{ConfigMap build-info
exists and
matches current
container image?} +E -->|not exists| F[Write signal file to shared data volume] +F --> G[Exit Init Container
Kubectl] +E -->|exists| G +``` + +3. The second Init Container uses the container image of the epi application and checks existance of *Signal* file from first Init Container. +4. If it does not exists, then no build process shall run and the container exists. +5. If the *Signal* file exists, then + 1. Starts the apihub server (`npm run server`), waits for a short period of time and then starts the build process (`npm run build-all`). + 2. After build process, it writes the SeedsBackup file on a shared temporary volume between init and main container. + +```mermaid +flowchart LR +D(Init Container
application) --> E{Signal file exists?} +E -->|yes, exists| F[start apihub server] +F --> G[sleep short time] +G --> H[build process] +H --> I[write SeedsBackup file to shared data with main container] +I --> J +E -->|no, does not exist| J[Exit Init Container
application] +``` + +6. The Main Container has kubectl installed and checks if SeedsBackup file was handed over by Init Container. + +```mermaid +flowchart LR +L(Main Container) --> M{SeedsBackup file exists?} +M -->|exists| N[Create ConfigMap SeedsBackup for current Image] +N --> O[Update ConfigMap SeedsBackup] +O --> P +M -->|not exists| P[Exit Pod] +``` + +After completion of the *Init Job* the application container will be deployed/restarted with the current *ConfigMap SeedsBackup*. + +## Cleanup Job + +On deletion/uninstall of the helm chart a Kubernetes `cleanup` will be deployed in order to delete unmanaged helm resources created by helm hooks at `pre-install`. +These resources are: + +1. Init Job - The Init Job was created on pre-install/pre-upgrade and will remain after its execution. +2. PersistentVolumeClaim - In case the PersistentVolumeClaim shall not be deleted on deletion of the helm release, set `persistence.deletePvcOnUninstall` to `false`. +3. ConfigMap SeedsBackup - Prior to deletion of the ConfigMap, a backup ConfigMap will be created with naming schema `{HELM_RELEASE_NAME}-seedsbackup-{IMAGE_TAG}-final-backup-{EPOCH_IN_SECONDS}`, e.g. `epi-seedsbackup-poc.1.6-final-backup-1646063552` + +### Quick install with internal service of type ClusterIP + +By default, this helm chart installs the Ethereum Adapter Service at an internal ClusterIP Service listening at port 3000. +This is to prevent exposing the service to the internet by accident! + +It is recommended to put non-sensitive configuration values in an configuration file and pass sensitive/secret values via commandline. + +1. Create configuration file, e.g. *my-config.yaml* + + ```yaml + config: + domain: "domain_value" + subDomain: "subDomain_value" + vaultDomain: "vaultDomain_value" + ethadapterUrl: "https://ethadapter.my-company.com:3000" + bdnsHosts: |- + # ... content of the BDNS Hosts file ... + + ``` + +2. Install via helm to namespace `default` + + ```bash + helm upgrade my-release-name pharmaledger-imi/epi --version=0.2.0 \ + --install \ + --values my-config.yaml \ + ``` + +### Expose Service via Load Balancer + +In order to expose the service **directly** by an **own dedicated** Load Balancer, just **add** `service.type` with value `LoadBalancer` to your config file (in order to override the default value which is `ClusterIP`). + +**Please note:** At AWS using `service.type` = `LoadBalancer` is not recommended any more, as it creates a Classic Load Balancer. Use [AWS Load Balancer Controller](https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.3/) with an ingress instead. A full sample is provided later in the docs. Using an Application Load Balancer (managed by AWS LB Controller) increases security (e.g. by using a Web Application Firewall for your http based traffic) and provides more features like hostname, pathname routing or built-in authentication mechanism via OIDC or AWS Cognito. + +Configuration file *my-config.yaml* + +```yaml +service: + type: LoadBalancer + +config: + # ... config section keys and values ... +``` + +There are more configuration options available like customizing the port and configuring the Load Balancer via annotations (e.g. for configuring SSL Listener). + +**Also note:** Annotations are very specific to your environment/cloud provider, see [Kubernetes Service Reference](https://kubernetes.io/docs/concepts/services-networking/service/#ssl-support-on-aws) for more information. For Azure, take a look [here](https://kubernetes-sigs.github.io/cloud-provider-azure/topics/loadbalancer/#loadbalancer-annotations). + +Sample for AWS (SSL and listening on port 1234 instead 80 which is the default): + +```yaml +service: + type: LoadBalancer + port: 80 + annotations: + service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012 + service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http + service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "80" + # https://docs.aws.amazon.com/de_de/elasticloadbalancing/latest/classic/elb-security-policy-table.html + service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy: "ELBSecurityPolicy-TLS-1-2-2017-01" + +# further config +``` + +### AWS Load Balancer Controler: Expose Service via Ingress + +Note: You need the [AWS Load Balancer Controller](https://kubernetes-sigs.github.io/aws-load-balancer-controller/) installed and configured properly. + +1. Enable ingress +2. Add *host*, *path* *`/*`* and *pathType* `ImplementationSpecific` +3. Add annotations for AWS LB Controller +4. A SSL certificate at AWS Certificate Manager (either for the hostname, here `epi.mydomain.com` or wildcard `*.mydomain.com`) + +Configuration file *my-config.yaml* + +```yaml +ingress: + enabled: true + # Let AWS LB Controller handle the ingress (default className is alb) + # Note: Use className instead of annotation 'kubernetes.io/ingress.class' which is deprecated since 1.18 + # For Kubernetes >= 1.18 it is required to have an existing IngressClass object. + # See: https://kubernetes.io/docs/concepts/services-networking/ingress/#deprecated-annotation + className: alb + hosts: + - host: epi.mydomain.com + # Path must be /* for ALB to match all paths + paths: + - path: /* + pathType: ImplementationSpecific + # For full list of annotations for AWS LB Controller, see https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.3/guide/ingress/annotations/ + annotations: + # The ARN of the existing SSL Certificate at AWS Certificate Manager + alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:REGION:ACCOUNT_ID:certificate/CERTIFICATE_ID + # The name of the ALB group, can be used to configure a single ALB by multiple ingress objects + alb.ingress.kubernetes.io/group.name: default + # Specifies the HTTP path when performing health check on targets. + alb.ingress.kubernetes.io/healthcheck-path: / + # Specifies the port used when performing health check on targets. + alb.ingress.kubernetes.io/healthcheck-port: traffic-port + # Specifies the HTTP status code that should be expected when doing health checks against the specified health check path. + alb.ingress.kubernetes.io/success-codes: "200" + # Listen on HTTPS protocol at port 443 at the ALB + alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]' + # Use internet facing + alb.ingress.kubernetes.io/scheme: internet-facing + # Use most current (as of Dec 2021) encryption ciphers + alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS-1-2-Ext-2018-06 + # Use target type IP which is the case if the service type is ClusterIP + alb.ingress.kubernetes.io/target-type: ip + +config: + # ... config section keys and values ... +``` + +### Additional helm options + +Run `helm upgrade --helm` for full list of options. + +1. Install to other namespace + + You can install into other namespace than `default` by setting the `--namespace` parameter, e.g. + + ```bash + helm upgrade my-release-name pharmaledger-imi/epi --version=0.2.0 \ + --install \ + --namespace=my-namespace \ + --values my-config.yaml \ + ``` + +2. Wait until installation has finished successfully and the deployment is up and running. + + Provide the `--wait` argument and time to wait (default is 5 minutes) via `--timeout` + + ```bash + helm upgrade my-release-name pharmaledger-imi/epi --version=0.2.0 \ + --install \ + --wait --timeout=600s \ + --values my-config.yaml \ + ``` + +### Potential issues + +1. `Error: admission webhook "vingress.elbv2.k8s.aws" denied the request: invalid ingress class: IngressClass.networking.k8s.io "alb" not found` + + **Description:** This error only applies to Kubernetes >= 1.18 and indicates that no matching *IngressClass* object was found. + + **Solution:** Either declare an appropriate IngressClass or omit *className* and add annotation `kubernetes.io/ingress.class` + + Further information: + + - [Kubernetes IngressClass](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class) + - [AWS Load Balancer controller documentation](https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.3/guide/ingress/ingress_class/) + +## Helm Unittesting + +[helm-unittest](https://github.com/quintush/helm-unittest) is being used for testing the output of the helm chart. +Tests can be found in [tests](./tests) + +## Maintainers + +| Name | Email | Url | +| ---- | ------ | --- | +| tgip-work | | https://github.com/tgip-work | + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | Affinity for scheduling a pod. See [https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/) | +| config | object | `{"bdnsHosts":"{\n \"epipoc\": {\n \"anchoringServices\": [\n \"$ORIGIN\"\n ],\n \"notifications\": [\n \"$ORIGIN\"\n ]\n },\n \"epipoc.my-company\": {\n \"brickStorages\": [\n \"$ORIGIN\"\n ],\n \"anchoringServices\": [\n \"$ORIGIN\"\n ],\n \"notifications\": [\n \"$ORIGIN\"\n ]\n },\n \"epipoc.other\": {\n \"brickStorages\": [\n \"https://epipoc.other-company.com\"\n ],\n \"anchoringServices\": [\n \"https://epipoc.other-company.com\"\n ],\n \"notifications\": [\n \"https://epipoc.other-company.com\"\n ]\n },\n \"vault.my-company\": {\n \"replicas\": [],\n \"brickStorages\": [\n \"$ORIGIN\"\n ],\n \"anchoringServices\": [\n \"$ORIGIN\"\n ],\n \"notifications\": [\n \"$ORIGIN\"\n ]\n }\n}","domain":"epipoc","ethadapterUrl":"http://ethadapter.ethadapter:3000","sleepTime":"10s","subDomain":"epipoc.my-company","vaultDomain":"vault.my-company"}` | Configuration. Will be put in ConfigMaps. | +| config.bdnsHosts | string | `"{\n \"epipoc\": {\n \"anchoringServices\": [\n \"$ORIGIN\"\n ],\n \"notifications\": [\n \"$ORIGIN\"\n ]\n },\n \"epipoc.my-company\": {\n \"brickStorages\": [\n \"$ORIGIN\"\n ],\n \"anchoringServices\": [\n \"$ORIGIN\"\n ],\n \"notifications\": [\n \"$ORIGIN\"\n ]\n },\n \"epipoc.other\": {\n \"brickStorages\": [\n \"https://epipoc.other-company.com\"\n ],\n \"anchoringServices\": [\n \"https://epipoc.other-company.com\"\n ],\n \"notifications\": [\n \"https://epipoc.other-company.com\"\n ]\n },\n \"vault.my-company\": {\n \"replicas\": [],\n \"brickStorages\": [\n \"$ORIGIN\"\n ],\n \"anchoringServices\": [\n \"$ORIGIN\"\n ],\n \"notifications\": [\n \"$ORIGIN\"\n ]\n }\n}"` | Centrally managed and provided BDNS Hosts Config | +| config.domain | string | `"epipoc"` | The Domain, e.g. "epipoc" | +| config.ethadapterUrl | string | `"http://ethadapter.ethadapter:3000"` | The Full URL of the Ethadapter including protocol and port, e.g. "https://ethadapter.my-company.com:3000" | +| config.subDomain | string | `"epipoc.my-company"` | The Subdomain, should be domain.company, e.g. epipoc.my-company | +| config.vaultDomain | string | `"vault.my-company"` | The Vault domain, should be vault.company, e.g. vault.my-company | +| deploymentStrategy.type | string | `"Recreate"` | | +| fullnameOverride | string | `""` | fullnameOverride completely replaces the generated name. From [https://stackoverflow.com/questions/63838705/what-is-the-difference-between-fullnameoverride-and-nameoverride-in-helm](https://stackoverflow.com/questions/63838705/what-is-the-difference-between-fullnameoverride-and-nameoverride-in-helm) | +| image.pullPolicy | string | `"IfNotPresent"` | Image Pull Policy | +| image.repository | string | `"public.ecr.aws/n4q1q0z2/pharmaledger-epi"` | The repository of the container image | +| image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | +| imagePullSecrets | list | `[]` | Secret(s) for pulling an container image from a private registry. See [https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/) | +| ingress.annotations | object | `{}` | Ingress annotations. For AWS LB Controller, see [https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.3/guide/ingress/annotations/](https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.3/guide/ingress/annotations/) For Azure Application Gateway Ingress Controller, see [https://azure.github.io/application-gateway-kubernetes-ingress/annotations/](https://azure.github.io/application-gateway-kubernetes-ingress/annotations/) For NGINX Ingress Controller, see [https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/) For Traefik Ingress Controller, see [https://doc.traefik.io/traefik/routing/providers/kubernetes-ingress/#annotations](https://doc.traefik.io/traefik/routing/providers/kubernetes-ingress/#annotations) | +| ingress.className | string | `""` | The className specifies the IngressClass object which is responsible for that class. Note for Kubernetes >= 1.18 it is required to have an existing IngressClass object. If IngressClass object does not exists, omit className and add the deprecated annotation 'kubernetes.io/ingress.class' instead. For Kubernetes < 1.18 either use className or annotation 'kubernetes.io/ingress.class'. See https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class | +| ingress.enabled | bool | `false` | Whether to create ingress or not. Note: For ingress an Ingress Controller (e.g. AWS LB Controller, NGINX Ingress Controller, Traefik, ...) is required and service.type should be ClusterIP or NodePort depending on your configuration | +| ingress.hosts[0].host | string | `"epi.some-pharma-company.com"` | The FQDN/hostname | +| ingress.hosts[0].paths[0].path | string | `"/"` | The Ingress Path. See [https://kubernetes.io/docs/concepts/services-networking/ingress/#examples](https://kubernetes.io/docs/concepts/services-networking/ingress/#examples) Note: For Ingress Controllers like AWS LB Controller see their specific documentation. | +| ingress.hosts[0].paths[0].pathType | string | `"ImplementationSpecific"` | The type of path. This value is required since Kubernetes 1.18. For Ingress Controllers like AWS LB Controller or Traefik it is usually required to set its value to ImplementationSpecific See [https://kubernetes.io/docs/concepts/services-networking/ingress/#path-types](https://kubernetes.io/docs/concepts/services-networking/ingress/#path-types) and [https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/](https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/) | +| ingress.tls | list | `[]` | | +| kubectl | object | `{"image":{"pullPolicy":"IfNotPresent","repository":"bitnami/kubectl","tag":"1.21.8"}}` | Settings for Container with kubectl installed used by Init and Cleanup Job | +| kubectl.image.pullPolicy | string | `"IfNotPresent"` | Image Pull Policy | +| kubectl.image.repository | string | `"bitnami/kubectl"` | The repository of the container image containing kubectl | +| kubectl.image.tag | string | `"1.21.8"` | The Tag of the image containing kubectl. Minor Version should match to your Kubernetes Cluster Version. | +| livenessProbe | object | `{"failureThreshold":3,"httpGet":{"path":"/","port":"http"},"initialDelaySeconds":10,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":1}` | Liveness probe. See [https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) | +| nameOverride | string | `""` | nameOverride replaces the name of the chart in the Chart.yaml file, when this is used to construct Kubernetes object names. From [https://stackoverflow.com/questions/63838705/what-is-the-difference-between-fullnameoverride-and-nameoverride-in-helm](https://stackoverflow.com/questions/63838705/what-is-the-difference-between-fullnameoverride-and-nameoverride-in-helm) | +| nodeSelector | object | `{}` | Node Selectors in order to assign pods to certain nodes. See [https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/) | +| persistence | object | `{"accessModes":["ReadWriteOnce"],"deletePvcOnUninstall":true,"finalizers":["kubernetes.io/pvc-protection"],"size":"20Gi","storageClassName":""}` | Enable persistence using Persistent Volume Claims See [http://kubernetes.io/docs/user-guide/persistent-volumes/](http://kubernetes.io/docs/user-guide/persistent-volumes/) | +| persistence.deletePvcOnUninstall | bool | `true` | Boolean flag whether to delete the persistent volume on uninstall or not. | +| persistence.size | string | `"20Gi"` | Size of the volume | +| persistence.storageClassName | string | `""` | Name of the storage class. If empty or not set then storage class will not be set - which means that the default storage class will be used. | +| podAnnotations | object | `{}` | Annotations added to the pod | +| podSecurityContext | object | `{}` | Security Context for the pod. IMPORTANT: Take a look at README.md for configuration for non-root user! See [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod) For running as non-root with uid 1000, remove {} from next line and uncomment fsGroup and runAsUser! | +| readinessProbe | object | `{"exec":{"command":["cat","/ePI-workspace/apihub-root/ready"]},"failureThreshold":60,"initialDelaySeconds":30,"periodSeconds":5,"successThreshold":1}` | Readiness probe. See [https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) | +| replicaCount | int | `1` | The number of replicas if autoscaling is false | +| resources | object | `{}` | Resource constraints for the container | +| securityContext | object | `{}` | | +| service.annotations | object | `{}` | Annotations for the service. See AWS, see [https://kubernetes.io/docs/concepts/services-networking/service/#ssl-support-on-aws](https://kubernetes.io/docs/concepts/services-networking/service/#ssl-support-on-aws) For Azure, see [https://kubernetes-sigs.github.io/cloud-provider-azure/topics/loadbalancer/#loadbalancer-annotations](https://kubernetes-sigs.github.io/cloud-provider-azure/topics/loadbalancer/#loadbalancer-annotations) | +| service.port | int | `80` | Port where the service will be exposed | +| service.type | string | `"ClusterIP"` | Either ClusterIP, NodePort or LoadBalancer. See [https://kubernetes.io/docs/concepts/services-networking/service/](https://kubernetes.io/docs/concepts/services-networking/service/) | +| serviceAccount.annotations | object | `{}` | Annotations to add to the service account | +| serviceAccount.create | bool | `false` | Specifies whether a service account should be created | +| serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | +| tolerations | list | `[]` | Tolerations for scheduling a pod. See [https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.5.0](https://github.com/norwoodj/helm-docs/releases/v1.5.0) diff --git a/charts/epi/README.md.gotmpl b/charts/epi/README.md.gotmpl new file mode 100644 index 00000000..0bf908a1 --- /dev/null +++ b/charts/epi/README.md.gotmpl @@ -0,0 +1,305 @@ +{{ template "chart.header" . }} + +{{ template "chart.versionBadge" . }}{{ template "chart.typeBadge" . }}{{ template "chart.appVersionBadge" . }} + +{{ template "chart.description" . }} + +## Requirements + +- [helm 3](https://helm.sh/docs/intro/install/) +- These mandatory configuration values: + - Domain - The Domain - e.g. `epipoc` + - Sub Domain - The Sub Domain - e.g. `epipoc.my-company` + - Vault Domain - The Vault Domain - e.g. `vault.my-company` + - ethadapterUrl - The Full URL of the Ethadapter including protocol and port - e.g. "https://ethadapter.my-company.com:3000" + - bdnsHosts - The Centrally managed and provided BDNS Hosts Config - + +## Usage + +- [Here](./README.md#values) is a full list of all configuration values. +- The [values.yaml file](./values.yaml) shows the raw view of all configuration values. + +## Changelog + +- From 0.1.x to 0.2.x - Technical release: Significant changes! Please uninstall old versions first! Upgrade from 0.1.x not tested and not guaranteed! + - Uses Helm hooks for Init and Cleanup + - Optimized Build process: SeedsBackup will only be created if the underlying Container image has changed, e.g. in case of an upgrade! + - Readiness probe implemented. Application container is considered as *ready* after build process has been finished. + - Value `config.ethadapterUrl` has changed from `https://ethadapter.my-company.com:3000` to `http://ethadapter.ethadapter:3000` in order to reflect changes in [ethadapter](https://github.com/PharmaLedger-IMI/helmchart-ethadapter/tree/epi-improve-build/charts/ethadapter). + - Value `persistence.storageClassName` has changed from `gp2` to empty string `""` in order to remove pre-defined setting for AWS and to be cloud-agnostic by default. + - Configurable sleep time between start of apihub and build process (`config.sleepTime`). + - Configuration options for PersistentVolumeClaim + - Configuration has been prepared for running as non-root user (commented out yet, see [values.yaml `podSecurityContext` and `securityContext`](./values.yaml)). + - Minor optimizations at Kubernetes resources, e.g. set sizeLimit of temporary shared volume, explictly set readOnly flags at volumeMounts. + +## Helm Lifecycle and Kubernetes Resources Lifetime + +This helm chart uses Helm [hooks](https://helm.sh/docs/topics/charts_hooks/) in order to install, upgrade and manage the application and its resources. + +```mermaid +sequenceDiagram + participant PIN as pre-install + participant PUP as pre-upgrade + participant I as install + participant U as uninstall + participant PUN as post-uninstall + Note over PIN,PUN: PersistentVolumeClaim + Note over PIN,PUN: ConfigMap SeedsBackup + Note over PIN:Init Job + Note over PIN:ConfigMaps Init + Note over PIN:ServiceAccount Init + Note over PIN:Role Init + Note over PIN:RoleBinding Init + note right of PIN: Note: The Init Job stores
Seeds in Configmap SeedsBackup and
is either executed by a) pre-install hook or
b)pre-upgrade hook + Note over PUP,U:Deployment + Note over PUP,U:ConfigMap build-info + Note over PUP,U:Configmaps for application + Note over PUP,U:Service + Note over PUP,U:Ingress + Note over PUP,U:ServiceAccount + Note over PUP:Init Job
and more
(see pre-install) + Note over PUN:Cleanup Job + Note over PUN:ServiceAccount Cleanup + Note over PUN:Role Cleanup + Note over PUN:RoleBinding Cleanup + note right of PUN: Note: The Cleanup job
1. deletes PersistentVolumeClaim (optional)
2. creates final backup of ConfigMap SeedsBackup
3. deletes ConfigMap SeedsBackup +``` + +## Init Job + +The Init Job is an important step and will be executed on helm [hooks](https://helm.sh/docs/topics/charts_hooks/) `pre-install` and `pre-upgrade`. +Its pod consists of three containers, two init containers and one main container. + +```mermaid +flowchart LR +A(Init Container 1:
Check necessity for build process) -->B(Init Container 2:
Run build process if necessary) +B --> C(Main Container:
Write/Update ConfigMap Seedsbackup) +``` + +### Init Job Details + +1. On `helm install` and `helm upgrade`, helm will deploy a Kubernete Job named *job-init* which schedules a pod consisting of two Init Containers and one Main Container. + +```mermaid +flowchart LR +A(Helm pre-install/pre-upgrade hook) -->|deploys| B(Init Job) +B -->|schedules| C(Init Pod) +``` + +2. The first Init Container runs `kubectl` command to check existance of ConfigMap `build-info` which contains information about latest successful build process. + 1. If ConfigMap `build-info` does not exist or latest build process does not match current epi application container image, then a *signal* file will be written to a shared volume between containers. + 2. Otherwise the build process has already been executed for current application container image. + +```mermaid +flowchart LR +D(Init Container
Kubectl) --> E{ConfigMap build-info
exists and
matches current
container image?} +E -->|not exists| F[Write signal file to shared data volume] +F --> G[Exit Init Container
Kubectl] +E -->|exists| G +``` + +3. The second Init Container uses the container image of the epi application and checks existance of *Signal* file from first Init Container. +4. If it does not exists, then no build process shall run and the container exists. +5. If the *Signal* file exists, then + 1. Starts the apihub server (`npm run server`), waits for a short period of time and then starts the build process (`npm run build-all`). + 2. After build process, it writes the SeedsBackup file on a shared temporary volume between init and main container. + +```mermaid +flowchart LR +D(Init Container
application) --> E{Signal file exists?} +E -->|yes, exists| F[start apihub server] +F --> G[sleep short time] +G --> H[build process] +H --> I[write SeedsBackup file to shared data with main container] +I --> J +E -->|no, does not exist| J[Exit Init Container
application] +``` + +6. The Main Container has kubectl installed and checks if SeedsBackup file was handed over by Init Container. + +```mermaid +flowchart LR +L(Main Container) --> M{SeedsBackup file exists?} +M -->|exists| N[Create ConfigMap SeedsBackup for current Image] +N --> O[Update ConfigMap SeedsBackup] +O --> P +M -->|not exists| P[Exit Pod] +``` + +After completion of the *Init Job* the application container will be deployed/restarted with the current *ConfigMap SeedsBackup*. + +## Cleanup Job + +On deletion/uninstall of the helm chart a Kubernetes `cleanup` will be deployed in order to delete unmanaged helm resources created by helm hooks at `pre-install`. +These resources are: + +1. Init Job - The Init Job was created on pre-install/pre-upgrade and will remain after its execution. +2. PersistentVolumeClaim - In case the PersistentVolumeClaim shall not be deleted on deletion of the helm release, set `persistence.deletePvcOnUninstall` to `false`. +3. ConfigMap SeedsBackup - Prior to deletion of the ConfigMap, a backup ConfigMap will be created with naming schema `{HELM_RELEASE_NAME}-seedsbackup-{IMAGE_TAG}-final-backup-{EPOCH_IN_SECONDS}`, e.g. `epi-seedsbackup-poc.1.6-final-backup-1646063552` + +### Quick install with internal service of type ClusterIP + +By default, this helm chart installs the Ethereum Adapter Service at an internal ClusterIP Service listening at port 3000. +This is to prevent exposing the service to the internet by accident! + +It is recommended to put non-sensitive configuration values in an configuration file and pass sensitive/secret values via commandline. + +1. Create configuration file, e.g. *my-config.yaml* + + ```yaml + config: + domain: "domain_value" + subDomain: "subDomain_value" + vaultDomain: "vaultDomain_value" + ethadapterUrl: "https://ethadapter.my-company.com:3000" + bdnsHosts: |- + # ... content of the BDNS Hosts file ... + + ``` + +2. Install via helm to namespace `default` + + ```bash + helm upgrade my-release-name pharmaledger-imi/epi --version={{ template "chart.version" . }} \ + --install \ + --values my-config.yaml \ + ``` + +### Expose Service via Load Balancer + +In order to expose the service **directly** by an **own dedicated** Load Balancer, just **add** `service.type` with value `LoadBalancer` to your config file (in order to override the default value which is `ClusterIP`). + +**Please note:** At AWS using `service.type` = `LoadBalancer` is not recommended any more, as it creates a Classic Load Balancer. Use [AWS Load Balancer Controller](https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.3/) with an ingress instead. A full sample is provided later in the docs. Using an Application Load Balancer (managed by AWS LB Controller) increases security (e.g. by using a Web Application Firewall for your http based traffic) and provides more features like hostname, pathname routing or built-in authentication mechanism via OIDC or AWS Cognito. + +Configuration file *my-config.yaml* + +```yaml +service: + type: LoadBalancer + +config: + # ... config section keys and values ... +``` + +There are more configuration options available like customizing the port and configuring the Load Balancer via annotations (e.g. for configuring SSL Listener). + +**Also note:** Annotations are very specific to your environment/cloud provider, see [Kubernetes Service Reference](https://kubernetes.io/docs/concepts/services-networking/service/#ssl-support-on-aws) for more information. For Azure, take a look [here](https://kubernetes-sigs.github.io/cloud-provider-azure/topics/loadbalancer/#loadbalancer-annotations). + +Sample for AWS (SSL and listening on port 1234 instead 80 which is the default): + +```yaml +service: + type: LoadBalancer + port: 80 + annotations: + service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012 + service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http + service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "80" + # https://docs.aws.amazon.com/de_de/elasticloadbalancing/latest/classic/elb-security-policy-table.html + service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy: "ELBSecurityPolicy-TLS-1-2-2017-01" + +# further config +``` + +### AWS Load Balancer Controler: Expose Service via Ingress + +Note: You need the [AWS Load Balancer Controller](https://kubernetes-sigs.github.io/aws-load-balancer-controller/) installed and configured properly. + +1. Enable ingress +2. Add *host*, *path* *`/*`* and *pathType* `ImplementationSpecific` +3. Add annotations for AWS LB Controller +4. A SSL certificate at AWS Certificate Manager (either for the hostname, here `epi.mydomain.com` or wildcard `*.mydomain.com`) + +Configuration file *my-config.yaml* + +```yaml +ingress: + enabled: true + # Let AWS LB Controller handle the ingress (default className is alb) + # Note: Use className instead of annotation 'kubernetes.io/ingress.class' which is deprecated since 1.18 + # For Kubernetes >= 1.18 it is required to have an existing IngressClass object. + # See: https://kubernetes.io/docs/concepts/services-networking/ingress/#deprecated-annotation + className: alb + hosts: + - host: epi.mydomain.com + # Path must be /* for ALB to match all paths + paths: + - path: /* + pathType: ImplementationSpecific + # For full list of annotations for AWS LB Controller, see https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.3/guide/ingress/annotations/ + annotations: + # The ARN of the existing SSL Certificate at AWS Certificate Manager + alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:REGION:ACCOUNT_ID:certificate/CERTIFICATE_ID + # The name of the ALB group, can be used to configure a single ALB by multiple ingress objects + alb.ingress.kubernetes.io/group.name: default + # Specifies the HTTP path when performing health check on targets. + alb.ingress.kubernetes.io/healthcheck-path: / + # Specifies the port used when performing health check on targets. + alb.ingress.kubernetes.io/healthcheck-port: traffic-port + # Specifies the HTTP status code that should be expected when doing health checks against the specified health check path. + alb.ingress.kubernetes.io/success-codes: "200" + # Listen on HTTPS protocol at port 443 at the ALB + alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]' + # Use internet facing + alb.ingress.kubernetes.io/scheme: internet-facing + # Use most current (as of Dec 2021) encryption ciphers + alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS-1-2-Ext-2018-06 + # Use target type IP which is the case if the service type is ClusterIP + alb.ingress.kubernetes.io/target-type: ip + +config: + # ... config section keys and values ... +``` + +### Additional helm options + +Run `helm upgrade --helm` for full list of options. + +1. Install to other namespace + + You can install into other namespace than `default` by setting the `--namespace` parameter, e.g. + + ```bash + helm upgrade my-release-name pharmaledger-imi/epi --version={{ template "chart.version" . }} \ + --install \ + --namespace=my-namespace \ + --values my-config.yaml \ + ``` + +2. Wait until installation has finished successfully and the deployment is up and running. + + Provide the `--wait` argument and time to wait (default is 5 minutes) via `--timeout` + + ```bash + helm upgrade my-release-name pharmaledger-imi/epi --version={{ template "chart.version" . }} \ + --install \ + --wait --timeout=600s \ + --values my-config.yaml \ + ``` + +### Potential issues + +1. `Error: admission webhook "vingress.elbv2.k8s.aws" denied the request: invalid ingress class: IngressClass.networking.k8s.io "alb" not found` + + **Description:** This error only applies to Kubernetes >= 1.18 and indicates that no matching *IngressClass* object was found. + + **Solution:** Either declare an appropriate IngressClass or omit *className* and add annotation `kubernetes.io/ingress.class` + + Further information: + + - [Kubernetes IngressClass](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class) + - [AWS Load Balancer controller documentation](https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.3/guide/ingress/ingress_class/) + +## Helm Unittesting + +[helm-unittest](https://github.com/quintush/helm-unittest) is being used for testing the output of the helm chart. +Tests can be found in [tests](./tests) + + +{{ template "chart.maintainersSection" . }} + +{{ template "chart.requirementsSection" . }} + +{{ template "chart.valuesSection" . }} + +{{ template "helm-docs.versionFooter" . }} diff --git a/charts/epi/templates/NOTES.txt b/charts/epi/templates/NOTES.txt new file mode 100644 index 00000000..592053e0 --- /dev/null +++ b/charts/epi/templates/NOTES.txt @@ -0,0 +1,22 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "epi.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "epi.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "epi.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "epi.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/charts/epi/templates/_configmap-bdns.tpl b/charts/epi/templates/_configmap-bdns.tpl new file mode 100644 index 00000000..ecf3bc63 --- /dev/null +++ b/charts/epi/templates/_configmap-bdns.tpl @@ -0,0 +1,24 @@ +{{- /* +Template for Configmap. Arguments to be passed are $ . suffix and an dictionary for annotations used for defining helm hooks. +See https://blog.flant.com/advanced-helm-templating/ +*/}} +{{- define "epi.configmap-bdns" -}} +{{- $ := index . 0 }} +{{- $suffix := index . 2 }} +{{- $annotations := index . 3 }} + {{- with index . 1 }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "epi.fullname" . }}-bdns{{ $suffix | default "" }} + {{- with $annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + {{- include "epi.labels" . | nindent 4 }} +data: + bdns.hosts: |- +{{ required "config.bdnsHosts must be set" .Values.config.bdnsHosts | indent 4 }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/epi/templates/_configmap-config.tpl b/charts/epi/templates/_configmap-config.tpl new file mode 100644 index 00000000..fc30a632 --- /dev/null +++ b/charts/epi/templates/_configmap-config.tpl @@ -0,0 +1,94 @@ +{{- /* +Template for Configmap. Arguments to be passed are $ . suffix and an dictionary for annotations used for defining helm hooks. +See https://blog.flant.com/advanced-helm-templating/ +*/}} +{{- define "epi.configmap-config" -}} +{{- $ := index . 0 }} +{{- $suffix := index . 2 }} +{{- $annotations := index . 3 }} +{{- with index . 1 }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "epi.fullname" . }}-config{{ $suffix | default "" }} + {{- with $annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + {{- include "epi.labels" . | nindent 4 }} +data: + env.json: | + { + "PSK_TMP_WORKING_DIR": "tmp", + "PSK_CONFIG_LOCATION": "../apihub-root/external-volume/config", + "SSAPPS_FAVORITE_EDFS_ENDPOINT": "http://localhost:8080", + "IS_PRODUCTION_BUILD": true, + "VAULT_DOMAIN": {{ required "config.vaultDomain must be set" .Values.config.vaultDomain | quote}} + } + + apihub.json: |- + { + "storage": "../apihub-root", + "port": 8080, + "preventRateLimit": true, + "activeComponents": [ + "virtualMQ", + "messaging", + "notifications", + "filesManager", + "bdns", + "bricksLedger", + "bricksFabric", + "bricking", + "anchoring", + "dsu-wizard", + "gtin-dsu-wizard", + "epi-mapping-engine", + "epi-mapping-engine-results", + "debugLogger", + "mq", + "staticServer" + ], + "componentsConfig": { + "epi-mapping-engine": { + "module": "./../../epi-utils", + "function": "getEPIMappingEngineForAPIHUB" + }, + "epi-mapping-engine-results": { + "module": "./../../epi-utils", + "function": "getEPIMappingEngineMessageResults" + }, + "gtin-dsu-wizard": { + "module": "./../../gtin-dsu-wizard" + }, + "bricking": {}, + "anchoring": {} + }, + "enableRequestLogger": true, + "enableJWTAuthorisation": false, + "enableLocalhostAuthorization": false, + "skipJWTAuthorisation": [ + "/assets", + "/leaflet-wallet", + "/dsu-fabric-wallet", + "/directory-summary", + "/resources", + "/bdns", + "/anchor/epi", + "/anchor/default", + "/anchor/vault", + "/bricking", + "/bricksFabric", + "/bricksledger", + "/create-channel", + "/forward-zeromq", + "/send-message", + "/receive-message", + "/files", + "/notifications", + "/mq" + ] + } +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/epi/templates/_configmap-domains.tpl b/charts/epi/templates/_configmap-domains.tpl new file mode 100644 index 00000000..43b3dd41 --- /dev/null +++ b/charts/epi/templates/_configmap-domains.tpl @@ -0,0 +1,56 @@ +{{- /* +Template for Configmap. Arguments to be passed are $ . suffix and an dictionary for annotations used for defining helm hooks. +See https://blog.flant.com/advanced-helm-templating/ +*/}} +{{- define "epi.configmap-domains" -}} +{{- $ := index . 0 }} +{{- $suffix := index . 2 }} +{{- $annotations := index . 3 }} +{{- with index . 1 }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "epi.fullname" . }}-domains{{ $suffix | default "" }} + {{- with $annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + {{- include "epi.labels" . | nindent 4 }} +data: + {{ required "config.domain must be set" .Values.config.domain }}.json: |- + { + "anchoring": { + "type": "ETH", + "option": { + "endpoint": {{ required "config.ethadapterUrl must be set" .Values.config.ethadapterUrl | quote }} + } + }, + "messagesEndpoint": "http://localhost:8080/mappingEngine/{{ required "config.domain must be set" .Values.config.domain }}/{{ required "config.subDomain must be set" .Values.config.subDomain }}/saveResult", + "enable": ["mq", "enclave"] + } + + {{ required "config.subDomain must be set" .Values.config.subDomain }}.json: |- + { + "anchoring": { + "type": "ETH", + "option": { + "endpoint": {{ required "config.ethadapterUrl must be set" .Values.config.ethadapterUrl | quote }} + } + }, + "enable": ["mq", "enclave"] + } + + {{ required "config.vaultDomain must be set" .Values.config.vaultDomain }}.json: |- + { + "anchoring": { + "type": "FS", + "option": { + "enableBricksLedger": false + } + }, + "enable": ["mq", "enclave"] + } + +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/epi/templates/_configmap-environment.tpl b/charts/epi/templates/_configmap-environment.tpl new file mode 100644 index 00000000..3ce7d748 --- /dev/null +++ b/charts/epi/templates/_configmap-environment.tpl @@ -0,0 +1,89 @@ +{{- /* +Template for Configmap. Arguments to be passed are $ . suffix and an dictionary for annotations used for defining helm hooks. +See https://blog.flant.com/advanced-helm-templating/ +*/}} +{{- define "epi.configmap-environment" -}} +{{- $ := index . 0 }} +{{- $suffix := index . 2 }} +{{- $annotations := index . 3 }} +{{- with index . 1 }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "epi.fullname" . }}-environment{{ $suffix | default "" }} + {{- with $annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + {{- include "epi.labels" . | nindent 4 }} +data: + demiurge-environment.js: |- + export default { + "appName": "Demiurge", + "vault": "server", + "agent": "browser", + "system": "any", + "browser": "any", + "mode": "dev-secure", + "vaultDomain": {{ required "config.vaultDomain must be set" .Values.config.vaultDomain | quote}}, + "didDomain": {{ required "config.vaultDomain must be set" .Values.config.vaultDomain | quote}}, + "enclaveType":"WalletDBEnclave", + "sw": false, + "pwa": false, + "legenda for properties": " vault:(server, browser) agent:(mobile, browser) system:(iOS, Android, any) browser:(Chrome, Firefox, any) mode:(autologin,dev-autologin, secure, dev-secure) sw:(true, false) pwa:(true, false)" + } + dsu-explorer-environment.js: |- + export default { + "appName": "DSU Explorer", + "vault": "server", + "agent": "browser", + "system": "any", + "browser": "any", + "mode": "dev-autologin", + "vaultDomain": {{ required "config.vaultDomain must be set" .Values.config.vaultDomain | quote}}, + "didDomain": {{ required "config.vaultDomain must be set" .Values.config.vaultDomain | quote}}, + "enclaveType": "WalletDBEnclave", + "sw": true, + "pwa": false, + "allowPinLogin": false, + "legenda for properties": " vault:(server, browser) agent:(mobile, browser) system:(iOS, Android, any) browser:(Chrome, Firefox, any) stage:(development, release) sw:(true, false) pwa:(true, false)" + } + dsu-fabric-environment.js: |- + export default { + "appName": "DSU_Fabric", + "vault": "server", + "agent": "browser", + "system": "any", + "browser": "any", + "mode": "dev-secure", + "vaultDomain": {{ required "config.vaultDomain must be set" .Values.config.vaultDomain | quote}}, + "didDomain": {{ required "config.vaultDomain must be set" .Values.config.vaultDomain | quote}}, + "epiDomain": {{ required "config.domain must be set" .Values.config.domain | quote}}, + "epiSubdomain": {{ required "config.subDomain must be set" .Values.config.subDomain | quote}}, + "enclaveType": "WalletDBEnclave", + "sw": false, + "pwa": false, + "allowPinLogin": false, + "legenda for properties": " vault:(server, browser) agent:(mobile, browser) system:(iOS, Android, any) browser:(Chrome, Firefox, any) mode:(autologin,dev-autologin, secure, dev-secure) sw:(true, false) pwa:(true, false)" + } + + leaflet-environment.js: |- + export default { + "appName": "eLeaflet", + "vault": "server", + "agent": "browser", + "system": "any", + "browser": "any", + "mode": "autologin", + "vaultDomain": {{ required "config.vaultDomain must be set" .Values.config.vaultDomain | quote}}, + "didDomain": {{ required "config.vaultDomain must be set" .Values.config.vaultDomain | quote}}, + "enclaveType": "WalletDBEnclave", + "sw": false, + "pwa": false, + "allowPinLogin": false, + "legenda for properties": " vault:(server, browser) agent:(mobile, browser) system:(iOS, Android, any) browser:(Chrome, Firefox, any) mode:(development, release) sw:(true, false) pwa:(true, false)" + } + +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/epi/templates/_helpers.tpl b/charts/epi/templates/_helpers.tpl new file mode 100644 index 00000000..c61b61f2 --- /dev/null +++ b/charts/epi/templates/_helpers.tpl @@ -0,0 +1,88 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "epi.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 "epi.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 "epi.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "epi.labels" -}} +helm.sh/chart: {{ include "epi.chart" . }} +{{ include "epi.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "epi.selectorLabels" -}} +app.kubernetes.io/name: {{ include "epi.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "epi.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "epi.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + + +{{/* +The Name of the ConfigMap for the Seeds Data +*/}} +{{- define "epi.configMapSeedsBackupName" -}} +{{- printf "%s-%s" (include "epi.fullname" .) "seedsbackup" }} +{{- end }} + +{{/* +Lookup potentially existing seedsBackup data +*/}} +{{- define "epi.seedsBackupData" -}} +{{- $configMap := lookup "v1" "ConfigMap" .Release.Namespace (include "epi.configMapSeedsBackupName" .) -}} +{{- if $configMap -}} +{{/* + Reusing existing data +*/}} +seedsBackup: {{ $configMap.data.seedsBackup | default "" | quote }} +{{- else -}} +{{/* + Use new data +*/}} +seedsBackup: "" +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/charts/epi/templates/configmap-seedsbackup.yaml b/charts/epi/templates/configmap-seedsbackup.yaml new file mode 100644 index 00000000..68652ba4 --- /dev/null +++ b/charts/epi/templates/configmap-seedsbackup.yaml @@ -0,0 +1,21 @@ +{{- /* +SeedsBackup ConfigMap will be created on pre-install and will remain for the whole lifetime of the helm installation! +It will be deleted be job-cleanup. +*/}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "epi.configMapSeedsBackupName" . }} + annotations: + "description": "Currently used Seedsbackup" + "helm.sh/hook": pre-install + "helm.sh/hook-delete-policy": before-hook-creation + "helm.sh/hook-weight": "-1" + {{- /* + Skip deleting this resource when a helm operation (such as helm uninstall, helm upgrade or helm rollback) would result in its deletion. + */}} + "helm.sh/resource-policy": keep + labels: + {{- include "epi.labels" . | nindent 4 }} +data: +{{ include "epi.seedsBackupData" . | indent 2}} diff --git a/charts/epi/templates/configmaps.yaml b/charts/epi/templates/configmaps.yaml new file mode 100644 index 00000000..bdffe9c1 --- /dev/null +++ b/charts/epi/templates/configmaps.yaml @@ -0,0 +1,22 @@ +{{- /* +Create Configmaps from templates +*/}} + +{{- include "epi.configmap-bdns" (list $ . "" (dict)) }} +--- +{{- include "epi.configmap-config" (list $ . "" (dict)) }} +--- +{{- include "epi.configmap-domains" (list $ . "" (dict)) }} +--- +{{- include "epi.configmap-environment" (list $ . "" (dict)) }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "epi.fullname" . }}-build-info + annotations: + "description": "Info about which image has been successfully built latest" + labels: + {{- include "epi.labels" . | nindent 4 }} +data: + lastBuiltImage: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" diff --git a/charts/epi/templates/deployment.yaml b/charts/epi/templates/deployment.yaml new file mode 100644 index 00000000..1e368125 --- /dev/null +++ b/charts/epi/templates/deployment.yaml @@ -0,0 +1,183 @@ +# +# The Deployment of the epi application. +# Note: +# 1. As of Feb-23 2022 the build process needs to run on every container startup as some files are added to ephemeral container disk space. +# Without these files, the wallet application won't startup. +# That is also the reason why the container cannot be made readonly currently. +# 2. As of Feb-23 2022 the seedBackup file is injected into the container but not to its desired destination +# as the build process is overwriting it. +# +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "epi.fullname" . }} + labels: + {{- include "epi.labels" . | nindent 4 }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "epi.selectorLabels" . | nindent 6 }} +{{- with .Values.deploymentStrategy }} + strategy: +{{ toYaml . | trim | indent 4 }} +{{- end }} + template: + metadata: + # https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "epi.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "epi.serviceAccountName" . }} + {{- with .Values.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: epi + {{- with .Values.securityContext }} + securityContext: + {{- toYaml . | nindent 10 }} + {{- end }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy | default "IfNotPresent" }} + ports: + - name: http + containerPort: 8080 + protocol: TCP + {{- with .Values.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 10 }} + {{- end }} + {{- with .Values.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 10 }} + {{- end }} + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + command: + - sh + - -c + args: + # + # NOT WORKING: As of Feb-23 2022 the build process must run on every startup as + # it also write files into ephemeral container disk space, e.g. /ePI-workspace/apihub-root/demiurge-wallet/loader/environment.js + # + # echo "=======> Starting server only - do not run build as apps are already built here..." + # npm run server + # + # Additionally mounting seedsBackup not working (Feb-23 2022) as mounted files are readonly + # and the build process overwrites it even if no changes occur. + # + - | + cd /ePI-workspace + echo "=======> Copying seedsBackupOnStartup to seedsBackup ..." + cp apihub-root/seedsBackupOnStartup apihub-root/seedsBackup + echo "=======> Starting application in background process ..." + npm run server & + server_pid=$! + echo "=======> Application running in background with PID=$server_pid" + echo "=======> Sleeping for {{ .Values.config.sleepTime }} ..." + sleep {{ .Values.config.sleepTime }} + echo "=======> Starting build process ..." + npm run build-all + rc=$? + echo "=======> Build process done - rc=$rc" + if [ $rc -eq 0 ] + then + echo "=======> Build process successful - Writing file that application is ready ..." + touch /ePI-workspace/apihub-root/ready + tail -f /dev/null + fi + volumeMounts: + # As of Feb-2023 we do NOT mount seedsBackup to its desired destination /ePI-workspace/apihub-root/seedsBackup + # as the startup build process will write to that even if there are no changes. + # Thus, we mount it to different location and copy it to desired location where the file is writeable then. + - name: epi-seeds-volume + mountPath: /ePI-workspace/apihub-root/seedsBackupOnStartup + subPath: seedsBackup + readOnly: true + - name: epi-external-volume + mountPath: /ePI-workspace/apihub-root/external-volume + - name: epi-config-volume + mountPath: /ePI-workspace/apihub-root/external-volume/config/apihub.json + subPath: apihub.json + readOnly: true + - name: epi-bdns-config-volume + mountPath: /ePI-workspace/apihub-root/external-volume/config/bdns.hosts + subPath: bdns.hosts + readOnly: true + - name: epi-config-volume + mountPath: /ePI-workspace/env.json + subPath: env.json + readOnly: true + - name: epi-domains-volume + mountPath: /ePI-workspace/apihub-root/external-volume/config/domains/{{ required "config.domain must be set" .Values.config.domain }}.json + subPath: {{ required "config.domain must be set" .Values.config.domain }}.json + readOnly: true + - name: epi-domains-volume + mountPath: /ePI-workspace/apihub-root/external-volume/config/domains/{{ required "config.subDomain must be set" .Values.config.subDomain }}.json + subPath: {{ required "config.subDomain must be set" .Values.config.subDomain }}.json + readOnly: true + - name: epi-domains-volume + mountPath: /ePI-workspace/apihub-root/external-volume/config/domains/{{ required "config.vaultDomain must be set" .Values.config.vaultDomain }}.json + subPath: {{ required "config.vaultDomain must be set" .Values.config.vaultDomain }}.json + readOnly: true + - name: epi-env-volume + mountPath: /ePI-workspace/trust-loader-config/demiurge-wallet/loader/environment.js + subPath: demiurge-environment.js + readOnly: true + - name: epi-env-volume + mountPath: /ePI-workspace/trust-loader-config/dsu-explorer/loader/environment.js + subPath: dsu-explorer-environment.js + readOnly: true + - name: epi-env-volume + mountPath: /ePI-workspace/trust-loader-config/dsu-fabric-wallet/loader/environment.js + subPath: dsu-fabric-environment.js + readOnly: true + - name: epi-env-volume + mountPath: /ePI-workspace/trust-loader-config/leaflet-wallet/loader/environment.js + subPath: leaflet-environment.js + readOnly: true + restartPolicy: Always + volumes: + - name: epi-seeds-volume + configMap: + name: {{ include "epi.configMapSeedsBackupName" . }} + - name: epi-config-volume + configMap: + name: {{ include "epi.fullname" . }}-config + - name: epi-bdns-config-volume + configMap: + name: {{ include "epi.fullname" . }}-bdns + - name: epi-domains-volume + configMap: + name: {{ include "epi.fullname" . }}-domains + - name: epi-env-volume + configMap: + name: {{ include "epi.fullname" . }}-environment + - name: epi-external-volume + persistentVolumeClaim: + claimName: {{ include "epi.fullname" . }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/epi/templates/ingress.yaml b/charts/epi/templates/ingress.yaml new file mode 100644 index 00000000..4d1b09de --- /dev/null +++ b/charts/epi/templates/ingress.yaml @@ -0,0 +1,61 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "epi.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "epi.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/epi/templates/job-cleanup.yaml b/charts/epi/templates/job-cleanup.yaml new file mode 100644 index 00000000..97f16f99 --- /dev/null +++ b/charts/epi/templates/job-cleanup.yaml @@ -0,0 +1,163 @@ +{{- /* +1. Role, RoleBinding and ServiceAccount for Cleanup Job +*/}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "epi.fullname" . }}-cleanup + annotations: + "description": "Role for Cleanup Job" + "helm.sh/hook": post-delete + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded,hook-failed + "helm.sh/hook-weight": "-1" +rules: +# Delete Init Job +- apiGroups: + - "batch" + resourceNames: + - "{{ include "epi.fullname" . }}-init" + resources: + - jobs + verbs: + - delete +# Get SeedsBackup, create backup from it and delete SeedsBackup +- apiGroups: + - "" + resourceNames: + - {{ include "epi.configMapSeedsBackupName" . | quote }} + resources: + - configmaps + verbs: + - get + # - patch + - delete +# Required to create a backup of SeedsBackup +# We cannot restrict create verb to a resourceName - See https://github.com/kubernetes/kubernetes/issues/80295 +- apiGroups: + - "" + resources: + - configmaps + verbs: + - create +{{- if eq (toString .Values.persistence.deletePvcOnUninstall) "true" }} +- apiGroups: + - "" + resourceNames: + - {{ include "epi.fullname" . | quote }} + resources: + - persistentvolumeclaims + verbs: + - delete +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "epi.fullname" . }}-cleanup + annotations: + "description": "RoleBinding for Cleanup Job" + "helm.sh/hook": post-delete + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded,hook-failed + "helm.sh/hook-weight": "-1" +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "epi.fullname" . }}-cleanup +subjects: +- kind: ServiceAccount + name: {{ include "epi.fullname" . }}-cleanup +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "epi.fullname" . }}-cleanup + labels: + {{- include "epi.labels" . | nindent 4 }} + annotations: + "description": "ServiceAccount for Cleanup Job" + "helm.sh/hook": post-delete + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded,hook-failed + "helm.sh/hook-weight": "-1" +--- + +{{- /* +3. This Job starts the apihub, then starts the build process. + After build process completion the seedsBackup ConfigMap will updated. + +Details: +The pod consists of an initContainer and a "main" container which share a temporary volume. +A dedicated ServiceAccount with write permissions to the ConfigMap containing the seedsBackup is used by the pod. +1. The apiHub/epi application runs in the initContainer as background process. + After a short delay (10s) the build process starts and writes the seedsBackup to the mounted temporary volume share with the "main" container. + Then the process exists and the init container stops. +2. The "main" container starts and writes the content of the seedBackup file into a ConfigMap. + It has the permission doing so via the ServiceAccount + +*/}} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "epi.fullname" . }}-cleanup + annotations: + "description": "Cleanup Job running after deletion of helm managed resource" + "helm.sh/hook": post-delete + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + "helm.sh/hook-weight": "0" +spec: + backoffLimit: 1 + template: + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + # Use the init ServiceAccount which has permissions to write to configMap + serviceAccountName: {{ include "epi.fullname" . }}-cleanup + {{- with .Values.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: Never + containers: + - name: cleanup + image: "{{ .Values.kubectl.image.repository }}:{{ .Values.kubectl.image.tag }}" + imagePullPolicy: {{ .Values.kubectl.image.pullPolicy | default "IfNotPresent" }} + command: + - sh + - -c + args: + - | + set -e + echo "Cleanup Job started" + + echo "1. Deleting Init Job ..." + kubectl delete job {{ include "epi.fullname" . }}-init --ignore-not-found=true + + backupname="{{ include "epi.configMapSeedsBackupName" . }}-${IMAGE_TAG}-final-backup-$(date +%s)" + echo "2. Backing up Configmap {{ include "epi.configMapSeedsBackupName" . }} to $backupname ..." + kubectl patch cm {{ include "epi.configMapSeedsBackupName" . }} -p "{\"metadata\":{ \"name\":\"$backupname\"}}" --dry-run=client -o yaml | kubectl create -f - + + echo "3. Deleting Configmap {{ include "epi.configMapSeedsBackupName" . }} ..." + kubectl delete cm {{ include "epi.configMapSeedsBackupName" . }} --ignore-not-found=true + + {{- if eq (toString .Values.persistence.deletePvcOnUninstall) "true" }} + echo "4. Deleting PersistentVolumeClaim {{ include "epi.fullname" . }} ..." + kubectl delete pvc {{ include "epi.fullname" . }} --ignore-not-found=true + {{- else }} + echo "4. SKIPPED: Deleting PersistentVolumeClaim {{ include "epi.fullname" . }}." + {{- end }} + env: + - name: IMAGE_TAG + value: "{{ .Values.image.tag | default .Chart.AppVersion }}" + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/epi/templates/job-init.yaml b/charts/epi/templates/job-init.yaml new file mode 100644 index 00000000..905e62dd --- /dev/null +++ b/charts/epi/templates/job-init.yaml @@ -0,0 +1,315 @@ +{{- /* +1. Create Configmaps required for hook from template +*/}} + +{{- include "epi.configmap-bdns" (list $ . "-init" (dict "helm.sh/hook" "pre-install,pre-upgrade" "helm.sh/hook-delete-policy" "before-hook-creation,hook-succeeded,hook-failed" "helm.sh/hook-weight" "-1")) }} +--- +{{- include "epi.configmap-config" (list $ . "-init" (dict "helm.sh/hook" "pre-install,pre-upgrade" "helm.sh/hook-delete-policy" "before-hook-creation,hook-succeeded,hook-failed" "helm.sh/hook-weight" "-1")) }} +--- +{{- include "epi.configmap-domains" (list $ . "-init" (dict "helm.sh/hook" "pre-install,pre-upgrade" "helm.sh/hook-delete-policy" "before-hook-creation,hook-succeeded,hook-failed" "helm.sh/hook-weight" "-1")) }} +--- +{{- include "epi.configmap-environment" (list $ . "-init" (dict "helm.sh/hook" "pre-install,pre-upgrade" "helm.sh/hook-delete-policy" "before-hook-creation,hook-succeeded,hook-failed" "helm.sh/hook-weight" "-1")) }} +--- + +{{- /* +2. Role, RoleBinding and ServiceAccount for Init Job +*/}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "epi.fullname" . }}-init + annotations: + "description": "Role for Init Job to create or update SeedsBackup ConfigMap" + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded,hook-failed + "helm.sh/hook-weight": "-1" +rules: +- apiGroups: + - "" + resourceNames: + - {{ include "epi.configMapSeedsBackupName" . | quote }} + - "{{ include "epi.fullname" . }}-build-info" + resources: + - configmaps + verbs: + - get + - patch + - update +# We cannot restrict create verb to a resourceName - See https://github.com/kubernetes/kubernetes/issues/80295 +- apiGroups: + - "" + resources: + - configmaps + verbs: + - create +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "epi.fullname" . }}-init + annotations: + "description": "RoleBinding for Init Job to create or update SeedsBackup ConfigMap" + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded,hook-failed + "helm.sh/hook-weight": "-1" +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "epi.fullname" . }}-init +subjects: +- kind: ServiceAccount + name: {{ include "epi.fullname" . }}-init +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "epi.fullname" . }}-init + labels: + {{- include "epi.labels" . | nindent 4 }} + annotations: + "description": "ServiceAccount for Init Job to create or update SeedsBackup ConfigMap" + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded,hook-failed + "helm.sh/hook-weight": "-1" +--- + +{{- /* +3. This Job starts the apihub, then starts the build process. + After build process completion the seedsBackup ConfigMap will updated. + +Details: +The pod consists of an initContainer and a "main" container which share a temporary volume. +A dedicated ServiceAccount with write permissions to the ConfigMap containing the seedsBackup is used by the pod. +1. The apiHub/epi application runs in the initContainer as background process. + After a short delay (10s) the build process starts and writes the seedsBackup to the mounted temporary volume share with the "main" container. + Then the process exists and the init container stops. +2. The "main" container starts and writes the content of the seedBackup file into a ConfigMap. + It has the permission doing so via the ServiceAccount + +*/}} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "epi.fullname" . }}-init + annotations: + "description": "Init Job for creating or updating SeedsBackup ConfigMap" + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-delete-policy": before-hook-creation + "helm.sh/hook-weight": "0" +spec: + backoffLimit: 1 + template: + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + # Use the init ServiceAccount which has permissions to write to configMap + serviceAccountName: {{ include "epi.fullname" . }}-init + {{- with .Values.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: Never + initContainers: + - name: build-necessity-check + image: "{{ .Values.kubectl.image.repository }}:{{ .Values.kubectl.image.tag }}" + imagePullPolicy: {{ .Values.kubectl.image.pullPolicy | default "IfNotPresent" }} + command: + - sh + - -c + args: + - | + # Exit on error + set -e + last_built_image=$(kubectl get cm --ignore-not-found {{ include "epi.fullname" . }}-build-info -o jsonpath='{.data.lastBuiltImage}') + if [ "$last_built_image" != "$FULL_IMAGE" ] + then + echo "=======> Not build yet for image=$FULL_IMAGE!" + echo "=======> Writing signal file in order to start build process ..." + touch /container-shared-data/doBuild + else + echo "=======> Already built for image=$FULL_IMAGE" + fi + echo "=======> Exiting ..." + exit 0 + env: + - name: FULL_IMAGE + value: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + volumeMounts: + # We mount a temporary volume in order to signal if build process must run or not + - name: container-shared-data + mountPath: /container-shared-data + readOnly: false + - name: init-epi + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy | default "IfNotPresent" }} + {{- with .Values.securityContext }} + securityContext: + {{- toYaml . | nindent 10 }} + {{- end }} + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + command: + - sh + - -c + args: + - | + # Exit on error + set -e + # 1. Check if build process needs to be done by checking if build process has not been executed in the past for current Image Tag. + # 2. If yes: Start server in background, wait, run build and copy seedBackup to shared folder with main container. + cd /ePI-workspace + if [ -f /container-shared-data/doBuild ] + then + echo "=======> Not build yet!" + echo "=======> Copying seedsBackupOnStartup to seedsBackup ..." + cp apihub-root/seedsBackupOnStartup apihub-root/seedsBackup + echo "=======> Starting application in background process ..." + npm run server & + server_pid=$! + echo "=======> Application running in background with PID=$server_pid" + echo "=======> Sleeping for {{ .Values.config.sleepTime }} ..." + sleep {{ .Values.config.sleepTime }} + echo "=======> Starting build process ..." + npm run build-all + rc=$? + echo "=======> Build process done - rc=$rc" + if [ $rc -eq 0 ] + then + echo "=======> Copying seedsBackup to container-shared-data ..." + cp /ePI-workspace/apihub-root/seedsBackup /container-shared-data + ls -las /container-shared-data + else + echo "=======> ERROR during build process - Exiting with rc=$rc ..." + exit $rc + fi + else + echo "=======> Already built for version=$IMAGE_TAG" + fi + echo "=======> Exiting ..." + exit 0 + env: + - name: IMAGE_TAG + value: "{{ .Values.image.tag | default .Chart.AppVersion }}" + volumeMounts: + # As of Feb-2023 we do NOT mount seedsBackup to its desired destination /ePI-workspace/apihub-root/seedsBackup + # as the startup build process will write to that even if there are no changes. + # Thus, we mount it to different location and copy it to desired location where the file is writeable then. + - name: epi-seeds-volume + mountPath: /ePI-workspace/apihub-root/seedsBackupOnStartup + subPath: seedsBackup + readOnly: true + - name: epi-external-volume + mountPath: /ePI-workspace/apihub-root/external-volume + - name: epi-config-volume + mountPath: /ePI-workspace/apihub-root/external-volume/config/apihub.json + subPath: apihub.json + readOnly: true + - name: epi-bdns-config-volume + mountPath: /ePI-workspace/apihub-root/external-volume/config/bdns.hosts + subPath: bdns.hosts + readOnly: true + - name: epi-config-volume + mountPath: /ePI-workspace/env.json + subPath: env.json + readOnly: true + - name: epi-domains-volume + mountPath: /ePI-workspace/apihub-root/external-volume/config/domains/{{ required "config.domain must be set" .Values.config.domain }}.json + subPath: {{ required "config.domain must be set" .Values.config.domain }}.json + readOnly: true + - name: epi-domains-volume + mountPath: /ePI-workspace/apihub-root/external-volume/config/domains/{{ required "config.subDomain must be set" .Values.config.subDomain }}.json + subPath: {{ required "config.subDomain must be set" .Values.config.subDomain }}.json + readOnly: true + - name: epi-domains-volume + mountPath: /ePI-workspace/apihub-root/external-volume/config/domains/{{ required "config.vaultDomain must be set" .Values.config.vaultDomain }}.json + subPath: {{ required "config.vaultDomain must be set" .Values.config.vaultDomain }}.json + readOnly: true + - name: epi-env-volume + mountPath: /ePI-workspace/trust-loader-config/demiurge-wallet/loader/environment.js + subPath: demiurge-environment.js + readOnly: true + - name: epi-env-volume + mountPath: /ePI-workspace/trust-loader-config/dsu-explorer/loader/environment.js + subPath: dsu-explorer-environment.js + readOnly: true + - name: epi-env-volume + mountPath: /ePI-workspace/trust-loader-config/dsu-fabric-wallet/loader/environment.js + subPath: dsu-fabric-environment.js + readOnly: true + - name: epi-env-volume + mountPath: /ePI-workspace/trust-loader-config/leaflet-wallet/loader/environment.js + subPath: leaflet-environment.js + readOnly: true + # We mount a temporary volume in order to hand over data from init to main container + - name: container-shared-data + mountPath: /container-shared-data + readOnly: false + containers: + - name: write-configmap + image: "{{ .Values.kubectl.image.repository }}:{{ .Values.kubectl.image.tag }}" + imagePullPolicy: {{ .Values.kubectl.image.pullPolicy | default "IfNotPresent" }} + command: + - sh + - -c + args: + - | + # Exit on error + set -e + # If seedsBackup file exists, apply Kubernetes ConfigMap. + if [ -f /container-shared-data/seedsBackup ] + then + backupname="{{ include "epi.configMapSeedsBackupName" . }}-${IMAGE_TAG}-$(date +%s)" + echo "=======> Writing Backup ConfigMap $backupname ..." + kubectl create configmap $backupname --from-file=seedsBackup=/container-shared-data/seedsBackup + echo "=======> Writing or updating ConfigMap {{ include "epi.configMapSeedsBackupName" . }} ..." + kubectl create configmap {{ include "epi.configMapSeedsBackupName" . }} --from-file=seedsBackup=/container-shared-data/seedsBackup --dry-run=client -o yaml | kubectl apply -f - + else + echo "=======> SeedsBackup file not present! Kubernetes ConfigMap was not created or updated!" + fi + env: + - name: IMAGE_TAG + value: "{{ .Values.image.tag | default .Chart.AppVersion }}" + volumeMounts: + - name: container-shared-data + mountPath: /container-shared-data + readOnly: true + volumes: + - name: epi-seeds-volume + configMap: + name: {{ include "epi.configMapSeedsBackupName" . }} + - name: epi-config-volume + configMap: + name: {{ include "epi.fullname" . }}-config-init + - name: epi-bdns-config-volume + configMap: + name: {{ include "epi.fullname" . }}-bdns-init + - name: epi-domains-volume + configMap: + name: {{ include "epi.fullname" . }}-domains-init + - name: epi-env-volume + configMap: + name: {{ include "epi.fullname" . }}-environment-init + - name: epi-external-volume + persistentVolumeClaim: + claimName: {{ include "epi.fullname" . }} + # Extra volume for passing data (seedsBackup) from initContainer to main container + # aka sharing data, see https://www.stratoscale.com/blog/kubernetes/kubernetes-how-to-share-disk-storage-between-containers-in-a-pod/ + - name: container-shared-data + emptyDir: + sizeLimit: "10Mi" + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/epi/templates/pvc.yaml b/charts/epi/templates/pvc.yaml new file mode 100644 index 00000000..6eab1348 --- /dev/null +++ b/charts/epi/templates/pvc.yaml @@ -0,0 +1,34 @@ +{{- /* +Persistent Storage for Bricks will be created on pre-install and will remain for the whole lifetime of the helm installation! +It will be deleted be job-cleanup. +*/}} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ include "epi.fullname" . }} + annotations: + "description": "Persistent Storage for whole lifetime" + "helm.sh/hook": pre-install + "helm.sh/hook-delete-policy": before-hook-creation + "helm.sh/hook-weight": "-1" + {{- /* + Skip deleting this resource when a helm operation (such as helm uninstall, helm upgrade or helm rollback) would result in its deletion. + */}} + "helm.sh/resource-policy": keep + labels: + {{- include "epi.labels" . | nindent 4 }} + {{- with .Values.persistence.finalizers }} + finalizers: +{{ toYaml . | indent 4 }} + {{- end }} +spec: + {{- if .Values.persistence.storageClassName }} + storageClassName: {{ .Values.persistence.storageClassName | quote }} + {{- end }} + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} diff --git a/charts/epi/templates/service.yaml b/charts/epi/templates/service.yaml new file mode 100644 index 00000000..6d3b8699 --- /dev/null +++ b/charts/epi/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "epi.fullname" . }} + labels: + {{- include "epi.labels" . | nindent 4 }} + {{- with .Values.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "epi.selectorLabels" . | nindent 4 }} diff --git a/charts/epi/templates/serviceaccount.yaml b/charts/epi/templates/serviceaccount.yaml new file mode 100644 index 00000000..4b076937 --- /dev/null +++ b/charts/epi/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "epi.serviceAccountName" . }} + labels: + {{- include "epi.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/epi/templates/tests/test-connection.yaml b/charts/epi/templates/tests/test-connection.yaml new file mode 100644 index 00000000..c7d923ab --- /dev/null +++ b/charts/epi/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "epi.fullname" . }}-test-connection" + labels: + {{- include "epi.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "epi.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/charts/epi/values.yaml b/charts/epi/values.yaml new file mode 100644 index 00000000..2ae16166 --- /dev/null +++ b/charts/epi/values.yaml @@ -0,0 +1,260 @@ +# Default values for epi. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# -- The number of replicas if autoscaling is false +replicaCount: 1 + +image: + # -- The repository of the container image + repository: public.ecr.aws/n4q1q0z2/pharmaledger-epi + # -- Image Pull Policy + pullPolicy: IfNotPresent + # -- Overrides the image tag whose default is the chart appVersion. + tag: "" + +# image: +# # -- The repository of the container image +# repository: 535161841476.dkr.ecr.eu-central-1.amazonaws.com/torsten-pharmaledger-epi +# # -- Image Pull Policy +# pullPolicy: Always # IfNotPresent +# # -- Overrides the image tag whose default is the chart appVersion. +# tag: "v1.0.2-builder" + +## -- The strategy of the deployment. Defaults to Recreate as a PVC is bound to it. +## See `kubectl explain deployment.spec.strategy` for more and [https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy) +deploymentStrategy: + type: Recreate + +# -- Secret(s) for pulling an container image from a private registry. +# See [https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/) +imagePullSecrets: [] +# -- nameOverride replaces the name of the chart in the Chart.yaml file, when this is used to construct Kubernetes object names. +# From [https://stackoverflow.com/questions/63838705/what-is-the-difference-between-fullnameoverride-and-nameoverride-in-helm](https://stackoverflow.com/questions/63838705/what-is-the-difference-between-fullnameoverride-and-nameoverride-in-helm) +nameOverride: "" +# -- fullnameOverride completely replaces the generated name. +# From [https://stackoverflow.com/questions/63838705/what-is-the-difference-between-fullnameoverride-and-nameoverride-in-helm](https://stackoverflow.com/questions/63838705/what-is-the-difference-between-fullnameoverride-and-nameoverride-in-helm) +fullnameOverride: "" + +serviceAccount: + # -- Specifies whether a service account should be created + create: false + # -- 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: "" + +# -- Annotations added to the pod +podAnnotations: {} + +# -- Security Context for the pod. +# IMPORTANT: Take a look at README.md for configuration for non-root user! +# See [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod) +# +# For running as non-root with uid 1000, remove {} from next line and uncomment fsGroup and runAsUser! +podSecurityContext: {} + # fsGroup: 1000 + # runAsUser: 1000 + + # # -- The SecComp configuration [https://kubernetes.io/docs/tutorials/security/seccomp/](https://kubernetes.io/docs/tutorials/security/seccomp/) + # seccompProfile: + # type: RuntimeDefault + + +# -- Security Context for the application container +# IMPORTANT: Take a look at README.md file for configuration for non-root user! +# See [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container) +# +# For running as non-root with uid 1000, remove {} from next line and uncomment next lines! +securityContext: {} + # capabilities: + # drop: + # - ALL + # # -- Running as readonly filesystem is currently (Feb 2022) not possible. + # readOnlyRootFilesystem: false + # allowPrivilegeEscalation: false + # runAsNonRoot: true + # runAsUser: 1000 + +# -- Settings for Container with kubectl installed used by Init and Cleanup Job +kubectl: + image: + # -- The repository of the container image containing kubectl + repository: bitnami/kubectl + # -- Image Pull Policy + pullPolicy: IfNotPresent + # -- The Tag of the image containing kubectl. Minor Version should match to your Kubernetes Cluster Version. + tag: "1.21.8" + +# -- Enable persistence using Persistent Volume Claims +# See [http://kubernetes.io/docs/user-guide/persistent-volumes/](http://kubernetes.io/docs/user-guide/persistent-volumes/) +persistence: + # -- Name of the storage class. + # If empty or not set then storage class will not be set - which means that the default storage class will be used. + storageClassName: "" + # -- Size of the volume + size: "20Gi" + # -- Boolean flag whether to delete the persistent volume on uninstall or not. + deletePvcOnUninstall: true + finalizers: + - kubernetes.io/pvc-protection + accessModes: + - ReadWriteOnce + +service: + # -- Either ClusterIP, NodePort or LoadBalancer. + # See [https://kubernetes.io/docs/concepts/services-networking/service/](https://kubernetes.io/docs/concepts/services-networking/service/) + type: ClusterIP + # -- Port where the service will be exposed + port: 80 + # -- Annotations for the service. + # See AWS, see [https://kubernetes.io/docs/concepts/services-networking/service/#ssl-support-on-aws](https://kubernetes.io/docs/concepts/services-networking/service/#ssl-support-on-aws) + # For Azure, see [https://kubernetes-sigs.github.io/cloud-provider-azure/topics/loadbalancer/#loadbalancer-annotations](https://kubernetes-sigs.github.io/cloud-provider-azure/topics/loadbalancer/#loadbalancer-annotations) + annotations: {} + +# -- Configuration. Will be put in ConfigMaps. +config: + # The time to sleep between start of apihub (npm run server) and build process (npm run build-all) + sleepTime: "10s" + # -- The Domain, e.g. "epipoc" + domain: "epipoc" + # -- The Subdomain, should be domain.company, e.g. epipoc.my-company + subDomain: "epipoc.my-company" + # -- The Vault domain, should be vault.company, e.g. vault.my-company + vaultDomain: "vault.my-company" + # -- The Full URL of the Ethadapter including protocol and port, e.g. "https://ethadapter.my-company.com:3000" + ethadapterUrl: "http://ethadapter.ethadapter:3000" + # -- Centrally managed and provided BDNS Hosts Config + bdnsHosts: |- + { + "epipoc": { + "anchoringServices": [ + "$ORIGIN" + ], + "notifications": [ + "$ORIGIN" + ] + }, + "epipoc.my-company": { + "brickStorages": [ + "$ORIGIN" + ], + "anchoringServices": [ + "$ORIGIN" + ], + "notifications": [ + "$ORIGIN" + ] + }, + "epipoc.other": { + "brickStorages": [ + "https://epipoc.other-company.com" + ], + "anchoringServices": [ + "https://epipoc.other-company.com" + ], + "notifications": [ + "https://epipoc.other-company.com" + ] + }, + "vault.my-company": { + "replicas": [], + "brickStorages": [ + "$ORIGIN" + ], + "anchoringServices": [ + "$ORIGIN" + ], + "notifications": [ + "$ORIGIN" + ] + } + } + +ingress: + # -- Whether to create ingress or not. + # Note: For ingress an Ingress Controller (e.g. AWS LB Controller, NGINX Ingress Controller, Traefik, ...) is required and service.type should be ClusterIP or NodePort depending on your configuration + enabled: false + # -- The className specifies the IngressClass object which is responsible for that class. + # Note for Kubernetes >= 1.18 it is required to have an existing IngressClass object. + # If IngressClass object does not exists, omit className and add the deprecated annotation 'kubernetes.io/ingress.class' instead. + # For Kubernetes < 1.18 either use className or annotation 'kubernetes.io/ingress.class'. + # See https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class + className: "" + # -- Ingress annotations. + # For AWS LB Controller, see [https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.3/guide/ingress/annotations/](https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.3/guide/ingress/annotations/) + # For Azure Application Gateway Ingress Controller, see [https://azure.github.io/application-gateway-kubernetes-ingress/annotations/](https://azure.github.io/application-gateway-kubernetes-ingress/annotations/) + # For NGINX Ingress Controller, see [https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/) + # For Traefik Ingress Controller, see [https://doc.traefik.io/traefik/routing/providers/kubernetes-ingress/#annotations](https://doc.traefik.io/traefik/routing/providers/kubernetes-ingress/#annotations) + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + # -- A list of hostnames and path(s) to listen at the Ingress Controller + hosts: + - + # -- The FQDN/hostname + host: epi.some-pharma-company.com + paths: + - + # -- The Ingress Path. See [https://kubernetes.io/docs/concepts/services-networking/ingress/#examples](https://kubernetes.io/docs/concepts/services-networking/ingress/#examples) + # Note: For Ingress Controllers like AWS LB Controller see their specific documentation. + path: / + # -- The type of path. This value is required since Kubernetes 1.18. + # For Ingress Controllers like AWS LB Controller or Traefik it is usually required to set its value to ImplementationSpecific + # See [https://kubernetes.io/docs/concepts/services-networking/ingress/#path-types](https://kubernetes.io/docs/concepts/services-networking/ingress/#path-types) + # and [https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/](https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/) + pathType: ImplementationSpecific + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +# -- Resource constraints for the container +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +# -- Node Selectors in order to assign pods to certain nodes. +# See [https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/) +nodeSelector: {} + +# -- Tolerations for scheduling a pod. +# See [https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) +tolerations: [] + +# -- Affinity for scheduling a pod. +# See [https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/) +affinity: {} + +# -- Liveness probe. +# See [https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) +livenessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 1 + successThreshold: 1 + failureThreshold: 3 + +# -- Readiness probe. +# See [https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) +readinessProbe: + exec: + command: + - cat + - /ePI-workspace/apihub-root/ready + initialDelaySeconds: 30 + periodSeconds: 5 + successThreshold: 1 + failureThreshold: 60