diff --git a/.github/workflows/merge.yml b/.github/workflows/merge.yml index fffacde..8350cd6 100644 --- a/.github/workflows/merge.yml +++ b/.github/workflows/merge.yml @@ -25,33 +25,21 @@ jobs: id: pr uses: bcgov-nr/action-get-pr@v0.0.1 - deploys: - name: TEST Deployments - needs: [vars] - environment: test - runs-on: ubuntu-22.04 - strategy: - matrix: - name: [frontend, rctool] - include: - - name: frontend - file: frontend/openshift.nginx.deploy.yml - - name: rctool - file: frontend/openshift.deploy.yml - steps: - - uses: bcgov-nr/action-deployer-openshift@v3.0.1 - with: - file: ${{ matrix.file }} - oc_namespace: ${{ secrets.OC_NAMESPACE }} - oc_server: ${{ vars.OC_SERVER }} - oc_token: ${{ secrets.OC_TOKEN }} - overwrite: true - parameters: - -p ZONE=test -p PROMOTE=${{ github.repository }}/${{ matrix.name }}:${{ needs.vars.outputs.pr }} -p MAX_REPLICAS=3 + deploy-test: + name: Deploy (test) + uses: bcgov/quickstart-openshift-helpers/.github/workflows/.deployer.yml@v0.7.1 + secrets: + oc_namespace: ${{ secrets.OC_NAMESPACE }} + oc_token: ${{ secrets.OC_TOKEN }} + with: + environment: test + params: --set global.autoscaling=true --set rctool.pdb.enabled=true --set frontend.pdb.enabled=true + + zap_scan: runs-on: ubuntu-22.04 - needs: [deploys, vars] + needs: [deploy-test, vars] name: Penetration Tests env: URL: ${{ github.event.repository.name }}-test-frontend.apps.silver.devops.gov.bc.ca @@ -66,7 +54,7 @@ jobs: target: https://${{ env.URL }} promotions: name: Promote Images - needs: [deploys, vars] + needs: [deploy-test, vars] permissions: packages: write runs-on: ubuntu-22.04 diff --git a/.github/workflows/pr-close.yml b/.github/workflows/pr-close.yml index cca89cb..01698df 100644 --- a/.github/workflows/pr-close.yml +++ b/.github/workflows/pr-close.yml @@ -17,5 +17,5 @@ jobs: oc_namespace: ${{ secrets.OC_NAMESPACE }} oc_token: ${{ secrets.OC_TOKEN }} with: - cleanup: label + cleanup: helm packages: frontend rctool diff --git a/.github/workflows/pr-open.yml b/.github/workflows/pr-open.yml index 086d3e7..1692fa0 100644 --- a/.github/workflows/pr-open.yml +++ b/.github/workflows/pr-open.yml @@ -34,29 +34,19 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} triggers: ('frontend/') + # https://github.com/bcgov/quickstart-openshift-helpers deploys: name: Deploys - needs: [builds] - runs-on: ubuntu-22.04 - strategy: - matrix: - name: [frontend, rctool] - include: - - name: frontend - file: frontend/openshift.nginx.deploy.yml - - name: rctool - file: frontend/openshift.deploy.yml - steps: - - uses: bcgov-nr/action-deployer-openshift@v3.0.1 - with: - file: ${{ matrix.file }} - oc_namespace: ${{ secrets.OC_NAMESPACE }} - oc_server: ${{ vars.OC_SERVER }} - oc_token: ${{ secrets.OC_TOKEN }} - overwrite: true - parameters: - -p ZONE=${{ github.event.number }} - -p PROMOTE=${{ github.repository }}/${{ matrix.name }}:${{ github.event.number }} + needs: [ builds ] + uses: bcgov/quickstart-openshift-helpers/.github/workflows/.deployer.yml@v0.7.1 + secrets: + oc_namespace: ${{ secrets.OC_NAMESPACE }} + oc_token: ${{ secrets.OC_TOKEN }} + with: + triggers: ('frontend/') + params: --set global.secrets.persist=false + oc_server: ${{ vars.OC_SERVER }} + results: name: PR Results diff --git a/.github/workflows/prod.yml b/.github/workflows/prod.yml index e5eb112..aa4c3f9 100644 --- a/.github/workflows/prod.yml +++ b/.github/workflows/prod.yml @@ -10,27 +10,15 @@ concurrency: jobs: deploys: - name: PROD Deployments - environment: prod - runs-on: ubuntu-22.04 - strategy: - matrix: - name: [frontend, rctool] - include: - - name: frontend - file: frontend/openshift.nginx.deploy.yml - - name: rctool - file: frontend/openshift.deploy.yml - steps: - - uses: bcgov-nr/action-deployer-openshift@v3.0.1 - with: - file: ${{ matrix.file }} - oc_namespace: ${{ secrets.OC_NAMESPACE }} - oc_server: ${{ vars.OC_SERVER }} - oc_token: ${{ secrets.OC_TOKEN }} - overwrite: true - parameters: - -p ZONE=prod -p PROMOTE=${{ github.repository }}/${{ matrix.name }}:test -p MAX_REPLICAS=3 + name: Deploy (test) + uses: bcgov/quickstart-openshift-helpers/.github/workflows/.deployer.yml@v0.7.1 + secrets: + oc_namespace: ${{ secrets.OC_NAMESPACE }} + oc_token: ${{ secrets.OC_TOKEN }} + with: + environment: prod + tag: test + params: --set global.autoscaling=true --set rctool.pdb.enabled=true --set frontend.pdb.enabled=true promotions: name: Promote Images diff --git a/charts/app/.helmignore b/charts/app/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/charts/app/.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/charts/app/Chart.lock b/charts/app/Chart.lock new file mode 100644 index 0000000..8114af6 --- /dev/null +++ b/charts/app/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: postgresql + repository: https://charts.bitnami.com/bitnami + version: 15.5.36 +digest: sha256:2a03d437947bc841ae70d07e6b84735b6cc4651a7a31804afa188cf75131669a +generated: "2024-10-03T22:49:27.151720296Z" diff --git a/charts/app/Chart.yaml b/charts/app/Chart.yaml new file mode 100644 index 0000000..0dfa6d3 --- /dev/null +++ b/charts/app/Chart.yaml @@ -0,0 +1,31 @@ +apiVersion: v2 +name: nr-hydrometric-rating-curve +description: A Helm chart for Kubernetes deployment. +icon: https://www.nicepng.com/png/detail/521-5211827_bc-icon-british-columbia-government-logo.png + +# 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: "1.16.0" + +maintainers: + - name: Om Mishra + email: omprakash.2.mishra@gov.bc.ca + - name: Derek Roberts + email: derek.roberts@gov.bc.ca diff --git a/charts/app/templates/_helpers.tpl b/charts/app/templates/_helpers.tpl new file mode 100644 index 0000000..9462c22 --- /dev/null +++ b/charts/app/templates/_helpers.tpl @@ -0,0 +1,47 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "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 "fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s" .Release.Name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "name.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "labels" -}} +helm.sh/chart: {{ include "name.chart" . }} +{{ include "selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "selectorLabels" -}} +app.kubernetes.io/name: {{ include "fullname" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + diff --git a/charts/app/templates/frontend/templates/_helpers.tpl b/charts/app/templates/frontend/templates/_helpers.tpl new file mode 100644 index 0000000..524c972 --- /dev/null +++ b/charts/app/templates/frontend/templates/_helpers.tpl @@ -0,0 +1,43 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "frontend.name" -}} +{{- printf "frontend" }} +{{- 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 "frontend.fullname" -}} +{{- $componentName := include "frontend.name" . }} +{{- if .Values.frontend.fullnameOverride }} +{{- .Values.frontend.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $componentName | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} + + +{{/* +Common labels +*/}} +{{- define "frontend.labels" -}} +{{ include "frontend.selectorLabels" . }} +{{- if .Values.global.tag }} +app.kubernetes.io/image-version: {{ .Values.global.tag | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/short-name: {{ include "frontend.name" . }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "frontend.selectorLabels" -}} +app.kubernetes.io/name: {{ include "frontend.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + + diff --git a/charts/app/templates/frontend/templates/deployment.yaml b/charts/app/templates/frontend/templates/deployment.yaml new file mode 100644 index 0000000..9b9b98c --- /dev/null +++ b/charts/app/templates/frontend/templates/deployment.yaml @@ -0,0 +1,88 @@ +{{- if .Values.frontend.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "frontend.fullname" . }} + labels: + {{- include "frontend.labels" . | nindent 4 }} +spec: + strategy: + type: {{ .Values.frontend.deploymentStrategy }} + {{- if not .Values.frontend.autoscaling.enabled }} + replicas: {{ .Values.frontend.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "frontend.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + rollme: {{ randAlphaNum 5 | quote }} + labels: + {{- include "frontend.labels" . | nindent 8 }} + spec: + {{- if .Values.frontend.podSecurityContext }} + securityContext: + {{- toYaml .Values.frontend.podSecurityContext | nindent 12 }} + {{- end }} + containers: + - name: {{ include "frontend.fullname" . }} + {{- if .Values.frontend.containerSecurityContext }} + securityContext: + {{- toYaml .Values.frontend.containerSecurityContext | nindent 12 }} + {{- end }} + image: "{{.Values.global.registry}}/{{.Values.global.repository}}/frontend:{{ .Values.global.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ default "Always" .Values.frontend.imagePullPolicy }} + env: + - name: BACKEND_URL + value: "http://{{ .Release.Name }}-rctool" + - name: LOG_LEVEL + value: "info" + ports: + - name: http + containerPort: 3000 + protocol: TCP + readinessProbe: + httpGet: + path: /rctool + port: 3000 + scheme: HTTP + initialDelaySeconds: 5 + periodSeconds: 2 + timeoutSeconds: 2 + successThreshold: 1 + failureThreshold: 30 + #-- the liveness probe for the container. it is optional and is an object. for default values check this link: https://github.com/bcgov/helm-service/blob/main/charts/component/templates/deployment.yaml#L324-L328 + livenessProbe: + successThreshold: 1 + failureThreshold: 3 + httpGet: + path: /rctool + port: 3000 + scheme: HTTP + initialDelaySeconds: 15 + periodSeconds: 30 + timeoutSeconds: 5 + resources: + limits: + cpu: 50m + memory: 60Mi + requests: + cpu: 10m + memory: 20Mi + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - {{ include "frontend.fullname" . }} + - key: app.kubernetes.io/instance + operator: In + values: + - {{ .Release.Name }} + topologyKey: "kubernetes.io/hostname" + +{{- end }} diff --git a/charts/app/templates/frontend/templates/hpa.yaml b/charts/app/templates/frontend/templates/hpa.yaml new file mode 100644 index 0000000..94191d1 --- /dev/null +++ b/charts/app/templates/frontend/templates/hpa.yaml @@ -0,0 +1,55 @@ +{{- if .Values.global.autoscaling }} +{{- if and .Values.frontend.autoscaling .Values.frontend.autoscaling.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "frontend.fullname" . }} + labels: + {{- include "frontend.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "frontend.fullname" . }} + minReplicas: {{ .Values.frontend.autoscaling.minReplicas }} + maxReplicas: {{ .Values.frontend.autoscaling.maxReplicas }} + behavior: + scaleDown: + stabilizationWindowSeconds: 300 + policies: + - type: Percent + value: 10 + periodSeconds: 60 + - type: Pods + value: 2 + periodSeconds: 60 + selectPolicy: Min + scaleUp: + stabilizationWindowSeconds: 0 + policies: + - type: Percent + value: 100 + periodSeconds: 30 + - type: Pods + value: 2 + periodSeconds: 30 + selectPolicy: Max + metrics: + {{- if .Values.frontend.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.frontend.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.frontend.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.frontend.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/app/templates/frontend/templates/ingress.yaml b/charts/app/templates/frontend/templates/ingress.yaml new file mode 100644 index 0000000..43ddd6a --- /dev/null +++ b/charts/app/templates/frontend/templates/ingress.yaml @@ -0,0 +1,27 @@ +{{- if .Values.frontend.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "frontend.fullname" . }} + labels: + {{- include "frontend.labels" . | nindent 4 }} + {{- if and .Values.frontend.ingress .Values.frontend.ingress.annotations }} + {{- with .Values.frontend.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +spec: + ingressClassName: openshift-default + rules: + - host: {{ include "frontend.fullname" . }}.{{ .Values.global.domain }} + http: + paths: + - path: / + pathType: ImplementationSpecific + backend: + service: + name: {{ include "frontend.fullname" . }} + port: + number: 80 +{{- end }} diff --git a/charts/app/templates/frontend/templates/pdb.yaml b/charts/app/templates/frontend/templates/pdb.yaml new file mode 100644 index 0000000..b7067bf --- /dev/null +++ b/charts/app/templates/frontend/templates/pdb.yaml @@ -0,0 +1,14 @@ +{{- if and .Values.frontend.pdb .Values.frontend.pdb.enabled }} +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ include "frontend.fullname" . }} + labels: + {{- include "frontend.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "frontend.selectorLabels" . | nindent 6 }} + minAvailable: {{ .Values.frontend.pdb.minAvailable }} +{{- end }} diff --git a/charts/app/templates/frontend/templates/service.yaml b/charts/app/templates/frontend/templates/service.yaml new file mode 100644 index 0000000..3cfe2e3 --- /dev/null +++ b/charts/app/templates/frontend/templates/service.yaml @@ -0,0 +1,21 @@ +{{- if .Values.frontend.enabled }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "frontend.fullname" . }} + labels: + {{- include "frontend.labels" . | nindent 4 }} +spec: + type: {{ .Values.frontend.service.type }} + ports: + - name: http + #-- the port for the service. the service will be accessible on this port within the namespace. + port: 80 + #-- the container port where the application is listening on + targetPort: 3000 + #-- the protocol for the port. it can be TCP or UDP. TCP is the default and is recommended. + protocol: TCP + selector: + {{- include "frontend.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/charts/app/templates/knp.yaml b/charts/app/templates/knp.yaml new file mode 100644 index 0000000..29ff1b2 --- /dev/null +++ b/charts/app/templates/knp.yaml @@ -0,0 +1,41 @@ +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ .Release.Name }}-openshift-ingress-to-frontend + labels: {{- include "selectorLabels" . | nindent 4 }} +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: frontend + app.kubernetes.io/instance: {{ .Release.Name }} + ingress: + - from: + - namespaceSelector: + matchLabels: + network.openshift.io/policy-group: ingress + policyTypes: + - Ingress + +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ .Release.Name }}-allow-frontend-to-backend + labels: {{- include "selectorLabels" . | nindent 4 }} +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: rctool + app.kubernetes.io/instance: {{ .Release.Name }} + ingress: + - ports: + - protocol: TCP + port: 3000 + from: + - podSelector: + matchLabels: + app.kubernetes.io/name: frontend + app.kubernetes.io/instance: {{ .Release.Name }} + policyTypes: + - Ingress diff --git a/charts/app/templates/rctool/templates/_helpers.tpl b/charts/app/templates/rctool/templates/_helpers.tpl new file mode 100644 index 0000000..5aafda5 --- /dev/null +++ b/charts/app/templates/rctool/templates/_helpers.tpl @@ -0,0 +1,42 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "rctool.name" -}} +{{- printf "rctool" }} +{{- 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 "rctool.fullname" -}} +{{- $componentName := include "rctool.name" . }} +{{- if .Values.rctool.fullnameOverride }} +{{- .Values.rctool.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $componentName | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "rctool.labels" -}} +{{ include "rctool.selectorLabels" . }} +{{- if .Values.global.tag }} +app.kubernetes.io/image-version: {{ .Values.global.tag | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/short-name: {{ include "rctool.name" . }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "rctool.selectorLabels" -}} +app.kubernetes.io/name: {{ include "rctool.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + + diff --git a/charts/app/templates/rctool/templates/deployment.yaml b/charts/app/templates/rctool/templates/deployment.yaml new file mode 100644 index 0000000..7a83fc5 --- /dev/null +++ b/charts/app/templates/rctool/templates/deployment.yaml @@ -0,0 +1,116 @@ +{{- if .Values.rctool.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "rctool.fullname" . }} + labels: + {{- include "rctool.labels" . | nindent 4 }} +spec: + strategy: + type: {{ .Values.rctool.deploymentStrategy }} + {{- if not .Values.rctool.autoscaling.enabled }} + replicas: {{ .Values.rctool.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "rctool.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + rollme: {{ randAlphaNum 5 | quote }} + labels: + {{- include "rctool.labels" . | nindent 8 }} + spec: + {{- if .Values.rctool.podSecurityContext }} + securityContext: + {{- toYaml .Values.rctool.podSecurityContext | nindent 12 }} + {{- end }} + containers: + - name: {{ include "rctool.fullname" . }} + {{- if .Values.rctool.containerSecurityContext }} + securityContext: + {{- toYaml .Values.rctool.containerSecurityContext | nindent 12 }} + {{- end }} + image: "{{.Values.global.registry}}/{{.Values.global.repository}}/rctool:{{ .Values.global.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ default "Always" .Values.rctool.imagePullPolicy }} + envFrom: + - secretRef: + name: {{.Release.Name}}-rctool + env: + - name: WEB_PORT_INTERNAL + value: "3000" + - + name: ALLOWED_HOSTS + value: "*" + - + name: DEBUG + value: "False" + - + name: GUNICORN_WORKERS + value: "2" + - + name: GUNICORN_LIMIT_REQ_LINE + value: "4094" + - + name: GUNICORN_LIMIT_REQ_FIELDSIZE + value: "8190" + - name: GUNICORN_TIMEOUT + value: "1800" + - + name: CSRF_TRUSTED_ORIGINS + value: 'https://*.apps.silver.devops.gov.bc.ca,https://*.apps.silver.devops.gov.bc.ca,https://hydra.nrs.gov.bc.ca' + ports: + - name: http + containerPort: {{ .Values.rctool.service.targetPort }} + protocol: TCP + readinessProbe: + httpGet: + path: /rctool + port: http + scheme: HTTP + initialDelaySeconds: 10 + periodSeconds: 5 + timeoutSeconds: 2 + successThreshold: 1 + failureThreshold: 30 + livenessProbe: + successThreshold: 1 + failureThreshold: 3 + httpGet: + path: /rctool + port: 3000 + scheme: HTTP + initialDelaySeconds: 60 + periodSeconds: 60 + timeoutSeconds: 5 + resources: # this is optional + limits: + cpu: 250m + memory: 500Mi + requests: + cpu: 50m + memory: 250Mi + {{- with .Values.rctool.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.rctool.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - {{ include "rctool.fullname" . }} + - key: app.kubernetes.io/instance + operator: In + values: + - {{ .Release.Name }} + topologyKey: "kubernetes.io/hostname" + +{{- end }} diff --git a/charts/app/templates/rctool/templates/hpa.yaml b/charts/app/templates/rctool/templates/hpa.yaml new file mode 100644 index 0000000..0a7bfce --- /dev/null +++ b/charts/app/templates/rctool/templates/hpa.yaml @@ -0,0 +1,55 @@ +{{- if .Values.global.autoscaling }} +{{- if and .Values.rctool.autoscaling .Values.rctool.autoscaling.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "rctool.fullname" . }} + labels: + {{- include "rctool.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "rctool.fullname" . }} + minReplicas: {{ .Values.rctool.autoscaling.minReplicas }} + maxReplicas: {{ .Values.rctool.autoscaling.maxReplicas }} + behavior: + scaleDown: + stabilizationWindowSeconds: 300 + policies: + - type: Percent + value: 10 + periodSeconds: 60 + - type: Pods + value: 2 + periodSeconds: 60 + selectPolicy: Min + scaleUp: + stabilizationWindowSeconds: 0 + policies: + - type: Percent + value: 100 + periodSeconds: 30 + - type: Pods + value: 2 + periodSeconds: 30 + selectPolicy: Max + metrics: + {{- if .Values.rctool.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.rctool.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.rctool.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.rctool.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/app/templates/rctool/templates/pdb.yaml b/charts/app/templates/rctool/templates/pdb.yaml new file mode 100644 index 0000000..1479832 --- /dev/null +++ b/charts/app/templates/rctool/templates/pdb.yaml @@ -0,0 +1,14 @@ +{{- if and .Values.rctool.pdb .Values.rctool.pdb.enabled }} +--- +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ include "rctool.fullname" . }} + labels: + {{- include "rctool.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "rctool.selectorLabels" . | nindent 6 }} + minAvailable: {{ .Values.rctool.pdb.minAvailable }} +{{- end }} diff --git a/charts/app/templates/rctool/templates/service.yaml b/charts/app/templates/rctool/templates/service.yaml new file mode 100644 index 0000000..5e40c80 --- /dev/null +++ b/charts/app/templates/rctool/templates/service.yaml @@ -0,0 +1,18 @@ +{{- if .Values.rctool.enabled }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "rctool.fullname" . }} + labels: + {{- include "rctool.labels" . | nindent 4 }} +spec: + type: {{ .Values.rctool.service.type }} + ports: + - port: {{ .Values.rctool.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "rctool.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/charts/app/templates/secret.yaml b/charts/app/templates/secret.yaml new file mode 100644 index 0000000..38e9cfb --- /dev/null +++ b/charts/app/templates/secret.yaml @@ -0,0 +1,22 @@ +{{- if and .Values.global.secrets .Values.global.secrets.enabled}} +{{- $secretKey:= .Values.global.secrets.secretKey | default (randAlphaNum 32) }} +{{- $secretName := printf "%s" .Release.Name }} +{{- $secretObj := (lookup "v1" "Secret" .Release.Namespace $secretName ) | default dict }} +{{- $secretData := (get $secretObj "data") | default dict }} + # set below to existing secret data or generate a random one when not exists +{{- $secretKey = (get $secretData "SECRET_KEY") | default ($secretKey | b64enc) }} + +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Release.Name }}-rctool + labels: {{- include "labels" . | nindent 4 }} + {{- if .Values.global.secrets.persist }} + annotations: + helm.sh/resource-policy: keep + {{- end }} +data: + SECRET_KEY: {{ $secretKey | quote }} +{{- end }} + diff --git a/charts/app/values.yaml b/charts/app/values.yaml new file mode 100644 index 0000000..ae17cf0 --- /dev/null +++ b/charts/app/values.yaml @@ -0,0 +1,109 @@ +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. +#-- global variables, can be accessed by sub-charts. +global: + #-- the registry where the images are stored. override during runtime for other registry at global level or individual level. + repository: ~ # provide the repo name from where images will be sourced for example bcgo + #-- the registry where the images are stored. override during runtime for other registry at global level or individual level. default is ghcr.io + registry: ghcr.io # ghcr.io for directly streaming from github container registry or "artifacts.developer.gov.bc.ca/github-docker-remote" for artifactory, or any other registry. + #-- the tag of the image, it can be latest, 1.0.0 etc..., or the sha256 hash + tag: ~ + #-- turn off autoscaling for the entire suite by setting this to false. default is true. + autoscaling: false + #-- global secrets, can be accessed by sub-charts. + secrets: + enabled: true + secretKey: ~ + persist: true + #-- domain of the application, it is required, apps.silver.devops.gov.bc.ca for silver cluster and apps.devops.gov.bc.ca for gold cluster + domain: "apps.silver.devops.gov.bc.ca" # it is apps.gold.devops.gov.bc.ca for gold cluster +rctool: + #-- enable or disable backend + enabled: true + replicaCount: 1 + #-- the deployment strategy, can be "Recreate" or "RollingUpdate" + deploymentStrategy: Recreate + #-- autoscaling for the component. it is optional and is an object. + autoscaling: + #-- enable or disable autoscaling. + enabled: true + #-- the minimum number of replicas. + minReplicas: 3 + #-- the maximum number of replicas. + maxReplicas: 5 + #-- the target cpu utilization percentage, is from request cpu and NOT LIMIT CPU. + targetCPUUtilizationPercentage: 80 + #-- the service for the component. for inter namespace communication, use the service name as the hostname. + service: + #-- the type of the service. it can be ClusterIP, NodePort, LoadBalancer, ExternalName. ClusterIP is the default and is recommended. + type: ClusterIP + port: 80 # this is the service port, where it will be exposed internal to the namespace. + targetPort: 3000 # this is container port where app listens on + pdb: + enabled: false # enable it in PRODUCTION for having pod disruption budget. + minAvailable: 1 # the minimum number of pods that must be available during the disruption budget. + podSecurityContext: + seccompProfile: + type: RuntimeDefault + runAsNonRoot: true + containerSecurityContext: + capabilities: + drop: + - ALL + add: + - NET_BIND_SERVICE + runAsNonRoot: true + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + +frontend: + # -- enable or disable a component deployment. + enabled: true + replicaCount: 1 + # -- the deployment strategy, can be "Recreate" or "RollingUpdate" + deploymentStrategy: Recreate + + #-- autoscaling for the component. it is optional and is an object. + autoscaling: + #-- enable or disable autoscaling. + enabled: true + #-- the minimum number of replicas. + minReplicas: 3 + #-- the maximum number of replicas. + maxReplicas: 5 + #-- the target cpu utilization percentage, is from request cpu and NOT LIMIT CPU. + targetCPUUtilizationPercentage: 80 + #-- the service for the component. for inter namespace communication, use the service name as the hostname. + service: + #-- enable or disable the service. + enabled: true + #-- the type of the service. it can be ClusterIP, NodePort, LoadBalancer, ExternalName. ClusterIP is the default and is recommended. + type: ClusterIP + #-- the ports for the service. + ports: + - name: http + #-- the port for the service. the service will be accessible on this port within the namespace. + port: 80 + #-- the container port where the application is listening on + targetPort: 3000 + #-- the protocol for the port. it can be TCP or UDP. TCP is the default and is recommended. + protocol: TCP + ingress: + annotations: + route.openshift.io/termination: "edge" + pdb: + enabled: false # enable it in PRODUCTION for having pod disruption budget. + minAvailable: 1 # the minimum number of pods that must be available during the disruption budget. + podSecurityContext: + seccompProfile: + type: RuntimeDefault + runAsNonRoot: true + containerSecurityContext: + capabilities: + drop: + - ALL + add: + - NET_BIND_SERVICE + runAsNonRoot: true + allowPrivilegeEscalation: false +