Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,29 @@ jobs:
- name: Run Code Analysis
run: dotnet build --no-restore --configuration Release /p:TreatWarningsAsErrors=false

validate-manifests:
name: Validate K8s Manifests
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Validate YAML syntax
run: |
pip install pyyaml
for f in k8s/base/*.yaml; do
echo "Validating $f..."
python3 -c "import yaml; yaml.safe_load(open('$f'))"
done

- name: Validate Kustomize overlays
run: |
echo "Validating staging overlay..."
kubectl kustomize k8s/overlays/staging > /dev/null
echo "Validating production overlay..."
kubectl kustomize k8s/overlays/production > /dev/null

security:
name: Security Scan
runs-on: ubuntu-latest
Expand Down
122 changes: 122 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
name: Deploy

on:
push:
tags: ['v*']
workflow_dispatch:
inputs:
environment:
description: 'Target environment'
required: true
type: choice
options:
- staging
- production
image_tag:
description: 'Docker image tag to deploy'
required: true
type: string

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
prepare:
name: Prepare Deployment
runs-on: ubuntu-latest
outputs:
image_tag: ${{ steps.resolve-tag.outputs.tag }}
version: ${{ steps.resolve-tag.outputs.version }}
steps:
- name: Resolve image tag
id: resolve-tag
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "tag=${{ inputs.image_tag }}" >> $GITHUB_OUTPUT
echo "version=${{ inputs.image_tag }}" >> $GITHUB_OUTPUT
else
TAG="${GITHUB_REF#refs/tags/}"
echo "tag=${TAG}" >> $GITHUB_OUTPUT
echo "version=${TAG}" >> $GITHUB_OUTPUT
fi

- name: Verify image exists
run: |
echo "Verifying image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.resolve-tag.outputs.tag }}"

deploy-staging:
name: Deploy to Staging
needs: prepare
runs-on: ubuntu-latest
environment:
name: staging
url: https://ordermonitor-api.staging.printerpix.com/health
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set image tag in manifests
run: |
cd k8s/overlays/staging
kustomize edit set image ghcr.io/printerpix/printerpix-backoffice-ordermonitor-api=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.image_tag }}

- name: Deploy to staging
run: |
echo "Deploying ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.image_tag }} to staging"
echo "kubectl apply -k k8s/overlays/staging"
# Uncomment when cluster credentials are configured:
# kubectl apply -k k8s/overlays/staging
# kubectl -n ordermonitor-staging rollout status deployment/staging-ordermonitor-api --timeout=300s

- name: Run smoke tests
run: |
echo "Running smoke tests against staging..."
# Uncomment when staging is accessible:
# chmod +x scripts/smoke-test.sh
# ./scripts/smoke-test.sh https://ordermonitor-api.staging.printerpix.com

- name: Staging deployment summary
run: |
echo "## Staging Deployment" >> $GITHUB_STEP_SUMMARY
echo "- **Image:** ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.image_tag }}" >> $GITHUB_STEP_SUMMARY
echo "- **Version:** ${{ needs.prepare.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "- **Environment:** staging" >> $GITHUB_STEP_SUMMARY

deploy-production:
name: Deploy to Production
needs: [prepare, deploy-staging]
runs-on: ubuntu-latest
environment:
name: production
url: https://ordermonitor-api.printerpix.com/health
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set image tag in manifests
run: |
cd k8s/overlays/production
kustomize edit set image ghcr.io/printerpix/printerpix-backoffice-ordermonitor-api=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.image_tag }}

- name: Deploy to production
run: |
echo "Deploying ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.image_tag }} to production"
echo "kubectl apply -k k8s/overlays/production"
# Uncomment when cluster credentials are configured:
# kubectl apply -k k8s/overlays/production
# kubectl -n ordermonitor rollout status deployment/ordermonitor-api --timeout=300s

- name: Run smoke tests
run: |
echo "Running smoke tests against production..."
# Uncomment when production is accessible:
# chmod +x scripts/smoke-test.sh
# ./scripts/smoke-test.sh https://ordermonitor-api.printerpix.com

- name: Production deployment summary
run: |
echo "## Production Deployment" >> $GITHUB_STEP_SUMMARY
echo "- **Image:** ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.prepare.outputs.image_tag }}" >> $GITHUB_STEP_SUMMARY
echo "- **Version:** ${{ needs.prepare.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "- **Environment:** production" >> $GITHUB_STEP_SUMMARY
15 changes: 15 additions & 0 deletions k8s/base/configmap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: ordermonitor-api-config
namespace: ordermonitor
labels:
app.kubernetes.io/name: ordermonitor-api
app.kubernetes.io/component: config
app.kubernetes.io/part-of: printerpix
data:
ASPNETCORE_ENVIRONMENT: "Production"
ASPNETCORE_URLS: "http://+:8080"
Logging__LogLevel__Default: "Information"
Logging__LogLevel__Microsoft.AspNetCore: "Warning"
Logging__LogLevel__Microsoft.EntityFrameworkCore: "Warning"
66 changes: 66 additions & 0 deletions k8s/base/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ordermonitor-api
namespace: ordermonitor
labels:
app.kubernetes.io/name: ordermonitor-api
app.kubernetes.io/component: api
app.kubernetes.io/part-of: printerpix
spec:
replicas: 2
selector:
matchLabels:
app.kubernetes.io/name: ordermonitor-api
template:
metadata:
labels:
app.kubernetes.io/name: ordermonitor-api
app.kubernetes.io/component: api
app.kubernetes.io/part-of: printerpix
spec:
containers:
- name: ordermonitor-api
image: ghcr.io/printerpix/printerpix-backoffice-ordermonitor-api:latest
ports:
- name: http
containerPort: 8080
protocol: TCP
envFrom:
- configMapRef:
name: ordermonitor-api-config
- secretRef:
name: ordermonitor-api-secrets
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 15
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
startupProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 5
failureThreshold: 12
restartPolicy: Always
terminationGracePeriodSeconds: 30
42 changes: 42 additions & 0 deletions k8s/base/hpa.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: ordermonitor-api
namespace: ordermonitor
labels:
app.kubernetes.io/name: ordermonitor-api
app.kubernetes.io/component: autoscaling
app.kubernetes.io/part-of: printerpix
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: ordermonitor-api
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Pods
value: 2
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Pods
value: 1
periodSeconds: 120
46 changes: 46 additions & 0 deletions k8s/base/ingress.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ordermonitor-api
namespace: ordermonitor
labels:
app.kubernetes.io/name: ordermonitor-api
app.kubernetes.io/component: ingress
app.kubernetes.io/part-of: printerpix
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
spec:
ingressClassName: nginx
tls:
- hosts:
- ordermonitor-api.printerpix.com
secretName: ordermonitor-api-tls
rules:
- host: ordermonitor-api.printerpix.com
http:
paths:
- path: /api(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: ordermonitor-api
port:
number: 8080
- path: /health
pathType: Exact
backend:
service:
name: ordermonitor-api
port:
number: 8080
- path: /swagger(.*)
pathType: ImplementationSpecific
backend:
service:
name: ordermonitor-api
port:
number: 8080
16 changes: 16 additions & 0 deletions k8s/base/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: ordermonitor

commonLabels:
app.kubernetes.io/managed-by: kustomize

resources:
- namespace.yaml
- deployment.yaml
- service.yaml
- configmap.yaml
- secret.yaml
- hpa.yaml
- ingress.yaml
7 changes: 7 additions & 0 deletions k8s/base/namespace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: v1
kind: Namespace
metadata:
name: ordermonitor
labels:
app.kubernetes.io/name: ordermonitor-api
app.kubernetes.io/part-of: printerpix
14 changes: 14 additions & 0 deletions k8s/base/secret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: v1
kind: Secret
metadata:
name: ordermonitor-api-secrets
namespace: ordermonitor
labels:
app.kubernetes.io/name: ordermonitor-api
app.kubernetes.io/component: config
app.kubernetes.io/part-of: printerpix
type: Opaque
data:
# Base64-encoded placeholders - replace with actual values in each environment
# echo -n "Server=host;Database=db;User Id=user;Password=pass;TrustServerCertificate=True" | base64
ConnectionStrings__DefaultConnection: "REPLACE_WITH_BASE64_ENCODED_CONNECTION_STRING"
18 changes: 18 additions & 0 deletions k8s/base/service.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
apiVersion: v1
kind: Service
metadata:
name: ordermonitor-api
namespace: ordermonitor
labels:
app.kubernetes.io/name: ordermonitor-api
app.kubernetes.io/component: api
app.kubernetes.io/part-of: printerpix
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: ordermonitor-api
ports:
- name: http
port: 8080
targetPort: http
protocol: TCP
Loading
Loading