# k8s/deployments/web-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata: name: web-app
spec: replicas: 3 selector: matchLabels: app: web-app template: metadata: labels: app: web-app spec: containers: - name: web image: myorg/web-app:1.2.0 ports: - containerPort: 8080
# k8s/deployments/web-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata: name: web-app
spec: replicas: 3 selector: matchLabels: app: web-app template: metadata: labels: app: web-app spec: containers: - name: web image: myorg/web-app:1.2.0 ports: - containerPort: 8080
# k8s/deployments/web-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata: name: web-app
spec: replicas: 3 selector: matchLabels: app: web-app template: metadata: labels: app: web-app spec: containers: - name: web image: myorg/web-app:1.2.0 ports: - containerPort: 8080
# .github/workflows/kube-lint.yml
name: Lint Kubernetes YAMLs on: [pull_request] jobs: kube-lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install kubeval run: | -weight: 500;">curl -sSL https://github.com/instrumenta/kubeval/releases/latest/download/kubeval-linux-amd64.tar.gz | tar xz -weight: 600;">sudo mv kubeval /usr/local/bin/ - name: Validate manifests run: kubeval k8s/deployments/*.yaml
# .github/workflows/kube-lint.yml
name: Lint Kubernetes YAMLs on: [pull_request] jobs: kube-lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install kubeval run: | -weight: 500;">curl -sSL https://github.com/instrumenta/kubeval/releases/latest/download/kubeval-linux-amd64.tar.gz | tar xz -weight: 600;">sudo mv kubeval /usr/local/bin/ - name: Validate manifests run: kubeval k8s/deployments/*.yaml
# .github/workflows/kube-lint.yml
name: Lint Kubernetes YAMLs on: [pull_request] jobs: kube-lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install kubeval run: | -weight: 500;">curl -sSL https://github.com/instrumenta/kubeval/releases/latest/download/kubeval-linux-amd64.tar.gz | tar xz -weight: 600;">sudo mv kubeval /usr/local/bin/ - name: Validate manifests run: kubeval k8s/deployments/*.yaml
infrastructure/
├── dev/
│ └── values.yaml
├── staging/
│ └── values.yaml
└── prod/ └── values.yaml
infrastructure/
├── dev/
│ └── values.yaml
├── staging/
│ └── values.yaml
└── prod/ └── values.yaml
infrastructure/
├── dev/
│ └── values.yaml
├── staging/
│ └── values.yaml
└── prod/ └── values.yaml
# argo-apps/prod-web-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata: name: prod-web-app
spec: project: default source: repoURL: https://github.com/myorg/my-infra-repo.-weight: 500;">git targetRevision: main path: infrastructure/prod destination: server: https://kubernetes.default.svc namespace: prod syncPolicy: automated: prune: true selfHeal: true
# argo-apps/prod-web-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata: name: prod-web-app
spec: project: default source: repoURL: https://github.com/myorg/my-infra-repo.-weight: 500;">git targetRevision: main path: infrastructure/prod destination: server: https://kubernetes.default.svc namespace: prod syncPolicy: automated: prune: true selfHeal: true
# argo-apps/prod-web-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata: name: prod-web-app
spec: project: default source: repoURL: https://github.com/myorg/my-infra-repo.-weight: 500;">git targetRevision: main path: infrastructure/prod destination: server: https://kubernetes.default.svc namespace: prod syncPolicy: automated: prune: true selfHeal: true
# policies/no-root.rego
package kubernetes.admission deny[msg] { input.request.kind.kind == "Pod" container := input.request.object.spec.containers[_] not container.securityContext.runAsNonRoot msg := "Container must not run as root"
}
# policies/no-root.rego
package kubernetes.admission deny[msg] { input.request.kind.kind == "Pod" container := input.request.object.spec.containers[_] not container.securityContext.runAsNonRoot msg := "Container must not run as root"
}
# policies/no-root.rego
package kubernetes.admission deny[msg] { input.request.kind.kind == "Pod" container := input.request.object.spec.containers[_] not container.securityContext.runAsNonRoot msg := "Container must not run as root"
}
conftest test k8s/deployments/web-app.yaml
conftest test k8s/deployments/web-app.yaml
conftest test k8s/deployments/web-app.yaml
# values.yaml
replicaCount: 3
image: repository: myorg/web-app tag: "1.2.0"
-weight: 500;">service: port: 8080
# values.yaml
replicaCount: 3
image: repository: myorg/web-app tag: "1.2.0"
-weight: 500;">service: port: 8080
# values.yaml
replicaCount: 3
image: repository: myorg/web-app tag: "1.2.0"
-weight: 500;">service: port: 8080
# templates/deployment.yaml (Helm syntax)
apiVersion: apps/v1
kind: Deployment
metadata: name: web-app
spec: replicas: {{ .Values.replicaCount }} template: spec: containers: - name: web image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" ports: - containerPort: {{ .Values.-weight: 500;">service.port }}
# templates/deployment.yaml (Helm syntax)
apiVersion: apps/v1
kind: Deployment
metadata: name: web-app
spec: replicas: {{ .Values.replicaCount }} template: spec: containers: - name: web image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" ports: - containerPort: {{ .Values.-weight: 500;">service.port }}
# templates/deployment.yaml (Helm syntax)
apiVersion: apps/v1
kind: Deployment
metadata: name: web-app
spec: replicas: {{ .Values.replicaCount }} template: spec: containers: - name: web image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" ports: - containerPort: {{ .Values.-weight: 500;">service.port }} - Store all infrastructure and configuration as code in Git to -weight: 500;">enable versioning, collaboration, and rollback.
- Always use pull requests and automated validation to catch errors early and maintain transparency.
- Separate environments with branches or folders, and automate reconciliation with GitOps controllers.
- Enforce security and compliance with policy-as-code in your CI/CD pipelines.
- Parameterize your manifests to reduce duplication and simplify environment-specific customization.