diff --git a/adminer/Chart.yaml b/adminer/Chart.yaml new file mode 100644 index 0000000..1830f5f --- /dev/null +++ b/adminer/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: adminer +description: Adminer Helm chart for Kubernetes +type: application +version: 0.1.0 +appVersion: "latest" diff --git a/adminer/README.md b/adminer/README.md new file mode 100644 index 0000000..4dc556a --- /dev/null +++ b/adminer/README.md @@ -0,0 +1,31 @@ +# Adminer + +Adminer is a lightweight, single-file web UI for managing databases such as +PostgreSQL. This chart deploys Adminer in your Spin namespace. + +## Install + +```bash +helm install -n . +``` + +## Configure + +Edit `values.yaml` before installing or upgrading. + +- `env.ADMINER_DEFAULT_SERVER`: default database host shown in the Adminer UI + (e.g. the PostgreSQL Service name like `postgres` or `postgresql`). +- `env.ADMINER_DESIGN`: UI theme (default `pepa-linha`). +- `service.port`: Adminer listens on 8080 by default. + +## Access after deployment + +With `service.type: ClusterIP`, use port-forwarding: + +```bash +kubectl -n port-forward svc/-adminer 8080:8080 +``` + +Then open `http://127.0.0.1:8080` in a browser. + +If you want external access, add an Ingress (not included in this chart). diff --git a/adminer/templates/_helpers.tpl b/adminer/templates/_helpers.tpl new file mode 100644 index 0000000..1234aba --- /dev/null +++ b/adminer/templates/_helpers.tpl @@ -0,0 +1,51 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "adminer.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 "adminer.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "adminer.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "adminer.labels" -}} +helm.sh/chart: {{ include "adminer.chart" . }} +{{ include "adminer.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "adminer.selectorLabels" -}} +app.kubernetes.io/name: {{ include "adminer.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} diff --git a/adminer/templates/deployment.yaml b/adminer/templates/deployment.yaml new file mode 100644 index 0000000..c9b5ac6 --- /dev/null +++ b/adminer/templates/deployment.yaml @@ -0,0 +1,64 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "adminer.fullname" . }} + labels: + {{- include "adminer.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "adminer.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "adminer.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: container-0 + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: + {{- toYaml .Values.command | nindent 12 }} + args: + {{- toYaml .Values.args | nindent 12 }} + env: + {{- range $key, $value := .Values.env }} + - name: {{ $key }} + value: {{ $value | quote }} + {{- end }} + ports: + - containerPort: {{ .Values.service.port }} + name: adminer-web + protocol: TCP + resources: + {{- toYaml .Values.resources | nindent 12 }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/adminer/templates/service.yaml b/adminer/templates/service.yaml new file mode 100644 index 0000000..8c4dc6d --- /dev/null +++ b/adminer/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "adminer.fullname" . }} + labels: + {{- include "adminer.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: {{ .Values.service.port }} + protocol: TCP + name: adminer-web + selector: + {{- include "adminer.selectorLabels" . | nindent 4 }} diff --git a/adminer/values.yaml b/adminer/values.yaml new file mode 100644 index 0000000..97b654e --- /dev/null +++ b/adminer/values.yaml @@ -0,0 +1,53 @@ +# Default values for adminer. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. +# Update the placeholders below before installing the chart. + +replicaCount: 1 + +image: + repository: adminer + pullPolicy: Always + tag: latest + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +podAnnotations: {} +podLabels: {} + +podSecurityContext: {} + +securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + privileged: false + readOnlyRootFilesystem: false + runAsNonRoot: true + runAsUser: + +command: + - php +args: + - "-S" + - "0.0.0.0:8080" + - "-t" + - "/var/www/html" + +env: + ADMINER_DESIGN: pepa-linha + # Name of the PostgreSQL Service in the same namespace; update before installing. + ADMINER_DEFAULT_SERVER: "" + +service: + type: ClusterIP + port: 8080 + +resources: {} + +nodeSelector: {} +tolerations: [] +affinity: {} diff --git a/postgresql/.helmignore b/postgresql/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/postgresql/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/postgresql/Chart.yaml b/postgresql/Chart.yaml new file mode 100644 index 0000000..a4113d7 --- /dev/null +++ b/postgresql/Chart.yaml @@ -0,0 +1,25 @@ +apiVersion: v2 +name: postgresql +description: A PostgreSQL Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into +# versioned archives to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. +# They're included as a dependency of application charts to inject those +# utilities and functions into the rendering pipeline. Library charts do not +# define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time +# you make changes to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version +# number should be incremented each time you make changes to the application. +# Versions are not expected to follow Semantic Versioning. They should reflect +# the version the application is using. It is recommended to use it with quotes. +appVersion: "18" diff --git a/postgresql/README.md b/postgresql/README.md new file mode 100644 index 0000000..195ad65 --- /dev/null +++ b/postgresql/README.md @@ -0,0 +1,49 @@ +# PostgreSQL Helm Chart + +This chart deploys PostgreSQL on Spin. Update the placeholders in +`values_template.yaml`, or use the helper script to generate `values.yaml`. + +## Prerequisites + +- `kubectl` and `helm` installed +- Access to a Spin namespace and its kubeconfig + +See `tls-acme/README.md` for installation steps for kubectl/helm and kubeconfig. + +## Configure values + +1. Edit `postgresql/prepare-values.sh` with your settings. +2. Generate a rendered values file: + +```bash +./prepare-values.sh +``` + +This writes `values.yaml` (or a custom path if you pass one). + +## Quick start + +```bash +cd postgresql +./prepare-values.sh +helm lint . +helm install -n . +``` + +## Install + +```bash +helm install -n . +``` + +## Upgrade or uninstall + +```bash +helm upgrade -n . +helm uninstall -n +``` + +## Notes + +- Persistent volume size is controlled by `persistentVolumeClaims..size` (where `deployment_name` defaults to `psql` in `prepare-values.sh`). +- Liveness and readiness probes use `pg_isready` with the configured database name and user. diff --git a/postgresql/prepare-values.sh b/postgresql/prepare-values.sh new file mode 100755 index 0000000..12b2c88 --- /dev/null +++ b/postgresql/prepare-values.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -euo pipefail + +base_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +values_file="${1:-"${base_dir}/values_template.yaml"}" +output_file="${2:-"${base_dir}/values.yaml"}" + +# Update these values before running this script. +# Output goes to values.yaml unless you pass a second argument. +nersc_user_id="" +nersc_user_group="" +app_name="postgresql" +version_tag="18" +deployment_name="psql" +db_name="" +db_user_password="" +db_user_name="user" +pvc_size="10Gi" + +tmp_file="$(mktemp)" +sed \ + -e "s|{{nersc_user_id}}|${nersc_user_id}|g" \ + -e "s|{{nersc_user_group}}|${nersc_user_group}|g" \ + -e "s|{{app_name}}|${app_name}|g" \ + -e "s|{{version_tag}}|${version_tag}|g" \ + -e "s|{{deployment_name}}|${deployment_name}|g" \ + -e "s|{{db_name}}|${db_name}|g" \ + -e "s|{{db_user_password}}|${db_user_password}|g" \ + -e "s|{{db_user_name}}|${db_user_name}|g" \ + -e "s|{{pvc_size}}|${pvc_size}|g" \ + "$values_file" > "$tmp_file" +mv "$tmp_file" "$output_file" diff --git a/postgresql/templates/NOTES.txt b/postgresql/templates/NOTES.txt new file mode 100644 index 0000000..c1e0060 --- /dev/null +++ b/postgresql/templates/NOTES.txt @@ -0,0 +1,22 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "postgresql.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 its status by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "postgresql.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "postgresql.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "postgresql.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/postgresql/templates/_helpers.tpl b/postgresql/templates/_helpers.tpl new file mode 100644 index 0000000..30c6288 --- /dev/null +++ b/postgresql/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "postgresql.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 "postgresql.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "postgresql.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "postgresql.labels" -}} +helm.sh/chart: {{ include "postgresql.chart" . }} +{{ include "postgresql.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "postgresql.selectorLabels" -}} +app.kubernetes.io/name: {{ include "postgresql.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "postgresql.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "postgresql.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/postgresql/templates/configmap.yaml b/postgresql/templates/configmap.yaml new file mode 100644 index 0000000..00919da --- /dev/null +++ b/postgresql/templates/configmap.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "postgresql.fullname" . }}-env-config + labels: + {{- include "postgresql.labels" . | nindent 4 }} +data: + POSTGRES_DB: {{ .Values.env.POSTGRES_DB | quote }} + POSTGRES_USER: {{ .Values.env.POSTGRES_USER | quote }} diff --git a/postgresql/templates/deployment.yaml b/postgresql/templates/deployment.yaml new file mode 100644 index 0000000..aaa7ee5 --- /dev/null +++ b/postgresql/templates/deployment.yaml @@ -0,0 +1,90 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "postgresql.fullname" . }} + labels: + {{- include "postgresql.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "postgresql.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "postgresql.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "postgresql.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: POSTGRES_DB + valueFrom: + configMapKeyRef: + name: {{ include "postgresql.fullname" . }}-env-config + key: POSTGRES_DB + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "postgresql.fullname" . }}-env-secret + key: POSTGRES_PASSWORD + - name: POSTGRES_USER + valueFrom: + configMapKeyRef: + name: {{ include "postgresql.fullname" . }}-env-config + key: POSTGRES_USER + - name: TZ + value: {{ .Values.env.TZ }} + - name: PGDATA + value: {{ .Values.env.PGDATA }} + ports: + - name: tcp + containerPort: {{ .Values.service.port }} + protocol: TCP + {{- with .Values.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.volumeMounts }} + volumeMounts: + {{- tpl (toYaml .) $ | nindent 12 }} + {{- end }} + {{- with .Values.volumes }} + volumes: + {{- tpl (toYaml .) $ | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/postgresql/templates/ingress.yaml b/postgresql/templates/ingress.yaml new file mode 100644 index 0000000..ce10293 --- /dev/null +++ b/postgresql/templates/ingress.yaml @@ -0,0 +1,43 @@ +{{- if .Values.ingress.enabled -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "postgresql.fullname" . }} + labels: + {{- include "postgresql.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- with .Values.ingress.className }} + ingressClassName: {{ . }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- with .pathType }} + pathType: {{ . }} + {{- end }} + backend: + service: + name: {{ include "postgresql.fullname" $ }} + port: + number: {{ $.Values.service.port }} + {{- end }} + {{- end }} +{{- end }} diff --git a/postgresql/templates/loadbalancer.yaml b/postgresql/templates/loadbalancer.yaml new file mode 100644 index 0000000..d75dda8 --- /dev/null +++ b/postgresql/templates/loadbalancer.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "postgresql.fullname" . }}-lb + labels: + {{- include "postgresql.labels" . | nindent 4 }} +spec: + type: LoadBalancer + ports: + - port: {{ .Values.service.port }} + targetPort: {{ .Values.service.port }} + protocol: TCP + name: {{ .Values.service.port }}tcp{{ .Values.service.port }} + selector: + {{- include "postgresql.selectorLabels" . | nindent 4 }} diff --git a/postgresql/templates/pvc.yaml b/postgresql/templates/pvc.yaml new file mode 100644 index 0000000..ce68380 --- /dev/null +++ b/postgresql/templates/pvc.yaml @@ -0,0 +1,17 @@ +{{- range $i, $vol := .Values.volumes -}} +{{- $pvc := index $.Values.persistentVolumeClaims $vol.name}} +{{- if not $pvc.existing -}} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ tpl $vol.persistentVolumeClaim.claimName $ }} +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: {{ $pvc.size | default "10Gi" }} + storageClassName: nfs-client-vast + volumeMode: Filesystem +{{- end }} +{{- end }} diff --git a/postgresql/templates/secret.yaml b/postgresql/templates/secret.yaml new file mode 100644 index 0000000..6bc68f3 --- /dev/null +++ b/postgresql/templates/secret.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "postgresql.fullname" . }}-env-secret + labels: + {{- include "postgresql.labels" . | nindent 4 }} +type: Opaque +stringData: + POSTGRES_PASSWORD: {{ .Values.env.POSTGRES_PASSWORD | quote }} diff --git a/postgresql/templates/service.yaml b/postgresql/templates/service.yaml new file mode 100644 index 0000000..097608f --- /dev/null +++ b/postgresql/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "postgresql.fullname" . }} + labels: + {{- include "postgresql.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: {{ .Values.service.port }} + protocol: TCP + name: {{ .Values.service.port }}tcp{{ .Values.service.port }}-{{ include "postgresql.fullname" . }} + selector: + {{- include "postgresql.selectorLabels" . | nindent 4 }} diff --git a/postgresql/templates/serviceaccount.yaml b/postgresql/templates/serviceaccount.yaml new file mode 100644 index 0000000..faa523e --- /dev/null +++ b/postgresql/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "postgresql.serviceAccountName" . }} + labels: + {{- include "postgresql.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automount }} +{{- end }} diff --git a/postgresql/templates/tests/test-connection.yaml b/postgresql/templates/tests/test-connection.yaml new file mode 100644 index 0000000..ca3f83e --- /dev/null +++ b/postgresql/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "postgresql.fullname" . }}-test-connection" + labels: + {{- include "postgresql.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "postgresql.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/postgresql/values_template.yaml b/postgresql/values_template.yaml new file mode 100644 index 0000000..dcd8bad --- /dev/null +++ b/postgresql/values_template.yaml @@ -0,0 +1,155 @@ +# Default values for postgresql. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. +# Update the placeholders below before installing the chart. +# You can run ./prepare-values.sh to replace the {{placeholders}} in this file. +# The script writes values.yaml for installation. + +# This will set the replicaset count more information can be found here: +# https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/ +replicaCount: 1 + +# This sets the container image more information can be found here: +# https://kubernetes.io/docs/concepts/containers/images/ +image: + repository: postgres + # This sets the pull policy for images. + pullPolicy: Always + # Overrides the image tag whose default is the chart appVersion. + tag: "{{version_tag}}" + +# This is for the secretes for pulling an image from a private repository more +# information can be found here: +# https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ +imagePullSecrets: [] +# This is to override the chart name. +nameOverride: "" # Update before installing. +fullnameOverride: "" + +# This section builds out the service account more information can be found +# here: https://kubernetes.io/docs/concepts/security/service-accounts/ +serviceAccount: + # Specifies whether a service account should be created + create: false + # Automatically mount a ServiceAccount's API credentials? + automount: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. If not set and create is true, a + # name is generated using the fullname template + name: "" + +# This is for setting Kubernetes Annotations to a Pod. +# For more information checkout: +# https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ +podAnnotations: {} +# This is for setting Kubernetes Labels to a Pod. +# For more information checkout: +# https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ +podLabels: {} + +env: + # Update these values before installing. + POSTGRES_DB: {{db_name}} + POSTGRES_PASSWORD: {{db_user_password}} + POSTGRES_USER: {{db_user_name}} + TZ: US/Pacific + PGDATA: /var/lib/postgresql/data/pgdata + +podSecurityContext: + fsGroup: {{nersc_user_group}} # Update before installing. + +securityContext: + capabilities: + add: + - CHOWN + - DAC_OVERRIDE + - FOWNER + - SETGID + - SETUID + drop: + - ALL + readOnlyRootFilesystem: false + runAsNonRoot: true + runAsUser: {{nersc_user_id}} # Update before installing. + +# This is for setting up a service more information can be found here: +# https://kubernetes.io/docs/concepts/services-networking/service/ +service: + # This sets the service type more information can be found here: + # https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types + type: ClusterIP + # This sets the ports more information can be found here: + # https://kubernetes.io/docs/concepts/services-networking/service/#field-spec-ports + port: 5432 + +persistentVolumeClaims: + data: + existing: false + size: {{pvc_size}} # Update before installing. + +# Additional volumeMounts on the output Deployment definition. +volumes: + - name: data + persistentVolumeClaim: + claimName: {{deployment_name}} + +# Additional volumeMounts on the output Deployment definition. +volumeMounts: + - mountPath: /var/lib/postgresql/data + name: data + +# This block is for setting up the ingress for more information can be found +# here: https://kubernetes.io/docs/concepts/services-networking/ingress/ +ingress: + enabled: false + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: + - path: / + pathType: ImplementationSpecific + tls: [] + # - 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 + +# This is to setup the liveness and readiness probes more information can be found here: +# https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ +# https://www.postgresql.org/docs/current/app-pg-isready.html +livenessProbe: + exec: + command: ["pg_isready", "-U", "{{db_user_name}}", "-d", "{{db_name}}"] + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 +readinessProbe: + exec: + # Check we can execute queries over TCP (skip-networking is off). + command: ["pg_isready", "-U", "{{db_user_name}}", "-d", "{{db_name}}"] + initialDelaySeconds: 5 + periodSeconds: 2 + timeoutSeconds: 1 + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/tls-acme/README.md b/tls-acme/README.md index 60a63a1..98dcb2c 100644 --- a/tls-acme/README.md +++ b/tls-acme/README.md @@ -55,6 +55,15 @@ kubectl -n create secret generic kubeconfig --from-file=kub This helm chart takes consideration of two different usage cases. The installation procedure is different. +### Quick start + +```bash +cd tls-acme +./prepare-values.sh +helm lint . +helm install -n -f values.yaml acmecron . +``` + ### Case 1 In this case, the following conditions must be met: @@ -84,14 +93,17 @@ tls-acme │ ├── service.yaml │ ├── webpvc.yaml │ └── websrv.yaml +├── values_template.yaml └── values.yaml -2 directories, 10 files +2 directories, 11 files ``` #### Customize values for chart installation -Make a copy of `values.yaml`, and modify it by setting: +Edit `values_template.yaml` by setting the placeholder values (including +`useCase` for case1 vs case2), then run `./prepare-values.sh` to generate +`values.yaml`. - `` - `` @@ -109,7 +121,8 @@ Make a copy of `values.yaml`, and modify it by setting: Install the helm chart with the following command. Replace `` with your namespace. `acmecron` is a release name for which you can name your own. ```bash -helm install -n -f modified-values.yaml acmecron ./spin-acme +./prepare-values.sh +helm install -n -f values.yaml acmecron . ``` #### Inspect the installation @@ -151,7 +164,8 @@ This is applicatable to the usage cases like: #### Installation and inspection -Similar as _Case 1_ above, but change the following in the copied `values.yaml`: +Similar as _Case 1_ above, but change the following in `values_template.yaml`, +set `useCase` to `case2`, and then re-run `./prepare-values.sh`: - `` - `` @@ -176,10 +190,12 @@ During, the future cronjob runs, your modified ingress will be saved first, chan ### Upgrade or uninstall the chart -If you made changes to `values.yml`, you can `upgrade` the installed chart by: +If you made changes to `values_template.yaml`, re-run `./prepare-values.sh` and +upgrade the installed chart by: ```bash -helm upgrade -n -f modified-values.yaml ./spin-acme +./prepare-values.sh +helm upgrade -n -f values.yaml . ``` Note the `` should be the same one you used during initial installation. In the Case 2, if you've made modifications to the ingress after the initial Cronjob run, the modifications will be lost after upgrade, and will need to be re-applied. It's recommended that you backup the YAML for the ingress before the upgrade. diff --git a/tls-acme/prepare-values.sh b/tls-acme/prepare-values.sh new file mode 100755 index 0000000..3b68c29 --- /dev/null +++ b/tls-acme/prepare-values.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +set -euo pipefail + +base_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +values_file="${1:-"${base_dir}/values_template.yaml"}" +output_file="${2:-"${base_dir}/values.yaml"}" + +# Update these values before running this script. +# Output goes to values.yaml unless you pass a second argument. +nersc_user_id="" +nersc_user_group="" +service_port="8080" +ingress_name="adminer" # ...svc.spin.nersc.org +domain="" +domain_list=":.." +email="" +cluster="" +use_case="case2" +# case 1: use an existing web-server, specify the same port number used by the webserver's cluster IP. +# case 2: no existing web-server, create one; + +webserver_existing="false" +if [ "${use_case}" = "case1" ]; then + webserver_existing="true" +fi + +tmp_file="$(mktemp)" +sed \ + -e "s|{{nersc_user_id}}|${nersc_user_id}|g" \ + -e "s|{{nersc_user_group}}|${nersc_user_group}|g" \ + -e "s|{{service_port}}|${service_port}|g" \ + -e "s|{{ingress_name}}|${ingress_name}|g" \ + -e "s|{{domain}}|${domain}|g" \ + -e "s|{{domain_list}}|${domain_list}|g" \ + -e "s|{{email}}|${email}|g" \ + -e "s|{{cluster}}|${cluster}|g" \ + -e "s|{{use_case}}|${use_case}|g" \ + -e "s|{{webserver_existing}}|${webserver_existing}|g" \ + "$values_file" > "$tmp_file" +mv "$tmp_file" "$output_file" diff --git a/tls-acme/values.yaml b/tls-acme/values_template.yaml similarity index 53% rename from tls-acme/values.yaml rename to tls-acme/values_template.yaml index b530767..cf7f588 100644 --- a/tls-acme/values.yaml +++ b/tls-acme/values_template.yaml @@ -1,6 +1,9 @@ # Default values for spin-acme. # This is a YAML-formatted file. # Declare variables to be passed into your templates. +# Update the placeholders below before installing the chart. +# You can run ./prepare-values.sh to replace the {{placeholders}} in this file. +# The script writes values.yaml for installation. --- replicaCount: 1 @@ -18,7 +21,7 @@ podAnnotations: {} podLabels: {} podSecurityContext: - fsGroup: # NERSC GID for the project + fsGroup: {{nersc_user_group}} # NERSC GID for the project securityContext: capabilities: @@ -26,38 +29,41 @@ securityContext: - ALL readOnlyRootFilesystem: false runAsNonRoot: true - runAsUser: # NERSC UID + runAsUser: {{nersc_user_id}} # NERSC UID service: type: ClusterIP - port: # (case 1) port of the existing web server, or 8080 if no pre-existing web server (case 2) + port: {{service_port}} # (case 1) port of the existing web server, or 8080 if no pre-existing web server (case 2) ingress: - name: # name of the ingress, which you already have a DNS CNAME record for. + name: {{ingress_name}} # name of the ingress, which you already have a DNS CNAME record for. enabled: true className: nginx hosts: # you can have multiple hosts, all will be added to the same ingress - - host: # DNS CNAME record, or ...svc.spin.nersc.org + - host: {{domain}} # DNS CNAME record, or ...svc.spin.nersc.org paths: - path: / pathType: Prefix tls: - # you can have multiple hosts, all will be added to the same ingres, + # you can have multiple hosts, all will be added to the same ingress, # and use the same certificate (with DNS alias in SANs) - hosts: - - # same as .ingress.hosts.host + - {{domain}} # same as .ingress.hosts.host # concatenate the list .ingress.hosts.host into ":" separated string -domain: +domain: {{domain_list}} -email: # email address to be used for the ACME account +email: {{email}} # email address to be used for the ACME account -cluster: # NERSC cluster name, development.svc.spin.nersc.org, or production.svc.spin.nersc.org +cluster: {{cluster}} # NERSC cluster name, development.svc.spin.nersc.org, or production.svc.spin.nersc.org + +useCase: {{use_case}} # case1 uses existing web server, case2 creates a new one webServer: webrootPath: '/www' - existing: false # true for case 1; false for case 2 -- use existing deployment and PVC + # Set by prepare-values.sh based on use_case (case1 or case2). + existing: {{webserver_existing}} # true for case 1; false for case 2 -- use existing deployment and PVC deploymentName: existing-websrv # case 2, use this deployment claimName: pvc-existing-webroot # case 2, use this PVC