From 790667b286661657634153da9cc60227aaff7379 Mon Sep 17 00:00:00 2001 From: tukue Date: Fri, 29 May 2026 12:03:55 +0200 Subject: [PATCH 1/4] feat: implement high-priority platform engineering improvements - Fix make deploy to use GitOps (remove imperative helm template | kubectl apply) - Move legacy/ to archive/ and update all references - Add PodDisruptionBudget template with Helm unit tests - Add ResourceQuota and RBAC for stage and prod namespaces - Add CI guard rejecting 'latest' image tags and 'HEAD' revisions - Parametrize AWS account ID across all values files --- .github/workflows/platform-validate.yml | 26 +++++++ Makefile | 63 +++++++++-------- README.md | 2 +- archive/legacy/ansible/ansible | 0 archive/legacy/ansible/ansible-inventory.tf | 29 ++++++++ archive/legacy/ansible/ansible-playbook.yml | 65 ++++++++++++++++++ archive/legacy/ansible/ansible.cfg | 6 ++ archive/legacy/ansible/configure-nodes.yml | 65 ++++++++++++++++++ archive/legacy/ansible/inventory | 5 ++ archive/legacy/ansible/roles | 0 archive/legacy/ansible/templates | 1 + .../ansible/terraform-ansible-integration.tf | 25 +++++++ archive/legacy/helm/simple-app/Chart.yaml | 6 ++ archive/legacy/helm/simple-app/README.md | 11 +++ .../helm/simple-app/templates/_helpers.tpl | 51 ++++++++++++++ .../helm/simple-app/templates/deployment.yaml | 24 +++++++ .../helm/simple-app/templates/ingress.yaml | 31 +++++++++ .../helm/simple-app/templates/service.yaml | 15 ++++ archive/legacy/helm/simple-app/values.yaml | 43 ++++++++++++ archive/legacy/kubernetes/README.md | 14 ++++ .../legacy/kubernetes/deployment-test.yaml | 20 ++++++ archive/legacy/kubernetes/deployment.yaml | 20 ++++++ archive/legacy/kubernetes/forwardservice.yaml | 12 ++++ archive/legacy/kubernetes/ingress.yaml | 16 +++++ archive/legacy/kubernetes/loadbalancer.yaml | 12 ++++ archive/legacy/kubernetes/service.yaml | 11 +++ archive/legacy/plan_outputekscluster | Bin 0 -> 8392 bytes docs/architecture.md | 2 +- platform/apps/app-b/dev/values.yaml | 1 - platform/apps/app-b/prod/values.yaml | 1 - platform/apps/app-b/stage/values.yaml | 1 - platform/apps/dev/values.yaml | 1 - platform/apps/prod/values.yaml | 1 - platform/apps/stage/values.yaml | 1 - platform/bootstrap/rbac-readonly.yaml | 54 +++++++++++++++ platform/bootstrap/resource-quota.yaml | 28 ++++++++ standardized-path/app/templates/pdb.yaml | 18 +++++ .../app/tests/deployment_test.yaml | 6 +- standardized-path/app/tests/pdb_test.yaml | 36 ++++++++++ standardized-path/app/values.yaml | 10 ++- 40 files changed, 695 insertions(+), 38 deletions(-) create mode 100644 archive/legacy/ansible/ansible create mode 100644 archive/legacy/ansible/ansible-inventory.tf create mode 100644 archive/legacy/ansible/ansible-playbook.yml create mode 100644 archive/legacy/ansible/ansible.cfg create mode 100644 archive/legacy/ansible/configure-nodes.yml create mode 100644 archive/legacy/ansible/inventory create mode 100644 archive/legacy/ansible/roles create mode 100644 archive/legacy/ansible/templates create mode 100644 archive/legacy/ansible/terraform-ansible-integration.tf create mode 100644 archive/legacy/helm/simple-app/Chart.yaml create mode 100644 archive/legacy/helm/simple-app/README.md create mode 100644 archive/legacy/helm/simple-app/templates/_helpers.tpl create mode 100644 archive/legacy/helm/simple-app/templates/deployment.yaml create mode 100644 archive/legacy/helm/simple-app/templates/ingress.yaml create mode 100644 archive/legacy/helm/simple-app/templates/service.yaml create mode 100644 archive/legacy/helm/simple-app/values.yaml create mode 100644 archive/legacy/kubernetes/README.md create mode 100644 archive/legacy/kubernetes/deployment-test.yaml create mode 100644 archive/legacy/kubernetes/deployment.yaml create mode 100644 archive/legacy/kubernetes/forwardservice.yaml create mode 100644 archive/legacy/kubernetes/ingress.yaml create mode 100644 archive/legacy/kubernetes/loadbalancer.yaml create mode 100644 archive/legacy/kubernetes/service.yaml create mode 100644 archive/legacy/plan_outputekscluster create mode 100644 standardized-path/app/templates/pdb.yaml create mode 100644 standardized-path/app/tests/pdb_test.yaml diff --git a/.github/workflows/platform-validate.yml b/.github/workflows/platform-validate.yml index 3ea1580..442901e 100644 --- a/.github/workflows/platform-validate.yml +++ b/.github/workflows/platform-validate.yml @@ -92,6 +92,32 @@ jobs: helm lint standardized-path/app -f platform/apps/app-b/stage/values.yaml helm lint standardized-path/app -f platform/apps/app-b/prod/values.yaml + - name: Enforce immutable tags and revisions + run: | + set +e + has_error=0 + for f in platform/apps/**/values.yaml argocd/**/*.yaml; do + [ -f "$f" ] || continue + if grep -qE 'tag:\s*"?latest"?' "$f" 2>/dev/null; then + echo "::error file=$f::Found 'latest' image tag — use an immutable version tag instead" + has_error=1 + fi + if grep -qE 'targetRevision:\s*"?HEAD"?' "$f" 2>/dev/null; then + echo "::error file=$f::Found 'HEAD' revision — pin to an explicit branch or tag" + has_error=1 + fi + done + # Also check per-environment values files explicitly + for f in platform/apps/dev/values.yaml platform/apps/stage/values.yaml platform/apps/prod/values.yaml platform/apps/app-b/dev/values.yaml platform/apps/app-b/stage/values.yaml platform/apps/app-b/prod/values.yaml; do + [ -f "$f" ] || continue + tag_val=$(grep -E '^\s+tag:' "$f" | sed 's/.*tag:\s*"\{0,1\}\([^"]*\)"\{0,1\}/\1/' | xargs) + if [ "$tag_val" = "latest" ]; then + echo "::error file=$f::Found 'latest' image tag — use an immutable version tag instead" + has_error=1 + fi + done + exit $has_error + - name: Helm unit tests run: helm unittest standardized-path/app diff --git a/Makefile b/Makefile index 80a40c2..8d1eaf9 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ help: @echo ' kind-up Create Kind cluster' @echo ' kind-down Delete Kind cluster' @echo ' argocd-install Install Argo CD and apply AppProjects' - @echo ' deploy Apply platform bootstrap + add-ons + demo app' + @echo ' deploy Apply platform bootstrap (Argo CD reconciles add-ons and apps via GitOps)' @echo ' test Run Helm unit tests' @echo ' validate Run CI checks locally (Helm lint + test + conftest)' @echo ' clean kind-down + remove tmp files' @@ -43,13 +43,8 @@ argocd-install: kind-up .PHONY: deploy deploy: - @echo "=== Applying platform bootstrap ===" - kubectl apply -f platform/bootstrap/namespaces.yaml - kubectl apply -f platform/bootstrap/resource-quota.yaml - kubectl apply -f platform/bootstrap/limit-range.yaml - kubectl apply -f platform/bootstrap/network-policy.yaml - kubectl apply -f platform/bootstrap/rbac-readonly.yaml - kubectl apply -f platform/bootstrap/cluster-secret-store.yaml + @echo "=== Applying platform bootstrap (foundation for Argo CD) ===" + kubectl apply -f platform/bootstrap/ @echo "=== Creating platform secrets namespace ===" kubectl create namespace platform-secrets --dry-run=client -o yaml | kubectl apply -f - @@ -59,27 +54,25 @@ deploy: --from-literal=db-password=$${DEV_DB_PASSWORD:-changeme} \ -n platform-secrets --dry-run=client -o yaml | kubectl apply -f - - @echo "=== Applying platform add-ons ===" - kubectl apply -f platform/addons/metrics-server.yaml - kubectl apply -f platform/addons/nginx-ingress.yaml - kubectl apply -f platform/addons/external-secrets.yaml - kubectl apply -f platform/addons/kube-prometheus-stack.yaml - kubectl apply -f platform/addons/grafana-dashboards-platform.yaml - - @echo "=== Deploying simple-app ===" - helm template simple-app-dev standardized-path/app \ - -f platform/apps/dev/values.yaml \ - --set image.repository=$(IMAGE_REPO) \ - | kubectl apply -f - 2>&1 | grep -v 'unchanged' || true + @echo "=== Argo CD manages add-ons and apps via GitOps (app-of-apps) ===" + @echo " Root app: kubectl get application/root -n argocd" + @echo " Child apps: kubectl get applications -n argocd" + @echo "" - @echo "=== Deploying app-b ===" - helm template app-b-dev standardized-path/app \ - -f platform/apps/app-b/dev/values.yaml \ - --set image.repository=$(IMAGE_REPO) \ - | kubectl apply -f - 2>&1 | grep -v 'unchanged' || true + @echo "=== Waiting for Argo CD to reconcile add-ons ===" + @for i in 1 2 3 4 5; do \ + ready=$$(kubectl -n argocd get applications 2>/dev/null | tail -n+2 | wc -l); \ + [ "$$ready" -gt 0 ] && break; \ + sleep 3; \ + done + kubectl get applications -n argocd 2>/dev/null || echo "(Argo CD syncing add-ons and apps)" - @echo "=== App status ===" - kubectl get pods -n dev --show-labels + @echo "" + @echo "=== Pod status ===" + @for ns in dev stage prod; do \ + echo "--- $$ns ---"; \ + kubectl get pods -n $$ns --show-labels 2>/dev/null || echo "(no pods yet - Argo CD is syncing)"; \ + done .PHONY: test test: @@ -88,6 +81,22 @@ test: .PHONY: validate validate: test + @echo "=== Immutable tags and revisions ===" + @for f in platform/apps/**/values.yaml; do \ + [ -f "$$f" ] || continue; \ + tag_val=$$(grep -E '^\s+tag:' "$$f" | sed 's/.*tag:\s*"\{0,1\}\([^"]*\)"\{0,1\}/\1/' | xargs); \ + if [ "$$tag_val" = "latest" ]; then \ + echo " FAIL: $$f uses 'latest' tag"; exit 1; \ + fi; \ + done + @for f in argocd/**/*.yaml; do \ + [ -f "$$f" ] || continue; \ + if grep -qE 'targetRevision:\s*"?HEAD"?' "$$f" 2>/dev/null; then \ + echo " FAIL: $$f uses 'HEAD' revision"; exit 1; \ + fi; \ + done + @echo " PASS" + @echo "=== Helm lint ===" helm lint standardized-path/app -f platform/apps/dev/values.yaml helm lint standardized-path/app -f platform/apps/stage/values.yaml diff --git a/README.md b/README.md index 92c4607..be15da1 100644 --- a/README.md +++ b/README.md @@ -140,7 +140,7 @@ Every app deployed through the platform contract automatically gets a ServiceMon ## What I'd do next - Add OPA/Gatekeeper policies for platform-level validation beyond what SCC provides -- Replace `legacy/` assets with a clean `examples/` directory +- Replaced `legacy/` assets with a clean `archive/` directory --- diff --git a/archive/legacy/ansible/ansible b/archive/legacy/ansible/ansible new file mode 100644 index 0000000..e69de29 diff --git a/archive/legacy/ansible/ansible-inventory.tf b/archive/legacy/ansible/ansible-inventory.tf new file mode 100644 index 0000000..f0f2a77 --- /dev/null +++ b/archive/legacy/ansible/ansible-inventory.tf @@ -0,0 +1,29 @@ +resource "local_file" "ansible_inventory" { + count = var.enable_ansible ? 1 : 0 + + content = <<-EOT +[eks_nodes] +%{for ip in module.eks.worker_node_ips} +${ip} ansible_user=ec2-user +%{endfor} + +[eks_nodes:vars] +ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' + EOT + + filename = "${path.module}/inventory" +} + +resource "null_resource" "ansible_playbook_runner" { + count = var.enable_ansible ? 1 : 0 + + depends_on = [local_file.ansible_inventory, module.eks] + + provisioner "local-exec" { + command = "ansible-playbook -i inventory ansible-playbook.yml" + } + + triggers = { + always_run = "${timestamp()}" + } +} \ No newline at end of file diff --git a/archive/legacy/ansible/ansible-playbook.yml b/archive/legacy/ansible/ansible-playbook.yml new file mode 100644 index 0000000..b73a171 --- /dev/null +++ b/archive/legacy/ansible/ansible-playbook.yml @@ -0,0 +1,65 @@ +--- +- name: Configure EKS Worker Nodes + hosts: eks_nodes + become: yes + + tasks: + - name: Update all packages + yum: + name: '*' + state: latest + update_only: yes + + - name: Install required packages + yum: + name: + - docker + - git + - jq + - python3 + - python3-pip + state: present + + - name: Start and enable Docker service + systemd: + name: docker + state: started + enabled: yes + + - name: Install AWS CLI + pip: + name: awscli + executable: pip3 + state: present + + - name: Install kubectl + get_url: + url: https://storage.googleapis.com/kubernetes-release/release/v1.23.6/bin/linux/amd64/kubectl + dest: /usr/local/bin/kubectl + mode: '0755' + + - name: Create .kube directory + file: + path: /home/ec2-user/.kube + state: directory + owner: ec2-user + group: ec2-user + mode: '0755' + + - name: Configure kubelet service + copy: + content: | + [Service] + Environment="KUBELET_EXTRA_ARGS=--node-labels=node.kubernetes.io/worker=true" + dest: /etc/systemd/system/kubelet.service.d/20-worker-labels.conf + owner: root + group: root + mode: '0644' + notify: Restart kubelet + + handlers: + - name: Restart kubelet + systemd: + name: kubelet + state: restarted + daemon_reload: yes \ No newline at end of file diff --git a/archive/legacy/ansible/ansible.cfg b/archive/legacy/ansible/ansible.cfg new file mode 100644 index 0000000..115b640 --- /dev/null +++ b/archive/legacy/ansible/ansible.cfg @@ -0,0 +1,6 @@ +[defaults] +inventory = ./inventory +host_key_checking = False +remote_user = ec2-user +private_key_file = ~/.ssh/id_rsa +roles_path = ./roles \ No newline at end of file diff --git a/archive/legacy/ansible/configure-nodes.yml b/archive/legacy/ansible/configure-nodes.yml new file mode 100644 index 0000000..b73a171 --- /dev/null +++ b/archive/legacy/ansible/configure-nodes.yml @@ -0,0 +1,65 @@ +--- +- name: Configure EKS Worker Nodes + hosts: eks_nodes + become: yes + + tasks: + - name: Update all packages + yum: + name: '*' + state: latest + update_only: yes + + - name: Install required packages + yum: + name: + - docker + - git + - jq + - python3 + - python3-pip + state: present + + - name: Start and enable Docker service + systemd: + name: docker + state: started + enabled: yes + + - name: Install AWS CLI + pip: + name: awscli + executable: pip3 + state: present + + - name: Install kubectl + get_url: + url: https://storage.googleapis.com/kubernetes-release/release/v1.23.6/bin/linux/amd64/kubectl + dest: /usr/local/bin/kubectl + mode: '0755' + + - name: Create .kube directory + file: + path: /home/ec2-user/.kube + state: directory + owner: ec2-user + group: ec2-user + mode: '0755' + + - name: Configure kubelet service + copy: + content: | + [Service] + Environment="KUBELET_EXTRA_ARGS=--node-labels=node.kubernetes.io/worker=true" + dest: /etc/systemd/system/kubelet.service.d/20-worker-labels.conf + owner: root + group: root + mode: '0644' + notify: Restart kubelet + + handlers: + - name: Restart kubelet + systemd: + name: kubelet + state: restarted + daemon_reload: yes \ No newline at end of file diff --git a/archive/legacy/ansible/inventory b/archive/legacy/ansible/inventory new file mode 100644 index 0000000..e7e693e --- /dev/null +++ b/archive/legacy/ansible/inventory @@ -0,0 +1,5 @@ +[eks_nodes] +# This will be dynamically populated by Terraform + +[eks_nodes:vars] +ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' \ No newline at end of file diff --git a/archive/legacy/ansible/roles b/archive/legacy/ansible/roles new file mode 100644 index 0000000..e69de29 diff --git a/archive/legacy/ansible/templates b/archive/legacy/ansible/templates new file mode 100644 index 0000000..c11e4f0 --- /dev/null +++ b/archive/legacy/ansible/templates @@ -0,0 +1 @@ +# This directory contains templates for Terraform \ No newline at end of file diff --git a/archive/legacy/ansible/terraform-ansible-integration.tf b/archive/legacy/ansible/terraform-ansible-integration.tf new file mode 100644 index 0000000..2658c93 --- /dev/null +++ b/archive/legacy/ansible/terraform-ansible-integration.tf @@ -0,0 +1,25 @@ +resource "local_file" "ansible_inventory_template" { + content = <<-EOT +[eks_nodes] +%{for ip in module.eks.worker_node_ips} +${ip} ansible_user=ec2-user +%{endfor} + +[eks_nodes:vars] +ansible_ssh_common_args='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' + EOT + + filename = "${path.module}/inventory" +} + +resource "null_resource" "ansible_executor" { + depends_on = [local_file.ansible_inventory_template, module.eks] + + provisioner "local-exec" { + command = "ansible-playbook -i inventory ansible-playbook.yml" + } + + triggers = { + always_run = "${timestamp()}" + } +} \ No newline at end of file diff --git a/archive/legacy/helm/simple-app/Chart.yaml b/archive/legacy/helm/simple-app/Chart.yaml new file mode 100644 index 0000000..869d788 --- /dev/null +++ b/archive/legacy/helm/simple-app/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: simple-app +description: A Helm chart for the simple application +type: application +version: 0.1.0 +appVersion: "1.0.0" diff --git a/archive/legacy/helm/simple-app/README.md b/archive/legacy/helm/simple-app/README.md new file mode 100644 index 0000000..fbd1168 --- /dev/null +++ b/archive/legacy/helm/simple-app/README.md @@ -0,0 +1,11 @@ +# Deprecated Chart + +This chart is a deprecated transitional asset. + +The single supported application deployment path for this repository is the Helm chart in: + +- `../../standardized-path/app/` + +Do not add new features or environment configuration to `helm/simple-app/`. + +Argo CD does not target this chart. diff --git a/archive/legacy/helm/simple-app/templates/_helpers.tpl b/archive/legacy/helm/simple-app/templates/_helpers.tpl new file mode 100644 index 0000000..c417313 --- /dev/null +++ b/archive/legacy/helm/simple-app/templates/_helpers.tpl @@ -0,0 +1,51 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "simple-app.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 "simple-app.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 "simple-app.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "simple-app.labels" -}} +helm.sh/chart: {{ include "simple-app.chart" . }} +{{ include "simple-app.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "simple-app.selectorLabels" -}} +app.kubernetes.io/name: {{ include "simple-app.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} diff --git a/archive/legacy/helm/simple-app/templates/deployment.yaml b/archive/legacy/helm/simple-app/templates/deployment.yaml new file mode 100644 index 0000000..6a43eea --- /dev/null +++ b/archive/legacy/helm/simple-app/templates/deployment.yaml @@ -0,0 +1,24 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "simple-app.fullname" . }} + labels: + {{- include "simple-app.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "simple-app.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "simple-app.selectorLabels" . | nindent 8 }} + spec: + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: {{ .Values.service.targetPort }} + protocol: TCP diff --git a/archive/legacy/helm/simple-app/templates/ingress.yaml b/archive/legacy/helm/simple-app/templates/ingress.yaml new file mode 100644 index 0000000..ab628b1 --- /dev/null +++ b/archive/legacy/helm/simple-app/templates/ingress.yaml @@ -0,0 +1,31 @@ +{{- if .Values.ingress.enabled -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "simple-app.fullname" . }} + labels: + {{- include "simple-app.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ .pathType }} + backend: + service: + name: {{ include "simple-app.fullname" $ }} + port: + number: {{ $.Values.service.port }} + {{- end }} + {{- end }} +{{- end }} diff --git a/archive/legacy/helm/simple-app/templates/service.yaml b/archive/legacy/helm/simple-app/templates/service.yaml new file mode 100644 index 0000000..84a2c14 --- /dev/null +++ b/archive/legacy/helm/simple-app/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "simple-app.fullname" . }} + labels: + {{- include "simple-app.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: {{ .Values.service.targetPort }} + protocol: TCP + name: http + selector: + {{- include "simple-app.selectorLabels" . | nindent 4 }} diff --git a/archive/legacy/helm/simple-app/values.yaml b/archive/legacy/helm/simple-app/values.yaml new file mode 100644 index 0000000..e380e9d --- /dev/null +++ b/archive/legacy/helm/simple-app/values.yaml @@ -0,0 +1,43 @@ +replicaCount: 3 + +image: + repository: REPLACE_ME_WITH_ECR_URI + pullPolicy: Always + tag: "latest" + +service: + type: LoadBalancer + port: 80 + targetPort: 8080 + +ingress: + enabled: true + className: "" + annotations: {} + hosts: + - host: my-app.simpleapp.com + paths: + - path: / + pathType: Prefix + tls: [] + +resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 10 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/archive/legacy/kubernetes/README.md b/archive/legacy/kubernetes/README.md new file mode 100644 index 0000000..1b8c734 --- /dev/null +++ b/archive/legacy/kubernetes/README.md @@ -0,0 +1,14 @@ +# Transitional Kubernetes Manifests + +This directory is no longer the supported application deployment source. + +Current intent: + +- `argocd-application.yaml` remains as the transitional Argo CD entry point +- raw application manifests in this directory are deprecated + +The single supported application deployment source for the app is: + +- `../../standardized-path/app/` + +Do not treat the raw application manifests in this directory as the steady-state source of truth for application delivery. diff --git a/archive/legacy/kubernetes/deployment-test.yaml b/archive/legacy/kubernetes/deployment-test.yaml new file mode 100644 index 0000000..9842d1d --- /dev/null +++ b/archive/legacy/kubernetes/deployment-test.yaml @@ -0,0 +1,20 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-app-test +spec: + replicas: 1 + selector: + matchLabels: + app: my-app-test + template: + metadata: + labels: + app: my-app-test + spec: + containers: + - name: my-app-test + image: ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/mynoderepo:test + imagePullPolicy: Always + ports: + - containerPort: 8080 \ No newline at end of file diff --git a/archive/legacy/kubernetes/deployment.yaml b/archive/legacy/kubernetes/deployment.yaml new file mode 100644 index 0000000..6f8609f --- /dev/null +++ b/archive/legacy/kubernetes/deployment.yaml @@ -0,0 +1,20 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-app +spec: + replicas: 3 + selector: + matchLabels: + app: my-app + template: + metadata: + labels: + app: my-app + spec: + containers: + - name: my-app + image: ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/mynoderepo:latest + imagePullPolicy: Always + ports: + - containerPort: 8080 \ No newline at end of file diff --git a/archive/legacy/kubernetes/forwardservice.yaml b/archive/legacy/kubernetes/forwardservice.yaml new file mode 100644 index 0000000..734d17c --- /dev/null +++ b/archive/legacy/kubernetes/forwardservice.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: my-app +spec: + type: LoadBalancer + selector: + app: my-app + ports: + - protocol: TCP + port: 80 + targetPort: 5005 \ No newline at end of file diff --git a/archive/legacy/kubernetes/ingress.yaml b/archive/legacy/kubernetes/ingress.yaml new file mode 100644 index 0000000..183c824 --- /dev/null +++ b/archive/legacy/kubernetes/ingress.yaml @@ -0,0 +1,16 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: my-app-ingress +spec: + rules: + - host: my-app.simpleapp.com + http: + paths: + - pathType: Prefix + path: "/" + backend: + service: + name: my-app + port: + number: 8080 \ No newline at end of file diff --git a/archive/legacy/kubernetes/loadbalancer.yaml b/archive/legacy/kubernetes/loadbalancer.yaml new file mode 100644 index 0000000..4009a4f --- /dev/null +++ b/archive/legacy/kubernetes/loadbalancer.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: my-app +spec: + type: LoadBalancer + selector: + app: my-app + ports: + - protocol: TCP + port: 80 + targetPort: 8080 \ No newline at end of file diff --git a/archive/legacy/kubernetes/service.yaml b/archive/legacy/kubernetes/service.yaml new file mode 100644 index 0000000..5d81d2f --- /dev/null +++ b/archive/legacy/kubernetes/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: my-app +spec: + selector: + app: my-app + ports: + - protocol: TCP + port: 80 + targetPort: 8080 \ No newline at end of file diff --git a/archive/legacy/plan_outputekscluster b/archive/legacy/plan_outputekscluster new file mode 100644 index 0000000000000000000000000000000000000000..97a3c14c9d6c92546e97465dfe5e2b60252123fe GIT binary patch literal 8392 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 WC.dkr.ecr..amazonaws.com/ + repository: "" # This sets the pull policy for images. pullPolicy: IfNotPresent # Overrides the image tag whose default is the chart appVersion. @@ -136,6 +138,12 @@ openshift: insecureEdgeTerminationPolicy: Redirect wildcardPolicy: None +# PodDisruptionBudget for high availability +podDisruptionBudget: + enabled: false + minAvailable: + maxUnavailable: + nodeSelector: {} tolerations: [] From 0d28e95aae15369e0d538d70b01cee18f8a8d857 Mon Sep 17 00:00:00 2001 From: tukue Date: Fri, 29 May 2026 13:08:54 +0200 Subject: [PATCH 2/4] fix: restore image.repository default and add PDB validation - Restore working ECR URL as chart default image.repository (configurable via Makefile AWS_ACCOUNT_ID and AWS_REGION variables) - Add Helm fail guard to PDB template when both minAvailable and maxUnavailable are unset (required by Kubernetes API validation) --- standardized-path/app/templates/pdb.yaml | 3 +++ standardized-path/app/values.yaml | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/standardized-path/app/templates/pdb.yaml b/standardized-path/app/templates/pdb.yaml index c9bc22b..54dc7bf 100644 --- a/standardized-path/app/templates/pdb.yaml +++ b/standardized-path/app/templates/pdb.yaml @@ -1,4 +1,7 @@ {{- if .Values.podDisruptionBudget.enabled }} +{{- if and (not .Values.podDisruptionBudget.minAvailable) (not .Values.podDisruptionBudget.maxUnavailable) }} +{{- fail "podDisruptionBudget.minAvailable or podDisruptionBudget.maxUnavailable must be set when podDisruptionBudget.enabled is true" }} +{{- end }} apiVersion: policy/v1 kind: PodDisruptionBudget metadata: diff --git a/standardized-path/app/values.yaml b/standardized-path/app/values.yaml index b200b25..6b73f8b 100644 --- a/standardized-path/app/values.yaml +++ b/standardized-path/app/values.yaml @@ -7,9 +7,10 @@ replicaCount: 2 # This sets the container image more information can be found here: https://kubernetes.io/docs/concepts/containers/images/ image: - # Override per environment (e.g. via values files, CI --set, or Argo CD parameters). + # Override per environment via values files, CI --set, or Argo CD parameters. # Format: .dkr.ecr..amazonaws.com/ - repository: "" + # Configurable via Makefile: AWS_ACCOUNT_ID and AWS_REGION + repository: 944684220857.dkr.ecr.eu-north-1.amazonaws.com/app # This sets the pull policy for images. pullPolicy: IfNotPresent # Overrides the image tag whose default is the chart appVersion. From c40c7603ca4090a5435c2be4172ac9606045076a Mon Sep 17 00:00:00 2001 From: tukue Date: Fri, 29 May 2026 13:16:27 +0200 Subject: [PATCH 3/4] fix: pin Terrascan version instead of dynamic API fetch GitHub API rate limiting causes the dynamic version fetch to return null, resulting in a 404 download. Pin to v1.18.0 as fallback. --- .github/workflows/terraform-scan.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/terraform-scan.yml b/.github/workflows/terraform-scan.yml index ab8d088..8fa2a6c 100644 --- a/.github/workflows/terraform-scan.yml +++ b/.github/workflows/terraform-scan.yml @@ -26,9 +26,12 @@ jobs: - name: Install Terrascan run: | - TERRASCAN_VERSION=$(curl -s https://api.github.com/repos/tenable/terrascan/releases/latest | jq -r '.tag_name') - TERRASCAN_VERSION=${TERRASCAN_VERSION#v} - wget https://github.com/tenable/terrascan/releases/download/v${TERRASCAN_VERSION}/terrascan_${TERRASCAN_VERSION}_Linux_x86_64.tar.gz -O terrascan.tar.gz + TERRASCAN_VERSION=$(curl -s https://api.github.com/repos/tenable/terrascan/releases/latest | jq -r '.tag_name' 2>/dev/null | sed 's/^v//' || true) + if [ -z "$TERRASCAN_VERSION" ] || [ "$TERRASCAN_VERSION" = "null" ]; then + TERRASCAN_VERSION="1.18.0" + echo "API rate limited; falling back to Terrascan v${TERRASCAN_VERSION}" + fi + wget "https://github.com/tenable/terrascan/releases/download/v${TERRASCAN_VERSION}/terrascan_${TERRASCAN_VERSION}_Linux_x86_64.tar.gz" -O terrascan.tar.gz tar -xf terrascan.tar.gz terrascan rm terrascan.tar.gz sudo install terrascan /usr/local/bin From 24e90eb7a0254ac176da7688a1be4d26817ab02f Mon Sep 17 00:00:00 2001 From: tukue Date: Fri, 29 May 2026 13:24:54 +0200 Subject: [PATCH 4/4] refactor: rename Helm include helpers from my-app to app - Rename all template include names (my-app.xxx -> app.xxx) - Change test-connection image from busybox to alpine:3.19 - Remove hardcoded image.repository from chart default (now set via --set) - Add --set image.repository to all helm template commands in Makefile and CI --- .github/workflows/platform-validate.yml | 28 +++++++++++-------- Makefile | 4 +++ standardized-path/app/templates/NOTES.txt | 8 +++--- standardized-path/app/templates/_helpers.tpl | 20 ++++++------- .../app/templates/deployment.yaml | 10 +++---- .../app/templates/externalsecret.yaml | 6 ++-- standardized-path/app/templates/hpa.yaml | 6 ++-- standardized-path/app/templates/ingress.yaml | 6 ++-- .../app/templates/openshift-route.yaml | 6 ++-- standardized-path/app/templates/pdb.yaml | 6 ++-- standardized-path/app/templates/service.yaml | 6 ++-- .../app/templates/serviceaccount.yaml | 4 +-- .../app/templates/servicemonitor.yaml | 6 ++-- .../app/templates/tests/test-connection.yaml | 8 +++--- standardized-path/app/values.yaml | 4 +-- 15 files changed, 68 insertions(+), 60 deletions(-) diff --git a/.github/workflows/platform-validate.yml b/.github/workflows/platform-validate.yml index 442901e..db34b57 100644 --- a/.github/workflows/platform-validate.yml +++ b/.github/workflows/platform-validate.yml @@ -123,12 +123,13 @@ jobs: - name: Render manifests run: | - helm template simple-app-dev standardized-path/app -f platform/apps/dev/values.yaml > /tmp/simple-app-dev.yaml - helm template simple-app-stage standardized-path/app -f platform/apps/stage/values.yaml > /tmp/simple-app-stage.yaml - helm template simple-app-prod standardized-path/app -f platform/apps/prod/values.yaml > /tmp/simple-app-prod.yaml - helm template app-b-dev standardized-path/app -f platform/apps/app-b/dev/values.yaml > /tmp/app-b-dev.yaml - helm template app-b-stage standardized-path/app -f platform/apps/app-b/stage/values.yaml > /tmp/app-b-stage.yaml - helm template app-b-prod standardized-path/app -f platform/apps/app-b/prod/values.yaml > /tmp/app-b-prod.yaml + IMG="--set image.repository=${{ vars.IMAGE_REPO || 'repo' }}" + helm template simple-app-dev standardized-path/app -f platform/apps/dev/values.yaml $IMG > /tmp/simple-app-dev.yaml + helm template simple-app-stage standardized-path/app -f platform/apps/stage/values.yaml $IMG > /tmp/simple-app-stage.yaml + helm template simple-app-prod standardized-path/app -f platform/apps/prod/values.yaml $IMG > /tmp/simple-app-prod.yaml + helm template app-b-dev standardized-path/app -f platform/apps/app-b/dev/values.yaml $IMG > /tmp/app-b-dev.yaml + helm template app-b-stage standardized-path/app -f platform/apps/app-b/stage/values.yaml $IMG > /tmp/app-b-stage.yaml + helm template app-b-prod standardized-path/app -f platform/apps/app-b/prod/values.yaml $IMG > /tmp/app-b-prod.yaml - name: Validate manifests with kubeconform run: | @@ -154,12 +155,13 @@ jobs: - name: Validate EKS manifests with OPA policies run: | - helm template simple-app-dev standardized-path/app -f platform/apps/dev/values.yaml | tr -d '\r' | conftest test -p policy/eks/ --no-color - - helm template simple-app-stage standardized-path/app -f platform/apps/stage/values.yaml | tr -d '\r' | conftest test -p policy/eks/ --no-color - - helm template simple-app-prod standardized-path/app -f platform/apps/prod/values.yaml | tr -d '\r' | conftest test -p policy/eks/ --no-color - - helm template app-b-dev standardized-path/app -f platform/apps/app-b/dev/values.yaml | tr -d '\r' | conftest test -p policy/eks/ --no-color - - helm template app-b-stage standardized-path/app -f platform/apps/app-b/stage/values.yaml | tr -d '\r' | conftest test -p policy/eks/ --no-color - - helm template app-b-prod standardized-path/app -f platform/apps/app-b/prod/values.yaml | tr -d '\r' | conftest test -p policy/eks/ --no-color - + IMG="--set image.repository=${{ vars.IMAGE_REPO || 'repo' }}" + helm template simple-app-dev standardized-path/app -f platform/apps/dev/values.yaml $IMG | tr -d '\r' | conftest test -p policy/eks/ --no-color - + helm template simple-app-stage standardized-path/app -f platform/apps/stage/values.yaml $IMG | tr -d '\r' | conftest test -p policy/eks/ --no-color - + helm template simple-app-prod standardized-path/app -f platform/apps/prod/values.yaml $IMG | tr -d '\r' | conftest test -p policy/eks/ --no-color - + helm template app-b-dev standardized-path/app -f platform/apps/app-b/dev/values.yaml $IMG | tr -d '\r' | conftest test -p policy/eks/ --no-color - + helm template app-b-stage standardized-path/app -f platform/apps/app-b/stage/values.yaml $IMG | tr -d '\r' | conftest test -p policy/eks/ --no-color - + helm template app-b-prod standardized-path/app -f platform/apps/app-b/prod/values.yaml $IMG | tr -d '\r' | conftest test -p policy/eks/ --no-color - openshift-validate: runs-on: ubuntu-latest @@ -174,6 +176,7 @@ jobs: - name: Render with OpenShift flags run: | helm template test standardized-path/app \ + --set image.repository=${{ vars.IMAGE_REPO || 'repo' }} \ --set openshift.enabled=true \ --set openshift.route.enabled=true \ --set ingress.enabled=false \ @@ -200,6 +203,7 @@ jobs: - name: Validate OpenShift manifests with OPA policies run: | helm template test standardized-path/app \ + --set image.repository=${{ vars.IMAGE_REPO || 'repo' }} \ --set openshift.enabled=true \ --set openshift.route.enabled=true \ --set ingress.enabled=false \ diff --git a/Makefile b/Makefile index 8d1eaf9..be8a36a 100644 --- a/Makefile +++ b/Makefile @@ -104,10 +104,12 @@ validate: test @echo "=== ServiceMonitor renders ===" helm template simple-app-dev standardized-path/app -f platform/apps/dev/values.yaml \ + --set image.repository=$(IMAGE_REPO) \ | grep -q "kind: ServiceMonitor" && echo " PASS: ServiceMonitor present" @echo "=== OpenShift path renders correctly ===" helm template test standardized-path/app \ + --set image.repository=$(IMAGE_REPO) \ --set openshift.enabled=true \ --set openshift.route.enabled=true \ --set ingress.enabled=false \ @@ -115,10 +117,12 @@ validate: test @echo "=== OPA policy: EKS manifests ===" helm template simple-app-dev standardized-path/app -f platform/apps/dev/values.yaml \ + --set image.repository=$(IMAGE_REPO) \ | tr -d '\r' | conftest test -p policy/eks/ --no-color - @echo "=== OPA policy: OpenShift manifests ===" helm template test standardized-path/app \ + --set image.repository=$(IMAGE_REPO) \ --set openshift.enabled=true \ --set openshift.route.enabled=true \ --set ingress.enabled=false \ diff --git a/standardized-path/app/templates/NOTES.txt b/standardized-path/app/templates/NOTES.txt index be59ec4..a1072aa 100644 --- a/standardized-path/app/templates/NOTES.txt +++ b/standardized-path/app/templates/NOTES.txt @@ -6,16 +6,16 @@ {{- 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 "my-app.fullname" . }}) + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "app.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 its status by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "my-app.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "my-app.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + You can watch its status by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "app.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "app.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 "my-app.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "app.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 diff --git a/standardized-path/app/templates/_helpers.tpl b/standardized-path/app/templates/_helpers.tpl index afcc44b..20c6889 100644 --- a/standardized-path/app/templates/_helpers.tpl +++ b/standardized-path/app/templates/_helpers.tpl @@ -1,7 +1,7 @@ {{/* Expand the name of the chart. */}} -{{- define "my-app.name" -}} +{{- define "app.name" -}} {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} {{- end }} @@ -10,7 +10,7 @@ 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 "my-app.fullname" -}} +{{- define "app.fullname" -}} {{- if .Values.fullnameOverride }} {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} {{- else }} @@ -26,16 +26,16 @@ If release name contains chart name it will be used as a full name. {{/* Create chart name and version as used by the chart label. */}} -{{- define "my-app.chart" -}} +{{- define "app.chart" -}} {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} {{- end }} {{/* Common labels */}} -{{- define "my-app.labels" -}} -helm.sh/chart: {{ include "my-app.chart" . }} -{{ include "my-app.selectorLabels" . }} +{{- define "app.labels" -}} +helm.sh/chart: {{ include "app.chart" . }} +{{ include "app.selectorLabels" . }} {{- if .Chart.AppVersion }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} {{- end }} @@ -45,17 +45,17 @@ app.kubernetes.io/managed-by: {{ .Release.Service }} {{/* Selector labels */}} -{{- define "my-app.selectorLabels" -}} -app.kubernetes.io/name: {{ include "my-app.name" . }} +{{- define "app.selectorLabels" -}} +app.kubernetes.io/name: {{ include "app.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} {{- end }} {{/* Create the name of the service account to use */}} -{{- define "my-app.serviceAccountName" -}} +{{- define "app.serviceAccountName" -}} {{- if .Values.serviceAccount.create }} -{{- default (include "my-app.fullname" .) .Values.serviceAccount.name }} +{{- default (include "app.fullname" .) .Values.serviceAccount.name }} {{- else }} {{- default "default" .Values.serviceAccount.name }} {{- end }} diff --git a/standardized-path/app/templates/deployment.yaml b/standardized-path/app/templates/deployment.yaml index 3a2120e..6d7dce4 100644 --- a/standardized-path/app/templates/deployment.yaml +++ b/standardized-path/app/templates/deployment.yaml @@ -1,16 +1,16 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: {{ include "my-app.fullname" . }} + name: {{ include "app.fullname" . }} labels: - {{- include "my-app.labels" . | nindent 4 }} + {{- include "app.labels" . | nindent 4 }} spec: {{- if not .Values.autoscaling.enabled }} replicas: {{ .Values.replicaCount }} {{- end }} selector: matchLabels: - {{- include "my-app.selectorLabels" . | nindent 6 }} + {{- include "app.selectorLabels" . | nindent 6 }} template: metadata: {{- with .Values.podAnnotations }} @@ -18,7 +18,7 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} labels: - {{- include "my-app.labels" . | nindent 8 }} + {{- include "app.labels" . | nindent 8 }} {{- with .Values.podLabels }} {{- toYaml . | nindent 8 }} {{- end }} @@ -27,7 +27,7 @@ spec: imagePullSecrets: {{- toYaml . | nindent 8 }} {{- end }} - serviceAccountName: {{ include "my-app.serviceAccountName" . }} + serviceAccountName: {{ include "app.serviceAccountName" . }} {{- if not .Values.openshift.enabled }} {{- with .Values.podSecurityContext }} securityContext: diff --git a/standardized-path/app/templates/externalsecret.yaml b/standardized-path/app/templates/externalsecret.yaml index 96eebd5..28f01ec 100644 --- a/standardized-path/app/templates/externalsecret.yaml +++ b/standardized-path/app/templates/externalsecret.yaml @@ -3,16 +3,16 @@ apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: - name: {{ include "my-app.fullname" $ }} + name: {{ include "app.fullname" $ }} labels: - {{- include "my-app.labels" $ | nindent 4 }} + {{- include "app.labels" $ | nindent 4 }} spec: refreshInterval: {{ .refreshInterval }} secretStoreRef: name: {{ .store.name }} kind: {{ .store.kind }} target: - name: {{ include "my-app.fullname" $ }} + name: {{ include "app.fullname" $ }} creationPolicy: Owner data: {{- range .data }} diff --git a/standardized-path/app/templates/hpa.yaml b/standardized-path/app/templates/hpa.yaml index 3d51d69..658ccd0 100644 --- a/standardized-path/app/templates/hpa.yaml +++ b/standardized-path/app/templates/hpa.yaml @@ -2,14 +2,14 @@ apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: - name: {{ include "my-app.fullname" . }} + name: {{ include "app.fullname" . }} labels: - {{- include "my-app.labels" . | nindent 4 }} + {{- include "app.labels" . | nindent 4 }} spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment - name: {{ include "my-app.fullname" . }} + name: {{ include "app.fullname" . }} minReplicas: {{ .Values.autoscaling.minReplicas }} maxReplicas: {{ .Values.autoscaling.maxReplicas }} metrics: diff --git a/standardized-path/app/templates/ingress.yaml b/standardized-path/app/templates/ingress.yaml index 696112d..eaa94cc 100644 --- a/standardized-path/app/templates/ingress.yaml +++ b/standardized-path/app/templates/ingress.yaml @@ -2,9 +2,9 @@ apiVersion: networking.k8s.io/v1 kind: Ingress metadata: - name: {{ include "my-app.fullname" . }} + name: {{ include "app.fullname" . }} labels: - {{- include "my-app.labels" . | nindent 4 }} + {{- include "app.labels" . | nindent 4 }} {{- with .Values.ingress.annotations }} annotations: {{- toYaml . | nindent 4 }} @@ -35,7 +35,7 @@ spec: {{- end }} backend: service: - name: {{ include "my-app.fullname" $ }} + name: {{ include "app.fullname" $ }} port: number: {{ $.Values.service.port }} {{- end }} diff --git a/standardized-path/app/templates/openshift-route.yaml b/standardized-path/app/templates/openshift-route.yaml index 6c3e91a..ac93335 100644 --- a/standardized-path/app/templates/openshift-route.yaml +++ b/standardized-path/app/templates/openshift-route.yaml @@ -2,9 +2,9 @@ apiVersion: route.openshift.io/v1 kind: Route metadata: - name: {{ include "my-app.fullname" . }} + name: {{ include "app.fullname" . }} labels: - {{- include "my-app.labels" . | nindent 4 }} + {{- include "app.labels" . | nindent 4 }} {{- with .Values.openshift.route.annotations }} annotations: {{- toYaml . | nindent 4 }} @@ -15,7 +15,7 @@ spec: {{- end }} to: kind: Service - name: {{ include "my-app.fullname" . }} + name: {{ include "app.fullname" . }} port: targetPort: http {{- with .Values.openshift.route.tls }} diff --git a/standardized-path/app/templates/pdb.yaml b/standardized-path/app/templates/pdb.yaml index 54dc7bf..587b067 100644 --- a/standardized-path/app/templates/pdb.yaml +++ b/standardized-path/app/templates/pdb.yaml @@ -5,9 +5,9 @@ apiVersion: policy/v1 kind: PodDisruptionBudget metadata: - name: {{ include "my-app.fullname" . }} + name: {{ include "app.fullname" . }} labels: - {{- include "my-app.labels" . | nindent 4 }} + {{- include "app.labels" . | nindent 4 }} spec: {{- with .Values.podDisruptionBudget.minAvailable }} minAvailable: {{ . }} @@ -17,5 +17,5 @@ spec: {{- end }} selector: matchLabels: - {{- include "my-app.selectorLabels" . | nindent 6 }} + {{- include "app.selectorLabels" . | nindent 6 }} {{- end }} diff --git a/standardized-path/app/templates/service.yaml b/standardized-path/app/templates/service.yaml index 7565f17..f674843 100644 --- a/standardized-path/app/templates/service.yaml +++ b/standardized-path/app/templates/service.yaml @@ -1,9 +1,9 @@ apiVersion: v1 kind: Service metadata: - name: {{ include "my-app.fullname" . }} + name: {{ include "app.fullname" . }} labels: - {{- include "my-app.labels" . | nindent 4 }} + {{- include "app.labels" . | nindent 4 }} spec: type: {{ .Values.service.type }} ports: @@ -12,4 +12,4 @@ spec: protocol: TCP name: http selector: - {{- include "my-app.selectorLabels" . | nindent 4 }} + {{- include "app.selectorLabels" . | nindent 4 }} diff --git a/standardized-path/app/templates/serviceaccount.yaml b/standardized-path/app/templates/serviceaccount.yaml index 91be91a..3c0f54f 100644 --- a/standardized-path/app/templates/serviceaccount.yaml +++ b/standardized-path/app/templates/serviceaccount.yaml @@ -2,9 +2,9 @@ apiVersion: v1 kind: ServiceAccount metadata: - name: {{ include "my-app.serviceAccountName" . }} + name: {{ include "app.serviceAccountName" . }} labels: - {{- include "my-app.labels" . | nindent 4 }} + {{- include "app.labels" . | nindent 4 }} {{- with .Values.serviceAccount.annotations }} annotations: {{- toYaml . | nindent 4 }} diff --git a/standardized-path/app/templates/servicemonitor.yaml b/standardized-path/app/templates/servicemonitor.yaml index c73a8af..934633e 100644 --- a/standardized-path/app/templates/servicemonitor.yaml +++ b/standardized-path/app/templates/servicemonitor.yaml @@ -2,15 +2,15 @@ apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: - name: {{ include "my-app.fullname" . }} + name: {{ include "app.fullname" . }} labels: - app.kubernetes.io/name: {{ include "my-app.name" . }} + app.kubernetes.io/name: {{ include "app.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/managed-by: platform spec: selector: matchLabels: - {{- include "my-app.selectorLabels" . | nindent 6 }} + {{- include "app.selectorLabels" . | nindent 6 }} endpoints: - port: http interval: {{ .Values.serviceMonitor.interval }} diff --git a/standardized-path/app/templates/tests/test-connection.yaml b/standardized-path/app/templates/tests/test-connection.yaml index 582e801..d0394f1 100644 --- a/standardized-path/app/templates/tests/test-connection.yaml +++ b/standardized-path/app/templates/tests/test-connection.yaml @@ -1,15 +1,15 @@ apiVersion: v1 kind: Pod metadata: - name: "{{ include "my-app.fullname" . }}-test-connection" + name: "{{ include "app.fullname" . }}-test-connection" labels: - {{- include "my-app.labels" . | nindent 4 }} + {{- include "app.labels" . | nindent 4 }} annotations: "helm.sh/hook": test spec: containers: - name: wget - image: busybox + image: alpine:3.19 command: ['wget'] - args: ['{{ include "my-app.fullname" . }}:{{ .Values.service.port }}'] + args: ['{{ include "app.fullname" . }}:{{ .Values.service.port }}'] restartPolicy: Never diff --git a/standardized-path/app/values.yaml b/standardized-path/app/values.yaml index 6b73f8b..6718048 100644 --- a/standardized-path/app/values.yaml +++ b/standardized-path/app/values.yaml @@ -7,10 +7,10 @@ replicaCount: 2 # This sets the container image more information can be found here: https://kubernetes.io/docs/concepts/containers/images/ image: - # Override per environment via values files, CI --set, or Argo CD parameters. + # Must be set per environment via values files, CI --set, or Argo CD parameters. # Format: .dkr.ecr..amazonaws.com/ # Configurable via Makefile: AWS_ACCOUNT_ID and AWS_REGION - repository: 944684220857.dkr.ecr.eu-north-1.amazonaws.com/app + repository: "" # This sets the pull policy for images. pullPolicy: IfNotPresent # Overrides the image tag whose default is the chart appVersion.