Skip to content

Commit 372bdca

Browse files
strukalexclaude
andcommitted
feat: implement US-010 - Integrate PLG Deployment with GitHub Actions and Scripts
Add PLG Helm deployment to GitHub Actions workflow and oc-deploy.sh script. PLG environment variables configurable per overlay. PLG is a separate Helm release that does not affect existing Kustomize deployment. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent dd3c2a3 commit 372bdca

9 files changed

Lines changed: 264 additions & 11 deletions

File tree

.github/workflows/build-apps.yml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,58 @@ jobs:
162162
rm -rf /tmp/.buildx-cache
163163
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
164164
165+
deploy-plg:
166+
name: Deploy PLG Stack
167+
needs: [build-apps, get-environment]
168+
if: ${{ always() && (needs.build-apps.result == 'success' || needs.build-apps.result == 'skipped') }}
169+
runs-on: ubuntu-latest
170+
environment:
171+
name: ${{ needs.get-environment.outputs.environment }}
172+
env:
173+
OPENSHIFT_SERVER: ${{ secrets.OPENSHIFT_SERVER }}
174+
OPENSHIFT_TOKEN: ${{ secrets.OPENSHIFT_TOKEN }}
175+
OPENSHIFT_NAMESPACE: ${{ secrets.OPENSHIFT_NAMESPACE }}
176+
GRAFANA_ADMIN_PASSWORD: ${{ secrets.GRAFANA_ADMIN_PASSWORD }}
177+
steps:
178+
- name: Checkout
179+
uses: actions/checkout@v4
180+
with:
181+
ref: ${{ github.ref }}
182+
183+
- name: Install Helm
184+
uses: azure/setup-helm@v4
185+
with:
186+
version: v3.17.0
187+
188+
- name: Install oc CLI
189+
uses: redhat-actions/openshift-tools-installer@v1
190+
with:
191+
oc: "4"
192+
193+
- name: Login to OpenShift
194+
run: |
195+
oc login "${{ env.OPENSHIFT_SERVER }}" \
196+
--token="${{ env.OPENSHIFT_TOKEN }}" \
197+
--insecure-skip-tls-verify=true
198+
199+
- name: Deploy PLG Helm Chart
200+
run: |
201+
CHART_DIR="deployments/openshift/helm/plg"
202+
203+
# Use environment-specific defaults; secrets override via GitHub environment
204+
GRAFANA_PWD="${{ env.GRAFANA_ADMIN_PASSWORD }}"
205+
if [ -z "${GRAFANA_PWD}" ]; then
206+
GRAFANA_PWD="admin"
207+
fi
208+
209+
helm upgrade --install plg "${CHART_DIR}" \
210+
--namespace "${{ env.OPENSHIFT_NAMESPACE }}" \
211+
-f "${CHART_DIR}/values-openshift.yaml" \
212+
--set "grafana.adminPassword=${GRAFANA_PWD}" \
213+
--wait --timeout 120s
214+
215+
echo "PLG stack deployed successfully."
216+
165217
# trigger_migration:
166218
# needs: [metadata, build-apps]
167219
# if: ${{ always() && needs.build-apps.result == 'success' && needs.metadata.outputs.changed-apps != '[]' && needs.metadata.outputs.changed-apps != '' }}

deployments/openshift/config/dev.env.example

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,17 @@ THROTTLE_AUTH_TTL_MS=60000
115115
THROTTLE_AUTH_LIMIT=10
116116
THROTTLE_AUTH_REFRESH_TTL_MS=60000
117117
THROTTLE_AUTH_REFRESH_LIMIT=5
118+
119+
# -----------------------------------------------------------------------------
120+
# PLG Monitoring Stack (Prometheus, Loki, Grafana)
121+
# -----------------------------------------------------------------------------
122+
# Grafana admin password. Change this from the default for any shared environment.
123+
GRAFANA_ADMIN_PASSWORD=admin
124+
# Loki log retention period in days.
125+
LOKI_RETENTION_DAYS=30
126+
# Loki PVC storage size.
127+
LOKI_PVC_SIZE=10Gi
128+
# Prometheus PVC storage size.
129+
PROMETHEUS_PVC_SIZE=10Gi
130+
# Prometheus scrape interval for all targets.
131+
METRICS_SCRAPE_INTERVAL=15s

deployments/openshift/config/prod.env.example

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,17 @@ THROTTLE_AUTH_TTL_MS=60000
115115
THROTTLE_AUTH_LIMIT=5
116116
THROTTLE_AUTH_REFRESH_TTL_MS=60000
117117
THROTTLE_AUTH_REFRESH_LIMIT=3
118+
119+
# -----------------------------------------------------------------------------
120+
# PLG Monitoring Stack (Prometheus, Loki, Grafana)
121+
# -----------------------------------------------------------------------------
122+
# Grafana admin password. Use a strong password in production.
123+
GRAFANA_ADMIN_PASSWORD=change-me-in-production
124+
# Loki log retention period in days.
125+
LOKI_RETENTION_DAYS=30
126+
# Loki PVC storage size.
127+
LOKI_PVC_SIZE=10Gi
128+
# Prometheus PVC storage size.
129+
PROMETHEUS_PVC_SIZE=10Gi
130+
# Prometheus scrape interval for all targets.
131+
METRICS_SCRAPE_INTERVAL=15s
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# PLG Deployment Integration
2+
3+
## Overview
4+
5+
The PLG (Prometheus, Loki, Grafana) monitoring stack is deployed as a separate Helm release alongside the application. It does not modify or interfere with the existing Kustomize-based application deployment. PLG deployment is integrated into both the GitHub Actions CI/CD pipeline and the local deployment scripts.
6+
7+
## Deployment Methods
8+
9+
### GitHub Actions (CI/CD)
10+
11+
The `build-apps.yml` workflow includes a `deploy-plg` job that runs after application images are built. This job:
12+
13+
1. Checks out the repository to access the Helm chart at `deployments/openshift/helm/plg/`
14+
2. Installs the Helm and `oc` CLIs
15+
3. Authenticates to OpenShift using environment secrets
16+
4. Runs `helm upgrade --install` with the OpenShift values file
17+
18+
The job runs regardless of whether application images were built (it depends on `build-apps` succeeding or being skipped), ensuring the PLG stack stays up to date even when no application code changed.
19+
20+
#### Required GitHub Environment Secrets
21+
22+
| Secret | Description |
23+
|--------|-------------|
24+
| `OPENSHIFT_SERVER` | OpenShift API server URL |
25+
| `OPENSHIFT_TOKEN` | Service account token for the target namespace |
26+
| `OPENSHIFT_NAMESPACE` | Target namespace (e.g., `fd34fb-dev`) |
27+
| `GRAFANA_ADMIN_PASSWORD` | Grafana admin password (falls back to `admin` if unset) |
28+
29+
### Local Deployment (`oc-deploy.sh`)
30+
31+
The `scripts/oc-deploy.sh` script deploys the PLG stack as **Step 7**, between applying the Kustomize overlay (Step 6) and creating instance secrets (Step 8). This step:
32+
33+
1. Reads PLG-specific configuration from the environment profile (`dev.env` or `prod.env`)
34+
2. Derives instance-specific Prometheus scrape targets from the Kustomize instance name
35+
3. Runs `helm upgrade --install` with environment-specific values passed via `--set` flags
36+
37+
If the `helm` CLI is not installed, the PLG step is skipped with a warning. The application deployment continues normally.
38+
39+
#### Instance-Specific Helm Release
40+
41+
Each application instance gets its own PLG Helm release named `<instance>-plg`. Prometheus scrape targets are configured to point at the instance-specific Kubernetes service names (e.g., `my-instance-backend-services`, `my-instance-temporal`).
42+
43+
### Teardown (`oc-teardown.sh`)
44+
45+
The `scripts/oc-teardown.sh` script includes a step (3b) that uninstalls the PLG Helm release for the instance being torn down. If Helm is not installed or no PLG release exists, the step is skipped gracefully.
46+
47+
## Environment Configuration
48+
49+
PLG-specific variables are configured in the same environment profile files used by the application (`deployments/openshift/config/<env>.env`). They follow the existing config merge pattern: profile defaults can be overridden by instance-specific files.
50+
51+
| Variable | Default | Description |
52+
|----------|---------|-------------|
53+
| `GRAFANA_ADMIN_PASSWORD` | `admin` | Grafana admin login password |
54+
| `LOKI_RETENTION_DAYS` | `30` | Log retention period in days |
55+
| `LOKI_PVC_SIZE` | `10Gi` | Persistent volume size for Loki data |
56+
| `PROMETHEUS_PVC_SIZE` | `10Gi` | Persistent volume size for Prometheus TSDB |
57+
| `METRICS_SCRAPE_INTERVAL` | `15s` | How often Prometheus scrapes targets |
58+
59+
These variables are read by `oc-deploy.sh` via the `config-loader.sh` library and passed to Helm as `--set` overrides on top of the `values-openshift.yaml` base.
60+
61+
## Separation from Kustomize
62+
63+
The PLG deployment is completely independent of the Kustomize-based application deployment:
64+
65+
- PLG resources are managed by Helm, not Kustomize
66+
- PLG uses its own labels (`app.kubernetes.io/managed-by: Helm`, `app.kubernetes.io/part-of: plg`)
67+
- No Kustomize base or overlay files are modified for PLG
68+
- If PLG deployment fails, the application deployment is unaffected
69+
70+
## Accessing Grafana
71+
72+
Grafana is not exposed via an OpenShift Route. Access it via port-forwarding:
73+
74+
```bash
75+
# For instance-specific deployments (via oc-deploy.sh)
76+
oc port-forward svc/<instance>-plg-grafana 3001:3001 -n <namespace>
77+
78+
# For CI-deployed PLG (single release per namespace)
79+
oc port-forward svc/plg-grafana 3001:3001 -n <namespace>
80+
```
81+
82+
Then open `http://localhost:3001` and log in with `admin` / `<GRAFANA_ADMIN_PASSWORD>`.
83+
84+
## Files
85+
86+
| File | Purpose |
87+
|------|---------|
88+
| `deployments/openshift/helm/plg/` | PLG Helm chart (templates, values) |
89+
| `deployments/openshift/helm/plg/values-openshift.yaml` | OpenShift-specific value overrides |
90+
| `deployments/openshift/config/dev.env.example` | Dev environment config template (includes PLG variables) |
91+
| `deployments/openshift/config/prod.env.example` | Prod environment config template (includes PLG variables) |
92+
| `.github/workflows/build-apps.yml` | CI workflow with `deploy-plg` job |
93+
| `scripts/oc-deploy.sh` | Local deployment script (Step 7: PLG) |
94+
| `scripts/oc-teardown.sh` | Teardown script (Step 3b: PLG uninstall) |

docs-md/openshift-deployment/ENVIRONMENT_CONFIGURATION.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,16 @@ These values are derived automatically by the deploy script — do not set them
170170
| `THROTTLE_AUTH_REFRESH_TTL_MS` | Token refresh rate limit window |
171171
| `THROTTLE_AUTH_REFRESH_LIMIT` | Max refresh requests per IP (stricter in prod) |
172172

173+
### PLG Monitoring Stack
174+
175+
| Variable | Default | Description |
176+
|----------|---------|-------------|
177+
| `GRAFANA_ADMIN_PASSWORD` | `admin` | Grafana admin login password |
178+
| `LOKI_RETENTION_DAYS` | `30` | Log retention period in days |
179+
| `LOKI_PVC_SIZE` | `10Gi` | Persistent volume size for Loki data |
180+
| `PROMETHEUS_PVC_SIZE` | `10Gi` | Persistent volume size for Prometheus TSDB |
181+
| `METRICS_SCRAPE_INTERVAL` | `15s` | How often Prometheus scrapes targets |
182+
173183
## How Secrets Reach the Pods
174184

175185
The deploy script creates per-instance OpenShift Secrets from values in the env file. Each instance gets its own copy.

feature-docs/20260315052727-plg-monitoring-stack/user_stories/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ After implementing the user story check it off at the bottom of this file.
5757
### Phase 4 — Deployment Integration (local + OpenShift)
5858
- [x] **US-008** (Create docker-compose.monitoring.yml with Promtail, Loki, Prometheus, Grafana)
5959
- [x] **US-009** (Add Promtail sidecar containers to all OpenShift application pods)
60-
- [ ] **US-010** (Integrate PLG Helm deployment into GitHub Actions workflow and /scripts)
60+
- [x] **US-010** (Integrate PLG Helm deployment into GitHub Actions workflow and /scripts)
6161

6262
### Phase 5 — Grafana Dashboards
6363
- [ ] **US-011** (Application Overview dashboard — request rate, error rate, latency, active sessions)

feature-docs/20260315052727-plg-monitoring-stack/user_stories/US-010-openshift-deployment-integration.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,22 @@
66

77
## Acceptance Criteria
88

9-
- [ ] **Scenario 1**: GitHub Actions workflow deploys PLG Helm chart
9+
- [x] **Scenario 1**: GitHub Actions workflow deploys PLG Helm chart
1010
- **Given** the existing GitHub Actions workflow builds and deploys the application
1111
- **When** the workflow runs
1212
- **Then** it also deploys the PLG Helm chart to the same namespace as the application
1313

14-
- [ ] **Scenario 2**: Local deployment scripts deploy PLG
14+
- [x] **Scenario 2**: Local deployment scripts deploy PLG
1515
- **Given** the existing deployment scripts in `/scripts` handle application deployment
1616
- **When** a developer runs the deployment scripts locally
1717
- **Then** the PLG Helm chart is also deployed to the target namespace
1818

19-
- [ ] **Scenario 3**: PLG environment variables configurable per overlay
19+
- [x] **Scenario 3**: PLG environment variables configurable per overlay
2020
- **Given** environment-specific configuration exists for dev, test, and prod
2121
- **When** deploying to a specific environment
2222
- **Then** PLG-specific variables (`GRAFANA_ADMIN_PASSWORD`, `LOKI_RETENTION_DAYS`, `LOKI_PVC_SIZE`, `PROMETHEUS_PVC_SIZE`, `METRICS_SCRAPE_INTERVAL`) are sourced from the environment's configuration
2323

24-
- [ ] **Scenario 4**: PLG deployment does not affect existing Kustomize deployment
24+
- [x] **Scenario 4**: PLG deployment does not affect existing Kustomize deployment
2525
- **Given** the application is deployed via Kustomize
2626
- **When** the PLG Helm chart is deployed
2727
- **Then** the existing Kustomize resources are not modified or disrupted

scripts/oc-deploy.sh

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -474,9 +474,56 @@ oc apply -k "${OVERLAY_DIR}" -n "${NAMESPACE}" || {
474474
log_info "Resources applied successfully."
475475

476476
# ============================================================
477-
# Step 7: Create/update instance secrets
477+
# Step 7: Deploy PLG monitoring stack (Helm)
478478
# ============================================================
479-
log_step "Step 7: Creating instance secrets"
479+
log_step "Step 7: Deploying PLG monitoring stack"
480+
481+
if ! command -v helm &>/dev/null; then
482+
log_error "'helm' CLI is not installed. Install Helm to deploy the PLG monitoring stack."
483+
log_error "Skipping PLG deployment — the application will still work without it."
484+
else
485+
PLG_CHART_DIR="${PROJECT_ROOT}/deployments/openshift/helm/plg"
486+
PLG_RELEASE_NAME="${INSTANCE_NAME}-plg"
487+
488+
# Read PLG-specific configuration with defaults
489+
GRAFANA_ADMIN_PASSWORD=$(get_config "GRAFANA_ADMIN_PASSWORD" 2>/dev/null || echo "admin")
490+
LOKI_RETENTION_DAYS=$(get_config "LOKI_RETENTION_DAYS" 2>/dev/null || echo "30")
491+
LOKI_PVC_SIZE=$(get_config "LOKI_PVC_SIZE" 2>/dev/null || echo "10Gi")
492+
PROMETHEUS_PVC_SIZE=$(get_config "PROMETHEUS_PVC_SIZE" 2>/dev/null || echo "10Gi")
493+
METRICS_SCRAPE_INTERVAL=$(get_config "METRICS_SCRAPE_INTERVAL" 2>/dev/null || echo "15s")
494+
495+
# Scrape targets use instance-prefixed service names (Kustomize namePrefix adds <instance>-)
496+
BACKEND_SERVICES_HOST=$(get_resource_name "${INSTANCE_NAME}" "backend-services")
497+
TEMPORAL_HOST=$(get_resource_name "${INSTANCE_NAME}" "temporal")
498+
499+
log_info "PLG release name: ${PLG_RELEASE_NAME}"
500+
log_info "Helm chart: ${PLG_CHART_DIR}"
501+
log_info "Loki retention: ${LOKI_RETENTION_DAYS} days, PVC: ${LOKI_PVC_SIZE}"
502+
log_info "Prometheus PVC: ${PROMETHEUS_PVC_SIZE}, scrape interval: ${METRICS_SCRAPE_INTERVAL}"
503+
504+
helm upgrade --install "${PLG_RELEASE_NAME}" "${PLG_CHART_DIR}" \
505+
--namespace "${NAMESPACE}" \
506+
-f "${PLG_CHART_DIR}/values-openshift.yaml" \
507+
--set "grafana.adminPassword=${GRAFANA_ADMIN_PASSWORD}" \
508+
--set "loki.retentionDays=${LOKI_RETENTION_DAYS}" \
509+
--set "loki.pvcSize=${LOKI_PVC_SIZE}" \
510+
--set "prometheus.pvcSize=${PROMETHEUS_PVC_SIZE}" \
511+
--set "prometheus.scrapeInterval=${METRICS_SCRAPE_INTERVAL}" \
512+
--set "prometheus.scrapeTargets.backendServices.host=${BACKEND_SERVICES_HOST}" \
513+
--set "prometheus.scrapeTargets.temporalServer.host=${TEMPORAL_HOST}" \
514+
--wait --timeout 120s || {
515+
log_error "Failed to deploy PLG monitoring stack."
516+
log_error "The application deployment is unaffected. PLG can be deployed manually later."
517+
log_error " helm upgrade --install ${PLG_RELEASE_NAME} ${PLG_CHART_DIR} -n ${NAMESPACE} -f ${PLG_CHART_DIR}/values-openshift.yaml"
518+
}
519+
520+
log_info "PLG monitoring stack deployed successfully."
521+
fi
522+
523+
# ============================================================
524+
# Step 8: Create/update instance secrets
525+
# ============================================================
526+
log_step "Step 8: Creating instance secrets"
480527

481528
# Secrets are read from the same env file loaded in Step 3 (via get_config).
482529
# No separate secrets file is needed.
@@ -524,9 +571,9 @@ oc label secret "${WORKER_SECRET_NAME}" \
524571
log_info "Instance secrets created successfully."
525572

526573
# ============================================================
527-
# Step 8: Wait for rollout completion
574+
# Step 9: Wait for rollout completion
528575
# ============================================================
529-
log_step "Step 8: Waiting for rollout completion"
576+
log_step "Step 9: Waiting for rollout completion"
530577

531578
DEPLOYMENT_SERVICES=("backend-services" "frontend" "temporal" "temporal-ui" "temporal-worker")
532579

@@ -547,9 +594,9 @@ done
547594
log_info "All deployments rolled out successfully."
548595

549596
# ============================================================
550-
# Step 9: Print access URLs
597+
# Step 10: Print access URLs
551598
# ============================================================
552-
log_step "Step 9: Deployment Complete"
599+
log_step "Step 10: Deployment Complete"
553600

554601
FRONTEND_ROUTE="https://${INSTANCE_NAME}-frontend-${NAMESPACE}.${CLUSTER_DOMAIN}"
555602
BACKEND_ROUTE="https://${INSTANCE_NAME}-backend-${NAMESPACE}.${CLUSTER_DOMAIN}"
@@ -571,6 +618,10 @@ To access Temporal UI (not publicly exposed):
571618
oc port-forward deployment/${INSTANCE_NAME}-temporal-ui 8080:8080 -n ${NAMESPACE}
572619
Then open http://localhost:8080
573620

621+
To access Grafana (not publicly exposed):
622+
oc port-forward svc/${INSTANCE_NAME}-plg-grafana 3001:3001 -n ${NAMESPACE}
623+
Then open http://localhost:3001 (admin / <GRAFANA_ADMIN_PASSWORD>)
624+
574625
To tear down this instance:
575626
./scripts/oc-teardown.sh --instance ${INSTANCE_NAME}
576627

scripts/oc-teardown.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,24 @@ done
174174

175175
log_info "All instance resources deleted."
176176

177+
# ============================================================
178+
# Step 3b: Uninstall PLG Helm release
179+
# ============================================================
180+
PLG_RELEASE_NAME="${INSTANCE_NAME}-plg"
181+
182+
if command -v helm &>/dev/null; then
183+
if helm status "${PLG_RELEASE_NAME}" -n "${NAMESPACE}" &>/dev/null; then
184+
log_info "Uninstalling PLG Helm release: ${PLG_RELEASE_NAME}"
185+
helm uninstall "${PLG_RELEASE_NAME}" -n "${NAMESPACE}" || {
186+
log_error "Failed to uninstall PLG Helm release '${PLG_RELEASE_NAME}'. Continuing with teardown."
187+
}
188+
else
189+
log_info "No PLG Helm release '${PLG_RELEASE_NAME}' found — skipping."
190+
fi
191+
else
192+
log_info "Helm CLI not installed — skipping PLG release cleanup."
193+
fi
194+
177195
# ============================================================
178196
# Step 4: Verify deletion
179197
# ============================================================

0 commit comments

Comments
 (0)