diff --git a/chart/Chart.yaml b/chart/Chart.yaml index 5f97b94bf137a7..d0f92f3c2a7c12 100644 --- a/chart/Chart.yaml +++ b/chart/Chart.yaml @@ -1,8 +1,6 @@ # Copyright (c) 2020 Gitpod GmbH. All rights reserved. # Licensed under the MIT License. See License-MIT.txt in the project root for license information. - apiVersion: v1 -appVersion: "0.1.5" description: The core chart for Gitpod name: gitpod -version: 0.4.0 +version: 0.6.0 diff --git a/chart/charts/docker-registry/.helmignore b/chart/charts/docker-registry/.helmignore new file mode 100755 index 00000000000000..f0c13194444163 --- /dev/null +++ b/chart/charts/docker-registry/.helmignore @@ -0,0 +1,21 @@ +# 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 +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/chart/charts/docker-registry/Chart.yaml b/chart/charts/docker-registry/Chart.yaml new file mode 100755 index 00000000000000..c9ceb8193ace5a --- /dev/null +++ b/chart/charts/docker-registry/Chart.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +appVersion: 2.7.1 +description: A Helm chart for Docker Registry +home: https://hub.docker.com/_/registry/ +icon: https://hub.docker.com/public/images/logos/mini-logo.svg +maintainers: +- email: jpds@protonmail.com + name: jpds +- email: pete.brown@powerhrg.com + name: rendhalver +name: docker-registry +sources: +- https://github.com/docker/distribution-library-image +version: 1.8.3 diff --git a/chart/charts/docker-registry/OWNERS b/chart/charts/docker-registry/OWNERS new file mode 100755 index 00000000000000..516d524e9f9455 --- /dev/null +++ b/chart/charts/docker-registry/OWNERS @@ -0,0 +1,6 @@ +approvers: +- jpds +- rendhalver +reviewers: +- jpds +- rendhalver diff --git a/chart/charts/docker-registry/README.md b/chart/charts/docker-registry/README.md new file mode 100755 index 00000000000000..9435574b4a9ffc --- /dev/null +++ b/chart/charts/docker-registry/README.md @@ -0,0 +1,81 @@ +# Docker Registry Helm Chart + +This directory contains a Kubernetes chart to deploy a private Docker Registry. + +## Prerequisites Details + +* PV support on underlying infrastructure (if persistence is required) + +## Chart Details + +This chart will do the following: + +* Implement a Docker registry deployment + +## Installing the Chart + +To install the chart, use the following: + +```console +$ helm install stable/docker-registry +``` + +## Configuration + +The following table lists the configurable parameters of the docker-registry chart and +their default values. + +| Parameter | Description | Default | +|:----------------------------|:-------------------------------------------------------------------------------------------|:----------------| +| `image.pullPolicy` | Container pull policy | `IfNotPresent` | +| `image.repository` | Container image to use | `registry` | +| `image.tag` | Container image tag to deploy | `2.7.1` | +| `imagePullSecrets` | Specify image pull secrets | `nil` (does not add image pull secrets to deployed pods) | +| `persistence.accessMode` | Access mode to use for PVC | `ReadWriteOnce` | +| `persistence.enabled` | Whether to use a PVC for the Docker storage | `false` | +| `persistence.deleteEnabled` | Enable the deletion of image blobs and manifests by digest | `nil` | +| `persistence.size` | Amount of space to claim for PVC | `10Gi` | +| `persistence.storageClass` | Storage Class to use for PVC | `-` | +| `persistence.existingClaim` | Name of an existing PVC to use for config | `nil` | +| `service.port` | TCP port on which the service is exposed | `5000` | +| `service.type` | service type | `ClusterIP` | +| `service.clusterIP` | if `service.type` is `ClusterIP` and this is non-empty, sets the cluster IP of the service | `nil` | +| `service.nodePort` | if `service.type` is `NodePort` and this is non-empty, sets the node port of the service | `nil` | +| `replicaCount` | k8s replicas | `1` | +| `updateStrategy` | update strategy for deployment | `{}` | +| `podAnnotations` | Annotations for pod | `{}` | +| `podLabels` | Labels for pod | `{}` | +| `podDisruptionBudget` | Pod disruption budget | `{}` | +| `resources.limits.cpu` | Container requested CPU | `nil` | +| `resources.limits.memory` | Container requested memory | `nil` | +| `priorityClassName ` | priorityClassName | `""` | +| `storage` | Storage system to use | `filesystem` | +| `tlsSecretName` | Name of secret for TLS certs | `nil` | +| `secrets.htpasswd` | Htpasswd authentication | `nil` | +| `secrets.s3.accessKey` | Access Key for S3 configuration | `nil` | +| `secrets.s3.secretKey` | Secret Key for S3 configuration | `nil` | +| `secrets.swift.username` | Username for Swift configuration | `nil` | +| `secrets.swift.password` | Password for Swift configuration | `nil` | +| `haSharedSecret` | Shared secret for Registry | `nil` | +| `configData` | Configuration hash for docker | `nil` | +| `s3.region` | S3 region | `nil` | +| `s3.regionEndpoint` | S3 region endpoint | `nil` | +| `s3.bucket` | S3 bucket name | `nil` | +| `s3.encrypt` | Store images in encrypted format | `nil` | +| `s3.secure` | Use HTTPS | `nil` | +| `swift.authurl` | Swift authurl | `nil` | +| `swift.container` | Swift container | `nil` | +| `nodeSelector` | node labels for pod assignment | `{}` | +| `tolerations` | pod tolerations | `[]` | +| `ingress.enabled` | If true, Ingress will be created | `false` | +| `ingress.annotations` | Ingress annotations | `{}` | +| `ingress.labels` | Ingress labels | `{}` | +| `ingress.path` | Ingress service path | `/` | +| `ingress.hosts` | Ingress hostnames | `[]` | +| `ingress.tls` | Ingress TLS configuration (YAML) | `[]` | + +Specify each parameter using the `--set key=value[,key=value]` argument to +`helm install`. + +To generate htpasswd file, run this docker command: +`docker run --entrypoint htpasswd registry:2 -Bbn user password > ./htpasswd`. diff --git a/chart/charts/docker-registry/templates/NOTES.txt b/chart/charts/docker-registry/templates/NOTES.txt new file mode 100755 index 00000000000000..4a9152b57ce82c --- /dev/null +++ b/chart/charts/docker-registry/templates/NOTES.txt @@ -0,0 +1,19 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range .Values.ingress.hosts }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "docker-registry.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 svc -w {{ template "docker-registry.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "docker-registry.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo http://$SERVICE_IP:{{ .Values.service.externalPort }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "docker-registry.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl -n {{ .Release.Namespace }} port-forward $POD_NAME 8080:5000 +{{- end }} diff --git a/chart/charts/docker-registry/templates/_helpers.tpl b/chart/charts/docker-registry/templates/_helpers.tpl new file mode 100755 index 00000000000000..a91077ef6fc97c --- /dev/null +++ b/chart/charts/docker-registry/templates/_helpers.tpl @@ -0,0 +1,24 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "docker-registry.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). +*/}} +{{- define "docker-registry.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 -}} diff --git a/chart/charts/docker-registry/templates/configmap.yaml b/chart/charts/docker-registry/templates/configmap.yaml new file mode 100755 index 00000000000000..820bb4f1f3b0ad --- /dev/null +++ b/chart/charts/docker-registry/templates/configmap.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "docker-registry.fullname" . }}-config + labels: + app: {{ template "docker-registry.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +data: + config.yml: |- +{{ toYaml .Values.configData | indent 4 }} diff --git a/chart/charts/docker-registry/templates/deployment.yaml b/chart/charts/docker-registry/templates/deployment.yaml new file mode 100755 index 00000000000000..230c96a0ed5478 --- /dev/null +++ b/chart/charts/docker-registry/templates/deployment.yaml @@ -0,0 +1,211 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "docker-registry.fullname" . }} + labels: + app: {{ template "docker-registry.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + selector: + matchLabels: + app: {{ template "docker-registry.name" . }} + release: {{ .Release.Name }} + replicas: {{ .Values.replicaCount }} +{{- if .Values.updateStrategy }} + strategy: +{{ toYaml .Values.updateStrategy | indent 4 }} +{{- end }} + minReadySeconds: 5 + template: + metadata: + labels: + app: {{ template "docker-registry.name" . }} + release: {{ .Release.Name }} + {{- if .Values.podLabels }} +{{ toYaml .Values.podLabels | indent 8 }} + {{- end }} + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} +{{- if $.Values.podAnnotations }} +{{ toYaml $.Values.podAnnotations | indent 8 }} +{{- end }} + spec: + {{- if .Values.imagePullSecrets }} + imagePullSecrets: +{{ toYaml .Values.imagePullSecrets | indent 8 }} + {{- end }} +{{- if .Values.priorityClassName }} + priorityClassName: "{{ .Values.priorityClassName }}" +{{- end }} +{{- if .Values.securityContext.enabled }} + securityContext: + fsGroup: {{ .Values.securityContext.fsGroup }} + runAsUser: {{ .Values.securityContext.runAsUser }} +{{- end }} + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: + - /bin/registry + - serve + - /etc/docker/registry/config.yml + ports: + - containerPort: 5000 + livenessProbe: + httpGet: +{{- if .Values.tlsSecretName }} + scheme: HTTPS +{{- end }} + path: / + port: 5000 + readinessProbe: + httpGet: +{{- if .Values.tlsSecretName }} + scheme: HTTPS +{{- end }} + path: / + port: 5000 + resources: +{{ toYaml .Values.resources | indent 12 }} + env: +{{- if .Values.secrets.htpasswd }} + - name: REGISTRY_AUTH + value: "htpasswd" + - name: REGISTRY_AUTH_HTPASSWD_REALM + value: "Registry Realm" + - name: REGISTRY_AUTH_HTPASSWD_PATH + value: "/auth/htpasswd" +{{- end }} + - name: REGISTRY_HTTP_SECRET + valueFrom: + secretKeyRef: + name: {{ template "docker-registry.fullname" . }}-secret + key: haSharedSecret +{{- if .Values.tlsSecretName }} + - name: REGISTRY_HTTP_TLS_CERTIFICATE + value: /etc/ssl/docker/tls.crt + - name: REGISTRY_HTTP_TLS_KEY + value: /etc/ssl/docker/tls.key +{{- end }} +{{- if eq .Values.storage "filesystem" }} + - name: REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY + value: "/var/lib/registry" +{{- else if eq .Values.storage "azure" }} + - name: REGISTRY_STORAGE_AZURE_ACCOUNTNAME + valueFrom: + secretKeyRef: + name: {{ template "docker-registry.fullname" . }}-secret + key: azureAccountName + - name: REGISTRY_STORAGE_AZURE_ACCOUNTKEY + valueFrom: + secretKeyRef: + name: {{ template "docker-registry.fullname" . }}-secret + key: azureAccountKey + - name: REGISTRY_STORAGE_AZURE_CONTAINER + valueFrom: + secretKeyRef: + name: {{ template "docker-registry.fullname" . }}-secret + key: azureContainer +{{- else if eq .Values.storage "s3" }} + {{- if and .Values.secrets.s3.secretKey .Values.secrets.s3.accessKey }} + - name: REGISTRY_STORAGE_S3_ACCESSKEY + valueFrom: + secretKeyRef: + name: {{ template "docker-registry.fullname" . }}-secret + key: s3AccessKey + - name: REGISTRY_STORAGE_S3_SECRETKEY + valueFrom: + secretKeyRef: + name: {{ template "docker-registry.fullname" . }}-secret + key: s3SecretKey + {{- end }} + - name: REGISTRY_STORAGE_S3_REGION + value: {{ required ".Values.s3.region is required" .Values.s3.region }} + {{- if .Values.s3.regionEndpoint }} + - name: REGISTRY_STORAGE_S3_REGIONENDPOINT + value: {{ .Values.s3.regionEndpoint }} + {{- end }} + - name: REGISTRY_STORAGE_S3_BUCKET + value: {{ required ".Values.s3.bucket is required" .Values.s3.bucket }} + {{- if .Values.s3.encrypt }} + - name: REGISTRY_STORAGE_S3_ENCRYPT + value: {{ .Values.s3.encrypt | quote }} + {{- end }} + {{- if .Values.s3.secure }} + - name: REGISTRY_STORAGE_S3_SECURE + value: {{ .Values.s3.secure | quote }} + {{- end }} +{{- else if eq .Values.storage "swift" }} + - name: REGISTRY_STORAGE_SWIFT_AUTHURL + value: {{ required ".Values.swift.authurl is required" .Values.swift.authurl }} + - name: REGISTRY_STORAGE_SWIFT_USERNAME + valueFrom: + secretKeyRef: + name: {{ template "docker-registry.fullname" . }}-secret + key: swiftUsername + - name: REGISTRY_STORAGE_SWIFT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "docker-registry.fullname" . }}-secret + key: swiftPassword + - name: REGISTRY_STORAGE_SWIFT_CONTAINER + value: {{ required ".Values.swift.container is required" .Values.swift.container }} +{{- end }} +{{- if .Values.persistence.deleteEnabled }} + - name: REGISTRY_STORAGE_DELETE_ENABLED + value: "true" +{{- end }} + volumeMounts: +{{- if .Values.secrets.htpasswd }} + - name: auth + mountPath: /auth + readOnly: true +{{- end }} +{{- if eq .Values.storage "filesystem" }} + - name: data + mountPath: /var/lib/registry/ +{{- end }} + - name: "{{ template "docker-registry.fullname" . }}-config" + mountPath: "/etc/docker/registry" +{{- if .Values.tlsSecretName }} + - mountPath: /etc/ssl/docker + name: tls-cert + readOnly: true +{{- end }} +{{- if .Values.nodeSelector }} + nodeSelector: +{{ toYaml .Values.nodeSelector | indent 8 }} +{{- end }} +{{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 8 }} +{{- end }} + volumes: +{{- if .Values.secrets.htpasswd }} + - name: auth + secret: + secretName: {{ template "docker-registry.fullname" . }}-secret + items: + - key: htpasswd + path: htpasswd +{{- end }} +{{- if eq .Values.storage "filesystem" }} + - name: data + {{- if .Values.persistence.enabled }} + persistentVolumeClaim: + claimName: {{ if .Values.persistence.existingClaim }}{{ .Values.persistence.existingClaim }}{{- else }}{{ template "docker-registry.fullname" . }}{{- end }} + {{- else }} + emptyDir: {} + {{- end -}} +{{- end }} + - name: {{ template "docker-registry.fullname" . }}-config + configMap: + name: {{ template "docker-registry.fullname" . }}-config +{{- if .Values.tlsSecretName }} + - name: tls-cert + secret: + secretName: {{ .Values.tlsSecretName }} +{{- end }} diff --git a/chart/charts/docker-registry/templates/ingress.yaml b/chart/charts/docker-registry/templates/ingress.yaml new file mode 100755 index 00000000000000..6fdf784c0850d5 --- /dev/null +++ b/chart/charts/docker-registry/templates/ingress.yaml @@ -0,0 +1,36 @@ +{{- if .Values.ingress.enabled -}} +{{- $serviceName := include "docker-registry.fullname" . -}} +{{- $servicePort := .Values.service.port -}} +{{- $path := .Values.ingress.path -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ template "docker-registry.fullname" . }} + labels: + app: {{ template "docker-registry.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- if .Values.ingress.labels }} +{{ toYaml .Values.ingress.labels | indent 4 }} +{{- end }} + annotations: + {{- range $key, $value := .Values.ingress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + rules: + {{- range $host := .Values.ingress.hosts }} + - host: {{ $host }} + http: + paths: + - path: {{ $path }} + backend: + serviceName: {{ $serviceName }} + servicePort: {{ $servicePort }} + {{- end -}} + {{- if .Values.ingress.tls }} + tls: +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end -}} +{{- end -}} diff --git a/chart/charts/docker-registry/templates/poddisruptionbudget.yaml b/chart/charts/docker-registry/templates/poddisruptionbudget.yaml new file mode 100755 index 00000000000000..38eb384021a161 --- /dev/null +++ b/chart/charts/docker-registry/templates/poddisruptionbudget.yaml @@ -0,0 +1,17 @@ +{{- if .Values.podDisruptionBudget -}} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: {{ template "docker-registry.fullname" . }} + labels: + app: {{ template "docker-registry.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + selector: + matchLabels: + app: {{ template "docker-registry.name" . }} + release: {{ .Release.Name }} +{{ toYaml .Values.podDisruptionBudget | indent 2 }} +{{- end -}} diff --git a/chart/charts/docker-registry/templates/pvc.yaml b/chart/charts/docker-registry/templates/pvc.yaml new file mode 100755 index 00000000000000..16196178e62f41 --- /dev/null +++ b/chart/charts/docker-registry/templates/pvc.yaml @@ -0,0 +1,26 @@ +{{- if .Values.persistence.enabled }} +{{- if not .Values.persistence.existingClaim -}} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ template "docker-registry.fullname" . }} + labels: + app: {{ template "docker-registry.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + accessModes: + - {{ .Values.persistence.accessMode | quote }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} +{{- if .Values.persistence.storageClass }} +{{- if (eq "-" .Values.persistence.storageClass) }} + storageClassName: "" +{{- else }} + storageClassName: "{{ .Values.persistence.storageClass }}" +{{- end }} +{{- end }} +{{- end }} +{{- end -}} diff --git a/chart/charts/docker-registry/templates/secret.yaml b/chart/charts/docker-registry/templates/secret.yaml new file mode 100755 index 00000000000000..c22fd3076fa6ab --- /dev/null +++ b/chart/charts/docker-registry/templates/secret.yaml @@ -0,0 +1,37 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "docker-registry.fullname" . }}-secret + labels: + app: {{ template "docker-registry.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +type: Opaque +data: + {{- if .Values.secrets.htpasswd }} + htpasswd: {{ .Values.secrets.htpasswd | b64enc }} + {{- end }} + {{- if .Values.secrets.haSharedSecret }} + haSharedSecret: {{ .Values.secrets.haSharedSecret | b64enc | quote }} + {{- else }} + haSharedSecret: {{ randAlphaNum 16 | b64enc | quote }} + {{- end }} + + {{- if eq .Values.storage "azure" }} + {{- if and .Values.secrets.azure.accountName .Values.secrets.azure.accountKey .Values.secrets.azure.container }} + azureAccountName: {{ .Values.secrets.azure.accountName | b64enc | quote }} + azureAccountKey: {{ .Values.secrets.azure.accountKey | b64enc | quote }} + azureContainer: {{ .Values.secrets.azure.container | b64enc | quote }} + {{- end }} + {{- else if eq .Values.storage "s3" }} + {{- if and .Values.secrets.s3.secretKey .Values.secrets.s3.accessKey }} + s3AccessKey: {{ .Values.secrets.s3.accessKey | b64enc | quote }} + s3SecretKey: {{ .Values.secrets.s3.secretKey | b64enc | quote }} + {{- end }} + {{- else if eq .Values.storage "swift" }} + {{- if and .Values.secrets.swift.username .Values.secrets.swift.password }} + swiftUsername: {{ .Values.secrets.swift.username | b64enc | quote }} + swiftPassword: {{ .Values.secrets.swift.password | b64enc | quote }} + {{- end }} + {{- end }} diff --git a/chart/charts/docker-registry/templates/service.yaml b/chart/charts/docker-registry/templates/service.yaml new file mode 100755 index 00000000000000..1414020805844c --- /dev/null +++ b/chart/charts/docker-registry/templates/service.yaml @@ -0,0 +1,29 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "docker-registry.fullname" . }} + labels: + app: {{ template "docker-registry.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- if .Values.service.annotations }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +{{- end }} +spec: + type: {{ .Values.service.type }} +{{- if (and (eq .Values.service.type "ClusterIP") (not (empty .Values.service.clusterIP))) }} + clusterIP: {{ .Values.service.clusterIP }} +{{- end }} + ports: + - port: {{ .Values.service.port }} + protocol: TCP + name: {{ .Values.service.name }} + targetPort: 5000 +{{- if (and (eq .Values.service.type "NodePort") (not (empty .Values.service.nodePort))) }} + nodePort: {{ .Values.service.nodePort }} +{{- end }} + selector: + app: {{ template "docker-registry.name" . }} + release: {{ .Release.Name }} diff --git a/chart/charts/docker-registry/values.yaml b/chart/charts/docker-registry/values.yaml new file mode 100755 index 00000000000000..0c42d5e7768995 --- /dev/null +++ b/chart/charts/docker-registry/values.yaml @@ -0,0 +1,127 @@ +# Default values for docker-registry. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. +replicaCount: 1 + +updateStrategy: + # type: RollingUpdate + # rollingUpdate: + # maxSurge: 1 + # maxUnavailable: 0 + +podAnnotations: {} +podLabels: {} + +image: + repository: registry + tag: 2.7.1 + pullPolicy: IfNotPresent +# imagePullSecrets: + # - name: docker +service: + name: registry + type: ClusterIP + # clusterIP: + port: 5000 + # nodePort: + annotations: {} + # foo.io/bar: "true" +ingress: + enabled: false + path: / + # Used to create an Ingress record. + hosts: + - chart-example.local + annotations: + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + labels: {} + tls: + # Secrets must be manually created in the namespace. + # - secretName: chart-example-tls + # hosts: + # - chart-example.local +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 +persistence: + accessMode: 'ReadWriteOnce' + enabled: false + size: 10Gi + # storageClass: '-' + +# set the type of filesystem to use: filesystem, s3 +storage: filesystem + +# Set this to name of secret for tls certs +# tlsSecretName: registry.docker.example.com +secrets: + haSharedSecret: "" + htpasswd: "" +# Secrets for Azure +# azure: +# accountName: "" +# accountKey: "" +# container: "" +# Secrets for S3 access and secret keys +# s3: +# accessKey: "" +# secretKey: "" +# Secrets for Swift username and password +# swift: +# username: "" +# password: "" + +# Options for s3 storage type: +# s3: +# region: us-east-1 +# regionEndpoint: s3.us-east-1.amazonaws.com +# bucket: my-bucket +# encrypt: false +# secure: true + +# Options for swift storage type: +# swift: +# authurl: http://swift.example.com/ +# container: my-container + +configData: + version: 0.1 + log: + fields: + service: registry + storage: + cache: + blobdescriptor: inmemory + http: + addr: :5000 + headers: + X-Content-Type-Options: [nosniff] + health: + storagedriver: + enabled: true + interval: 10s + threshold: 3 + +securityContext: + enabled: true + runAsUser: 1000 + fsGroup: 1000 + +priorityClassName: "" + +podDisruptionBudget: {} + # maxUnavailable: 1 + # minAvailable: 2 + +nodeSelector: {} + +tolerations: [] diff --git a/chart/charts/mysql/.helmignore b/chart/charts/mysql/.helmignore new file mode 100644 index 00000000000000..a1c17ae4508c52 --- /dev/null +++ b/chart/charts/mysql/.helmignore @@ -0,0 +1,2 @@ +.git +OWNERS \ No newline at end of file diff --git a/chart/charts/mysql/Chart.yaml b/chart/charts/mysql/Chart.yaml new file mode 100644 index 00000000000000..33d3b27932887e --- /dev/null +++ b/chart/charts/mysql/Chart.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +appVersion: 5.7.30 +deprecated: true +description: DEPRECATED - Fast, reliable, scalable, and easy to use open-source relational + database system. +home: https://www.mysql.com/ +icon: https://www.mysql.com/common/logos/logo-mysql-170x115.png +keywords: +- mysql +- database +- sql +name: mysql +sources: +- https://github.com/kubernetes/charts +- https://github.com/docker-library/mysql +version: 1.6.9 diff --git a/chart/charts/mysql/README.md b/chart/charts/mysql/README.md new file mode 100644 index 00000000000000..6923e2ae2f4395 --- /dev/null +++ b/chart/charts/mysql/README.md @@ -0,0 +1,255 @@ +# ⚠️ Repo Archive Notice + +As of Nov 13, 2020, charts in this repo will no longer be updated. +For more information, see the Helm Charts [Deprecation and Archive Notice](https://github.com/helm/charts#%EF%B8%8F-deprecation-and-archive-notice), and [Update](https://helm.sh/blog/charts-repo-deprecation/). + +# MySQL + +[MySQL](https://MySQL.org) is one of the most popular database servers in the world. Notable users include Wikipedia, Facebook and Google. + +## DEPRECATION NOTICE + +This chart is deprecated and no longer supported. + +## Introduction + +This chart bootstraps a single node MySQL deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. + +## Prerequisites + +- Kubernetes 1.10+ with Beta APIs enabled +- PV provisioner support in the underlying infrastructure + +## Installing the Chart + +To install the chart with the release name `my-release`: + +```bash +$ helm install --name my-release stable/mysql +``` + +The command deploys MySQL on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists the parameters that can be configured during installation. + +By default a random password will be generated for the root user. If you'd like to set your own password change the mysqlRootPassword +in the values.yaml. + +You can retrieve your root password by running the following command. Make sure to replace [YOUR_RELEASE_NAME]: + + printf $(printf '\%o' `kubectl get secret [YOUR_RELEASE_NAME]-mysql -o jsonpath="{.data.mysql-root-password[*]}"`) + +> **Tip**: List all releases using `helm list` + +## Uninstalling the Chart + +To uninstall/delete the `my-release` deployment: + +```bash +$ helm delete --purge my-release +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release completely. + +## Configuration + +The following table lists the configurable parameters of the MySQL chart and their default values. + +| Parameter | Description | Default | +| -------------------------------------------- | -------------------------------------------------------------------------------------------- | ---------------------------------------------------- | +| `args` | Additional arguments to pass to the MySQL container. | `[]` | +| `initContainer.resources` | initContainer resource requests/limits | Memory: `10Mi`, CPU: `10m` | +| `image` | `mysql` image repository. | `mysql` | +| `imageTag` | `mysql` image tag. | `5.7.30` | +| `busybox.image` | `busybox` image repository. | `busybox` | +| `busybox.tag` | `busybox` image tag. | `1.32` | +| `testFramework.enabled` | `test-framework` switch. | `true` | +| `testFramework.image` | `test-framework` image repository. | `bats/bats` | +| `testFramework.tag` | `test-framework` image tag. | `1.2.1` | +| `testFramework.imagePullPolicy` | `test-framework` image pull policy. | `IfNotPresent` | +| `testFramework.securityContext` | `test-framework` securityContext | `{}` | +| `imagePullPolicy` | Image pull policy | `IfNotPresent` | +| `existingSecret` | Use Existing secret for Password details | `nil` | +| `extraVolumes` | Additional volumes as a string to be passed to the `tpl` function | | +| `extraVolumeMounts` | Additional volumeMounts as a string to be passed to the `tpl` function | | +| `extraInitContainers` | Additional init containers as a string to be passed to the `tpl` function | | +| `extraEnvVars` | Additional environment variables as a string to be passed to the `tpl` function | | +| `mysqlRootPassword` | Password for the `root` user. Ignored if existing secret is provided | Random 10 characters | +| `mysqlUser` | Username of new user to create. | `nil` | +| `mysqlPassword` | Password for the new user. Ignored if existing secret is provided | Random 10 characters | +| `mysqlDatabase` | Name for new database to create. | `nil` | +| `livenessProbe.initialDelaySeconds` | Delay before liveness probe is initiated | 30 | +| `livenessProbe.periodSeconds` | How often to perform the probe | 10 | +| `livenessProbe.timeoutSeconds` | When the probe times out | 5 | +| `livenessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed. | 1 | +| `livenessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 3 | +| `readinessProbe.initialDelaySeconds` | Delay before readiness probe is initiated | 5 | +| `readinessProbe.periodSeconds` | How often to perform the probe | 10 | +| `readinessProbe.timeoutSeconds` | When the probe times out | 1 | +| `readinessProbe.successThreshold` | Minimum consecutive successes for the probe to be considered successful after having failed. | 1 | +| `readinessProbe.failureThreshold` | Minimum consecutive failures for the probe to be considered failed after having succeeded. | 3 | +| `schedulerName` | Name of the k8s scheduler (other than default) | `nil` | +| `mysqlx.port.enabled` | Boolean to toggle a port for mysqlx `33060` protocol. | false | +| `persistence.enabled` | Create a volume to store data | true | +| `persistence.size` | Size of persistent volume claim | 8Gi RW | +| `persistence.storageClass` | Type of persistent volume claim | nil | +| `persistence.accessMode` | ReadWriteOnce or ReadOnly | ReadWriteOnce | +| `persistence.existingClaim` | Name of existing persistent volume | `nil` | +| `persistence.subPath` | Subdirectory of the volume to mount | `nil` | +| `persistence.annotations` | Persistent Volume annotations | {} | +| `nodeSelector` | Node labels for pod assignment | {} | +| `affinity` | Affinity rules for pod assignment | {} | +| `tolerations` | Pod taint tolerations for deployment | {} | +| `metrics.enabled` | Start a side-car prometheus exporter | `false` | +| `metrics.image` | Exporter image | `prom/mysqld-exporter` | +| `metrics.imageTag` | Exporter image | `v0.10.0` | +| `metrics.imagePullPolicy` | Exporter image pull policy | `IfNotPresent` | +| `metrics.resources` | Exporter resource requests/limit | `nil` | +| `metrics.livenessProbe.initialDelaySeconds` | Delay before metrics liveness probe is initiated | 15 | +| `metrics.livenessProbe.timeoutSeconds` | When the probe times out | 5 | +| `metrics.readinessProbe.initialDelaySeconds` | Delay before metrics readiness probe is initiated | 5 | +| `metrics.readinessProbe.timeoutSeconds` | When the probe times out | 1 | +| `metrics.flags` | Additional flags for the mysql exporter to use | `[]` | +| `metrics.serviceMonitor.enabled` | Set this to `true` to create ServiceMonitor for Prometheus operator | `false` | +| `metrics.serviceMonitor.additionalLabels` | Additional labels that can be used so ServiceMonitor will be discovered by Prometheus | `{}` | +| `resources` | CPU/Memory resource requests/limits | Memory: `256Mi`, CPU: `100m` | +| `configurationFiles` | List of mysql configuration files | `nil` | +| `configurationFilesPath` | Path of mysql configuration files | `/etc/mysql/conf.d/` | +| `securityContext.enabled` | Enable security context (mysql pod) | `false` | +| `securityContext.fsGroup` | Group ID for the container (mysql pod) | 999 | +| `securityContext.runAsUser` | User ID for the container (mysql pod) | 999 | +| `service.annotations` | Kubernetes annotations for mysql | {} | +| `service.type` | Kubernetes service type | ClusterIP | +| `service.loadBalancerIP` | LoadBalancer service IP | `""` | +| `serviceAccount.create` | Specifies whether a ServiceAccount should be created | `false` | +| `serviceAccount.name` | The name of the ServiceAccount to create | Generated using the mysql.fullname template | +| `ssl.enabled` | Setup and use SSL for MySQL connections | `false` | +| `ssl.secret` | Name of the secret containing the SSL certificates | mysql-ssl-certs | +| `ssl.certificates[0].name` | Name of the secret containing the SSL certificates | `nil` | +| `ssl.certificates[0].ca` | CA certificate | `nil` | +| `ssl.certificates[0].cert` | Server certificate (public key) | `nil` | +| `ssl.certificates[0].key` | Server key (private key) | `nil` | +| `imagePullSecrets` | Name of Secret resource containing private registry credentials | `nil` | +| `initializationFiles` | List of SQL files which are run after the container started | `nil` | +| `timezone` | Container and mysqld timezone (TZ env) | `nil` (UTC depending on image) | +| `podAnnotations` | Map of annotations to add to the pods | `{}` | +| `podLabels` | Map of labels to add to the pods | `{}` | +| `priorityClassName` | Set pod priorityClassName | `{}` | +| `deploymentAnnotations` | Map of annotations for deployment | `{}` | +| `strategy` | Update strategy policy | `{type: "Recreate"}` | + +Some of the parameters above map to the env variables defined in the [MySQL DockerHub image](https://hub.docker.com/_/mysql/). + +Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, + +```bash +$ helm install --name my-release \ + --set mysqlRootPassword=secretpassword,mysqlUser=my-user,mysqlPassword=my-password,mysqlDatabase=my-database \ + stable/mysql +``` + +The above command sets the MySQL `root` account password to `secretpassword`. Additionally it creates a standard database user named `my-user`, with the password `my-password`, who has access to a database named `my-database`. + +Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example, + +```bash +$ helm install --name my-release -f values.yaml stable/mysql +``` + +> **Tip**: You can use the default [values.yaml](values.yaml) + +## Persistence + +The [MySQL](https://hub.docker.com/_/mysql/) image stores the MySQL data and configurations at the `/var/lib/mysql` path of the container. + +By default a PersistentVolumeClaim is created and mounted into that directory. In order to disable this functionality +you can change the values.yaml to disable persistence and use an emptyDir instead. + +> *"An emptyDir volume is first created when a Pod is assigned to a Node, and exists as long as that Pod is running on that node. When a Pod is removed from a node for any reason, the data in the emptyDir is deleted forever."* + +**Notice**: You may need to increase the value of `livenessProbe.initialDelaySeconds` when enabling persistence by using PersistentVolumeClaim from PersistentVolume with varying properties. Since its IO performance has impact on the database initialization performance. The default limit for database initialization is `60` seconds (`livenessProbe.initialDelaySeconds` + `livenessProbe.periodSeconds` * `livenessProbe.failureThreshold`). Once such initialization process takes more time than this limit, kubelet will restart the database container, which will interrupt database initialization then causing persisent data in an unusable state. + +## Custom MySQL configuration files + +The [MySQL](https://hub.docker.com/_/mysql/) image accepts custom configuration files at the path `/etc/mysql/conf.d`. If you want to use a customized MySQL configuration, you can create your alternative configuration files by passing the file contents on the `configurationFiles` attribute. Note that according to the MySQL documentation only files ending with `.cnf` are loaded. + +```yaml +configurationFiles: + mysql.cnf: |- + [mysqld] + skip-host-cache + skip-name-resolve + sql-mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION + mysql_custom.cnf: |- + [mysqld] +``` + +## MySQL initialization files + +The [MySQL](https://hub.docker.com/_/mysql/) image accepts *.sh, *.sql and *.sql.gz files at the path `/docker-entrypoint-initdb.d`. +These files are being run exactly once for container initialization and ignored on following container restarts. +If you want to use initialization scripts, you can create initialization files by passing the file contents on the `initializationFiles` attribute. + + +```yaml +initializationFiles: + first-db.sql: |- + CREATE DATABASE IF NOT EXISTS first DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; + second-db.sql: |- + CREATE DATABASE IF NOT EXISTS second DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; +``` + +## SSL + +This chart supports configuring MySQL to use [encrypted connections](https://dev.mysql.com/doc/refman/5.7/en/encrypted-connections.html) with TLS/SSL certificates provided by the user. This is accomplished by storing the required Certificate Authority file, the server public key certificate, and the server private key as a Kubernetes secret. The SSL options for this chart support the following use cases: + +* Manage certificate secrets with helm +* Manage certificate secrets outside of helm + +## Manage certificate secrets with helm + +Include your certificate data in the `ssl.certificates` section. For example: + +``` +ssl: + enabled: false + secret: mysql-ssl-certs + certificates: + - name: mysql-ssl-certs + ca: |- + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + cert: |- + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + key: |- + -----BEGIN RSA PRIVATE KEY----- + ... + -----END RSA PRIVATE KEY----- +``` + +> **Note**: Make sure your certificate data has the correct formatting in the values file. + +## Manage certificate secrets outside of helm + +1. Ensure the certificate secret exist before installation of this chart. +2. Set the name of the certificate secret in `ssl.secret`. +3. Make sure there are no entries underneath `ssl.certificates`. + +To manually create the certificate secret from local files you can execute: +``` +kubectl create secret generic mysql-ssl-certs \ + --from-file=ca.pem=./ssl/certificate-authority.pem \ + --from-file=server-cert.pem=./ssl/server-public-key.pem \ + --from-file=server-key.pem=./ssl/server-private-key.pem +``` +> **Note**: `ca.pem`, `server-cert.pem`, and `server-key.pem` **must** be used as the key names in this generic secret. + +If you are using a certificate your configurationFiles must include the three ssl lines under [mysqld] + +``` +[mysqld] + ssl-ca=/ssl/ca.pem + ssl-cert=/ssl/server-cert.pem + ssl-key=/ssl/server-key.pem +``` diff --git a/chart/charts/mysql/templates/NOTES.txt b/chart/charts/mysql/templates/NOTES.txt new file mode 100644 index 00000000000000..864170c072d5a7 --- /dev/null +++ b/chart/charts/mysql/templates/NOTES.txt @@ -0,0 +1,48 @@ +MySQL can be accessed via port 3306 on the following DNS name from within your cluster: +{{ template "mysql.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local + +{{- if .Values.mysqlx.port.enabled }} +Connection to the X protocol of MySQL can be done via 33060 on the following DNS name from within your cluster: +{{ template "mysql.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local +{{- end }} + +{{- if .Values.existingSecret }} +If you have not already created the mysql password secret: + + kubectl create secret generic {{ .Values.existingSecret }} --namespace {{ .Release.Namespace }} --from-file=./mysql-root-password --from-file=./mysql-password +{{ else }} + +To get your root password run: + + MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "mysql.fullname" . }} -o jsonpath="{.data.mysql-root-password}" | base64 --decode; echo) +{{- end }} + +To connect to your database: + +1. Run an Ubuntu pod that you can use as a client: + + kubectl run -i --tty ubuntu --image=ubuntu:16.04 --restart=Never -- bash -il + +2. Install the mysql client: + + $ apt-get update && apt-get install mysql-client -y + +3. Connect using the mysql cli, then provide your password: + $ mysql -h {{ template "mysql.fullname" . }} -p + +To connect to your database directly from outside the K8s cluster: + {{- if contains "NodePort" .Values.service.type }} + MYSQL_HOST=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath='{.items[0].status.addresses[0].address}') + MYSQL_PORT=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "mysql.fullname" . }} -o jsonpath='{.spec.ports[0].nodePort}') + + {{- else if contains "ClusterIP" .Values.service.type }} + MYSQL_HOST=127.0.0.1 + MYSQL_PORT={{ .Values.service.port }} + + # Execute the following command to route the connection: + kubectl port-forward svc/{{ template "mysql.fullname" . }} {{ .Values.service.port }} + + {{- end }} + + mysql -h ${MYSQL_HOST} -P${MYSQL_PORT} -u root -p${MYSQL_ROOT_PASSWORD} + diff --git a/chart/charts/mysql/templates/_helpers.tpl b/chart/charts/mysql/templates/_helpers.tpl new file mode 100644 index 00000000000000..f1084257788656 --- /dev/null +++ b/chart/charts/mysql/templates/_helpers.tpl @@ -0,0 +1,43 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "mysql.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 "mysql.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- printf .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Generate chart secret name +*/}} +{{- define "mysql.secretName" -}} +{{ default (include "mysql.fullname" .) .Values.existingSecret }} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "mysql.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} +{{ default (include "mysql.fullname" .) .Values.serviceAccount.name }} +{{- else -}} +{{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/chart/charts/mysql/templates/configurationFiles-configmap.yaml b/chart/charts/mysql/templates/configurationFiles-configmap.yaml new file mode 100644 index 00000000000000..ebed8cc7b4e82d --- /dev/null +++ b/chart/charts/mysql/templates/configurationFiles-configmap.yaml @@ -0,0 +1,12 @@ +{{- if .Values.configurationFiles }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "mysql.fullname" . }}-configuration + namespace: {{ .Release.Namespace }} +data: +{{- range $key, $val := .Values.configurationFiles }} + {{ $key }}: |- +{{ $val | indent 4}} +{{- end }} +{{- end -}} \ No newline at end of file diff --git a/chart/charts/mysql/templates/deployment.yaml b/chart/charts/mysql/templates/deployment.yaml new file mode 100644 index 00000000000000..94f94b0c52ae4c --- /dev/null +++ b/chart/charts/mysql/templates/deployment.yaml @@ -0,0 +1,259 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "mysql.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mysql.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +{{- with .Values.deploymentAnnotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} + +spec: + strategy: +{{ toYaml .Values.strategy | indent 4 }} + selector: + matchLabels: + app: {{ template "mysql.fullname" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "mysql.fullname" . }} + release: {{ .Release.Name }} +{{- with .Values.podLabels }} +{{ toYaml . | indent 8 }} +{{- end }} +{{- with .Values.podAnnotations }} + annotations: +{{ toYaml . | indent 8 }} +{{- end }} + spec: + {{- if .Values.schedulerName }} + schedulerName: "{{ .Values.schedulerName }}" + {{- end }} + {{- if .Values.imagePullSecrets }} + imagePullSecrets: +{{ toYaml .Values.imagePullSecrets | indent 8 }} + {{- end }} + {{- if .Values.priorityClassName }} + priorityClassName: "{{ .Values.priorityClassName }}" + {{- end }} + {{- if .Values.securityContext.enabled }} + securityContext: + fsGroup: {{ .Values.securityContext.fsGroup }} + runAsUser: {{ .Values.securityContext.runAsUser }} + {{- end }} + serviceAccountName: {{ template "mysql.serviceAccountName" . }} + initContainers: + - name: "remove-lost-found" + image: "{{ .Values.busybox.image}}:{{ .Values.busybox.tag }}" + imagePullPolicy: {{ .Values.imagePullPolicy | quote }} + resources: +{{ toYaml .Values.initContainer.resources | indent 10 }} + command: ["rm", "-fr", "/var/lib/mysql/lost+found"] + volumeMounts: + - name: data + mountPath: /var/lib/mysql + {{- if .Values.persistence.subPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + {{- if .Values.extraInitContainers }} +{{ tpl .Values.extraInitContainers . | indent 6 }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: +{{ toYaml .Values.nodeSelector | indent 8 }} + {{- end }} + {{- if .Values.affinity }} + affinity: +{{ toYaml .Values.affinity | indent 8 }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 8 }} + {{- end }} + containers: + - name: {{ template "mysql.fullname" . }} + image: "{{ .Values.image }}:{{ .Values.imageTag }}" + imagePullPolicy: {{ .Values.imagePullPolicy | quote }} + + {{- with .Values.args }} + args: + {{- range . }} + - {{ . | quote }} + {{- end }} + {{- end }} + resources: +{{ toYaml .Values.resources | indent 10 }} + env: + {{- if .Values.mysqlAllowEmptyPassword }} + - name: MYSQL_ALLOW_EMPTY_PASSWORD + value: "true" + {{- end }} + {{- if not (and .Values.allowEmptyRootPassword (not .Values.mysqlRootPassword)) }} + - name: MYSQL_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "mysql.secretName" . }} + key: mysql-root-password + {{- if .Values.mysqlAllowEmptyPassword }} + optional: true + {{- end }} + {{- end }} + {{- if not (and .Values.allowEmptyRootPassword (not .Values.mysqlPassword)) }} + - name: MYSQL_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "mysql.secretName" . }} + key: mysql-password + {{- if or .Values.mysqlAllowEmptyPassword (empty .Values.mysqlUser) }} + optional: true + {{- end }} + {{- end }} + - name: MYSQL_USER + value: {{ default "" .Values.mysqlUser | quote }} + - name: MYSQL_DATABASE + value: {{ default "" .Values.mysqlDatabase | quote }} + {{- if .Values.timezone }} + - name: TZ + value: {{ .Values.timezone }} + {{- end }} + {{- if .Values.extraEnvVars }} +{{ tpl .Values.extraEnvVars . | indent 8 }} + {{- end }} + ports: + - name: mysql + containerPort: 3306 + {{- if .Values.mysqlx.port.enabled }} + - name: mysqlx + port: 33060 + {{- end }} + livenessProbe: + exec: + command: + {{- if .Values.mysqlAllowEmptyPassword }} + - mysqladmin + - ping + {{- else }} + - sh + - -c + - "mysqladmin ping -u root -p${MYSQL_ROOT_PASSWORD}" + {{- end }} + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + readinessProbe: + exec: + command: + {{- if .Values.mysqlAllowEmptyPassword }} + - mysqladmin + - ping + {{- else }} + - sh + - -c + - "mysqladmin ping -u root -p${MYSQL_ROOT_PASSWORD}" + {{- end }} + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + volumeMounts: + - name: data + mountPath: /var/lib/mysql + {{- if .Values.persistence.subPath }} + subPath: {{ .Values.persistence.subPath }} + {{- end }} + {{- if .Values.configurationFiles }} + {{- range $key, $val := .Values.configurationFiles }} + - name: configurations + mountPath: {{ $.Values.configurationFilesPath }}{{ $key }} + subPath: {{ $key }} + {{- end -}} + {{- end }} + {{- if .Values.initializationFiles }} + - name: migrations + mountPath: /docker-entrypoint-initdb.d + {{- end }} + {{- if .Values.ssl.enabled }} + - name: certificates + mountPath: /ssl + {{- end }} + {{- if .Values.extraVolumeMounts }} +{{ tpl .Values.extraVolumeMounts . | indent 8 }} + {{- end }} + {{- if .Values.metrics.enabled }} + - name: metrics + image: "{{ .Values.metrics.image }}:{{ .Values.metrics.imageTag }}" + imagePullPolicy: {{ .Values.metrics.imagePullPolicy | quote }} + {{- if .Values.mysqlAllowEmptyPassword }} + command: + - 'sh' + - '-c' + - 'DATA_SOURCE_NAME="root@(localhost:3306)/" /bin/mysqld_exporter' + {{- else }} + env: + - name: MYSQL_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "mysql.secretName" . }} + key: mysql-root-password + command: + - 'sh' + - '-c' + - 'DATA_SOURCE_NAME="root:$MYSQL_ROOT_PASSWORD@(localhost:3306)/" /bin/mysqld_exporter' + {{- end }} + {{- range $f := .Values.metrics.flags }} + - {{ $f | quote }} + {{- end }} + ports: + - name: metrics + containerPort: 9104 + livenessProbe: + httpGet: + path: / + port: metrics + initialDelaySeconds: {{ .Values.metrics.livenessProbe.initialDelaySeconds }} + timeoutSeconds: {{ .Values.metrics.livenessProbe.timeoutSeconds }} + readinessProbe: + httpGet: + path: / + port: metrics + initialDelaySeconds: {{ .Values.metrics.readinessProbe.initialDelaySeconds }} + timeoutSeconds: {{ .Values.metrics.readinessProbe.timeoutSeconds }} + resources: +{{ toYaml .Values.metrics.resources | indent 10 }} + {{- end }} + volumes: + {{- if .Values.configurationFiles }} + - name: configurations + configMap: + name: {{ template "mysql.fullname" . }}-configuration + {{- end }} + {{- if .Values.initializationFiles }} + - name: migrations + configMap: + name: {{ template "mysql.fullname" . }}-initialization + {{- end }} + {{- if .Values.ssl.enabled }} + - name: certificates + secret: + secretName: {{ .Values.ssl.secret }} + {{- end }} + - name: data + {{- if .Values.persistence.enabled }} + persistentVolumeClaim: + claimName: {{ .Values.persistence.existingClaim | default (include "mysql.fullname" .) }} + {{- else }} + emptyDir: {} + {{- end -}} + {{- if .Values.extraVolumes }} +{{ tpl .Values.extraVolumes . | indent 6 }} + {{- end }} diff --git a/chart/charts/mysql/templates/initializationFiles-configmap.yaml b/chart/charts/mysql/templates/initializationFiles-configmap.yaml new file mode 100644 index 00000000000000..38c3795c765a3d --- /dev/null +++ b/chart/charts/mysql/templates/initializationFiles-configmap.yaml @@ -0,0 +1,12 @@ +{{- if .Values.initializationFiles }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "mysql.fullname" . }}-initialization + namespace: {{ .Release.Namespace }} +data: +{{- range $key, $val := .Values.initializationFiles }} + {{ $key }}: |- +{{ $val | indent 4}} +{{- end }} +{{- end -}} \ No newline at end of file diff --git a/chart/charts/mysql/templates/pvc.yaml b/chart/charts/mysql/templates/pvc.yaml new file mode 100644 index 00000000000000..39e9bf8e26f726 --- /dev/null +++ b/chart/charts/mysql/templates/pvc.yaml @@ -0,0 +1,29 @@ +{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ template "mysql.fullname" . }} + namespace: {{ .Release.Namespace }} +{{- with .Values.persistence.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} + labels: + app: {{ template "mysql.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + accessModes: + - {{ .Values.persistence.accessMode | quote }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} +{{- if .Values.persistence.storageClass }} +{{- if (eq "-" .Values.persistence.storageClass) }} + storageClassName: "" +{{- else }} + storageClassName: "{{ .Values.persistence.storageClass }}" +{{- end }} +{{- end }} +{{- end }} diff --git a/chart/charts/mysql/templates/secrets.yaml b/chart/charts/mysql/templates/secrets.yaml new file mode 100644 index 00000000000000..d9dfd126d59e2b --- /dev/null +++ b/chart/charts/mysql/templates/secrets.yaml @@ -0,0 +1,51 @@ +{{- if not .Values.existingSecret }} +{{- if or (not .Values.allowEmptyRootPassword) (or .Values.mysqlRootPassword .Values.mysqlPassword) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "mysql.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mysql.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +type: Opaque +data: + {{ if .Values.mysqlRootPassword }} + mysql-root-password: {{ .Values.mysqlRootPassword | b64enc | quote }} + {{ else }} + {{ if not .Values.allowEmptyRootPassword }} + mysql-root-password: {{ randAlphaNum 10 | b64enc | quote }} + {{ end }} + {{ end }} + {{ if .Values.mysqlPassword }} + mysql-password: {{ .Values.mysqlPassword | b64enc | quote }} + {{ else }} + {{ if not .Values.allowEmptyRootPassword }} + mysql-password: {{ randAlphaNum 10 | b64enc | quote }} + {{ end }} + {{ end }} +{{ end }} +{{- if .Values.ssl.enabled }} +{{ if .Values.ssl.certificates }} +{{- range .Values.ssl.certificates }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ .name }} + labels: + app: {{ template "mysql.fullname" $ }} + chart: "{{ $.Chart.Name }}-{{ $.Chart.Version }}" + release: "{{ $.Release.Name }}" + heritage: "{{ $.Release.Service }}" +type: Opaque +data: + ca.pem: {{ .ca | b64enc }} + server-cert.pem: {{ .cert | b64enc }} + server-key.pem: {{ .key | b64enc }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/chart/charts/mysql/templates/serviceaccount.yaml b/chart/charts/mysql/templates/serviceaccount.yaml new file mode 100644 index 00000000000000..36ce6b3b7a5b13 --- /dev/null +++ b/chart/charts/mysql/templates/serviceaccount.yaml @@ -0,0 +1,11 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "mysql.serviceAccountName" . }} + labels: + app: {{ template "mysql.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +{{- end }} diff --git a/chart/charts/mysql/templates/servicemonitor.yaml b/chart/charts/mysql/templates/servicemonitor.yaml new file mode 100644 index 00000000000000..bd830be654dd48 --- /dev/null +++ b/chart/charts/mysql/templates/servicemonitor.yaml @@ -0,0 +1,26 @@ +{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "mysql.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mysql.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" + {{- if .Values.metrics.serviceMonitor.additionalLabels }} +{{ toYaml .Values.metrics.serviceMonitor.additionalLabels | indent 4 }} + {{- end }} +spec: + endpoints: + - port: metrics + interval: 30s + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} + selector: + matchLabels: + app: {{ include "mysql.fullname" . }} + release: {{ .Release.Name }} +{{- end }} diff --git a/chart/charts/mysql/templates/svc.yaml b/chart/charts/mysql/templates/svc.yaml new file mode 100644 index 00000000000000..3185193b08e9db --- /dev/null +++ b/chart/charts/mysql/templates/svc.yaml @@ -0,0 +1,42 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "mysql.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mysql.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" + annotations: +{{- if .Values.service.annotations }} +{{ toYaml .Values.service.annotations | indent 4 }} +{{- end }} +{{- if and (.Values.metrics.enabled) (.Values.metrics.annotations) }} +{{ toYaml .Values.metrics.annotations | indent 4 }} +{{- end }} +spec: + type: {{ .Values.service.type }} + {{- if (and (eq .Values.service.type "LoadBalancer") (not (empty .Values.service.loadBalancerIP))) }} + loadBalancerIP: {{ .Values.service.loadBalancerIP }} + {{- end }} + ports: + - name: mysql + port: {{ .Values.service.port }} + targetPort: mysql + {{- if .Values.service.nodePort }} + nodePort: {{ .Values.service.nodePort }} + {{- end }} + {{- if .Values.mysqlx.port.enabled }} + - name: mysqlx + port: 33060 + targetPort: mysqlx + protocol: TCP + {{- end }} + {{- if .Values.metrics.enabled }} + - name: metrics + port: 9104 + targetPort: metrics + {{- end }} + selector: + app: {{ template "mysql.fullname" . }} diff --git a/chart/charts/mysql/templates/tests/test-configmap.yaml b/chart/charts/mysql/templates/tests/test-configmap.yaml new file mode 100644 index 00000000000000..ece5a4705c1935 --- /dev/null +++ b/chart/charts/mysql/templates/tests/test-configmap.yaml @@ -0,0 +1,23 @@ +{{- if .Values.testFramework.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "mysql.fullname" . }}-test + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mysql.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: "{{ .Release.Service }}" + release: "{{ .Release.Name }}" +data: + run.sh: |- + {{- if .Values.ssl.enabled | and .Values.mysqlRootPassword }} + @test "Testing SSL MySQL Connection" { + mysql --host={{ template "mysql.fullname" . }} --port={{ .Values.service.port | default "3306" }} --ssl-cert=/ssl/server-cert.pem --ssl-key=ssl/server-key.pem -u root -p{{ .Values.mysqlRootPassword }} + } + {{- else if .Values.mysqlRootPassword }} + @test "Testing MySQL Connection" { + mysql --host={{ template "mysql.fullname" . }} --port={{ .Values.service.port | default "3306" }} -u root -p{{ .Values.mysqlRootPassword }} + } + {{- end }} +{{- end }} diff --git a/chart/charts/mysql/templates/tests/test.yaml b/chart/charts/mysql/templates/tests/test.yaml new file mode 100644 index 00000000000000..1771cd0df20dc6 --- /dev/null +++ b/chart/charts/mysql/templates/tests/test.yaml @@ -0,0 +1,59 @@ +{{- if .Values.testFramework.enabled }} +apiVersion: v1 +kind: Pod +metadata: + name: {{ template "mysql.fullname" . }}-test + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "mysql.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: "{{ .Release.Service }}" + release: "{{ .Release.Name }}" + annotations: + "helm.sh/hook": test-success +spec: + {{- if .Values.testFramework.securityContext }} + securityContext: {{ toYaml .Values.testFramework.securityContext | nindent 4 }} + {{- end }} + {{- if .Values.imagePullSecrets }} + imagePullSecrets: + {{- range .Values.imagePullSecrets }} + - name: {{ . }} + {{- end}} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 4 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 4 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 4 }} + {{- end }} + containers: + - name: {{ .Release.Name }}-test + image: "{{ .Values.testFramework.image }}:{{ .Values.testFramework.tag }}" + imagePullPolicy: "{{ .Values.testFramework.imagePullPolicy}}" + command: ["/opt/bats/bin/bats", "-t", "/tests/run.sh"] + volumeMounts: + - mountPath: /tests + name: tests + readOnly: true + {{- if .Values.ssl.enabled }} + - name: certificates + mountPath: /ssl + {{- end }} + volumes: + - name: tests + configMap: + name: {{ template "mysql.fullname" . }}-test + {{- if .Values.ssl.enabled }} + - name: certificates + secret: + secretName: {{ .Values.ssl.secret }} + {{- end }} + restartPolicy: Never +{{- end }} diff --git a/chart/charts/mysql/values.yaml b/chart/charts/mysql/values.yaml new file mode 100644 index 00000000000000..b287e9cff65658 --- /dev/null +++ b/chart/charts/mysql/values.yaml @@ -0,0 +1,247 @@ +## mysql image version +## ref: https://hub.docker.com/r/library/mysql/tags/ +## +image: "mysql" +imageTag: "5.7.30" + +strategy: + type: Recreate + +busybox: + image: "busybox" + tag: "1.32" + +testFramework: + enabled: true + image: "bats/bats" + tag: "1.2.1" + imagePullPolicy: IfNotPresent + securityContext: {} + +## Specify password for root user +## +## Default: random 10 character string +# mysqlRootPassword: testing + +## Create a database user +## +# mysqlUser: +## Default: random 10 character string +# mysqlPassword: + +## Allow unauthenticated access, uncomment to enable +## +# mysqlAllowEmptyPassword: true + +## Create a database +## +# mysqlDatabase: + +## Specify an imagePullPolicy (Required) +## It's recommended to change this to 'Always' if the image tag is 'latest' +## ref: http://kubernetes.io/docs/user-guide/images/#updating-images +## +imagePullPolicy: IfNotPresent + +## Additionnal arguments that are passed to the MySQL container. +## For example use --default-authentication-plugin=mysql_native_password if older clients need to +## connect to a MySQL 8 instance. +args: [] + +extraVolumes: | + # - name: extras + # emptyDir: {} + +extraVolumeMounts: | + # - name: extras + # mountPath: /usr/share/extras + # readOnly: true + +extraInitContainers: | + # - name: do-something + # image: busybox + # command: ['do', 'something'] + +## A string to add extra environment variables +# extraEnvVars: | +# - name: EXTRA_VAR +# value: "extra" + +# Optionally specify an array of imagePullSecrets. +# Secrets must be manually created in the namespace. +# ref: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod +# imagePullSecrets: + # - name: myRegistryKeySecretName + +## Node selector +## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector +nodeSelector: {} + +## Affinity +## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity +affinity: {} + +## Tolerations for pod assignment +## Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ +## +tolerations: [] + +livenessProbe: + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 3 + +readinessProbe: + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 1 + successThreshold: 1 + failureThreshold: 3 + +## Persist data to a persistent volume +persistence: + enabled: true + ## database data Persistent Volume Storage Class + ## If defined, storageClassName: + ## If set to "-", storageClassName: "", which disables dynamic provisioning + ## If undefined (the default) or set to null, no storageClassName spec is + ## set, choosing the default provisioner. (gp2 on AWS, standard on + ## GKE, AWS & OpenStack) + ## + # storageClass: "-" + accessMode: ReadWriteOnce + size: 8Gi + annotations: {} + +## Use an alternate scheduler, e.g. "stork". +## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ +## +# schedulerName: + +## Security context +securityContext: + enabled: false + runAsUser: 999 + fsGroup: 999 + +## Configure resource requests and limits +## ref: http://kubernetes.io/docs/user-guide/compute-resources/ +## +resources: + requests: + memory: 256Mi + cpu: 100m + +# Custom mysql configuration files path +configurationFilesPath: /etc/mysql/conf.d/ + +# Custom mysql configuration files used to override default mysql settings +configurationFiles: {} +# mysql.cnf: |- +# [mysqld] +# skip-name-resolve +# ssl-ca=/ssl/ca.pem +# ssl-cert=/ssl/server-cert.pem +# ssl-key=/ssl/server-key.pem + +# Custom mysql init SQL files used to initialize the database +initializationFiles: {} + +# first-db.sql: |- +# CREATE DATABASE IF NOT EXISTS first DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; +# second-db.sql: |- +# CREATE DATABASE IF NOT EXISTS second DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; + +# To enaable the mysql X Protocol's port +# .. will expose the port 33060 +# .. Note the X Plugin needs installation +# ref: https://dev.mysql.com/doc/refman/8.0/en/x-plugin-checking-installation.html +mysqlx: + port: + enabled: false + +metrics: + enabled: false + image: prom/mysqld-exporter + imageTag: v0.10.0 + imagePullPolicy: IfNotPresent + resources: {} + annotations: {} + # prometheus.io/scrape: "true" + # prometheus.io/port: "9104" + livenessProbe: + initialDelaySeconds: 15 + timeoutSeconds: 5 + readinessProbe: + initialDelaySeconds: 5 + timeoutSeconds: 1 + flags: [] + serviceMonitor: + enabled: false + additionalLabels: {} + +## Configure the service +## ref: http://kubernetes.io/docs/user-guide/services/ +service: + annotations: {} + ## Specify a service type + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services---service-types + type: ClusterIP + port: 3306 + # nodePort: 32000 + # loadBalancerIP: + +## Pods Service Account +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ +serviceAccount: + ## Specifies whether a ServiceAccount should be created + ## + create: false + ## The name of the ServiceAccount to use. + ## If not set and create is true, a name is generated using the mariadb.fullname template + # name: + +ssl: + enabled: false + secret: mysql-ssl-certs + certificates: +# - name: mysql-ssl-certs +# ca: |- +# -----BEGIN CERTIFICATE----- +# ... +# -----END CERTIFICATE----- +# cert: |- +# -----BEGIN CERTIFICATE----- +# ... +# -----END CERTIFICATE----- +# key: |- +# -----BEGIN RSA PRIVATE KEY----- +# ... +# -----END RSA PRIVATE KEY----- + +## Populates the 'TZ' system timezone environment variable +## ref: https://dev.mysql.com/doc/refman/5.7/en/time-zone-support.html +## +## Default: nil (mysql will use image's default timezone, normally UTC) +## Example: 'Australia/Sydney' +# timezone: + +# Deployment Annotations +deploymentAnnotations: {} + +# To be added to the database server pod(s) +podAnnotations: {} +podLabels: {} + +## Set pod priorityClassName +# priorityClassName: {} + + +## Init container resources defaults +initContainer: + resources: + requests: + memory: 10Mi + cpu: 10m diff --git a/chart/config/db/init/00-testdb-user.sql b/chart/config/db/init/00-testdb-user.sql deleted file mode 100644 index 2615a7745e5e97..00000000000000 --- a/chart/config/db/init/00-testdb-user.sql +++ /dev/null @@ -1,6 +0,0 @@ --- Copyright (c) 2020 Gitpod GmbH. All rights reserved. --- Licensed under the MIT License. See License-MIT.txt in the project root for license information. - - --- create test DB user -SET @gitpodDbPassword = IFNULL(@gitpodDbPassword, 'test'); diff --git a/chart/config/db/init/01-create-user.sql b/chart/config/db/init/01-create-user.sql index 4ba6496d22d31d..5daec4af7f3dc0 100644 --- a/chart/config/db/init/01-create-user.sql +++ b/chart/config/db/init/01-create-user.sql @@ -1,14 +1,5 @@ -- Copyright (c) 2020 Gitpod GmbH. All rights reserved. -- Licensed under the MIT License. See License-MIT.txt in the project root for license information. --- must be idempotent - --- create user (parameterized) -SET @statementStr = CONCAT( - 'CREATE USER IF NOT EXISTS "gitpod"@"%" IDENTIFIED BY "', @gitpodDbPassword, '";' -); -SELECT @statementStr ; -PREPARE stmt FROM @statementStr; EXECUTE stmt; DEALLOCATE PREPARE stmt; - -- Grant privileges GRANT ALL ON `gitpod%`.* TO "gitpod"@"%"; diff --git a/chart/requirements.lock b/chart/requirements.lock deleted file mode 100644 index 57cfad3f9d0e60..00000000000000 --- a/chart/requirements.lock +++ /dev/null @@ -1,12 +0,0 @@ -dependencies: -- name: docker-registry - repository: https://helm.twun.io - version: 1.10.0 -- name: minio - repository: https://helm.min.io/ - version: 8.0.7 -- name: mysql - repository: https://charts.helm.sh/stable - version: 1.6.9 -digest: sha256:e01ec50c4c6f56e8f07f6a8f32536a5e39c3b32615404f2050d561d8f8bccb1d -generated: "2021-01-29T09:34:06.093536234Z" diff --git a/chart/requirements.yaml b/chart/requirements.yaml index e6c686ff7ea9fc..4bec96b2a7c0be 100644 --- a/chart/requirements.yaml +++ b/chart/requirements.yaml @@ -4,8 +4,8 @@ # requirements.yaml dependencies: - name: docker-registry - version: 1.10.0 - repository: https://helm.twun.io + version: 1.8.x + repository: "file://./charts/docker-registry" condition: docker-registry.enabled - name: minio version: 8.0.7 @@ -13,5 +13,5 @@ dependencies: condition: minio.enabled - name: mysql version: 1.6.9 - repository: https://charts.helm.sh/stable - condition: mysql.enabled \ No newline at end of file + repository: "file://./charts/mysql" + condition: mysql.enabled \ No newline at end of file diff --git a/chart/templates/db-deployment.yaml b/chart/templates/db-deployment.yaml index 8f93dbba78c8b2..432132150a195b 100644 --- a/chart/templates/db-deployment.yaml +++ b/chart/templates/db-deployment.yaml @@ -62,4 +62,4 @@ spec: secret: secretName: gcloud-sql-token {{ toYaml .Values.defaults | indent 6 }} -{{- end -}} +{{- end }} diff --git a/chart/templates/db-service.yaml b/chart/templates/db-service.yaml index 1fe950e977d572..dc3fc8ee1ca81f 100644 --- a/chart/templates/db-service.yaml +++ b/chart/templates/db-service.yaml @@ -26,7 +26,7 @@ spec: component: {{ $comp.name }} kind: pod {{- else }} - app: mysql + app: gitpod-mysql {{- end }} type: {{ $comp.serviceType }} sessionAffinity: None \ No newline at end of file diff --git a/chart/values.yaml b/chart/values.yaml index ba087b4e7adfb5..9200bb084c06c6 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -1,7 +1,7 @@ # Copyright (c) 2020 Gitpod GmbH. All rights reserved. # Licensed under the MIT License. See License-MIT.txt in the project root for license information. -version: "0.7.0" +version: "0.7.0-beta1" hostname: localhost # ingressModes determines how Gitpod makes workspaces and their ports available. Possible values are: @@ -506,8 +506,8 @@ docker-registry: minio: enabled: true fullnameOverride: minio - accessKey: # create random accesskey and secretkey - secretKey: # create random accesskey and secretkey + accessKey: sadsadasdsd # create random accesskey and secretkey + secretKey: sduasgagiffg # create random accesskey and secretkey serviceAccount: create: true name: minio @@ -518,16 +518,23 @@ minio: mysql: enabled: true - fullnameOverride: mysql - testFramework: - enabled: false - existingSecret: db-password - serviceAccount: - name: db - extraVolumes: | - - name: init-scripts - configMap: - name: db-init-scripts - extraVolumeMounts: | - - mountPath: /docker-entrypoint-initdb.d - name: init-scripts + mysqlRootPassword: test + initializationFiles: + init.sql: |- + GRANT ALL ON `gitpod%`.* TO "gitpod"@"%"; + CREATE DATABASE IF NOT EXISTS `gitpod-sessions` CHARSET utf8mb4; + USE `gitpod-sessions`; + CREATE TABLE IF NOT EXISTS sessions ( + `session_id` varchar(128) COLLATE utf8mb4_bin NOT NULL, + `expires` int(11) unsigned NOT NULL, + `data` text COLLATE utf8mb4_bin, + `_lastModified` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), + PRIMARY KEY (`session_id`) + ); + SET @gitpodDB = IFNULL(@gitpodDB, '`gitpod`'); + SET @statementStr = CONCAT('DROP DATABASE IF EXISTS ', @gitpodDB); + PREPARE statement FROM @statementStr; + EXECUTE statement; + SET @statementStr = CONCAT('CREATE DATABASE ', @gitpodDB, ' CHARSET utf8mb4'); + PREPARE statement FROM @statementStr; + EXECUTE statement; diff --git a/install/gcp-terraform/environment/full/main.tf b/install/gcp-terraform/environment/full/main.tf index ab9d1b2c9a1e5b..73d7c841fede64 100644 --- a/install/gcp-terraform/environment/full/main.tf +++ b/install/gcp-terraform/environment/full/main.tf @@ -3,6 +3,10 @@ * Licensed under the MIT License. See License-MIT.txt in the project root for license information. */ +locals { + region = trimsuffix(var.location,local.zone_suffix) + zone_suffix = regex("-[a-z]$",var.location) +} resource "google_compute_network" "gitpod" { name = "gitpod" @@ -17,27 +21,15 @@ module "kubernetes" { name = "gitpod" network = google_compute_network.gitpod.name project = var.project - region = var.region + location = var.location } -module "kubeconfig" { - source = "../../modules/kubeconfig" - - cluster = { - name = "gitpod" - } - - depends_on = [ - module.kubernetes - ] -} - module "dns" { source = "../../modules/dns" project = var.project - region = var.region + location = var.location zone_name = var.zone_name name = "gitpod-dns" subdomain = var.subdomain @@ -83,21 +75,21 @@ module "storage" { name = var.subdomain project = var.project - region = var.region + region = local.region location = "EU" } -module "database" { - source = "../../modules/database" +# module "database" { +# source = "../../modules/database" - project = var.project - name = var.database.name - region = var.region - network = { - id = google_compute_network.gitpod.id - name = google_compute_network.gitpod.name - } -} +# project = var.project +# name = var.database.name +# region = local.region +# network = { +# id = google_compute_network.gitpod.id +# name = google_compute_network.gitpod.name +# } +# } # # Gitpod @@ -107,18 +99,19 @@ module "gitpod" { source = "../../modules/gitpod" project = var.project - region = var.region namespace = var.namespace values = file("values.yaml") dns_values = module.dns.values certificate_values = module.certmanager.values - database_values = module.database.values + # database_values = module.database.values registry_values = module.registry.values storage_values = module.storage.values license = var.license gitpod = { - chart = "../../../../chart" + repository = var.gitpod_repository + chart = var.gitpod_chart + version = var.gitpod_version image_prefix = "gcr.io/gitpod-io/self-hosted/" } diff --git a/install/gcp-terraform/environment/full/providers.tf b/install/gcp-terraform/environment/full/providers.tf index 743e3c099b1c34..0ce339a432a5d2 100644 --- a/install/gcp-terraform/environment/full/providers.tf +++ b/install/gcp-terraform/environment/full/providers.tf @@ -5,14 +5,12 @@ provider "google" { project = var.project - region = var.region + region = local.region } data "google_client_config" "provider" {} provider "kubernetes" { - load_config_file = "false" - host = module.kubernetes.cluster.endpoint token = data.google_client_config.provider.access_token cluster_ca_certificate = base64decode(module.kubernetes.cluster.master_auth[0].cluster_ca_certificate) @@ -27,8 +25,6 @@ provider "helm" { } provider "kubectl" { - load_config_file = "false" - host = module.kubernetes.cluster.endpoint token = data.google_client_config.provider.access_token cluster_ca_certificate = base64decode(module.kubernetes.cluster.master_auth[0].cluster_ca_certificate) diff --git a/install/gcp-terraform/environment/full/values.yaml b/install/gcp-terraform/environment/full/values.yaml index 4e24bf460497cc..26640e0d988564 100644 --- a/install/gcp-terraform/environment/full/values.yaml +++ b/install/gcp-terraform/environment/full/values.yaml @@ -1,11 +1,6 @@ ingressMode: noDomain certificatesSecret: {} +authProviders: [] -components: - wsProxy: - ingress: - portRange: - start: 10000 - end: 11000 - -authProviders: [] \ No newline at end of file +mysql: + enabled: true diff --git a/install/gcp-terraform/environment/full/variables.tf b/install/gcp-terraform/environment/full/variables.tf index 16dd7519d2484a..334e36f8cfed87 100644 --- a/install/gcp-terraform/environment/full/variables.tf +++ b/install/gcp-terraform/environment/full/variables.tf @@ -8,7 +8,7 @@ variable "project" { type = string } -variable "region" { +variable "location" { type = string } @@ -49,3 +49,16 @@ variable "subdomain" { type = string default = "gitpod" } + + +variable "gitpod_repository" { + type = string +} + +variable "gitpod_chart" { + type = string +} + +variable "gitpod_version" { + type = string +} \ No newline at end of file diff --git a/install/gcp-terraform/environment/minimal/.gitignore b/install/gcp-terraform/environment/minimal/.gitignore new file mode 100644 index 00000000000000..ab1acdd1a253e0 --- /dev/null +++ b/install/gcp-terraform/environment/minimal/.gitignore @@ -0,0 +1,9 @@ +**/.terraform/* +*.tfstate +*.tfstate.* +crash.log +override.tf +override.tf.json +*_override.tf +*_override.tf.json +*.auto.tfvars \ No newline at end of file diff --git a/install/gcp-terraform/environment/minimal/.kubeconfig b/install/gcp-terraform/environment/minimal/.kubeconfig new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/install/gcp-terraform/environment/minimal/.terraform.lock.hcl b/install/gcp-terraform/environment/minimal/.terraform.lock.hcl new file mode 100644 index 00000000000000..7a6b6038fe12c1 --- /dev/null +++ b/install/gcp-terraform/environment/minimal/.terraform.lock.hcl @@ -0,0 +1,119 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/gavinbunney/kubectl" { + version = "1.9.4" + constraints = "1.9.4" + hashes = [ + "h1:i/U6AFQ0carwoKyZTyePBMnz11UMZSE+7vgSPbRnqpA=", + "zh:4cde6a0dacb2046e501b906c67deafaf424162b7ffa827d3003d62ee1d815169", + "zh:4fe3a53b0bb96c0e78b98118797528afbdc3e7b1a3583eb9d239f2b3a9b38692", + "zh:5e6b9d915f9c3c92ff49b3bd9892a2d7007296132b9a713c8d08f20752f25d05", + "zh:95df66eb37f0cfd0dd5d5425be34be969c426fa7b143c6b197177b2113868ef2", + "zh:9f494b9fc0466f97d9a4bbc63c8946560114a682b881041d17168fc9b22d2ba6", + "zh:b8d52467766c20902ae0f6e0e93db32b72f7919d69d54d72bdb77920223b3e30", + "zh:bbe6f23a3596a5c7a8c0d61f77d45003ab7e83776ceb4f74bc9216914c38dfcc", + ] +} + +provider "registry.terraform.io/hashicorp/google" { + version = "3.54.0" + hashes = [ + "h1:XF/CXXSzsCGI0vaq2iz27gPL8Gf0dC2sqE7ItVkrDWM=", + "zh:211dcbc641712250c1903f1ac031968aad1baba62c3cc350ffc6b42317613075", + "zh:934f5afa3bc46bb6f4941c4a003178613e8566e8b6cedaf160312b5456fd0822", + "zh:ac02478b4280cfe7064924bff2a653d9b3a010d0b3c6cf1b232ec7b0be00a2d3", + "zh:b1738d6811849f81aac0a117cf9f2025e28385bd7a96652f4ef33b3402db2a36", + "zh:b81e9699184fbff1fc8d08371989fabf89f8eedf2ec8531183e0c74cfd38bd11", + "zh:ca5e59925bf3174892364c9e125886870bd51e3acdd1152861d9ed2c198e0957", + "zh:cff24b8d85f420dccc099d29968856807d2f2e5ba47a80160d13bf5d78c1e9be", + "zh:dc5d8d989dffed103b8ad897868d3b2efd33316f08c83b61a3a9ec5bb8c1cbee", + "zh:e78677deaad77d0e36866fb0b25fab7f01bae4f812942c6c1fa0bf8eb02edb1a", + "zh:e9d94ddfb1ad845a005098f1644e1fb5e5e77e3fc67142859de5818023b775b7", + ] +} + +provider "registry.terraform.io/hashicorp/helm" { + version = "2.0.2" + hashes = [ + "h1:NeS94WlOI85mRXQblK/s1oGO/pdz+2HCAsQp8ePQqH0=", + "zh:09f7b2389f0e41f51c933d014fe3a89aa53c12801ab45c082d3626689961d5a6", + "zh:0af792512adf59648b7cb7f0f194151ac926ae6805ffdb2baf61512b55933e17", + "zh:0e29837d65bf4dbe3b9766221a1a4448b2c9df7f4d3049a0b6812055e299c063", + "zh:25a0c4d1cba9a22f4d12f6465f191db6e2ec675cbc2c7751bf128bcae23848a8", + "zh:6d92f9ffd43a45f0f0da4c59cbb1790b163235882532a88344a53b8526808979", + "zh:7c98a0e05f106d4bbfc0c81f7d8b41bc8e867a99b30ccd472367d0414e778c30", + "zh:8de8232eedfa4ade990faea4ed3706f0846eb1d66fb82aa22718c7a9aeda92b1", + "zh:baff5ff10c9573104d25eece9f79477112ed6882c0ea9280ecbfa944d117838d", + "zh:d151fac8be471922cbe137f5a263f4854cdcfbf3fb8af7db83c709d64956934b", + "zh:e4d238facc27fc91d26aef79b7f398a6b9f3a1fe078c8d3f0cd4df47ec5aaacd", + ] +} + +provider "registry.terraform.io/hashicorp/kubernetes" { + version = "2.0.1" + hashes = [ + "h1:jyg7vjMLicz7dawGK0sFlvJlaE3J7e4eC1bBzNbZgS8=", + "zh:19a5656300f92e265b521a91b70fa822139589f5b53d7be5a990462b4bc93c8e", + "zh:2c1a8faffaa1cce16f651a60e02f26979772def6e1d30bf2efcb6daa343dbc36", + "zh:465d6b4c29c82a1b3ad9bbb16b35d2706ac120a24ea301f9d3fe155ad243ae3b", + "zh:4e32ff62f73732b629b66298a22884707a814e82d4025e04d08893ee0f9cf389", + "zh:7de1c9cf8524d2c2320dc18601aa20451a0a8ea31662fd54f5bbf125cf7b477b", + "zh:a5f8c5cd8c91eb27791261c07745e7143349594fd058278031a85e97fbbe830e", + "zh:a8f1b39f69e0dd29635ce5b1c88527ec5e4ef308a45088842e32ff825c32ab21", + "zh:ae8ce3e057f2645efca1fe10b65e9b80d60de37d8a8f01cb6e7ed19d12782be2", + "zh:cf1326f8e253b1cc27f8b4367696e07efc1020f9828ed56df17f5bb4e4bf65ad", + "zh:d3c1942e8cc5a1bbc84e89c9320bf55840ee079937003a0d6e245b3f9c744d55", + ] +} + +provider "registry.terraform.io/hashicorp/local" { + version = "2.0.0" + hashes = [ + "h1:EC6eh7avwx1rF56h3RZcxgEp/14ihi7Sk/4J3Hn4nIE=", + "zh:34ce8b79493ace8333d094752b579ccc907fa9392a2c1d6933a6c95d0786d3f1", + "zh:5c5a19c4f614a4ffb68bae0b0563f3860115cf7539b8adc21108324cfdc10092", + "zh:67ddb1ca2cd3e1a8f948302597ceb967f19d2eeb2d125303493667388fe6330e", + "zh:68e6b16f3a8e180fcba1a99754118deb2d82331b51f6cca39f04518339bfdfa6", + "zh:8393a12eb11598b2799d51c9b0a922a3d9fadda5a626b94a1b4914086d53120e", + "zh:90daea4b2010a86f2aca1e3a9590e0b3ddcab229c2bd3685fae76a832e9e836f", + "zh:99308edc734a0ac9149b44f8e316ca879b2670a1cae387a8ae754c180b57cdb4", + "zh:c76594db07a9d1a73372a073888b672df64adb455d483c2426cc220eda7e092e", + "zh:dc09c1fb36c6a706bdac96cce338952888c8423978426a09f5df93031aa88b84", + "zh:deda88134e9780319e8de91b3745520be48ead6ec38cb662694d09185c3dac70", + ] +} + +provider "registry.terraform.io/hashicorp/random" { + version = "3.0.1" + hashes = [ + "h1:SzM8nt2wzLMI28A3CWAtW25g3ZCm1O4xD0h3Ps/rU1U=", + "zh:0d4f683868324af056a9eb2b06306feef7c202c88dbbe6a4ad7517146a22fb50", + "zh:4824b3c7914b77d41dfe90f6f333c7ac9860afb83e2a344d91fbe46e5dfbec26", + "zh:4b82e43712f3cf0d0cbc95b2cbcd409ba8f0dc7848fdfb7c13633c27468ed04a", + "zh:78b3a2b860c3ebc973a794000015f5946eb59b82705d701d487475406b2612f1", + "zh:88bc65197bd74ff408d147b32f0045372ae3a3f2a2fdd7f734f315d988c0e4a2", + "zh:91bd3c9f625f177f3a5d641a64e54d4b4540cb071070ecda060a8261fb6eb2ef", + "zh:a6818842b28d800f784e0c93284ff602b0c4022f407e4750da03f50b853a9a2c", + "zh:c4a1a2b52abd05687e6cfded4a789dcd7b43e7a746e4d02dd1055370cf9a994d", + "zh:cf65041bf12fc3bde709c1d267dbe94142bc05adcabc4feb17da3b12249132ac", + "zh:e385e00e7425dda9d30b74ab4ffa4636f4b8eb23918c0b763f0ffab84ece0c5c", + ] +} + +provider "registry.terraform.io/hashicorp/template" { + version = "2.2.0" + hashes = [ + "h1:94qn780bi1qjrbC3uQtjJh3Wkfwd5+tTtJHOb7KTg9w=", + "zh:01702196f0a0492ec07917db7aaa595843d8f171dc195f4c988d2ffca2a06386", + "zh:09aae3da826ba3d7df69efeb25d146a1de0d03e951d35019a0f80e4f58c89b53", + "zh:09ba83c0625b6fe0a954da6fbd0c355ac0b7f07f86c91a2a97849140fea49603", + "zh:0e3a6c8e16f17f19010accd0844187d524580d9fdb0731f675ffcf4afba03d16", + "zh:45f2c594b6f2f34ea663704cc72048b212fe7d16fb4cfd959365fa997228a776", + "zh:77ea3e5a0446784d77114b5e851c970a3dde1e08fa6de38210b8385d7605d451", + "zh:8a154388f3708e3df5a69122a23bdfaf760a523788a5081976b3d5616f7d30ae", + "zh:992843002f2db5a11e626b3fc23dc0c87ad3729b3b3cff08e32ffb3df97edbde", + "zh:ad906f4cebd3ec5e43d5cd6dc8f4c5c9cc3b33d2243c89c5fc18f97f7277b51d", + "zh:c979425ddb256511137ecd093e23283234da0154b7fa8b21c2687182d9aea8b2", + ] +} diff --git a/install/gcp-terraform/environment/minimal/README.md b/install/gcp-terraform/environment/minimal/README.md new file mode 100644 index 00000000000000..ae1b0effebde43 --- /dev/null +++ b/install/gcp-terraform/environment/minimal/README.md @@ -0,0 +1,76 @@ +# Gitpod installation on GCP using Terraform + +## Prerequisites + +### Terraform + +Terraform is used to deploy the cloud infrastructure (https://terraform.io) + +### GCP Project + +To install Gitpod, a GCP project has to be present (https://support.google.com/googleapi/answer/6251787?hl=en). + +### Registering a domain + +The script creates an own DNS-Zone on GCP for Gitpod to avoid any interferences with other projects. If a subdomain is used an extra resource could create a domain delegation to the DNS-Zone created by the script. + +If the parent domain is also hosted on GCP the resource looks like this: +``` +resource "google_dns_record_set" "delegation" { + name = module.dns.zone.dns_name + type = "NS" + ttl = 300 + managed_zone = "" + rrdatas = module.dns.zone.name_servers + project = "" + + depends_on = [ + module.dns.done + ] + +} +``` + +A best practice would be to set up an extra GCP project (`PARENT_PROJECT_ID`) with a DNS-Zone managing the `PARENT_DOMAIN`. + + +### Terraform backend + +If the Terraform deployment should be shared in a team it is useful to create a backend storing the Terraform state (https://www.terraform.io/docs/backends/index.html). + +Therefore a Google storage bucket could used: +``` +terraform { + backend "gcs" { + bucket = "tf-state-prod" + prefix = "terraform/state" + } +} +``` +https://www.terraform.io/docs/backends/types/gcs.html + +## Setup + +A file has to be created to set every variable needed by the Terraform script, i.e. `project.auto.tfvars`. Using the ending `.auto.tfvars` the file is automatically recognized by Terraform. + +``` +project = "PROJECT_ID" +region = "europe-west3" +dns_name = "your-domain.com" +container_registry = { + location = "EU" +} +certificate_email = "certificates@your-domain.com" +``` + +Several OAuth provider could be added ([docs.gitpod.io](https://www.gitpod.io/docs/self-hosted/latest/install/oauth/)). + + + +## Installation + +After the variables are set up, the installation could be started. + +``` +$ make install +``` diff --git a/install/gcp-terraform/environment/minimal/main.tf b/install/gcp-terraform/environment/minimal/main.tf new file mode 100644 index 00000000000000..ae186f33d739d4 --- /dev/null +++ b/install/gcp-terraform/environment/minimal/main.tf @@ -0,0 +1,116 @@ +/** + * Copyright (c) 2020 Gitpod GmbH. All rights reserved. + * Licensed under the MIT License. See License-MIT.txt in the project root for license information. + */ + +locals { + google_services = [ + "compute.googleapis.com", + ] + region = trimsuffix(var.location,local.zone_suffix) + zone_suffix = regex("-[a-z]$",var.location) +} + +# https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/google_project_service +resource "google_project_service" "main" { + count = length(local.google_services) + project = var.project + service = local.google_services[count.index] + + disable_dependent_services = false + disable_on_destroy = false +} + + +resource "google_compute_network" "gitpod" { + name = "gitpod" + description = "Gitpod Cluster Network" + auto_create_subnetworks = false + project = var.project + + depends_on = [ + google_project_service.main, + ] +} + +module "kubernetes" { + source = "../../modules/kubernetes" + + name = "gitpod" + network = google_compute_network.gitpod.name + project = var.project + location = var.location +} + +module "dns" { + source = "../../modules/dns" + + project = var.project + location = var.location + zone_name = var.zone_name + name = "gitpod-dns" + subdomain = var.subdomain + + depends_on = [ + module.kubernetes, + ] + + providers = { + google = google + kubernetes = kubernetes + } +} + + +module "certmanager" { + source = "../../modules/certmanager" + + project = var.project + email = var.certificate_email + domain = module.dns.hostname + + providers = { + google = google + kubernetes = kubernetes + helm = helm + kubectl = kubectl + } + + depends_on = [ + module.kubernetes, + module.dns, + ] +} + +# +# Gitpod +# + +module "gitpod" { + source = "../../modules/gitpod" + + project = var.project + namespace = var.namespace + values = file("values.yaml") + dns_values = module.dns.values + certificate_values = module.certmanager.values + license = var.license + gitpod = { + repository = var.gitpod_repository + chart = var.gitpod_chart + version = var.gitpod_version + image_prefix = "gcr.io/gitpod-io/self-hosted/" + } + + providers = { + google = google + kubernetes = kubernetes + helm = helm + } + + depends_on = [ + module.kubernetes, + module.dns, + module.certmanager, + ] +} diff --git a/install/gcp-terraform/environment/minimal/providers.tf b/install/gcp-terraform/environment/minimal/providers.tf new file mode 100644 index 00000000000000..83000ddb1744da --- /dev/null +++ b/install/gcp-terraform/environment/minimal/providers.tf @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2020 Gitpod GmbH. All rights reserved. + * Licensed under the MIT License. See License-MIT.txt in the project root for license information. + */ + +provider "google" { + project = var.project + region = local.region +} + +data "google_client_config" "provider" {} + +provider "kubernetes" { + config_path = ".kubeconfig" + host = module.kubernetes.cluster.endpoint + token = data.google_client_config.provider.access_token + cluster_ca_certificate = base64decode(module.kubernetes.cluster.master_auth[0].cluster_ca_certificate) +} + +provider "helm" { + kubernetes { + host = module.kubernetes.cluster.endpoint + token = data.google_client_config.provider.access_token + cluster_ca_certificate = base64decode(module.kubernetes.cluster.master_auth[0].cluster_ca_certificate) + } +} + +provider "kubectl" { + host = module.kubernetes.cluster.endpoint + token = data.google_client_config.provider.access_token + cluster_ca_certificate = base64decode(module.kubernetes.cluster.master_auth[0].cluster_ca_certificate) +} diff --git a/install/gcp-terraform/environment/minimal/values.yaml b/install/gcp-terraform/environment/minimal/values.yaml new file mode 100644 index 00000000000000..816a7ab661ca48 --- /dev/null +++ b/install/gcp-terraform/environment/minimal/values.yaml @@ -0,0 +1,4 @@ +ingressMode: noDomain +certificatesSecret: {} + +authProviders: [] diff --git a/install/gcp-terraform/environment/minimal/variables.tf b/install/gcp-terraform/environment/minimal/variables.tf new file mode 100644 index 00000000000000..015abadc653cf9 --- /dev/null +++ b/install/gcp-terraform/environment/minimal/variables.tf @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2020 Gitpod GmbH. All rights reserved. + * Licensed under the MIT License. See License-MIT.txt in the project root for license information. + */ + + +variable "project" { + type = string +} + +variable "location" { + type = string +} + +variable "zone_name" { + type = string +} + +variable "namespace" { + type = string + default = "default" +} + +variable "certificate_email" { + type = string +} + +variable "license" { + type = string + default = "" +} + +variable "database" { + type = object({ + name = string + }) + default = { + name = "db" + } +} + +variable "subdomain" { + type = string + default = "gitpod" +} + + +variable "gitpod_repository" { + type = string +} + +variable "gitpod_chart" { + type = string +} + +variable "gitpod_version" { + type = string +} \ No newline at end of file diff --git a/install/gcp-terraform/environment/minimal/versions.tf b/install/gcp-terraform/environment/minimal/versions.tf new file mode 100644 index 00000000000000..d8977b3b5586df --- /dev/null +++ b/install/gcp-terraform/environment/minimal/versions.tf @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2020 Gitpod GmbH. All rights reserved. + * Licensed under the MIT License. See License-MIT.txt in the project root for license information. + */ + +terraform { + required_version = ">= 0.14" + required_providers { + google = { + source = "hashicorp/google" + } + kubernetes = { + source = "hashicorp/kubernetes" + } + helm = { + source = "hashicorp/helm" + } + kubectl = { + source = "gavinbunney/kubectl" + version = "1.9.4" + } + } +} diff --git a/install/gcp-terraform/modules/certmanager/main.tf b/install/gcp-terraform/modules/certmanager/main.tf index eb6f420fb844db..6dccc6548768c7 100644 --- a/install/gcp-terraform/modules/certmanager/main.tf +++ b/install/gcp-terraform/modules/certmanager/main.tf @@ -3,10 +3,14 @@ * Licensed under the MIT License. See License-MIT.txt in the project root for license information. */ +resource "random_id" "certmanager" { + byte_length = 4 +} + # resource "google_service_account" "certmanager" { - account_id = var.certmanager.name - display_name = var.certmanager.name + account_id = "${var.certmanager.name}-${random_id.certmanager.hex}" + display_name = "${var.certmanager.name}-${random_id.certmanager.hex}" description = "Cert-Manager Account ${var.certmanager.name}" project = var.project } diff --git a/install/gcp-terraform/modules/dns/main.tf b/install/gcp-terraform/modules/dns/main.tf index b720356525b8f7..aade30e41d8c36 100644 --- a/install/gcp-terraform/modules/dns/main.tf +++ b/install/gcp-terraform/modules/dns/main.tf @@ -10,6 +10,8 @@ locals { "dns.googleapis.com", "compute.googleapis.com" ] + region = trimsuffix(var.location,local.zone_suffix) + zone_suffix = regex("-[a-z]$",var.location) } # https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/dns_managed_zone @@ -30,7 +32,7 @@ data "google_dns_managed_zone" "gitpod" { resource "google_compute_address" "gitpod" { name = var.name project = var.project - region = var.region + region = local.region } resource "google_dns_record_set" "gitpod" { diff --git a/install/gcp-terraform/modules/dns/templates/values.tpl b/install/gcp-terraform/modules/dns/templates/values.tpl index e5e94753e1fd9b..01857c12953165 100644 --- a/install/gcp-terraform/modules/dns/templates/values.tpl +++ b/install/gcp-terraform/modules/dns/templates/values.tpl @@ -5,6 +5,7 @@ ingressMode: hosts hostname: ${hostname} components: proxy: + serviceType: LoadBalancer loadBalancerIP: ${loadBalancerIP} branding: diff --git a/install/gcp-terraform/modules/dns/variables.tf b/install/gcp-terraform/modules/dns/variables.tf index c4463d8ddcae14..92f312bdcc91fa 100644 --- a/install/gcp-terraform/modules/dns/variables.tf +++ b/install/gcp-terraform/modules/dns/variables.tf @@ -7,7 +7,7 @@ variable "project" { type = string } -variable "region" { +variable "location" { type = string } diff --git a/install/gcp-terraform/modules/gitpod/main.tf b/install/gcp-terraform/modules/gitpod/main.tf index ca2665192412f1..8d77658545d97f 100644 --- a/install/gcp-terraform/modules/gitpod/main.tf +++ b/install/gcp-terraform/modules/gitpod/main.tf @@ -3,10 +3,6 @@ * Licensed under the MIT License. See License-MIT.txt in the project root for license information. */ - - - - # # Gitpod # @@ -19,14 +15,17 @@ data "template_file" "values" { template = file("${path.module}/templates/values.tpl") vars = { image_prefix = var.gitpod.image_prefix - version = var.gitpod.version license = var.license + version = var.gitpod.version } } resource "helm_release" "gitpod" { name = "gitpod" - chart = "${path.root}/${var.gitpod.chart}" + + repository = var.gitpod.repository + chart = var.gitpod.chart + version = var.gitpod.version namespace = var.namespace create_namespace = false diff --git a/install/gcp-terraform/modules/gitpod/templates/values.tpl b/install/gcp-terraform/modules/gitpod/templates/values.tpl index 90f839d4596e48..534593c9c14342 100644 --- a/install/gcp-terraform/modules/gitpod/templates/values.tpl +++ b/install/gcp-terraform/modules/gitpod/templates/values.tpl @@ -3,5 +3,5 @@ installPodSecurityPolicies: true imagePrefix: ${image_prefix} -version: ${version} license: ${license} +version: ${version} diff --git a/install/gcp-terraform/modules/gitpod/variables.tf b/install/gcp-terraform/modules/gitpod/variables.tf index 9efb39804c0c92..8e87e4c025aabe 100644 --- a/install/gcp-terraform/modules/gitpod/variables.tf +++ b/install/gcp-terraform/modules/gitpod/variables.tf @@ -8,10 +8,6 @@ variable "project" { type = string } -variable "region" { - type = string -} - variable "database_values" { type = string default = "" @@ -49,6 +45,7 @@ variable "values" { variable "gitpod" { type = object({ + repository = string chart = string version = string image_prefix = string diff --git a/install/gcp-terraform/modules/kubeconfig/main.tf b/install/gcp-terraform/modules/kubeconfig/main.tf deleted file mode 100644 index 94176402120429..00000000000000 --- a/install/gcp-terraform/modules/kubeconfig/main.tf +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) 2020 Gitpod GmbH. All rights reserved. - * Licensed under the MIT License. See License-MIT.txt in the project root for license information. - */ - - -data "google_client_config" "provider" {} - -# https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/container_cluster -data "google_container_cluster" "kubernetes" { - name = var.cluster.name - project = data.google_client_config.provider.project - location = data.google_client_config.provider.region -} - -# https://registry.terraform.io/providers/hashicorp/template/latest/docs/data-sources/file -data "template_file" "kubeconfig" { - template = file("${path.module}/templates/kubeconfig.tpl") - vars = { - cluster_ca_certificate = data.google_container_cluster.kubernetes.master_auth[0].cluster_ca_certificate - host = data.google_container_cluster.kubernetes.endpoint - name = data.google_container_cluster.kubernetes.name - token = data.google_client_config.provider.access_token - namespace = "default" - } -} - -# https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file -resource "local_file" "kubeconfig" { - content = data.template_file.kubeconfig.rendered - filename = "${path.root}/secrets/kubeconfig" - file_permission = 0400 -} diff --git a/install/gcp-terraform/modules/kubeconfig/outputs.tf b/install/gcp-terraform/modules/kubeconfig/outputs.tf deleted file mode 100644 index fa486cc74c887f..00000000000000 --- a/install/gcp-terraform/modules/kubeconfig/outputs.tf +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Copyright (c) 2020 Gitpod GmbH. All rights reserved. - * Licensed under the MIT License. See License-MIT.txt in the project root for license information. - */ - - -output "path" { - value = local_file.kubeconfig.filename -} diff --git a/install/gcp-terraform/modules/kubeconfig/templates/kubeconfig.tpl b/install/gcp-terraform/modules/kubeconfig/templates/kubeconfig.tpl deleted file mode 100644 index a10499070f1d5d..00000000000000 --- a/install/gcp-terraform/modules/kubeconfig/templates/kubeconfig.tpl +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) 2020 Gitpod GmbH. All rights reserved. -# Licensed under the MIT License. See License-MIT.txt in the project root for license information. - - -apiVersion: v1 -clusters: -- cluster: - certificate-authority-data: ${cluster_ca_certificate} - server: https://${host} - name: ${name}-cluster -contexts: -- context: - cluster: ${name}-cluster - namespace: ${namespace} - user: ${name}-user - name: ${name} -current-context: ${name} -kind: Config -preferences: {} -users: -- name: ${name}-user - user: - auth-provider: - name: gcp - access-token: ${token} - \ No newline at end of file diff --git a/install/gcp-terraform/modules/kubeconfig/variables.tf b/install/gcp-terraform/modules/kubeconfig/variables.tf deleted file mode 100644 index f4ab83558b1612..00000000000000 --- a/install/gcp-terraform/modules/kubeconfig/variables.tf +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Copyright (c) 2020 Gitpod GmbH. All rights reserved. - * Licensed under the MIT License. See License-MIT.txt in the project root for license information. - */ - - -variable "cluster" { - type = object({ - name = string - }) -} \ No newline at end of file diff --git a/install/gcp-terraform/modules/kubernetes/main.tf b/install/gcp-terraform/modules/kubernetes/main.tf index 08693b7ba5a402..56d9372f5d4ec9 100644 --- a/install/gcp-terraform/modules/kubernetes/main.tf +++ b/install/gcp-terraform/modules/kubernetes/main.tf @@ -22,6 +22,8 @@ locals { "container.googleapis.com", "logging.googleapis.com", ] + region = trimsuffix(var.location,local.zone_suffix) + zone_suffix = regex("-[a-z]$",var.location) } # https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/google_project_service @@ -37,9 +39,13 @@ resource "google_project_service" "kubernetes" { resource "google_compute_subnetwork" "gitpod" { name = var.subnet.name ip_cidr_range = var.subnet.cidr - region = var.region + region = local.region network = var.network private_ip_google_access = true + + depends_on = [ + local.google_services + ] } resource "google_service_account" "gitpod" { @@ -47,6 +53,10 @@ resource "google_service_account" "gitpod" { display_name = "${var.name}-nodes" description = "Gitpod Nodes ${var.name}" project = var.project + + depends_on = [ + local.google_services + ] } resource "google_project_iam_member" "gitpod" { @@ -54,12 +64,16 @@ resource "google_project_iam_member" "gitpod" { project = var.project role = local.roles[count.index] member = "serviceAccount:${google_service_account.gitpod.email}" + + depends_on = [ + local.google_services + ] } resource "google_container_cluster" "gitpod" { name = var.name project = var.project - location = var.region + location = var.location remove_default_node_pool = true initial_node_count = 1 @@ -93,12 +107,16 @@ resource "google_container_cluster" "gitpod" { ip_allocation_policy {} min_master_version = "1.16" + + depends_on = [ + local.google_services + ] } resource "google_container_node_pool" "gitpod" { name = "nodepool-0" - location = var.region + location = var.location cluster = google_container_cluster.gitpod.name initial_node_count = 1 diff --git a/install/gcp-terraform/modules/kubernetes/variables.tf b/install/gcp-terraform/modules/kubernetes/variables.tf index 592bafd600d6df..ae7365799bdc61 100644 --- a/install/gcp-terraform/modules/kubernetes/variables.tf +++ b/install/gcp-terraform/modules/kubernetes/variables.tf @@ -8,7 +8,7 @@ variable "project" { type = string } -variable "region" { +variable "location" { type = string } diff --git a/install/gcp-terraform/modules/storage/main.tf b/install/gcp-terraform/modules/storage/main.tf index 7defaf2d540a8f..2d93e39b2dc771 100644 --- a/install/gcp-terraform/modules/storage/main.tf +++ b/install/gcp-terraform/modules/storage/main.tf @@ -11,10 +11,13 @@ locals { ] } +data "google_project" "project" { +} + # https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/google_project_service resource "google_project_service" "storage" { count = length(local.google_services) - project = var.project + project = data.google_project.project.project_id service = local.google_services[count.index] disable_dependent_services = false @@ -22,7 +25,6 @@ resource "google_project_service" "storage" { } - # # Service Account # @@ -31,11 +33,11 @@ resource "google_service_account" "gitpod_storage" { account_id = "gitpod-storage-${var.name}" display_name = "gitpod-storage-${var.name}" description = "gitpod-workspace-syncer ${var.name}" - project = var.project + project = data.google_project.project.project_id } resource "google_project_iam_member" "gitpod_storage" { - project = var.project + project = data.google_project.project.project_id role = "roles/storage.admin" member = "serviceAccount:${google_service_account.gitpod_storage.email}" } @@ -60,6 +62,6 @@ data "template_file" "values" { vars = { secretName = kubernetes_secret.storage.metadata[0].name region = var.region - project = var.project + project = data.google_project.project.project_id } } diff --git a/install/gcp-terraform/modules/kubeconfig/terraform.tf b/install/gcp-terraform/modules/storage/versions.tf similarity index 99% rename from install/gcp-terraform/modules/kubeconfig/terraform.tf rename to install/gcp-terraform/modules/storage/versions.tf index 1daecfafccbd7e..744644882b5b28 100644 --- a/install/gcp-terraform/modules/kubeconfig/terraform.tf +++ b/install/gcp-terraform/modules/storage/versions.tf @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License-MIT.txt in the project root for license information. */ - terraform { required_providers { google = {