diff --git a/.github/workflows/build-push-helm.yaml b/.github/workflows/build-push-helm.yaml new file mode 100644 index 0000000..4909697 --- /dev/null +++ b/.github/workflows/build-push-helm.yaml @@ -0,0 +1,23 @@ +name: build and push helm +on: + push: + branches: + - main + - wip/sal/helm +permissions: + contents: read + packages: write +jobs: + helm-build: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v3 + - name: helm build + uses: azure/setup-helm@v1 + with: + version: v3.12.0 + - name: helm login + run: helm registry login -u ${{ github.actor }} -p ${{ github.token}} ghcr.io + - name: helm build and release + run: ci/make_helm_release.sh \ No newline at end of file diff --git a/README.md b/README.md index 969ab55..f33b310 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,24 @@ For kind this will unintuitively be the `INTERNAL-IP`, for a cloud cluster use t E.g. in a browser go to: `172.19.0.2:` +### Kubernetes using Helm + +Helm chart is supplied in the `helm/quotes-flask` directory. + +Deploying the application using `helm`: + +```sh +helm install quotes-flask helm/quotes-flask +``` + +See the release with `helm list`, and get the NodePort with `kubectl get service frontend`. + +You can change the values of the helm chart by supplying a `values.yaml` file, or by using the `--set` flag. + +```sh +helm install quotes-flask helm/quotes-flask --set frontend.tag="3.0.0" +``` + ## Developing ### docker-compose diff --git a/ci/make_helm_release.sh b/ci/make_helm_release.sh new file mode 100755 index 0000000..e370822 --- /dev/null +++ b/ci/make_helm_release.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +REGISTRY="ghcr.io/eficode-academy" +FRONTEND_REPOSITORY="quotes-flask-frontend" +BACKEND_REPOSITORY="quotes-flask-backend" +HELM_REPOSITORY="quotes-flask-helm" +QUOTES="quotes-flask" +VERSIONS=" +1.0.0 +2.0.0 +3.0.0 +4.0.0 +5.0.0 +" + +echo "Creating Helm releases ..." +cd helm + +for VERSION in $VERSIONS; do + echo "Creating Helm release: $VERSION" + echo "generating helm release for $VERSION" + VERSION=$VERSION yq -i '.version = env(VERSION)' quotes-flask/Chart.yaml + VERSION=$VERSION yq -i '.appVersion = env(VERSION)' quotes-flask/Chart.yaml + VERSION=$VERSION yq -i '.backend.tag = env(VERSION)' quotes-flask/values.yaml + VERSION=$VERSION yq -i '.frontend.tag = env(VERSION)' quotes-flask/values.yaml + echo "helm push quotes-flask $VERSION" + helm package quotes-flask + helm push $QUOTES-$VERSION.tgz oci://ghcr.io/eficode-academy + +done \ No newline at end of file diff --git a/helm/quotes-flask/.helmignore b/helm/quotes-flask/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/helm/quotes-flask/.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/helm/quotes-flask/Chart.yaml b/helm/quotes-flask/Chart.yaml new file mode 100644 index 0000000..2b45d7c --- /dev/null +++ b/helm/quotes-flask/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: quotes-flask +description: A 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: "1.0.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: "1.0.0" diff --git a/helm/quotes-flask/templates/NOTES.txt b/helm/quotes-flask/templates/NOTES.txt new file mode 100644 index 0000000..5653ec3 --- /dev/null +++ b/helm/quotes-flask/templates/NOTES.txt @@ -0,0 +1 @@ +Congratulations you have now installed the quotes-flask application on your machine! \ No newline at end of file diff --git a/helm/quotes-flask/templates/backend-configmap.yaml b/helm/quotes-flask/templates/backend-configmap.yaml new file mode 100644 index 0000000..2913abf --- /dev/null +++ b/helm/quotes-flask/templates/backend-configmap.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: backend-config +data: + # all data points are handled as strings + backend_host: "backend" + backend_port: "5000" diff --git a/helm/quotes-flask/templates/backend-deployment.yaml b/helm/quotes-flask/templates/backend-deployment.yaml new file mode 100644 index 0000000..b081cf1 --- /dev/null +++ b/helm/quotes-flask/templates/backend-deployment.yaml @@ -0,0 +1,31 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + creationTimestamp: null + labels: + app: backend + name: backend +spec: + replicas: {{ .Values.backend.replicas }} + selector: + matchLabels: + app: backend + strategy: {} + template: + metadata: + creationTimestamp: null + labels: + app: backend + spec: + containers: + - image: ghcr.io/eficode-academy/quotes-flask-backend:{{ .Values.backend.tag }} + name: quotes-flask-backend + ports: + - containerPort: 5000 + resources: {} + envFrom: + - configMapRef: + name: postgres-config + - secretRef: + name: postgres-secret +status: {} diff --git a/helm/quotes-flask/templates/backend-service.yaml b/helm/quotes-flask/templates/backend-service.yaml new file mode 100644 index 0000000..05a3d44 --- /dev/null +++ b/helm/quotes-flask/templates/backend-service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + creationTimestamp: null + labels: + app: backend + name: backend +spec: + ports: + - port: 5000 + protocol: TCP + targetPort: 5000 + selector: + app: backend + type: ClusterIP +status: + loadBalancer: {} diff --git a/helm/quotes-flask/templates/frontend-deployment.yaml b/helm/quotes-flask/templates/frontend-deployment.yaml new file mode 100644 index 0000000..8427e77 --- /dev/null +++ b/helm/quotes-flask/templates/frontend-deployment.yaml @@ -0,0 +1,44 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + creationTimestamp: null + labels: + app: frontend + name: frontend +spec: + replicas: {{ .Values.frontend.replicas }} + selector: + matchLabels: + app: frontend + strategy: {} + template: + metadata: + creationTimestamp: null + labels: + app: frontend + spec: + containers: + - image: ghcr.io/eficode-academy/quotes-flask-frontend:{{ .Values.frontend.tag }} + name: quotes-flask-frontend + ports: + - containerPort: 5000 + resources: {} + env: + # load namespace from downward api + # https://github.com/kubernetes/kubernetes/blob/release-1.0/docs/user-guide/downward-api.md + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: BACKEND_HOST + valueFrom: + configMapKeyRef: + name: backend-config + key: backend_host + - name: BACKEND_PORT + valueFrom: + configMapKeyRef: + name: backend-config + key: backend_port + +status: {} diff --git a/helm/quotes-flask/templates/frontend-service.yaml b/helm/quotes-flask/templates/frontend-service.yaml new file mode 100644 index 0000000..dba5648 --- /dev/null +++ b/helm/quotes-flask/templates/frontend-service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + creationTimestamp: null + labels: + app: frontend + name: frontend +spec: + ports: + - port: 5000 + protocol: TCP + targetPort: 5000 + selector: + app: frontend + type: {{ .Values.frontend.service.type}} +status: diff --git a/helm/quotes-flask/templates/postgres-configmap.yaml b/helm/quotes-flask/templates/postgres-configmap.yaml new file mode 100644 index 0000000..d363505 --- /dev/null +++ b/helm/quotes-flask/templates/postgres-configmap.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: postgres-config +data: + DB_HOST: postgres + DB_PORT: '5432' + DB_USER: superuser + DB_NAME: quotes \ No newline at end of file diff --git a/helm/quotes-flask/templates/postgres-deployment.yaml b/helm/quotes-flask/templates/postgres-deployment.yaml new file mode 100644 index 0000000..934c34c --- /dev/null +++ b/helm/quotes-flask/templates/postgres-deployment.yaml @@ -0,0 +1,50 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + creationTimestamp: null + labels: + app: postgres + name: postgres +spec: + replicas: 1 + selector: + matchLabels: + app: postgres + strategy: {} + template: + metadata: + creationTimestamp: null + labels: + app: postgres + spec: + volumes: + - name: postgres-pvc # name we can reference below in container + persistentVolumeClaim: + claimName: postgres-pvc # name of the actual pvc + containers: + - image: postgres:14.3 + name: postgres + ports: + - containerPort: 5432 + resources: {} + env: + - name: POSTGRES_USER + valueFrom: + configMapKeyRef: + name: postgres-config + key: DB_USER + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: postgres-secret + key: DB_PASSWORD + - name: POSTGRES_DB + valueFrom: + configMapKeyRef: + name: postgres-config + key: DB_NAME + volumeMounts: + - name: postgres-pvc + mountPath: /var/lib/postgresql/data + subPath: postgres +status: {} diff --git a/helm/quotes-flask/templates/postgres-pvc.yaml b/helm/quotes-flask/templates/postgres-pvc.yaml new file mode 100644 index 0000000..98d94e4 --- /dev/null +++ b/helm/quotes-flask/templates/postgres-pvc.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: postgres-pvc +spec: + # default. Use `kubectl get sc` too what storage classes are configured + storageClassName: "gp2" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi diff --git a/helm/quotes-flask/templates/postgres-secret.yaml b/helm/quotes-flask/templates/postgres-secret.yaml new file mode 100644 index 0000000..063f08a --- /dev/null +++ b/helm/quotes-flask/templates/postgres-secret.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +data: + DB_PASSWORD: Y29tcGxpY2F0ZWQ= +kind: Secret +metadata: + creationTimestamp: + name: postgres-secret diff --git a/helm/quotes-flask/templates/postgres-service.yaml b/helm/quotes-flask/templates/postgres-service.yaml new file mode 100644 index 0000000..9b8277c --- /dev/null +++ b/helm/quotes-flask/templates/postgres-service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + creationTimestamp: null + labels: + app: postgres + name: postgres +spec: + ports: + - port: 5432 + protocol: TCP + targetPort: 5432 + selector: + app: postgres + type: ClusterIP +status: + loadBalancer: {} diff --git a/helm/quotes-flask/values.yaml b/helm/quotes-flask/values.yaml new file mode 100644 index 0000000..2b65513 --- /dev/null +++ b/helm/quotes-flask/values.yaml @@ -0,0 +1,8 @@ +backend: + replicas: 1 + tag: release +frontend: + replicas: 1 + service: + type: NodePort + tag: release