diff --git a/.github/build.yml b/.github/build.yml new file mode 100644 index 000000000..60c340607 --- /dev/null +++ b/.github/build.yml @@ -0,0 +1,120 @@ +name: "Build Pipeline" + +on: + push: + branches: + - jesse/pipeline-deploy + - main + paths-ignore: + - 'helm-chart/**' + +env: + PROJECT_ID: "polygonlabs-wbutton-dev" + GAR_LOCATION: "europe-west2" + WIF_PROVIDER: "projects/104168936956/locations/global/workloadIdentityPools/wbutton-test-pool/providers/wbutton-test" # this was hard to find: WIP --> Expand pool --> Click pencil icon + WIF_SERVICE_ACCOUNT: "wbutton-test-github-actions@polygonlabs-wbutton-dev.iam.gserviceaccount.com" + CRITICAL_COUNT: 5 + IMAGE_NAME: "europe-west2-docker.pkg.dev/prj-polygonlabs-shared-dev/polygonlabs-docker-dev/jesse/polygon-cli" + + ATTESTOR_PROJECT_ID: "polygonlabs-wbutton-dev" + KEY_RING: "wbutton-test-ring" + KEY: "wbutton-test-binary-auth-key" + ATTESTOR: "wbutton-test-attestor" + +jobs: + build-pipeline: + name: "Build, push, scan, and sign Docker image" + permissions: + contents: "write" + id-token: "write" + + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Google Auth + id: auth + uses: google-github-actions/auth@v1 + with: + token_format: "access_token" + workload_identity_provider: "${{ env.WIF_PROVIDER }}" + service_account: "${{ env.WIF_SERVICE_ACCOUNT }}" + + - name: Docker Auth + id: docker-auth + uses: docker/login-action@v1 + with: + username: "oauth2accesstoken" + password: "${{ steps.auth.outputs.access_token }}" + registry: "${{ env.GAR_LOCATION }}-docker.pkg.dev" + + - name: Build and Push Docker Image to GCP Artifact Registry + run: |- + docker build -t "${{ env.IMAGE_NAME }}:${{ github.sha }}" . + docker push "${{ env.IMAGE_NAME }}:${{ github.sha }}" + + - name: "Set up Cloud SDK" + uses: "google-github-actions/setup-gcloud@v1" + + - name: Scan Vulnerabilities + run: | + (gcloud artifacts docker images scan "${{ env.IMAGE_NAME }}:${{ github.sha }}" --format="value(response.scan)" --remote --quiet) > ./scan_id.txt + + - name: Checking Critical Vulnerabilities + run: |- + #!/bin/bash + + # Check if the scan_id.txt file exists + if [ ! -f ./scan_id.txt ]; then + echo "Error: scan_id.txt not found." + exit 1 + fi + + # Use gcloud to list vulnerabilities and check for CRITICAL severity + severity=$(gcloud artifacts docker images list-vulnerabilities \ + "$(cat ./scan_id.txt)" \ + --format="value(vulnerability.effectiveSeverity)") + + # Check if CRITICAL vulnerability is found + chk=$(echo "$severity" | grep -c "CRITICAL") + if [ "$chk" -gt ${{ env.CRITICAL_COUNT }} ]; then + echo "Failed vulnerability check for CRITICAL level" + exit 1 + else + echo "No CRITICAL vulnerability found. Congratulations!" + exit 0 + fi + + - name: Sign the docker image + run: |- + export CLOUDSDK_CORE_DISABLE_PROMPTS=1 + gcloud components install beta --quiet + + DIGEST=$(gcloud container images describe ${{ env.IMAGE_NAME }}:${{ github.sha }} --format='get(image_summary.digest)') + + gcloud beta container binauthz attestations sign-and-create \ + --artifact-url="${{ env.IMAGE_NAME }}@${DIGEST}" \ + --attestor="${{ env.ATTESTOR }}" \ + --attestor-project="${{ env.ATTESTOR_PROJECT_ID }}" \ + --keyversion-project="${{ env.ATTESTOR_PROJECT_ID }}" \ + --keyversion-location="${{ env.GAR_LOCATION }}" \ + --keyversion-keyring="${{ env.KEY_RING }}" \ + --keyversion-key="${{ env.KEY }}" \ + --keyversion="1" + + - name: Update Helm values # the helm-chart name should be standardized or parameterized + run: |- + DIGEST=$(gcloud container images describe ${{ env.IMAGE_NAME }}:${{ github.sha }} \ + --format='get(image_summary.digest)') + + sed -i "s|image:.*|image: ${{ env.IMAGE_NAME }}@${DIGEST}|" ./helm-chart/values.yaml + + - name: Set up Git, Commit and Push Changes to Update Container Image + uses: stefanzweifel/git-auto-commit-action@v5 + with: # the helm-chart name should be standardized or parameterized + commit_message: Apply automatic changes to Update image repository in Helm values + file_pattern: './helm-chart/values.yaml' + branch: wbutton-dev-test + create_branch: true \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..615f249e1 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +# Use an official Go runtime as a parent image +FROM golang:1.21 as builder + +# Set the working directory inside the container +WORKDIR /go/src/app + +# Copy the Go source code into the container +COPY . . + +# Build your Go app +RUN make build + +# Use a smaller base image to create a minimal final image +FROM alpine:latest +RUN apk --no-cache add ca-certificates + +WORKDIR /root/ + +# Copy the binary from the builder stage +COPY --from=builder /go/src/app/out/polycli . + +# Command to run the binary +CMD ["./polycli"] diff --git a/helm-chart/.helmignore b/helm-chart/.helmignore new file mode 100644 index 000000000..e69de29bb diff --git a/helm-chart/Chart.yaml b/helm-chart/Chart.yaml new file mode 100644 index 000000000..38b73036c --- /dev/null +++ b/helm-chart/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: webflow-apis +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 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" diff --git a/helm-chart/README.md b/helm-chart/README.md new file mode 100644 index 000000000..3554a3811 --- /dev/null +++ b/helm-chart/README.md @@ -0,0 +1,265 @@ +# Application Helm Chart Module + +![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.16.0](https://img.shields.io/badge/AppVersion-1.16.0-informational?style=flat-square) + +This Helm chart module creates and manage the following application resources: + +* Config Map +* Deployment +* Frontend Config +* Horizontal Pod Autoscaling +* Ingress +* Managed Certificate +* Service + +## Getting started + +To quickly get started, use the following: + +```yaml +name: +commonLabels: + + +containers: + - name: + image: + pullPolicy: IfNotPresent + port: + +service: + type: + port: + +ingress: + annotations: + kubernetes.io/ingress.class: gce + networking.gke.io/v1beta1.FrontendConfig: -frontendconfig + kubernetes.io/ingress.global-static-ip-name: webflow-api-ingress-static-ip + networking.gke.io/managed-certificates: -certificate + hosts: + - host: + paths: + - path: + pathType: + backend: + service: + name: -service + port: + number: + +``` + +**Note**: The provided snippet is not recommended for long use. It is for swiftly deploying a simple bare-bones application, experimenting, and subsequently deleting it. + +For higher environments like dev, stage, and prod etc. consider the following: + +* Setting number of replicas to be created +* Enabling and setting Liveness and readiness probes +* Setting up autoscaling configurations +* Adding additional settings to container configuration such as resources.requests, command, envFromEnabled in case configmap is to be referenced, and onepasswords InjectorEnvs. +* Add podAnnotations in case 1password is used + +Here is an example snippet with recommended options + +```yaml +name: +commonLabels: + + +replicaCount: + +podAnnotations: + operator.1password.io/inject: + +containers: + - name: + image: + pullPolicy: IfNotPresent + port: + securityContext: {} + command: ["",] + envFromEnabled: true + onePassword: + InjectorEnvs: + + resources: + requests: + cpu: + memory: + +service: + type: + port: + +ingress: + annotations: + kubernetes.io/ingress.class: gce + networking.gke.io/v1beta1.FrontendConfig: -frontendconfig + kubernetes.io/ingress.global-static-ip-name: webflow-api-ingress-static-ip + networking.gke.io/managed-certificates: -certificate + hosts: + - host: + paths: + - path: + pathType: + backend: + service: + name: -service + port: + number: + +livenessProbe: + httpGet: + path: + port: +readinessProbe: + httpGet: + path: + port: + +autoscaling: + minReplicas: + maxReplicas: + targetCPUUtilizationPercentage: + targetMemoryUtilizationPercentage: + +configMapData: + +``` + +## Deploying webflow-api helm chart + +Before deploying this Helm chart, ensure that you have performed the following steps: + +* Confirm your ability to connect to the cluster. +* Install the Helm binary. +* Obtain the vault connect credentials: _1password-credentials.json_ and access token. +* Reserve a global static IP and configure the name in the values file polygon-webflow-apis.yaml. (In the current configuration it is reserved as `webflow-api-ingress-static-ip`) + +#### Deploying 1Password connect + Injector Using Helm + +The following commands create a namespace `op` and deploy the 1Password connect server and injector. Make sure to set the correct path for the _1password-credentials.json_ file. + + +```shell +helm repo add 1password https://1password.github.io/connect-helm-charts +helm install connect 1password/connect --set-file connect.credentials=1password-credentials.json --namespace op --create-namespace +helm install injector 1password/secrets-injector --set injector.applicationName=injector --namespace op --create-namespace +``` + +### Creating Kubernets secret using 1Password token + +Create the namespace(s) where you want to deploy the applications and label the namespace with secret injection. For webflow-apis, we are going to deploy the resources in `webflow-apis-test` namespace. + +```shell +kubectl create namespace webflow-apis +kubectl label namespace webflow-apis secrets-injection=enabled +kubectl -n webflow-apis create secret generic connect-token --from-literal=token="YOUR 1Password TOKEN" +``` +In the _deployment.yaml_ file under the _templates_ directory, there is an ENV specified as `OP_CONNECT_HOST`, which needs to be mapped to the kube-dns of the 1Password connector http://onepassword-connect.op:8080. + +Here, `onepassword-connect` is the name of the 1Password connector Kubernetes service, and `op` is the Kubernetes namespace. If you configure the 1Password Connect server in a different namespace, that value would be `http://onepassword-connect.<1password-namespace>:8080`. + + +## Provisioning + +To provision the helm chart, perform the following steps: + +1. Run helm template to check if the values provided does not throw any syntax errors +```bash + helm template -f / +``` +2. If no errors are thrown by the above step, run helm install to install the helm chart +```bash + helm install -f / +``` +3. Once the helm chart is installed, the helm chart name as well as relevant info will be output to confirm the installation. + +## Parameters + +When configuring the values, make sure to double check the Immutable options. These parameters can not be modified later. + +### Required Parameters + +| Parameter | Notes | Immutable | +|---|---|---| +| name | The name of the application | Yes | +| commonLabels | The labels used by all resources of the application | No | +| containers.name | The name of the container | Yes | +| containers.image | The image of the container | No | +| service.port | The service port used to listen to incoming traffic | No | +| service.targetPort | The target port to which the service sends requests to | No | + + +### Recommended variables + +Few of the varibles will be mandatory based on your helm template configuration + +| Parameter | Notes | Immutable | Default | +|---|---|---|---| +| replicaCount | The number of replicas to be created | No | 1 | +| deploymentAnnotations | Annotations to be provided in deployment metadata | No | +| podAnnotations | Annotations to be provided for a given pod | No | +| imagePullSecrets | Secrets that are need to access images | No | +| podSecurityContext | Security context for users in a pod | No | +| containers.SecurityContext | Security contextfor users in a container | No | +| containers.imagePullPolicy | Image pull policy of a container | No | "IfNotPresent" | +| containers.command | list of string specifying commands to be performed inside container | No | +| containers.env | Environment varibles to be used inside a container | No | +| containers.onePassword | If specified, will provide environment variables of 1password inside container | No | +| containers.onePassword.connectHost | The host used to connect to 1password | No | "http://onepassword-connect.op:8080" | +| containers.onePassword.secretName | The name of the token used to connect to 1password | No | "connect-token" | +| containers.onePassword.secretKey | The key of the token used to connect to 1password | No | "token" | +| containers.onePassword.InjectorEnvs | List of objects which specifies the 1password secret name and related vault directory | No | +| containers.envFromEnabled | If enabled, references environments from config maps or secrets | No | +| containers.port | The port of the container | No | +| containers.resources | The cpu and memory requests for the container | No | +| nodeSelector | Constrains pods to nodes with specific labels | No | +| affinity | Constrains pods to nodes with specific labels and specified rules | No | +| tolerations | Allow the scheduler to schedule pods with matching taints | No | +| configMapData | If specified, will create config map and sets the data for config map | Yes | +| ingress | If provided, creates Ingress, frontend config and managed certificate | Yes | | +| ingress.annotations | The annotations required by ingress | No | +| ingress.hosts | A list of objects that specifies the hosts and related paths and ports | No | +| ingress.hosts.host | A hostname used by the ingress | No | +| ingress.hosts.paths | A list of objects that specifies the path and related service name and ports and ports | No | +| ingress.hosts.paths.path | The path that is used by the specified backend | No | +| ingress.hosts.paths.pathType | The path type of the path provided | No | +| ingress.hosts.paths.backend.service.name | The name of the service related to the provided path | No | +| ingress.hosts.paths.backend.service.port.number | The port of the service related to the provided path | No | +| autoscaling | If specified, creates HorizontalPodAutoscaler | No | +| autoscaling.minReplicas | The minimum number of replicas to be created | No | 1 | +| autoscaling.maxReplicas | The maximum number of replicas to be created | No | 100 | +| autoscaling.targetCPUUtilizationPercentage | The target CPU Utilization percentage for the pod | No | 80 | +| autoscaling.targetMemoryUtilizationPercentage | The target Memory Utilization percentage for the pod | No | 80 | +| httpsRedirect | Boolean Value to check if redirect to https is enabled | No | + + + + + + +### Templatetized Configuration + +Certain configurations are Templetized to provide ease in referencing certain parameters which may be specific to certain resources. + +| Config | Notes | Immutable | +|---|---|---| +| webflowapis.deploymentLabels | Role and name of resource deployment | No | +| webflowapis.serviceLabels | Role and name of resource service | No | +| webflowapis.configmapLabels | Role and name of resource configmap | No | +| webflowapis.frontendLabels | Role and name of resource frontend | No | +| webflowapis.ingressLabels | Role and name of resource ingress | No | +| webflowapis.managedCertificateLabels | Role and name of resource Managed certificate | No | + + +## Resources Provisioned + +1. Deployment with provided configurations +2. If config map is enabled, configmap with provided data +3. If Ingress is enabled, frontend config with redirecttoHttps config +4. If autoscaling is enabled, Horizontal pod Autoscaling with provided configurations +5. If Ingress is enabled, Ingress with provided configurations +6. If Ingress is enabled, managed certificate with provided domains +7. Service with provided configurations \ No newline at end of file diff --git a/helm-chart/templates/NOTES.txt b/helm-chart/templates/NOTES.txt new file mode 100644 index 000000000..a42cac1dd --- /dev/null +++ b/helm-chart/templates/NOTES.txt @@ -0,0 +1,25 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + https://{{ $host.host }}{{ .path }} + {{- end }} +{{- end }} +{{- if .Values.service }} +{{- if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "balance.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 "balance.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "balance.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "balance.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} +{{- end }} +{{- end }} diff --git a/helm-chart/templates/_helpers.tpl b/helm-chart/templates/_helpers.tpl new file mode 100644 index 000000000..979d16c7c --- /dev/null +++ b/helm-chart/templates/_helpers.tpl @@ -0,0 +1,107 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "balance.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 "balance.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 "balance.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "balance.labels" -}} +helm.sh/chart: {{ include "balance.chart" . }} +{{ include "balance.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "balance.selectorLabels" -}} +app.kubernetes.io/name: {{ include "balance.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "balance.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "balance.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{- define "webflowapis.deploymentLabels" -}} + role: deployment + #name: {{ .Values.name }}-deployment +{{- end }} + +{{- define "webflowapis.serviceLabels" -}} + role: service + name: {{ .Values.name }}-service +{{- end }} + +{{- define "webflowapis.configmapLabels" -}} + role: configmap + name: {{ .Values.name }}-configmap +{{- end }} + +{{- define "webflowapis.frontendLabels" -}} + role: frontendconfig + name: {{ .Values.name }}-frontendconfig +{{- end }} + +{{- define "webflowapis.ingressLabels" -}} + role: ingress + name: {{ .Values.name }}-ingress +{{- end }} + +{{- define "webflowapis.managedCertificateLabels" -}} + role: managedcertificate + name: {{ .Values.name }}-certificates +{{- end }} + +# {{- define "webflowapis.injectContainers" -}} +# {{- printf "%s" (include "webflowapis.injectContainer" .) }} +# {{- end }} + +{{- define "webflowapis.injectContainer" -}} + {{- $result := list -}} + {{- range . }} + {{- if and .onePassword.InjectorEnvs (len .onePassword.InjectorEnvs) }} + {{- $result = $result | append (list .name) }} + {{- end }} + {{- $result = $result | append (include "webflowapis.injectContainer" . ) | cat }} + {{- end }} + {{- $result | join "," }} +{{- end }} \ No newline at end of file diff --git a/helm-chart/templates/configmap.yaml b/helm-chart/templates/configmap.yaml new file mode 100644 index 000000000..89d1c1951 --- /dev/null +++ b/helm-chart/templates/configmap.yaml @@ -0,0 +1,15 @@ +{{- if .Values.configMapData }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Values.name }}-configmap + {{- with .Values.commonLabels }} + labels: + {{- toYaml . | nindent 4 }} + {{- end }} + {{ include "webflowapis.configmapLabels" .}} +{{- with .Values.configMapData }} +data: +{{- toYaml . | nindent 2 }} +{{- end }} +{{end}} \ No newline at end of file diff --git a/helm-chart/templates/deployment.yaml b/helm-chart/templates/deployment.yaml new file mode 100644 index 000000000..e167d5e87 --- /dev/null +++ b/helm-chart/templates/deployment.yaml @@ -0,0 +1,100 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Values.name }}-deployment + {{- with .Values.commonLabels }} + labels: + {{- toYaml . | nindent 4 }} + {{- end }} + {{ include "webflowapis.deploymentLabels" .}} + {{- with .Values.deploymentAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + replicas: {{ .Values.replicaCount | default 1 }} + selector: + matchLabels: + {{- range $key, $value := .Values.commonLabels }} + {{ $key }}: {{ $value | quote }} + {{- end }} + template: + metadata: + labels: + {{- range $key, $value := .Values.commonLabels }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{ include "webflowapis.deploymentLabels" .}} + annotations: + {{- range $key, $value := .Values.podAnnotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + {{- range .Values.containers }} + - name: {{ .name }} + {{- with .securityContext }} + securityContext: + {{- toYaml .securityContext | nindent 12 }} + {{- end }} + image: {{ .image | quote }} + imagePullPolicy: {{ .imagePullPolicy | default "IfNotPresent" }} + {{- if .command }} + command: {{ .command | toYaml | nindent 10 }} + {{- end }} + {{- if or .env ( and .onePassword .onePassword.InjectorEnvs) }} + env: + {{- if and .onePassword .onePassword.InjectorEnvs }} + - name: OP_CONNECT_HOST + value: {{ .onePassword.connectHost | default "http://onepassword-connect.op:8080" }} + - name: OP_CONNECT_TOKEN + valueFrom: + secretKeyRef: + name: {{ .onePassword.secretName | default "connect-token" }} + key: {{ .onePassword.secretKey | default "token" }} + {{- range $key, $value := .onePassword.InjectorEnvs }} + - name: {{ $key }} + value: {{ $value }} + {{- end }} + {{- end }} + {{- range .env }} + - name: {{ .name }} + value: {{ .value }} + {{- end }} + {{- end }} + {{- if .envFromEnabled }} + envFrom: + - configMapRef: + name: {{ $.Values.name }}-configmap + {{- end }} + {{- if .port }} + ports: + - name: http + containerPort: {{ .port }} + protocol: TCP + {{- end }} + {{- with .resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- 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/helm-chart/templates/frontendconfig.yaml b/helm-chart/templates/frontendconfig.yaml new file mode 100644 index 000000000..38db733ff --- /dev/null +++ b/helm-chart/templates/frontendconfig.yaml @@ -0,0 +1,14 @@ +{{ if .Values.ingress }} +apiVersion: networking.gke.io/v1beta1 +kind: FrontendConfig +metadata: + name: {{ .Values.name }}-frontendconfig + {{- with .Values.commonLabels }} + labels: + {{- toYaml . | nindent 4 }} + {{- end }} + {{ include "webflowapis.frontendLabels" .}} +spec: + redirectToHttps: + enabled: {{ .Values.httpsRedirect }} +{{- end }} diff --git a/helm-chart/templates/hpa.yaml b/helm-chart/templates/hpa.yaml new file mode 100644 index 000000000..3337a7e3b --- /dev/null +++ b/helm-chart/templates/hpa.yaml @@ -0,0 +1,34 @@ +{{- if .Values.autoscaling }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ .Values.name }}-hpa + {{- with .Values.commonLabels }} + labels: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ .Values.name }}-deployment + minReplicas: {{ ((.Values.autoscaling).minReplicas) | default 1 }} + maxReplicas: {{ ((.Values.autoscaling).maxReplicas) | default 100 }} + metrics: + {{- if ((.Values.autoscaling).targetCPUUtilizationPercentage) | default 80 }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ ((.Values.autoscaling).targetCPUUtilizationPercentage) | default 80 }} + {{- end }} + {{- if ((.Values.autoscaling).targetMemoryUtilizationPercentage) | default 80 }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ ((.Values.autoscaling).targetMemoryUtilizationPercentage) | default 80 }} + {{- end }} +{{- end }} diff --git a/helm-chart/templates/ingress.yaml b/helm-chart/templates/ingress.yaml new file mode 100644 index 000000000..98af05fc0 --- /dev/null +++ b/helm-chart/templates/ingress.yaml @@ -0,0 +1,32 @@ +{{- if .Values.ingress }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ .Values.name }}-ingress + {{- with .Values.commonLabels }} + labels: + {{- toYaml . | nindent 4 }} + {{- end }} + {{ include "webflowapis.ingressLabels" .}} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ .pathType }} + backend: + service: + name: {{ ((.backend.service).name) }} + port: + number: {{ (((.backend.service).port).number) }} + {{- end }} + {{- end }} + {{- end }} + diff --git a/helm-chart/templates/managedcertificate.yaml b/helm-chart/templates/managedcertificate.yaml new file mode 100644 index 000000000..7a982c79b --- /dev/null +++ b/helm-chart/templates/managedcertificate.yaml @@ -0,0 +1,16 @@ +{{- if .Values.ingress }} +apiVersion: networking.gke.io/v1 +kind: ManagedCertificate +metadata: + name: {{ .Values.name }}-certificates + {{- with .Values.commonLabels }} + labels: + {{- toYaml . | nindent 4 }} + {{- end }} + {{ include "webflowapis.managedCertificateLabels" .}} +spec: + domains: + {{- range ((.Values.ingress).hosts) }} + - {{ .host }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/helm-chart/templates/service.yaml b/helm-chart/templates/service.yaml new file mode 100644 index 000000000..abaae60c0 --- /dev/null +++ b/helm-chart/templates/service.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ ((.Values.service).name) | default (printf "%s-service" .Values.name) }} + {{- with .Values.commonLabels }} + labels: + {{- toYaml . | nindent 4 }} + {{- end }} + {{ include "webflowapis.serviceLabels" .}} +spec: + type: {{ ((.Values.service).type) | default "NodePort" }} + ports: + - port: {{ ((.Values.service).port) }} + targetPort: {{ ((.Values.service).targetPort) }} + protocol: TCP + name: http + {{- with .Values.commonLabels }} + selector: + {{- toYaml . | nindent 4 }} + {{- end }} + {{ include "webflowapis.deploymentLabels" .}} \ No newline at end of file diff --git a/helm-chart/values.yaml b/helm-chart/values.yaml new file mode 100644 index 000000000..4f4a47089 --- /dev/null +++ b/helm-chart/values.yaml @@ -0,0 +1,48 @@ +# Default values for polygon-cli. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +name: polygon-cli +commonLabels: + team: devtools + location: europe-west-2 + host: gcp-openapi-gke-dev + env: dev + tag-version: v2 + +replicaCount: 1 + +podAnnotations: + operator.1password.io/inject: "polygon-cli" + +containers: + - name: polycli + image: europe-west2-docker.pkg.dev/prj-polygonlabs-shared-dev/polygonlabs-docker-dev/polygon-cli:latest + imagePullPolicy: IfNotPresent + ports: + - containerPort: 3000 + command: ["/path/to/your/polycli"] + envFromEnabled: true + +service: + type: NodePort + port: 3000 + targetPort: 3000 + +ingress: + httpsRedirect: true + annotations: + kubernetes.io/ingress.class: gce + networking.gke.io/v1beta1.FrontendConfig: polygon-cli-frontendconfig + kubernetes.io/ingress.global-static-ip-name: polygon-cli-ingress-static-ip + networking.gke.io/managed-certificates: polygon-cli-certificates + hosts: + - host: polygon-cli.openapi-polygon.site + paths: + - path: /* + pathType: ImplementationSpecific + backend: + service: + name: polygon-cli-service + port: + number: 3000