diff --git a/flyway/.helmignore b/flyway/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/flyway/.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/flyway/Chart.yaml b/flyway/Chart.yaml new file mode 100644 index 0000000..8baac7c --- /dev/null +++ b/flyway/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v2 +name: flyway +description: A Helm chart for applying database migrations with Flyway + +# 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. +appVersion: "9" diff --git a/flyway/templates/NOTES.txt b/flyway/templates/NOTES.txt new file mode 100644 index 0000000..e69de29 diff --git a/flyway/templates/_helpers.tpl b/flyway/templates/_helpers.tpl new file mode 100644 index 0000000..297705d --- /dev/null +++ b/flyway/templates/_helpers.tpl @@ -0,0 +1,68 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "flyway.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 "flyway.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 "flyway.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "flyway.labels" -}} +helm.sh/chart: {{ include "flyway.chart" . }} +{{ include "flyway.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "flyway.selectorLabels" -}} +app.kubernetes.io/name: {{ include "flyway.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "flyway.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "flyway.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + + +{{- define "flyway.jobName" -}} +{{ printf "%s-%s" (include "flyway.fullname" .) ((dict "repo" .Values.checkout.repository "command" .Values.flyway.command) | toJson | sha1sum | trunc 9) }} +{{- end }} + diff --git a/flyway/templates/job.yaml b/flyway/templates/job.yaml new file mode 100644 index 0000000..bbb51a6 --- /dev/null +++ b/flyway/templates/job.yaml @@ -0,0 +1,121 @@ +# vim: set filetype=helm: +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "flyway.jobName" . }} + labels: + {{- include "flyway.labels" . | nindent 4 }} +spec: + backoffLimit: 1 + completions: 1 + parallelism: 1 + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "flyway.selectorLabels" . | nindent 8 }} + spec: + restartPolicy: Never + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "flyway.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + volumes: + - name: work + emptyDir: {} + - name: ssh-key + secret: + secretName: {{ .Values.checkout.sshKey.secretName }} + defaultMode: 0600 + - name: ssh-known-hosts + configMap: + name: {{ .Values.checkout.knownHosts.configMapName }} + defaultMode: 0660 + initContainers: + - name: checkout + image: "{{ .Values.checkout.image.repository }}:{{ .Values.checkout.image.tag }}" + imagePullPolicy: {{ .Values.checkout.image.pullPolicy }} + securityContext: + {{- toYaml .Values.checkout.securityContext | nindent 10 }} + env: + - name: REPO_URL + value: {{ .Values.checkout.repository.url }} + - name: REPO_BRANCH + value: {{ .Values.checkout.repository.branch }} + - name: PATH_TO_CHECKOUT + value: {{ .Values.checkout.repository.path }} + - name: SSH_KEY_FILE + value: {{ .Values.checkout.homeDir }}/.ssh/key + - name: GIT_SSH_COMMAND + value: >- + ssh -i $(SSH_KEY_FILE) -o IdentitiesOnly=true + command: + - sh + - -eux + args: + - -c + - |- + git clone --sparse --depth 1 --branch ${REPO_BRANCH} ${REPO_URL} . + git sparse-checkout init --cone && git sparse-checkout set ${PATH_TO_CHECKOUT} + workingDir: {{ .Values.checkout.homeDir }}/code + volumeMounts: + - name: work + mountPath: {{ .Values.checkout.homeDir }}/code + - name: ssh-key + mountPath: {{ .Values.checkout.homeDir }}/.ssh/key + subPath: ssh-privatekey + - name: ssh-known-hosts + mountPath: {{ .Values.checkout.homeDir }}/.ssh/known_hosts + subPath: ssh_known_hosts + containers: + - name: flyway + image: "{{ .Values.flyway.image.repository }}:{{ .Values.flyway.image.tag }}" + imagePullPolicy: {{ .Values.flyway.image.pullPolicy }} + args: + - {{ .Values.flyway.command }} + env: + - name: PATH_TO_CHECKOUT + value: {{ .Values.checkout.repository.path }} + - name: FLYWAY_SCHEMAS + value: {{ .Values.flyway.schemas }} + - name: FLYWAY_DEFAULT_SCHEMA + value: {{ .Values.flyway.defaultSchema }} + - name: FLYWAY_TABLE + value: {{ .Values.flyway.table }} + - name: FLYWAY_BASELINE_VERSION + value: {{ .Values.flyway.baselineVersion | squote }} + - name: FLYWAY_BASELINE_ON_MIGRATE + value: {{ .Values.flyway.baselineOnMigrate | squote }} + - name: FLYWAY_URL + value: {{ .Values.flyway.url | squote }} + - name: FLYWAY_USER + value: {{ .Values.flyway.user }} + - name: FLYWAY_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.flyway.password.secretName }} + key: password + volumeMounts: + - name: work + mountPath: /flyway/sql + subPathExpr: $(PATH_TO_CHECKOUT) + readOnly: true + resources: {{- toYaml .Values.resources | nindent 10 }} + {{- 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/flyway/templates/serviceaccount.yaml b/flyway/templates/serviceaccount.yaml new file mode 100644 index 0000000..bf26e6b --- /dev/null +++ b/flyway/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "flyway.serviceAccountName" . }} + labels: + {{- include "flyway.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/flyway/values.yaml b/flyway/values.yaml new file mode 100644 index 0000000..101a4e1 --- /dev/null +++ b/flyway/values.yaml @@ -0,0 +1,83 @@ + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + create: false + annotations: {} + name: "" + +podAnnotations: {} + +podSecurityContext: + fsGroup: 1000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +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 + +nodeSelector: {} +tolerations: [] +affinity: {} + +checkout: + image: + repository: bitnami/git + pullPolicy: IfNotPresent + tag: 2.30.1 + securityContext: + # uid of bitnami user + runAsUser: 1000 + runAsGroup: 1000 + # home of bitnami user + homeDir: /home/bitnami + # name of the secret holding the SSH key (as "ssh-privatekey") for the Git repository + sshKey: + secretName: ssh-key + # name of the configmap holding a known-hosts file (as "ssh_known_hosts") for connecting to the Git host + knownHosts: + configMapName: ssh-known-hosts + # target repository with SQL migrations + repository: + url: git@github.com:example/helloworld.git + branch: master + path: src/main/resources/db/migration + +flyway: + image: + repository: flyway/flyway + pullPolicy: IfNotPresent + tag: "9.15" + # Flyway subcommand to execute (info, migrate, validate) + command: "info" + # Flyway configuration + schemas: "public" + defaultSchema: "public" + table: "_schema_version" + baselineVersion: "1_0_0" + baselineOnMigrate: true + # database connection URL + url: >- + jdbc:postgresql://postgres.default.svc.cluster.local/helloworld? + # database user + user: postgres + # name of the secret holding the password (as "password") for the database user + password: + secretName: postgres-password