From 92add749254e202538138ff4b2d12761c1d7b938 Mon Sep 17 00:00:00 2001 From: xmlking Date: Fri, 5 Apr 2019 12:55:27 -0700 Subject: [PATCH] feat(deploy): using Helm for API deployment --- .deploy/api/Dockerfile | 2 + .deploy/api/README.md | 22 +-- .deploy/api/helm/.sops.yaml | 2 + .deploy/api/helm/README.md | 112 ++++++++++++++ .deploy/api/helm/generated/.gitignore | 3 + .deploy/api/helm/nodeapp/.helmignore | 22 +++ .deploy/api/helm/nodeapp/Chart.yaml | 7 + .deploy/api/helm/nodeapp/README.md | 134 ++++++++++++++++ .deploy/api/helm/nodeapp/templates/NOTES.txt | 21 +++ .../api/helm/nodeapp/templates/_helpers.tpl | 32 ++++ .../helm/nodeapp/templates/deployment.yaml | 102 +++++++++++++ .deploy/api/helm/nodeapp/templates/hpa.yaml | 27 ++++ .../api/helm/nodeapp/templates/ingress.yaml | 39 +++++ .deploy/api/helm/nodeapp/templates/istio.yaml | 24 +++ .../helm/nodeapp/templates/networkpolicy.yaml | 29 ++++ .../api/helm/nodeapp/templates/secrets.yaml | 18 +++ .../api/helm/nodeapp/templates/service.yaml | 28 ++++ .../templates/tests/test-connection.yaml | 18 +++ .deploy/api/helm/nodeapp/values.yaml | 144 ++++++++++++++++++ .deploy/api/helm/secrets.dev.yaml | 31 ++++ .deploy/api/helm/secrets.prod.yaml | 31 ++++ .deploy/api/helm/values-dev.yaml | 75 +++++++++ .deploy/api/helm/values-prod.yaml | 105 +++++++++++++ .deploy/api/manual/README.md | 33 ++-- .deploy/helm/README.md | 106 ++++++++++++- .deploy/keycloak/helm/README.md | 24 +-- .deploy/keycloak/helm/values-dev.yaml | 15 +- .deploy/keycloak/helm/values-prod.yaml | 15 +- .deploy/keycloak/helm/values.yaml | 5 + .../manual/02-keycloak-secrets-tls.yml | 2 + .../keycloak/manual/02-keycloak-secrets.yaml | 2 + .../manual/04-keycloak-deployment.yaml | 2 +- .../manual/05-keycloak-service-nodeport.yaml | 2 +- .../keycloak/manual/05-keycloak-service.yaml | 2 +- .deploy/keycloak/manual/README.md | 9 +- .deploy/keycloak/realm-manual-import.json | 25 ++- .../postgres/helm/postgres-init-scripts.yaml | 2 + .deploy/postgres/helm/values-dev.yaml | 10 ++ .deploy/postgres/helm/values-prod.yaml | 5 + .deploy/postgres/manual/04-statefulset.yaml | 1 - .deploy/postgres/manual/README.md | 4 +- .deploy/webapp/default.conf | 29 ++++ .deploy/webapp/helm/README.md | 84 ++++++++++ .deploy/webapp/helm/generated/.gitignore | 3 + .deploy/webapp/helm/values-dev.yaml | 11 ++ .deploy/webapp/helm/values-prod.yaml | 19 +++ .../webapp/{ => openshift}/webapp.tmpl.yml | 0 47 files changed, 1373 insertions(+), 65 deletions(-) create mode 100644 .deploy/api/helm/.sops.yaml create mode 100644 .deploy/api/helm/README.md create mode 100644 .deploy/api/helm/generated/.gitignore create mode 100644 .deploy/api/helm/nodeapp/.helmignore create mode 100644 .deploy/api/helm/nodeapp/Chart.yaml create mode 100755 .deploy/api/helm/nodeapp/README.md create mode 100644 .deploy/api/helm/nodeapp/templates/NOTES.txt create mode 100644 .deploy/api/helm/nodeapp/templates/_helpers.tpl create mode 100644 .deploy/api/helm/nodeapp/templates/deployment.yaml create mode 100755 .deploy/api/helm/nodeapp/templates/hpa.yaml create mode 100644 .deploy/api/helm/nodeapp/templates/ingress.yaml create mode 100755 .deploy/api/helm/nodeapp/templates/istio.yaml create mode 100755 .deploy/api/helm/nodeapp/templates/networkpolicy.yaml create mode 100755 .deploy/api/helm/nodeapp/templates/secrets.yaml create mode 100644 .deploy/api/helm/nodeapp/templates/service.yaml create mode 100644 .deploy/api/helm/nodeapp/templates/tests/test-connection.yaml create mode 100644 .deploy/api/helm/nodeapp/values.yaml create mode 100644 .deploy/api/helm/secrets.dev.yaml create mode 100644 .deploy/api/helm/secrets.prod.yaml create mode 100644 .deploy/api/helm/values-dev.yaml create mode 100644 .deploy/api/helm/values-prod.yaml create mode 100644 .deploy/webapp/default.conf create mode 100644 .deploy/webapp/helm/README.md create mode 100644 .deploy/webapp/helm/generated/.gitignore create mode 100644 .deploy/webapp/helm/values-dev.yaml create mode 100644 .deploy/webapp/helm/values-prod.yaml rename .deploy/webapp/{ => openshift}/webapp.tmpl.yml (100%) diff --git a/.deploy/api/Dockerfile b/.deploy/api/Dockerfile index d62970957..ce71fda10 100644 --- a/.deploy/api/Dockerfile +++ b/.deploy/api/Dockerfile @@ -27,6 +27,8 @@ ENV NODE_ENV production RUN $(npm bin)/ng build api --prod # Final stage: the running container. +#FROM astefanutti/scratch-node +#COPY --from=busybox:1.30.1 /bin/busybox /bin/busybox FROM mhart/alpine-node:11 # Import the user and group files from the first stage. diff --git a/.deploy/api/README.md b/.deploy/api/README.md index 6ac7bed90..9fdc8c1bb 100644 --- a/.deploy/api/README.md +++ b/.deploy/api/README.md @@ -1,8 +1,9 @@ -API -=== +# API + Build and Deploy NgxApi ### Build + ```bash # build VERSION=1.5.0-SNAPSHOT @@ -25,13 +26,18 @@ docker image prune -f ``` ### Run + ```bash -docker-compose up api -kubectl run -it --rm ngxapi --port 3000 --hostport=3000 --expose=true --image=xmlking/ngxapi --restart=Never --env TYPEORM_HOST=ngxdb-postgresql +# start ngxapi pod in interative mode. Use 'Ctrl+C' to terminate pod and delete temp service. +kubectl run -it --rm ngxapi --port 3000 --hostport=3000 --expose=true --image=xmlking/ngxapi:$VERSION --restart=Never --env TYPEORM_HOST=ngxdb-postgresql kubectl port-forward ngxapi 3000:3000 +#kubectl exec -it ngxapi /bin/busybox sh +kubectl exec -it ngxapi -- /bin/sh +# if you are using `docker-compose` instead of `Kubernetes` +docker-compose up api # docker run -it --env TYPEORM_HOST=postgres -p 3000:3000 xmlking/ngxapi -# to see ditectory content: +# to see ditectory content: (as we are using scratch container, we dont have any unix commands to interact with) docker-compose exec api node docker-compose exec api node -e 'console.log(__dirname);' docker-compose exec api node -e 'const fs = require('fs'); fs.readdirSync('.').forEach(file => { console.log(file);}) @@ -51,9 +57,3 @@ curl -v -X GET \ ### Deploy Follow instructions from [manual](./manual) or [helm](./helm) or [OpenShift](./openshift) - -### Test API -```bash -curl -X GET "https://ngxapi.traefik.k8s/" -k -H "accept: application/json" -curl -X GET "https://ngxapi.traefik.k8s/echo?sumo=demo" -k -H "accept: application/json" -``` diff --git a/.deploy/api/helm/.sops.yaml b/.deploy/api/helm/.sops.yaml new file mode 100644 index 000000000..10eaf2213 --- /dev/null +++ b/.deploy/api/helm/.sops.yaml @@ -0,0 +1,2 @@ +creation_rules: + - pgp: 438F624ADE96A9DE20DE7C5672EB37BA9AB0F7E7 diff --git a/.deploy/api/helm/README.md b/.deploy/api/helm/README.md new file mode 100644 index 000000000..388cdce1c --- /dev/null +++ b/.deploy/api/helm/README.md @@ -0,0 +1,112 @@ +# NgxApi Helm + +Deploying `NgxApi` to `Kubernetes` via `Helm` + +## Prerequisites + +1. Helm command line and Tiller backend [installed](../../helm/README.md). +2. `helm-secrets` [installed](../../helm/README.md). + +first create plain `secrets.dev.yaml` e.g., + +```yaml +envSecrets: + - name: TYPEORM_PASSWORD + value: postgres321 + - name: EMAIL_AUTH_PASS + value: auth_pass + - name: VAPID_PRIVATE_KEY + value: cwh2CYK5h_B_Gobnv8Ym9x61B3qFE2nTeb9BeiZbtMI +``` + +encrypt before check-in to Git. + +```bash +helm secrets enc secrets.dev.yaml +# verify +helm secrets view secrets.dev.yaml +``` + +## Deploy + +### With Tiller + +```bash +cd .deploy/api/helm + +# To install the chart with the release name `ngxapi` +# `--dry-run --debug` flags help you to see before you really deploy +# use `secrets` plugin for on-the-fly decryption +helm secrets install --name=ngxapi --namespace=default -f values-dev.yaml -f secrets.dev.yaml ./nodeapp + +# verify deployment +helm ls +kubectl get all,configmap,secret,ingress,replicasets -lapp.kubernetes.io/instance=ngxapi +kubectl describe pod ngxapi-nodeapp +kubectl get deployment ngxapi-nodeapp -o yaml +kubectl get ingress ngxapi-nodeapp -o yaml + +POD_NAME=$(kubectl get pods -lapp.kubernetes.io/instance=ngxapi -o jsonpath='{.items[0].metadata.name}') +kubectl exec -it $POD_NAME -- /bin/sh +kubectl logs $POD_NAME -f +echo | openssl s_client -showcerts -connect ngxapi.traefik.k8s:443 2>/dev/null + + +# To update +helm secrets upgrade --namespace=default -f values-dev.yaml -f secrets.dev.yaml ngxapi ./nodeapp + +# To uninstall/delete the `ngxapi` release +helm delete ngxapi +helm delete ngxapi --purge # delete ngxapi and purge + +# Scale to zero +kubectl scale deployment ngxapi-nodeapp --replicas=0 +``` + +### Without Tiller + +```bash +cd .deploy/api/helm + +helm secrets template ./nodeapp \ +--name ngxapi \ +--namespace default \ +-f values-dev.yaml \ +-f secrets.dev.yaml \ +--output-dir generated + +kubectl apply --recursive -f generated/nodeapp/* --namespace default +``` + + +### Access NgxApi + +ngxapi can be accessed: + +* Within your cluster, at the following DNS name at port 80: + + ``` + ngxapi-nodeapp.default.svc.cluster.local + ``` + +* From outside the cluster: + + ``` + - https://ngxapi.traefik.k8s + ``` + +* From outside the cluster, run these commands in the same shell: (`when NodePort used in values.yaml`) + + ```bash + export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services ngxapi-nodeapp) + export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT + ``` + +## Test +```bash +curl -X GET "https://ngxapi.traefik.k8s/" -k -H "accept: application/json" +curl -X GET "https://ngxapi.traefik.k8s/echo?sumo=demo" -k -H "accept: application/json" +``` + +## Reference diff --git a/.deploy/api/helm/generated/.gitignore b/.deploy/api/helm/generated/.gitignore new file mode 100644 index 000000000..a5baada18 --- /dev/null +++ b/.deploy/api/helm/generated/.gitignore @@ -0,0 +1,3 @@ +* +!.gitignore + diff --git a/.deploy/api/helm/nodeapp/.helmignore b/.deploy/api/helm/nodeapp/.helmignore new file mode 100644 index 000000000..50af03172 --- /dev/null +++ b/.deploy/api/helm/nodeapp/.helmignore @@ -0,0 +1,22 @@ +# 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 +.vscode/ diff --git a/.deploy/api/helm/nodeapp/Chart.yaml b/.deploy/api/helm/nodeapp/Chart.yaml new file mode 100644 index 000000000..6d8697fd3 --- /dev/null +++ b/.deploy/api/helm/nodeapp/Chart.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: nodeapp +sources: + - https://github.com/xmlking/ngx-starter-kit/.deploy/api/helm/nodeapp +version: 0.1.0 diff --git a/.deploy/api/helm/nodeapp/README.md b/.deploy/api/helm/nodeapp/README.md new file mode 100755 index 000000000..c5b3a0cf7 --- /dev/null +++ b/.deploy/api/helm/nodeapp/README.md @@ -0,0 +1,134 @@ +# Helm Chart Templates for Node.js in Kubernetes + +This project provides template Helm Charts for deploying a Node.js web application into any Kubernetes based cloud. + +The templates require your application to built into a Docker image. The [Docker Templates](../../Dockerfile) provides assistance in creating an image for your application. + +In order to use these template, copy the files from this project into your application directory. You should only need to edit the `Chart.yaml` and `values.yaml` files. + +## Prerequisites + +Using the template Helm charts assumes the following pre-requisites are complete: + +1. You have a Kubernetes cluster + This could be one hosted by a cloud provider or running locally, for example using [Minikube](https://kubernetes.io/docs/setup/minikube/) + +2. You have kubectl installed and configured for your cluster + The [Kuberenetes command line](https://kubernetes.io/docs/tasks/tools/install-kubectl/) tool, `kubectl`, is used to view and control your Kubernetes cluster. + +3. You have the Helm command line and Tiller backend installed + [Helm and Tiller](https://docs.helm.sh/using_helm/) provide the command line tool and backend service for deploying your application using the Helm chart. + +4. You have created and published a Docker image for your application +The Docker Template project provides guidance on [building](../../README.md#build) and [publishing it to the DockerHub registry](../../README.md#build). + +5. Your application has a `/live` and `/ready` health check endpoints + This allows Kubernetes to restart your application if it fails or becomes unresponsive. + The [@nestjs/terminu](https://github.com/nestjs/terminu) add-on can be used to add health check endpoints. + +## Adding the Chart to your Application + +In order to add Helm Charts to your application, copy the `nodeapp` directory from this project into your application's root directory. + +You then need to make a single change before the charts are usable: to set the `image.repository` for your application. + +### Setting the `image.repository` parameter + +In order to change the `image.respository` parameter, open the `nodeapp/values.yaml` file and change the following entry: + +```sh +image: + repository: /nodeapp +``` +to set `` to your namespace on DockerHub where you published your application as `nodeapp`. + +## Configuring the Chart for your Application + +The following table lists the configurable parameters of the template Helm chart and their default values. + +`livenessProbe` check if pod is in a bad state, will `restart` pod if probe failed +`readinessProbe` check if service in a healthy state, will remove pod from `service/loadbalancer` if probe failed + +| Parameter | Description | Default | +| ----------------------- | --------------------------------------------- | ---------------------------------------------------------- | +| `image.repository` | image repository | `/nodeapp` | +| `image.tag` | Image tag | `latest` | +| `image.pullPolicy` | Image pull policy | `Always` | +| `livenessProbe.path` | Liveness Probe `path` | `/live` | +| `livenessProbe.initialDelaySeconds` | How long to wait before beginning the checks our pod(s) are up | 30 | +| `livenessProbe.periodSeconds` | The interval at which we'll check if a pod is running OK before being restarted | 10 | +| `livenessProbe.timeoutSeconds` | if response time is logger than 3 seconds, we consider the check as failed | 3 | +| `livenessProbe.failureThreshold` | if check fails for `N` times in a row, we consider the pod is in a bad state, pod will be restarted | 3 | +| `livenessProbe.successThreshold` | if check succeeds for once, we consider the pod is back to normal | 1 | +| `readinessProbe.path` | Readiness Probe `path` | `/ready` | +| `readinessProbe.initialDelaySeconds` | Start checking after 30s after pod starts. should set to a minimal value such that service able to receive requests as soon as it is ready| `30` | +| `readinessProbe.periodSeconds` | Readiness Probe `timeoutSeconds` | `10` | +| `readinessProbe.timeoutSeconds` | if response time is logger than 3 seconds, we consider the check as failed | 3 | +| `readinessProbe.failureThreshold` | if check fails for `N` times in a row, we consider the pod is in a bad state, pod will be removed from loadbalancer | 3 | +| `readinessProbe.successThreshold` | if check succeeds for once, we consider the pod is back to normal | 1 | +| `service.type` | Kubernetes service type exposing port | `ClusterIP` | +| `service.nodePort` | The node port used if the service is of type `NodePort`| `""` | +| `service.port` | TCP Port for this service | `3000` | +| `resources` | CPU, Memory resource limits | `{}` no default set | +| `autoscaling.enabled` | Enable HorizontalPodAutoscaler | `{}` | +| `networkPolicy.enabled` | Enable NetworkPolicy | `false` | +| `ingress.enabled` | if `true`, an ingress is created | `false` | +| `ingress.annotations` | annotations for the ingress | `{}` | +| `ingress.path` | a list ingress paths | `[/]` | +| `ingress.hosts` | a list of ingress hosts | `[ngxapi.example.com]` | +| `ingress.tls` | a list of [IngressTLS](https://v1-9.docs.kubernetes.io/docs/reference/generated/kubernetes-api/v1.9/#ingresstls-v1beta1-extensions) items | `[]` | +| `metrics.enabled` | add prometheus annotations | `false` | + + +## Using the Chart to deploy your Application to Kubernetes + +In order to use the Helm chart to deploy and verify your applicaton in Kubernetes, run the following commands: + +1. From the directory containing `Chart.yaml`, run: + + ```sh + helm install --name ngxapi . + ``` + This deploys and runs your application in Kubernetes, and prints the following text to the console: + + ```sh + Congratulations, you have deployed your Node.js Application to Kubernetes using Helm! + + To verify your application is running, run the following two commands to set the SAMPLE_NODE_PORT and SAMPPLE_NODE_IP environment variables to the locaton of your application: + + export SAMPLE_NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services nodeapp-service) + export SAMPLE_NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}") + + And then open your web browser to http://${SAMPLE_NODE_IP}:${SAMPLE_NODE_PORT} from the command line, eg: + + open http://${SAMPLE_NODE_IP}:${SAMPLE_NODE_PORT} + ``` + +2. Copy, paste and run the `export` lines printed to the console + eg: + + ```sh + export SAMPLE_NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services nodeapp-service) + export SAMPLE_NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}") + ``` + +3. Open a browser to view your application: + Open your browser to `http://${SAMPLE_NODE_IP}:${SAMPLE_NODE_PORT}` from the command line using: + + ```sh + open http://${SAMPLE_NODE_IP}:${SAMPLE_NODE_PORT} + ``` + +You application should now be visible in your browser. + + +## Uninstalling your Application +If you installed your application with: + +```sh +helm install --name ngxapi . +``` +then you can: + +* Find the deployment using `helm list --all` and searching for an entry with the chart name "ngxapi". +* Remove the application with `helm delete --purge ngxapi`. diff --git a/.deploy/api/helm/nodeapp/templates/NOTES.txt b/.deploy/api/helm/nodeapp/templates/NOTES.txt new file mode 100644 index 000000000..6b8e545d3 --- /dev/null +++ b/.deploy/api/helm/nodeapp/templates/NOTES.txt @@ -0,0 +1,21 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "nodeapp.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "nodeapp.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "nodeapp.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + 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 "nodeapp.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl port-forward $POD_NAME 8080:3000 +{{- end }} diff --git a/.deploy/api/helm/nodeapp/templates/_helpers.tpl b/.deploy/api/helm/nodeapp/templates/_helpers.tpl new file mode 100644 index 000000000..12e3d35a3 --- /dev/null +++ b/.deploy/api/helm/nodeapp/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "nodeapp.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 "nodeapp.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 "nodeapp.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/.deploy/api/helm/nodeapp/templates/deployment.yaml b/.deploy/api/helm/nodeapp/templates/deployment.yaml new file mode 100644 index 000000000..8b7d60f9d --- /dev/null +++ b/.deploy/api/helm/nodeapp/templates/deployment.yaml @@ -0,0 +1,102 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "nodeapp.fullname" . }} + labels: + app.kubernetes.io/name: {{ include "nodeapp.name" . }} + helm.sh/chart: {{ include "nodeapp.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + strategy: + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + revisionHistoryLimit: {{ .Values.revisionHistoryLimit }} + selector: + matchLabels: + app.kubernetes.io/name: {{ include "nodeapp.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ include "nodeapp.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + spec: + {{- with .Values.securityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.initContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: {{ .Values.service.port }} + protocol: TCP + {{- if .Values.envSecrets }} + envFrom: + - secretRef: + name: {{ include "nodeapp.fullname" . }} + {{- end }} + env: + {{- with .Values.env }} + {{- toYaml . | nindent 12 }} + {{- end }} + - name: PORT + value: "{{ .Values.service.port }}" + - name: HOST + valueFrom: { fieldRef: { fieldPath: status.podIP } } + livenessProbe: + httpGet: + path: {{ .Values.livenessProbe.path }} + port: http + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + {{- if .Values.livenessProbe.timeoutSeconds }} + timeoutSeconds: {{ .Values.livenessProbe.periodSeconds }} + {{- end }} + {{- if .Values.livenessProbe.failureThreshold }} + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + {{- end }} + {{- if .Values.livenessProbe.successThreshold }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} + {{- end }} + readinessProbe: + httpGet: + path: {{ .Values.readinessProbe.path }} + port: http + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + {{- if .Values.readinessProbe.timeoutSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + {{- end }} + {{- if .Values.readinessProbe.failureThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + {{- end }} + {{- if .Values.readinessProbe.successThreshold }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + {{- end }} + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- 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/.deploy/api/helm/nodeapp/templates/hpa.yaml b/.deploy/api/helm/nodeapp/templates/hpa.yaml new file mode 100755 index 000000000..bd65e575e --- /dev/null +++ b/.deploy/api/helm/nodeapp/templates/hpa.yaml @@ -0,0 +1,27 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "nodeapp.fullname" . }} + labels: + app.kubernetes.io/name: {{ include "nodeapp.name" . }} + helm.sh/chart: {{ include "nodeapp.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "nodeapp.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.autoscaling.metrics.cpu.targetAverageUtilization }} + - type: Resource + resource: + name: memory + targetAverageUtilization: {{ .Values.autoscaling.metrics.memory.targetAverageUtilization }} +{{- end }} diff --git a/.deploy/api/helm/nodeapp/templates/ingress.yaml b/.deploy/api/helm/nodeapp/templates/ingress.yaml new file mode 100644 index 000000000..09d809f75 --- /dev/null +++ b/.deploy/api/helm/nodeapp/templates/ingress.yaml @@ -0,0 +1,39 @@ +{{- if .Values.ingress.enabled }} +{{- $fullName := include "nodeapp.fullname" . }} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + app.kubernetes.io/name: {{ include "nodeapp.name" . }} + helm.sh/chart: {{ include "nodeapp.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: +{{- 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: {{ . }} + backend: + serviceName: {{ $fullName }} + servicePort: http + {{- end }} + {{- end }} +{{- end }} diff --git a/.deploy/api/helm/nodeapp/templates/istio.yaml b/.deploy/api/helm/nodeapp/templates/istio.yaml new file mode 100755 index 000000000..63c38b3ae --- /dev/null +++ b/.deploy/api/helm/nodeapp/templates/istio.yaml @@ -0,0 +1,24 @@ +{{- if .Values.istio.enabled }} +apiVersion: config.istio.io/v1alpha2 +kind: RouteRule +metadata: + name: {{ include "nodeapp.fullname" . }} + labels: + app.kubernetes.io/name: {{ include "nodeapp.name" . }} + helm.sh/chart: {{ include "nodeapp.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +spec: + destination: + name: {{ include "nodeapp.fullname" . }} + precedence: 1 + route: + - labels: + version: "current" + weight: {{ .Values.istio.weight }} +{{- if .Values.base.enabled }} + - labels: + version: "base" + weight: {{ .Values.base.weight }} +{{- end }} +{{- end }} diff --git a/.deploy/api/helm/nodeapp/templates/networkpolicy.yaml b/.deploy/api/helm/nodeapp/templates/networkpolicy.yaml new file mode 100755 index 000000000..2e144469f --- /dev/null +++ b/.deploy/api/helm/nodeapp/templates/networkpolicy.yaml @@ -0,0 +1,29 @@ +{{- if .Values.networkPolicy.enabled }} +kind: NetworkPolicy +apiVersion: networking.k8s.io/v1 +metadata: + name: {{ include "nodeapp.fullname" . }} + labels: + app.kubernetes.io/name: {{ include "nodeapp.name" . }} + helm.sh/chart: {{ include "nodeapp.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: {{ include "nodeapp.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + policyTypes: + - Ingress + {{- with .Values.networkPolicy.egress }} + - Egress + {{- end }} + ingress: + # Allow inbound connections + - ports: + - port: {{ .Values.service.port}} +{{- with .Values.networkPolicy.egress }} + egress: + {{- toYaml . | nindent 4 }} +{{- end }} +{{- end }} diff --git a/.deploy/api/helm/nodeapp/templates/secrets.yaml b/.deploy/api/helm/nodeapp/templates/secrets.yaml new file mode 100755 index 000000000..6ca7c8901 --- /dev/null +++ b/.deploy/api/helm/nodeapp/templates/secrets.yaml @@ -0,0 +1,18 @@ +{{- if .Values.envSecrets }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "nodeapp.fullname" . }} + labels: + app.kubernetes.io/name: {{ include "nodeapp.name" . }} + helm.sh/chart: {{ include "nodeapp.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + annotations: + "helm.sh/resource-policy": keep +type: Opaque +data: + {{- range .Values.envSecrets }} + {{ .name }}: {{ .value | b64enc | quote }} + {{- end }} +{{- end }} diff --git a/.deploy/api/helm/nodeapp/templates/service.yaml b/.deploy/api/helm/nodeapp/templates/service.yaml new file mode 100644 index 000000000..e6b0bca61 --- /dev/null +++ b/.deploy/api/helm/nodeapp/templates/service.yaml @@ -0,0 +1,28 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "nodeapp.fullname" . }} + labels: + app.kubernetes.io/name: {{ include "nodeapp.name" . }} + helm.sh/chart: {{ include "nodeapp.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- if .Values.metrics.enabled }} + annotations: + prometheus.io/scrape: "true" + prometheus.io/healthcheck: "true" + prometheus.io/port: "9187" +{{- end }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + {{- if (and (eq .Values.service.type "NodePort") (not (empty .Values.service.nodePort))) }} + nodePort: {{ .Values.service.nodePort }} + {{- end }} + protocol: TCP + name: http + selector: + app.kubernetes.io/name: {{ include "nodeapp.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/.deploy/api/helm/nodeapp/templates/tests/test-connection.yaml b/.deploy/api/helm/nodeapp/templates/tests/test-connection.yaml new file mode 100644 index 000000000..4470dd215 --- /dev/null +++ b/.deploy/api/helm/nodeapp/templates/tests/test-connection.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "nodeapp.fullname" . }}-test-connection" + labels: + app.kubernetes.io/name: {{ include "nodeapp.name" . }} + helm.sh/chart: {{ include "nodeapp.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + annotations: + "helm.sh/hook": test-success +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "nodeapp.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/.deploy/api/helm/nodeapp/values.yaml b/.deploy/api/helm/nodeapp/values.yaml new file mode 100644 index 000000000..c93956653 --- /dev/null +++ b/.deploy/api/helm/nodeapp/values.yaml @@ -0,0 +1,144 @@ +# Default values for nodeapp. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 +revisionHistoryLimit: 1 + +image: + repository: nodeapp + tag: stable + pullPolicy: IfNotPresent + +nameOverride: "" +fullnameOverride: "" + +service: + type: ClusterIP + port: 3000 + +## Use either ingress or NodePort +ingress: + enabled: false + annotations: {} + ## If you do want to specify ingress, uncomment the following + ## lines, adjust them as necessary, and remove the curly braces after 'ingress:'. + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: nodeapp.local + paths: [/] + + tls: [] + # - secretName: chart-example-tls + # hosts: + # - nodeapp.local + +initContainers: {} +## If you do want to specify initContainers, uncomment the following +## lines, adjust them as necessary, and remove the curly braces after 'initContainers:'. +# - name: wait-for-postgresql +# image: alpine:3.8 +# imagePullPolicy: IfNotPresent +# command: +# - sh +# - -c +# - | +# until printf "." && nc -z -w 2 ngxdb-postgresql 5432; do +# sleep 2; +# done; +# +# echo 'PostgreSQL OK ✓' + +env: [] +## If you do want to specify env, uncomment the following +## lines, adjust them as necessary, and remove the array braces after 'extraEnv:'. +# - name: TYPEORM_HOST +# value: ngxdb-postgresql +# - name: TYPEORM_PORT +# value: '5432' +# - name: TYPEORM_DATABASE +# value: postgres +# - name: TYPEORM_USERNAME +# value: postgres +# - name: TYPEORM_LOGGING +# value: 'false' + +envSecrets: [] +## If you do want to specify env from secrets, uncomment the following +## lines, adjust them as necessary, and remove the array braces after 'extraSecrets:'. +# - name: TYPEORM_PASSWORD +# value: postgres321 +# - name: EMAIL_AUTH_PASS +# value: auth_pass +# - name: VAPID_PRIVATE_KEY +# value: cwh2CYK5h_B_Gobnv8Ym9x61B3qFE2nTeb9BeiZbtMI + +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: 200m +# memory: 256Mi +# requests: +# cpu: 100m +# memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +livenessProbe: + path: / + initialDelaySeconds: 120 + periodSeconds: 30 +readinessProbe: + path: / + initialDelaySeconds: 60 + periodSeconds: 20 + +securityContext: {} +## We usually recommend to specify securityContext for containers +## This increases chances charts run on restricted environments such as OpenShift. +## If you do want to specify securityContext, uncomment the following +## lines, adjust them as necessary, and remove the curly braces after 'securityContext:'. +# fsGroup: 65534 +# runAsUser: 65534 + +## Create HorizontalPodAutoscaler object. +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 2 + metrics: + cpu: + targetAverageUtilization: 70 + memory: + targetAverageUtilization: 70 + +## Create NetworkPolicy resources. +networkPolicy: + enabled: false +## If you do want to specify egress, uncomment the following +# egress: +# - to: +# - ipBlock: # Allow nodeapp to talk to external servers +# cidr: 0.0.0.0/0 +# - ports: # Allow nodeapp to talk with the api server +# - port: 6443 +# protocol: TCP +# - port: 6443 +# protocol: UDP + +## Enabled istio. +istio: + enabled: false + weight: 100 + +## Enabled prometheus. +metrics: + enabled: false diff --git a/.deploy/api/helm/secrets.dev.yaml b/.deploy/api/helm/secrets.dev.yaml new file mode 100644 index 000000000..663ddc2f3 --- /dev/null +++ b/.deploy/api/helm/secrets.dev.yaml @@ -0,0 +1,31 @@ +envSecrets: +- name: ENC[AES256_GCM,data:j49m+hIvwADspA4SyrQ7Vw==,iv:vi8eAv6qE6HFuAHmhdG1eUaf/VqE9UnY1njxBtfnxNg=,tag:o1CCX8ao/A12NfMSPEmveg==,type:str] + value: ENC[AES256_GCM,data:oCiz15CGTe1rjg8=,iv:Hz5rnBYj9vGHVMZf1dsISs7gMMM5O91lEIJjO89S7lM=,tag:lP+cSv9/st4wZ9dY7hDoQw==,type:str] +- name: ENC[AES256_GCM,data:5+uBxpn+Q2UeC2uXhF5k,iv:qhG0kfaAmMha8CyTIggUX925NwDsql/zm9vKkwbiMxY=,tag:YaEPKlbei5Szs2eloINauQ==,type:str] + value: ENC[AES256_GCM,data:0nsAEGhBRMqx,iv:0XQtpG0AqUja0qigrv9TiMi0CbltRMH7kJd/Twcyy4o=,tag:tgUkpguTZYYYOba/QwTS2A==,type:str] +- name: ENC[AES256_GCM,data:/Kts0rswJFSr7HWwYAhW96M=,iv:v8FuthP6aMtVS4SkoCxUzaT/N3hM9PI8m943sj5UgA0=,tag:MDtHO9f2aDqep4Tjv5Am0g==,type:str] + value: ENC[AES256_GCM,data:cw9KHNy1A/s0rrUzCwRX6DEifN6vRgrYWvpJABCBrF6DnnlmoqyaCuCt6w==,iv:AU+WjTK3jldT5Uz4XWQ99t2P2/gZuJiun3RFIYJgpGU=,tag:FwaipJA+KJZGDtZ+kVWmAQ==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + lastmodified: '2019-04-02T08:47:48Z' + mac: ENC[AES256_GCM,data:XcliwQ7ra8ucTvf8+vQoE2S0lxziPqq/UWa2P288CkXvNiaJZ8q4WFxjGjoEyjXCOtfzvbwhRqaMUg/qd1igf18iEXS9T6urRvTklQkQmczqU3d05CGqJQD5bw6+OchtvmMkm8L6sgyTVKfO5huL+KSL/VMSiW+VtbFrHGsXlyE=,iv:w3a4FDMIPS2BQehta7Byn8QZOSMGsTCpAV+NeNdqzxA=,tag:x7KoMryyAVl2zeDXfOZMpw==,type:str] + pgp: + - created_at: '2019-04-02T08:47:48Z' + enc: |- + -----BEGIN PGP MESSAGE----- + + wcBMA0lc+u+GLoPGAQgAbVswSTLIYu/XClfXGVZ65wn/Rxhuq0/yQRlf0NnUXuQz + B+p41j6i6U2E/ScD+/GKRLbOeQRBRFxcdZ6M3ZwKdkuY2kkjSR0BLHg5M/TiXyVr + vE12ZHTqVmFRWLFZjMyjKRkWbxDXJ09coLe+hQNHqIv3pzuEdAuLefDs/Q/mH8IK + U1VE2fNmf6TsS6C3Aw1oxslNqdnyEFl8c/H/Om8QdcEF5YjWZ6NTmjXB7ajMawnA + 0FYHmVqO/aPFemIqoSHUNbDcCzx5VsSzjf+8uFtrVFaRNB1Pl4Mqxhc+VMliV8ad + sLSCAbQaAYtetdJvFT+J9AYIkOHlS9XsPZRwYL7v+tLgAeQPm1PbZV42fl0d7ZGM + FnfV4d5b4PDgXeEs1uA84jawCbrgOOWVblOnho9I8fC0HuY6m4nAGRndyCQ3++u0 + 5QAA6lzH++Ac5AC3iIpeWICIn3Fl7uP+K9vipVZ1BuFWawA= + =Se54 + -----END PGP MESSAGE----- + fp: 438F624ADE96A9DE20DE7C5672EB37BA9AB0F7E7 + unencrypted_suffix: _unencrypted + version: 3.2.0 diff --git a/.deploy/api/helm/secrets.prod.yaml b/.deploy/api/helm/secrets.prod.yaml new file mode 100644 index 000000000..663ddc2f3 --- /dev/null +++ b/.deploy/api/helm/secrets.prod.yaml @@ -0,0 +1,31 @@ +envSecrets: +- name: ENC[AES256_GCM,data:j49m+hIvwADspA4SyrQ7Vw==,iv:vi8eAv6qE6HFuAHmhdG1eUaf/VqE9UnY1njxBtfnxNg=,tag:o1CCX8ao/A12NfMSPEmveg==,type:str] + value: ENC[AES256_GCM,data:oCiz15CGTe1rjg8=,iv:Hz5rnBYj9vGHVMZf1dsISs7gMMM5O91lEIJjO89S7lM=,tag:lP+cSv9/st4wZ9dY7hDoQw==,type:str] +- name: ENC[AES256_GCM,data:5+uBxpn+Q2UeC2uXhF5k,iv:qhG0kfaAmMha8CyTIggUX925NwDsql/zm9vKkwbiMxY=,tag:YaEPKlbei5Szs2eloINauQ==,type:str] + value: ENC[AES256_GCM,data:0nsAEGhBRMqx,iv:0XQtpG0AqUja0qigrv9TiMi0CbltRMH7kJd/Twcyy4o=,tag:tgUkpguTZYYYOba/QwTS2A==,type:str] +- name: ENC[AES256_GCM,data:/Kts0rswJFSr7HWwYAhW96M=,iv:v8FuthP6aMtVS4SkoCxUzaT/N3hM9PI8m943sj5UgA0=,tag:MDtHO9f2aDqep4Tjv5Am0g==,type:str] + value: ENC[AES256_GCM,data:cw9KHNy1A/s0rrUzCwRX6DEifN6vRgrYWvpJABCBrF6DnnlmoqyaCuCt6w==,iv:AU+WjTK3jldT5Uz4XWQ99t2P2/gZuJiun3RFIYJgpGU=,tag:FwaipJA+KJZGDtZ+kVWmAQ==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + lastmodified: '2019-04-02T08:47:48Z' + mac: ENC[AES256_GCM,data:XcliwQ7ra8ucTvf8+vQoE2S0lxziPqq/UWa2P288CkXvNiaJZ8q4WFxjGjoEyjXCOtfzvbwhRqaMUg/qd1igf18iEXS9T6urRvTklQkQmczqU3d05CGqJQD5bw6+OchtvmMkm8L6sgyTVKfO5huL+KSL/VMSiW+VtbFrHGsXlyE=,iv:w3a4FDMIPS2BQehta7Byn8QZOSMGsTCpAV+NeNdqzxA=,tag:x7KoMryyAVl2zeDXfOZMpw==,type:str] + pgp: + - created_at: '2019-04-02T08:47:48Z' + enc: |- + -----BEGIN PGP MESSAGE----- + + wcBMA0lc+u+GLoPGAQgAbVswSTLIYu/XClfXGVZ65wn/Rxhuq0/yQRlf0NnUXuQz + B+p41j6i6U2E/ScD+/GKRLbOeQRBRFxcdZ6M3ZwKdkuY2kkjSR0BLHg5M/TiXyVr + vE12ZHTqVmFRWLFZjMyjKRkWbxDXJ09coLe+hQNHqIv3pzuEdAuLefDs/Q/mH8IK + U1VE2fNmf6TsS6C3Aw1oxslNqdnyEFl8c/H/Om8QdcEF5YjWZ6NTmjXB7ajMawnA + 0FYHmVqO/aPFemIqoSHUNbDcCzx5VsSzjf+8uFtrVFaRNB1Pl4Mqxhc+VMliV8ad + sLSCAbQaAYtetdJvFT+J9AYIkOHlS9XsPZRwYL7v+tLgAeQPm1PbZV42fl0d7ZGM + FnfV4d5b4PDgXeEs1uA84jawCbrgOOWVblOnho9I8fC0HuY6m4nAGRndyCQ3++u0 + 5QAA6lzH++Ac5AC3iIpeWICIn3Fl7uP+K9vipVZ1BuFWawA= + =Se54 + -----END PGP MESSAGE----- + fp: 438F624ADE96A9DE20DE7C5672EB37BA9AB0F7E7 + unencrypted_suffix: _unencrypted + version: 3.2.0 diff --git a/.deploy/api/helm/values-dev.yaml b/.deploy/api/helm/values-dev.yaml new file mode 100644 index 000000000..37089bc3b --- /dev/null +++ b/.deploy/api/helm/values-dev.yaml @@ -0,0 +1,75 @@ +test: + enabled: false + +image: + repository: xmlking/ngxapi + tag: 1.5.0-SNAPSHOT + pullPolicy: IfNotPresent + +securityContext: + fsGroup: 65534 + runAsUser: 65534 + +initContainers: + - name: wait-for-postgresql + image: alpine:3.6 + imagePullPolicy: IfNotPresent + command: + - sh + - -c + - | + until printf "." && nc -z -w 2 ngxdb-postgresql 5432; do + sleep 2; + done; + + echo 'PostgreSQL OK ✓' + +livenessProbe: + path: /live +readinessProbe: + path: /ready + +env: + - name: NODE_TLS_REJECT_UNAUTHORIZED + value: '0' + - name: DOMAIN_URL + value: 'https://ngxapi.traefik.k8s' + - name: TYPEORM_HOST + value: ngxdb-postgresql + - name: TYPEORM_PORT + value: '5432' + - name: TYPEORM_DATABASE + value: postgres + - name: TYPEORM_USERNAME + value: postgres + - name: TYPEORM_LOGGING + value: 'false' + - name: OIDC_ISSUER_URL + value: 'https://keycloak-ngx1.1d35.starter-us-east-1.openshiftapps.com/auth/realms/ngx' + - name: OIDC_CLIENT_ID + value: ngxapi + - name: EMAIL_HOST + value: mail.google.com + - name: EMAIL_PORT + value: '25' + - name: EMAIL_SECURE + value: 'false' + - name: EMAIL_AUTH_USER + value: auth_user + - name: EMAIL_FROM + value: '"sumo demo" ' + - name: VAPID_PUBLIC_KEY + value: 'BAJq-yHlSNjUqKW9iMY0hG96X9WdVwetUFDa5rQIGRPqOHKAL_fkKUe_gUTAKnn9IPAltqmlNO2OkJrjdQ_MXNg' + +ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: traefik + traefik.frontend.passHostHeader: "true" + hosts: + - host: ngxapi.traefik.k8s + paths: [/] + tls: + - secretName: keycloak-secrets-tls + hosts: + - ngxapi.traefik.k8s diff --git a/.deploy/api/helm/values-prod.yaml b/.deploy/api/helm/values-prod.yaml new file mode 100644 index 000000000..494d2bb35 --- /dev/null +++ b/.deploy/api/helm/values-prod.yaml @@ -0,0 +1,105 @@ +test: + enabled: false + +resources: + limits: + cpu: 4 + memory: "4096Mi" + requests: + cpu: 2 + memory: "2048Mi" + +image: + repository: xmlking/ngxapi + tag: 1.5.0-SNAPSHOT + pullPolicy: IfNotPresent + +securityContext: + fsGroup: 65534 + runAsUser: 65534 + +initContainers: + - name: wait-for-postgresql + image: alpine:3.6 + imagePullPolicy: IfNotPresent + command: + - sh + - -c + - | + until printf "." && nc -z -w 2 ngxdb-postgresql 5432; do + sleep 2; + done; + + echo 'PostgreSQL OK ✓' + +livenessProbe: + path: /live + initialDelaySeconds: 180 + periodSeconds: 60 + timeoutSeconds: 20 +readinessProbe: + path: /ready + initialDelaySeconds: 60 + periodSeconds: 30 + +env: + - name: NODE_TLS_REJECT_UNAUTHORIZED + value: '0' + - name: DOMAIN_URL + value: 'https://ngxapi.traefik.k8s' + - name: TYPEORM_HOST + value: ngxdb-postgresql + - name: TYPEORM_PORT + value: '5432' + - name: TYPEORM_DATABASE + value: postgres + - name: TYPEORM_USERNAME + value: postgres + - name: TYPEORM_LOGGING + value: 'false' + - name: OIDC_ISSUER_URL + value: 'https://keycloak-ngx1.1d35.starter-us-east-1.openshiftapps.com/auth/realms/ngx' + - name: OIDC_CLIENT_ID + value: ngxapi + - name: EMAIL_HOST + value: mail.google.com + - name: EMAIL_PORT + value: '25' + - name: EMAIL_SECURE + value: 'false' + - name: EMAIL_AUTH_USER + value: auth_user + - name: EMAIL_FROM + value: '"sumo demo" ' + - name: VAPID_PUBLIC_KEY + value: 'BAJq-yHlSNjUqKW9iMY0hG96X9WdVwetUFDa5rQIGRPqOHKAL_fkKUe_gUTAKnn9IPAltqmlNO2OkJrjdQ_MXNg' + +ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: traefik + traefik.frontend.passHostHeader: "true" + hosts: + - host: ngxapi.traefik.k8s + paths: [/] + tls: + - secretName: keycloak-secrets-tls + hosts: + - ngxapi.traefik.k8s + +autoscaling: + enabled: true + +networkPolicy: + enabled: true + egress: + - to: + - ipBlock: # Allow nodeapp to talk to external servers + cidr: 0.0.0.0/0 + +istio: + enabled: false + weight: 100 + +metrics: + enabled: true diff --git a/.deploy/api/manual/README.md b/.deploy/api/manual/README.md index 0b4968f9b..bf4faff03 100644 --- a/.deploy/api/manual/README.md +++ b/.deploy/api/manual/README.md @@ -1,6 +1,6 @@ # NgxApi -Deploying **NgxApi** on Kubernetes +Deploying **NgxApi** on Kubernetes manually ## Prerequisites @@ -45,6 +45,8 @@ kubectl get deployment ngxapi -o yaml kubectl get po -o wide --watch POD_NAME=$(kubectl get pods -lapp=ngxapi -o jsonpath='{.items[0].metadata.name}') kubectl logs $POD_NAME -f +# awesome for interactive debugging, or even sending ctrl-c to misbehaving app +kubectl attach $POD_NAME -i # create service (use -service.yaml and -ingress.yaml for development, -nodeport.yaml for prod) kubectl create -f 05-ngxapi-service.yaml @@ -58,35 +60,28 @@ kubectl create -f 06-ngxapi-ingress.yaml kubectl get all,configmap,secret,ingress -l app=ngxapi -## delete -kubectl delete service ngxapi -kubectl delete deployment ngxapi -kubectl delete configmap ngxapi -kubectl delete secret ngxapi - ## redeploy (new image) -update tag in 04-ngxapi-deployment.yaml and delete and create again. +update tag in 04-ngxapi-deployment.yaml and delete and create deployment again. ## Scale to zero kubectl scale deploy ngxapi --replicas=0 ``` -### Deleting NgxApi Deployment +### Deleting Deployment ```bash -kubectl delete ingress keycloak -kubectl delete service keycloak -kubectl delete deployment keycloak -kubectl delete configmap keycloak -kubectl delete secret keycloak -kubectl delete persistentvolumeclaim keycloak -kubectl delete networkpolicy -lapp=keycloak +kubectl delete ingress ngxapi +kubectl delete service ngxapi +kubectl delete deployment ngxapi +kubectl delete configmap ngxapi +kubectl delete secret ngxapi +kubectl delete persistentvolumeclaim ngxapi +kubectl delete networkpolicy -lapp=ngxapi ``` ---- -## Test API +## Test + ```bash curl -X GET "https://ngxapi.traefik.k8s/" -k -H "accept: application/json" curl -X GET "https://ngxapi.traefik.k8s/echo?sumo=demo" -k -H "accept: application/json" ``` - diff --git a/.deploy/helm/README.md b/.deploy/helm/README.md index 18c8f40db..3047c3a8d 100644 --- a/.deploy/helm/README.md +++ b/.deploy/helm/README.md @@ -2,8 +2,8 @@ > One time Helm setup and configuration - ### Install Helm CLI + ```bash brew install kubernetes-helm ``` @@ -27,17 +27,17 @@ helm version --tiller-namespace=kube-system helm ls -a --tiller-namespace=kube-system --debug # Uninstall tiller from your namespace -helm reset --tiller-namespace=kube-system +helm reset --tiller-namespace=kube-system # if needed -helm init --client-only --tiller-namespace=kube-system -helm repo update --tiller-namespace=kube-system -``` +helm init --client-only --tiller-namespace=kube-system +helm repo update --tiller-namespace=kube-system +``` ### Install Charts ```bash -# example chart instalation +# example chart instalation # --dry-run --debug flags help you to see before you really deploy helm install --name=nginx-ingress --namespace=default --tiller-namespace=kube-system ./charts-master/incubator/nginx-ingress helm install --name=traefik --namespace=default --tiller-namespace=kube-system -f traefik-values.yaml stable/traefik @@ -72,12 +72,104 @@ helm template \ --namespace default \ --output-dir manual/stable \ charts/stable/traefik - + # Applying the result to the cluster kubectl apply --recursive --filename manual/stable/traefik ``` +### Managing Helm Chart Secrets with `helm-secrets` + +#### Install dependencies for `helm-secrets` plugin + +```bash +brew install gnu-getopt +# brew install gnupg +brew install gpg1 +ln -s /usr/local/bin/gpg1 /usr/local/bin/gpg +``` + +#### Create your `GPG` key: + +```bash +gpg --gen-key +``` + +#### Create your `GPG` key with `YubiKey`: + +> only works when using latest gpg2 + +```bash +gpg --expert --full-gen-key +# note key ID, in this case is 1234ABC +"gpg: key 1234ABC marked as ultimately trusted" +``` + +#### To export your public key: + +```bash +gpg --export --armor > mypubkey.asc +``` + +#### To backup your private key: + +```bash +gpg --export -secret-key --armor <1234ABC> +``` + +#### To import another person’s public key: + +``` +gpg --import theirpubkey.asc +``` + +#### To list the public keys in your keyring: + +```bash +gpg --list-keys +``` + +#### To list private keys in your keyring: + +```bash +gpg --list-secret-keys +``` + +#### To find out the fingerprint of your key + +```bash +gpg --fingerprint +``` + +Install `helm-secrets` plugin + +```bash +helm plugin install https://github.com/futuresimple/helm-secrets + +# test +helm secrets help +``` + +> With the helm wrapper you can easily run `helm secrets install/upgrade/rollback` with secrets files included as `-f` option from you values dir tree. + +Follow infractions [Kubernetes Deployments with Helm - Secrets](https://developer.epages.com/blog/tech-stories/kubernetes-deployments-with-helm-secrets/) + +> secrets file should be named with `secrets[.*].yaml` pattern + +Additional Commands + +```bash +helm secrets enc secrets.yaml +helm secrets view secrets.yaml +helm secrets edit secrets.yaml +helm secrets dec secrets.yaml +helm secrets clean +``` + ### Reference + 1. [What You Yaml is What You Get](https://blog.giantswarm.io/what-you-yaml-is-what-you-get/) 2. [helm-nomagic](https://github.com/giantswarm/helm-nomagic) 3. [Helm from the trenches](https://hackernoon.com/helm-from-the-trenches-17f87859ee47) +4. [How To Use GPG on the Command Line](http://blog.ghostinthemachines.com/2015/03/01/how-to-use-gpg-command-line/) +5. [Using Your YubiKey with OpenPGP](https://support.yubico.com/support/solutions/articles/15000006420-using-your-yubikey-with-openpgp) +6. [Kubernetes Deployments with Helm - Secrets](https://developer.epages.com/blog/tech-stories/kubernetes-deployments-with-helm-secrets/) diff --git a/.deploy/keycloak/helm/README.md b/.deploy/keycloak/helm/README.md index b0b7d1e50..9ec392132 100644 --- a/.deploy/keycloak/helm/README.md +++ b/.deploy/keycloak/helm/README.md @@ -2,7 +2,7 @@ Deploying `KeyCloak` to `Kubernetes` via `Helm` -### With Tiller +### With Tiller ```bash cd .deploy/keycloak/helm @@ -22,14 +22,17 @@ POD_NAME=$(kubectl get pods -lapp=keycloak -o jsonpath='{.items[0].metadata.nam kubectl exec -it $POD_NAME -- /bin/bash kubectl logs $POD_NAME -f echo | openssl s_client -showcerts -connect keycloak.traefik.k8s:443 2>/dev/null - - -# To update + + +# To update helm upgrade --namespace=default -f values-dev.yaml keycloak stable/keycloak # To uninstall/delete the `keycloak` deployment helm delete keycloak helm delete keycloak --purge # delete keycloak and purge + +# Scale to zero +kubectl scale statefulset keycloak --replicas=0 ``` ### Without Tiller @@ -39,7 +42,7 @@ cd .deploy/keycloak/helm helm fetch stable/keycloak -helm template ./keycloak-4.6.0.tgz \ +helm template ./keycloak-4.7.0.tgz \ --name keycloak \ --namespace default \ --values values-dev.yaml \ @@ -48,38 +51,37 @@ helm template ./keycloak-4.6.0.tgz \ kubectl apply --recursive -f generated/keycloak/* --namespace default ``` - ### Access Keycloak Keycloak can be accessed: -* Within your cluster, at the following DNS name at port 80: +- Within your cluster, at the following DNS name at port 80: ``` keycloak-http.default.svc.cluster.local ``` -* From outside the cluster: +- From outside the cluster: ``` - https://keycloak.traefik.k8s ``` -* From outside the cluster, run these commands in the same shell: (`when NodePort used in values.yaml`) +- From outside the cluster, run these commands in the same shell: (`when NodePort used in values.yaml`) ```bash export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services keycloak-http) export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}") echo http://$NODE_IP:$NODE_PORT ``` - + Login with the following credentials: `Username: admin` To retrieve the initial user password run: + ```bash kubectl get secret --namespace default keycloak-http -o jsonpath="{.data.password}" | base64 --decode; echo ``` - ### Reference diff --git a/.deploy/keycloak/helm/values-dev.yaml b/.deploy/keycloak/helm/values-dev.yaml index 993d8a563..c66af7c47 100644 --- a/.deploy/keycloak/helm/values-dev.yaml +++ b/.deploy/keycloak/helm/values-dev.yaml @@ -10,12 +10,23 @@ keycloak: existingSecret: postgres-init-scripts existingSecretKey: keycloak-db-password extraEnv: | - - name: PROXY_ADDRESS_FORWARDING - value: 'true' - name: ROOT_LOGLEVEL value: INFO - name: KEYCLOAK_LOGLEVEL value: INFO + extraInitContainers: | + - name: wait-for-postgresql + image: alpine:3.8 + imagePullPolicy: IfNotPresent + command: + - sh + - -c + - | + until printf "." && nc -z -w 2 ngxdb-postgresql 5432; do + sleep 2; + done; + + echo 'PostgreSQL OK ✓' # use `service` for prod and `ingress` for dev. Comment other before install. # service: diff --git a/.deploy/keycloak/helm/values-prod.yaml b/.deploy/keycloak/helm/values-prod.yaml index 5a318eaad..30b02807a 100644 --- a/.deploy/keycloak/helm/values-prod.yaml +++ b/.deploy/keycloak/helm/values-prod.yaml @@ -27,12 +27,23 @@ keycloak: existingSecret: postgres-init-scripts existingSecretKey: keycloak-db-password extraEnv: | - - name: PROXY_ADDRESS_FORWARDING - value: 'true' - name: ROOT_LOGLEVEL value: INFO - name: KEYCLOAK_LOGLEVEL value: INFO + extraInitContainers: | + - name: wait-for-postgresql + image: alpine:3.8 + imagePullPolicy: IfNotPresent + command: + - sh + - -c + - | + until printf "." && nc -z -w 2 ngxdb-postgresql 5432; do + sleep 2; + done; + + echo 'PostgreSQL OK ✓' # use `service` for prod and `ingress` for dev. Comment other before install. service: diff --git a/.deploy/keycloak/helm/values.yaml b/.deploy/keycloak/helm/values.yaml index 2e58c2693..4eb5d2836 100644 --- a/.deploy/keycloak/helm/values.yaml +++ b/.deploy/keycloak/helm/values.yaml @@ -240,7 +240,12 @@ postgresql: enabled: false test: + enabled: true image: repository: unguiculus/docker-python3-phantomjs-selenium tag: v1 pullPolicy: IfNotPresent + securityContext: + runAsUser: 1000 + fsGroup: 1000 + runAsNonRoot: true diff --git a/.deploy/keycloak/manual/02-keycloak-secrets-tls.yml b/.deploy/keycloak/manual/02-keycloak-secrets-tls.yml index 74b260a35..68db895f2 100644 --- a/.deploy/keycloak/manual/02-keycloak-secrets-tls.yml +++ b/.deploy/keycloak/manual/02-keycloak-secrets-tls.yml @@ -4,6 +4,8 @@ metadata: name: keycloak-secrets-tls labels: app: keycloak + annotations: + "helm.sh/resource-policy": keep type: kubernetes.io/tls data: tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURwakNDQW80Q0NRRFF4MUFHcGpVQVVqQU5CZ2txaGtpRzl3MEJBUXNGQURDQmxERUxNQWtHQTFVRUJoTUMKVlZNeEV6QVJCZ05WQkFnTUNrTmhiR2xtYjNKdWFXRXhGREFTQmdOVkJBY01DMHh2Y3lCQmJtZGxiR1Z6TVEwdwpDd1lEVlFRS0RBUlRkVzF2TVEwd0N3WURWUVFMREFSRVpXMXZNUll3RkFZRFZRUUREQTBxTG5SeVlXVm1hV3N1CmF6aHpNU1F3SWdZSktvWklodmNOQVFrQkZoVjNaV0p0WVhOMFpYSkFkSEpoWldacGF5NXJPSE13SGhjTk1Ua3cKTXpFd01qSTFNVFU1V2hjTk1qQXdNekE1TWpJMU1UVTVXakNCbERFTE1Ba0dBMVVFQmhNQ1ZWTXhFekFSQmdOVgpCQWdNQ2tOaGJHbG1iM0p1YVdFeEZEQVNCZ05WQkFjTUMweHZjeUJCYm1kbGJHVnpNUTB3Q3dZRFZRUUtEQVJUCmRXMXZNUTB3Q3dZRFZRUUxEQVJFWlcxdk1SWXdGQVlEVlFRRERBMHFMblJ5WVdWbWFXc3Vhemh6TVNRd0lnWUoKS29aSWh2Y05BUWtCRmhWM1pXSnRZWE4wWlhKQWRISmhaV1pwYXk1ck9ITXdnZ0VpTUEwR0NTcUdTSWIzRFFFQgpBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQy91OFRYRTljdVlSM3FweWhid255RWRKSWhHdllodHl2VUJBUEdGVW91CnN6M040Q08yZzNvZWtTL1pMaXA0bFZhTGxNVktnVUQ2L3B4aHlORndMRTFxcmNaaXhkYTZVZXB4c1BXS2dQZVYKTlFvMVZzZkVtT0c5Yit5V1Y4QzFQWGllcmxxOCtLRlo2UlJJVnBTVzVscklSdytDV0d0OEZPYnhBKzViMWx1dQp2V0N6ekZsTGVlanF4TkhHaG1JL3BWNnJmMWRMajFETm5QT2pwa3BIelpHNXdGc3Z3NWlWbENXY1pCMkJuZ2drClZERkdSUC83ekExZWR6b2RXYmhJOW4zUE4yZHN5b1diVW5KWEFjb1lMQlFMRVM4L1kzczh5V1I5WHBlNXB1Zk0KZ1doZjlzT3piandKK0FRQmd0UXdlVmZLcHNYcEJjQ2IyV1FGZHFlRzNMUW5BZ01CQUFFd0RRWUpLb1pJaHZjTgpBUUVMQlFBRGdnRUJBRDV6WHp0ZHZ2ZGl3d2hGYzdFNjFMTk9nQWV0L21HTDFjbHY4dXlEU0h5Mi9iNlVwZGw4CjkzTW5vblh2a2pDaHZNdXdiaitzblFaajY2YnlyeFBkMjJ5YjFzMnVTQ0JwRDRhRUs4VVd0Z0JyWmI5RWZqWTEKY0UydDNrZEkzV2o0TmxPcjB4N0dXS2M4SUJZVDFNbk43UnBtT0orL1d1SktZMVNORWJXMXEwUDF3ZFlQdTdpZgo4THl6K2ZNd1cvTWVpUm9aWmRtWVh0dmRVV2JaZzJGeFcwc3FQWmMwK2VabFVNcDlqRFREaUNHZ3RtRHVJazQ4CmdWcjlldzdMR0NhWFRyeFcrc2NPVW5uaUFpZFl4VCtmR1FFUGh4bWh3ZFFpRWJ6ZXNERDUrUi9uQVd3V3UvOWQKSXcwQzJpUStPaGpiTER6Sk5RTmhyY2lML0szSmc0bWUrWEU9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K diff --git a/.deploy/keycloak/manual/02-keycloak-secrets.yaml b/.deploy/keycloak/manual/02-keycloak-secrets.yaml index ae8228a38..066fdc155 100644 --- a/.deploy/keycloak/manual/02-keycloak-secrets.yaml +++ b/.deploy/keycloak/manual/02-keycloak-secrets.yaml @@ -4,6 +4,8 @@ metadata: name: keycloak labels: app: keycloak + annotations: + "helm.sh/resource-policy": keep type: Opaque data: KEYCLOAK_PASSWORD: YWRtaW4xMjM= diff --git a/.deploy/keycloak/manual/04-keycloak-deployment.yaml b/.deploy/keycloak/manual/04-keycloak-deployment.yaml index 131c1bf1d..540310d68 100644 --- a/.deploy/keycloak/manual/04-keycloak-deployment.yaml +++ b/.deploy/keycloak/manual/04-keycloak-deployment.yaml @@ -18,7 +18,7 @@ spec: terminationGracePeriodSeconds: 60 initContainers: - name: wait-for-postgresql - image: busybox + image: alpine:3.8 imagePullPolicy: IfNotPresent command: - sh diff --git a/.deploy/keycloak/manual/05-keycloak-service-nodeport.yaml b/.deploy/keycloak/manual/05-keycloak-service-nodeport.yaml index d8ffa313e..10d128d6c 100644 --- a/.deploy/keycloak/manual/05-keycloak-service-nodeport.yaml +++ b/.deploy/keycloak/manual/05-keycloak-service-nodeport.yaml @@ -10,7 +10,7 @@ spec: - name: http port: 8080 protocol: TCP - targetPort: 8080 + targetPort: http nodePort: 32080 selector: app: keycloak diff --git a/.deploy/keycloak/manual/05-keycloak-service.yaml b/.deploy/keycloak/manual/05-keycloak-service.yaml index 38bfea4b8..23de78699 100644 --- a/.deploy/keycloak/manual/05-keycloak-service.yaml +++ b/.deploy/keycloak/manual/05-keycloak-service.yaml @@ -10,6 +10,6 @@ spec: - name: http port: 8080 protocol: TCP - targetPort: 8080 + targetPort: http selector: app: keycloak diff --git a/.deploy/keycloak/manual/README.md b/.deploy/keycloak/manual/README.md index 73eb2c767..f5dca848f 100644 --- a/.deploy/keycloak/manual/README.md +++ b/.deploy/keycloak/manual/README.md @@ -13,7 +13,8 @@ Deploying **KeyCloak** on Kubernetes ## Deploy ### TLS Certs -> first time only: generate a self-signed certificate to configure Ingress + +> first time only: generate a self-signed certificate to configure Ingress ```bash cd .deploy/keycloak/manual @@ -33,7 +34,6 @@ kubectl create secret tls keycloak-secrets-tls \ kubectl create -f 02-keycloak-secrets-tls.yml --namespace default ``` - ### Deploying to Kubernetes > 1. assume you already setup `ngx` kubernetes context @@ -84,7 +84,7 @@ kubectl create -f 05-keycloak-service-nodeport.yaml kubectl get svc keycloak -o wide kubectl get ep -# create network policy (if your k8s enabled with network policies) +# create network policy (if your k8s enabled with network policies) kubectl create -f 06-keycloak-network-policy.yaml kubectl create -f 06-keycloak-helm-network-policy.yaml # test network policy @@ -95,6 +95,9 @@ open http://node2:32080 open http://node3:32080 kubectl get all,configmap,secret,ingress -l app=keycloak + +# Scale to zero +kubectl scale deploy keycloak --replicas=0 ``` #### Delete Keycloak Deployment diff --git a/.deploy/keycloak/realm-manual-import.json b/.deploy/keycloak/realm-manual-import.json index 3e9f360fa..43250cdba 100644 --- a/.deploy/keycloak/realm-manual-import.json +++ b/.deploy/keycloak/realm-manual-import.json @@ -14,7 +14,10 @@ "value": "ngxadmin" } ], - "realmRoles": ["ROLE_ADMIN"] + "realmRoles": ["ROLE_ADMIN"], + "clientRoles": { + "account": ["manage-account"] + } }, { "username": "sumo", @@ -28,7 +31,10 @@ "value": "demo" } ], - "realmRoles": ["ROLE_USER"] + "realmRoles": ["ROLE_USER"], + "clientRoles": { + "account": ["manage-account"] + } }, { "username": "sumo1", @@ -42,7 +48,10 @@ "value": "demo" } ], - "realmRoles": ["ROLE_USER"] + "realmRoles": ["ROLE_USER"], + "clientRoles": { + "account": ["manage-account"] + } }, { "username": "sumo2", @@ -56,7 +65,10 @@ "value": "demo" } ], - "realmRoles": ["ROLE_USER"] + "realmRoles": ["ROLE_USER"], + "clientRoles": { + "account": ["manage-account"] + } }, { "username": "sumo3", @@ -70,7 +82,10 @@ "value": "demo" } ], - "realmRoles": ["ROLE_USER"] + "realmRoles": ["ROLE_USER"], + "clientRoles": { + "account": ["manage-account"] + } } ], "roles": { diff --git a/.deploy/postgres/helm/postgres-init-scripts.yaml b/.deploy/postgres/helm/postgres-init-scripts.yaml index 2099cbb81..b8160b30e 100644 --- a/.deploy/postgres/helm/postgres-init-scripts.yaml +++ b/.deploy/postgres/helm/postgres-init-scripts.yaml @@ -4,6 +4,8 @@ metadata: name: postgres-init-scripts labels: app: postgresql + annotations: + "helm.sh/resource-policy": keep type: Opaque stringData: keycloak-db-password: keycloak123 diff --git a/.deploy/postgres/helm/values-dev.yaml b/.deploy/postgres/helm/values-dev.yaml index 5ff22ff18..ce1329333 100644 --- a/.deploy/postgres/helm/values-dev.yaml +++ b/.deploy/postgres/helm/values-dev.yaml @@ -1,3 +1,8 @@ +image: + tag: 10.7.0 + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + pullPolicy: IfNotPresent + postgresqlPassword: postgres321 #initdbScripts: @@ -18,3 +23,8 @@ service: type: NodePort nodePort: 31432 +volumePermissions: + image: + tag: 1.0.0 + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + pullPolicy: IfNotPresent diff --git a/.deploy/postgres/helm/values-prod.yaml b/.deploy/postgres/helm/values-prod.yaml index 1bda889fb..1ed438342 100644 --- a/.deploy/postgres/helm/values-prod.yaml +++ b/.deploy/postgres/helm/values-prod.yaml @@ -28,3 +28,8 @@ metrics: #volumePermissions: # enabled: false + +resources: + requests: + memory: 2048Mi + cpu: 1 diff --git a/.deploy/postgres/manual/04-statefulset.yaml b/.deploy/postgres/manual/04-statefulset.yaml index 8cf3890c5..534fe7dce 100644 --- a/.deploy/postgres/manual/04-statefulset.yaml +++ b/.deploy/postgres/manual/04-statefulset.yaml @@ -52,7 +52,6 @@ spec: requests: cpu: 250m memory: 256Mi - securityContext: runAsUser: 1001 env: diff --git a/.deploy/postgres/manual/README.md b/.deploy/postgres/manual/README.md index 503581148..8dab2e9d7 100644 --- a/.deploy/postgres/manual/README.md +++ b/.deploy/postgres/manual/README.md @@ -58,6 +58,9 @@ kubectl get svc -lapp=postgresql kubectl get ep kubectl get all,configmap,secret -l app=postgresql + +# Scale to zero +kubectl scale statefulset ngxdb-postgresql --replicas=0 ``` ### Connect to PostgreSQL @@ -77,7 +80,6 @@ kubectl delete secret postgres kubectl delete persistentvolumeclaim postgres ``` - #### TODO > deploy via typescript diff --git a/.deploy/webapp/default.conf b/.deploy/webapp/default.conf new file mode 100644 index 000000000..a2181b40f --- /dev/null +++ b/.deploy/webapp/default.conf @@ -0,0 +1,29 @@ +server { + + listen 80; + + sendfile on; + + default_type application/octet-stream; + + gzip on; + gzip_http_version 1.1; + gzip_disable "MSIE [1-6]\."; + gzip_min_length 1100; + gzip_vary on; + gzip_proxied expired no-cache no-store private auth; + gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; + gzip_comp_level 9; + + + root /usr/share/nginx/html; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + + location / { + try_files $uri $uri/ /index.html =404; + } + +} diff --git a/.deploy/webapp/helm/README.md b/.deploy/webapp/helm/README.md new file mode 100644 index 000000000..615d68144 --- /dev/null +++ b/.deploy/webapp/helm/README.md @@ -0,0 +1,84 @@ +# WebApp Helm + +Deploying `WebApp` to `Kubernetes` via `Helm` + +## Deploy + +### With Tiller + +```bash +cd .deploy/webapp/helm + +# To install the chart with the release name `ngxapp` +# `--dry-run --debug` flags help you to see before you really deploy +helm install --name=ngxapp --namespace=default -f values-dev.yaml ./angular + +# verify deployment +helm ls +kubectl get all,configmap,secret,ingress,replicasets -lapp.kubernetes.io/instance=ngxapp +kubectl describe pod ngxapp-angular +kubectl get deployment ngxapp-angular -o yaml +kubectl get ingress ngxapp-angular -o yaml + +POD_NAME=$(kubectl get pods -lapp.kubernetes.io/instance=ngxapp -o jsonpath='{.items[0].metadata.name}') +kubectl exec -it $POD_NAME -- /bin/sh +kubectl logs $POD_NAME -f +echo | openssl s_client -showcerts -connect ngxapp.traefik.k8s:443 2>/dev/null + + +# To update +helm upgrade --namespace=default -f values-dev.yaml ngxapp ./angular + +# To uninstall/delete the `ngxapp` release +helm delete ngxapp +helm delete ngxapp --purge # delete ngxapp and purge + +# Scale to zero +kubectl scale deployment ngxapp-angular --replicas=0 +``` + +### Without Tiller + +```bash +cd .deploy/webapp/helm + +helm template ./angular \ +--name ngxapp \ +--namespace default \ +--values values-dev.yaml \ +--output-dir generated + +kubectl apply --recursive -f generated/angular/* --namespace default +``` + + +### Access ngxapp + +ngxapp can be accessed: + +* Within your cluster, at the following DNS name at port 80: + + ``` + ngxapp-angular.default.svc.cluster.local + ``` + +* From outside the cluster: + + ``` + - https://ngxapp.traefik.k8s + ``` + +* From outside the cluster, run these commands in the same shell: (`when NodePort used in values.yaml`) + + ```bash + export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services ngxapp-angular) + export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT + ``` + +## Test +```bash +open https://ngxapp.traefik.k8s +``` + +## Reference diff --git a/.deploy/webapp/helm/generated/.gitignore b/.deploy/webapp/helm/generated/.gitignore new file mode 100644 index 000000000..a5baada18 --- /dev/null +++ b/.deploy/webapp/helm/generated/.gitignore @@ -0,0 +1,3 @@ +* +!.gitignore + diff --git a/.deploy/webapp/helm/values-dev.yaml b/.deploy/webapp/helm/values-dev.yaml new file mode 100644 index 000000000..05966e547 --- /dev/null +++ b/.deploy/webapp/helm/values-dev.yaml @@ -0,0 +1,11 @@ +test: + enabled: false + +image: + repository: xmlking/ngxapp + tag: 1.5.0-SNAPSHOT + pullPolicy: IfNotPresent + +securityContext: + fsGroup: 65534 + runAsUser: 65534 diff --git a/.deploy/webapp/helm/values-prod.yaml b/.deploy/webapp/helm/values-prod.yaml new file mode 100644 index 000000000..2ee3d77b7 --- /dev/null +++ b/.deploy/webapp/helm/values-prod.yaml @@ -0,0 +1,19 @@ +test: + enabled: false + +resources: + limits: + cpu: 2 + memory: "2048Mi" + requests: + cpu: 1 + memory: "1024Mi" + +image: + repository: xmlking/ngxapp + tag: 1.5.0-SNAPSHOT + pullPolicy: IfNotPresent + +securityContext: + fsGroup: 65534 + runAsUser: 65534 diff --git a/.deploy/webapp/webapp.tmpl.yml b/.deploy/webapp/openshift/webapp.tmpl.yml similarity index 100% rename from .deploy/webapp/webapp.tmpl.yml rename to .deploy/webapp/openshift/webapp.tmpl.yml