feat(lab-06): PostgreSQL production -- HA replication (bitnami), PgBo… #13
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main, develop, 'feature/**', 'bugfix/**'] | |
| pull_request: | |
| branches: [main, develop] | |
| permissions: | |
| contents: read | |
| security-events: write | |
| jobs: | |
| validate: | |
| name: Validate Configuration | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Validate Docker Compose files | |
| run: | | |
| # Strictly validate the standalone lab (fully built out) | |
| echo "Validating: docker/docker-compose.standalone.yml" | |
| docker compose -f docker/docker-compose.standalone.yml config -q | |
| echo "OK: docker/docker-compose.standalone.yml" | |
| # Strictly validate lan.yml (Lab 02 — fully built out) | |
| echo "Validating: docker/docker-compose.lan.yml" | |
| docker compose -f docker/docker-compose.lan.yml config -q | |
| echo "OK: docker/docker-compose.lan.yml" | |
| # Parse-check remaining scaffold files | |
| echo "Validating: docker/docker-compose.advanced.yml" | |
| docker compose -f docker/docker-compose.advanced.yml config -q | |
| echo "OK: docker/docker-compose.advanced.yml" | |
| echo "Validating: docker/docker-compose.sso.yml" | |
| docker compose -f docker/docker-compose.sso.yml config -q | |
| echo "OK: docker/docker-compose.sso.yml" | |
| echo "Validating: docker/docker-compose.integration.yml" | |
| docker compose -f docker/docker-compose.integration.yml config -q | |
| echo "OK: docker/docker-compose.integration.yml" | |
| echo "Validating: docker/docker-compose.production.yml" | |
| docker compose -f docker/docker-compose.production.yml config -q | |
| echo "OK: docker/docker-compose.production.yml" | |
| - name: ShellCheck — lab test scripts | |
| run: | | |
| sudo apt-get install -y shellcheck -qq | |
| shellcheck tests/labs/*.sh | |
| - name: Validate module manifest | |
| run: | | |
| python3 -c " | |
| import sys, re | |
| with open('it-stack-postgresql.yml') as f: | |
| content = f.read() | |
| required = ['module:', 'version:', 'phase:', 'category:', 'ports:'] | |
| missing = [k for k in required if k not in content] | |
| if missing: | |
| print('Missing fields:', missing); sys.exit(1) | |
| print('Manifest valid') | |
| " | |
| security-scan: | |
| name: Security Scan | |
| runs-on: ubuntu-latest | |
| needs: validate | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Trivy — scan Dockerfile | |
| uses: aquasecurity/trivy-action@0.28.0 | |
| with: | |
| scan-type: config | |
| scan-ref: . | |
| exit-code: '0' | |
| severity: CRITICAL,HIGH | |
| - name: Trivy — SARIF output | |
| uses: aquasecurity/trivy-action@0.28.0 | |
| with: | |
| scan-type: config | |
| scan-ref: . | |
| format: sarif | |
| output: trivy-results.sarif | |
| - name: Upload SARIF to GitHub Security | |
| uses: github/codeql-action/upload-sarif@v3 | |
| if: always() | |
| with: | |
| sarif_file: trivy-results.sarif | |
| lab-01-smoke: | |
| name: Lab 01 — Smoke Test | |
| runs-on: ubuntu-latest | |
| needs: validate | |
| continue-on-error: true # scaffold stubs; full lab runs on real VMs | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install PostgreSQL client tools | |
| run: sudo apt-get install -y postgresql-client netcat-openbsd | |
| - name: Start standalone stack | |
| run: docker compose -f docker/docker-compose.standalone.yml up -d | |
| - name: Wait for PostgreSQL to be ready | |
| run: | | |
| echo "Waiting for PostgreSQL..." | |
| timeout 120 bash -c 'until pg_isready -h localhost -p 5432 -U labadmin; do sleep 3; done' | |
| docker compose -f docker/docker-compose.standalone.yml ps | |
| - name: Run Lab 03-01 test script | |
| env: | |
| PGPASSWORD: "Lab01Password!" | |
| run: bash tests/labs/test-lab-03-01.sh | |
| - name: Collect logs on failure | |
| if: failure() | |
| run: docker compose -f docker/docker-compose.standalone.yml logs | |
| - name: Cleanup | |
| if: always() | |
| run: docker compose -f docker/docker-compose.standalone.yml down -v | |
| lab-02-smoke: | |
| name: Lab 02 — Streaming Replication | |
| runs-on: ubuntu-latest | |
| needs: validate | |
| continue-on-error: true | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install PostgreSQL client tools | |
| run: sudo apt-get install -y postgresql-client netcat-openbsd curl | |
| - name: Start LAN stack (primary + replica + pgAdmin) | |
| run: docker compose -f docker/docker-compose.lan.yml up -d | |
| - name: Wait for primary PostgreSQL | |
| run: | | |
| echo "Waiting for primary..." | |
| timeout 120 bash -c 'until pg_isready -h localhost -p 5432 -U labadmin; do sleep 3; done' | |
| - name: Wait for replica PostgreSQL | |
| run: | | |
| echo "Waiting for replica (base backup ~30s)..." | |
| timeout 180 bash -c 'until pg_isready -h localhost -p 5433 -U labadmin; do echo -n "."; sleep 5; done' | |
| echo "" | |
| - name: Run Lab 03-02 test script | |
| env: | |
| ADMIN_PASS: "Lab02Password!" | |
| run: bash tests/labs/test-lab-03-02.sh | |
| - name: Collect logs on failure | |
| if: failure() | |
| run: docker compose -f docker/docker-compose.lan.yml logs | |
| - name: Cleanup | |
| if: always() | |
| run: docker compose -f docker/docker-compose.lan.yml down -v | |
| lab-03-smoke: | |
| name: Lab 03 — PgBouncer + pg_stat_statements + Metrics | |
| runs-on: ubuntu-latest | |
| needs: validate | |
| continue-on-error: true | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install tools | |
| run: sudo apt-get install -y postgresql-client netcat-openbsd curl | |
| - name: Start advanced stack (primary + replica + PgBouncer + pg-exporter) | |
| run: docker compose -f docker/docker-compose.advanced.yml up -d | |
| - name: Wait for primary | |
| run: timeout 120 bash -c 'until pg_isready -h localhost -p 5432 -U labadmin; do sleep 3; done' | |
| - name: Wait for replica | |
| run: timeout 180 bash -c 'until pg_isready -h localhost -p 5433 -U labadmin; do sleep 5; done' | |
| - name: Wait for PgBouncer | |
| run: timeout 60 bash -c 'until pg_isready -h localhost -p 5434 -U labadmin; do sleep 3; done' | |
| - name: Run Lab 03-03 test script | |
| env: | |
| ADMIN_PASS: "Lab03Password!" | |
| run: bash tests/labs/test-lab-03-03.sh | |
| - name: Collect logs on failure | |
| if: failure() | |
| run: docker compose -f docker/docker-compose.advanced.yml logs | |
| - name: Cleanup | |
| if: always() | |
| run: docker compose -f docker/docker-compose.advanced.yml down -v | |
| lab-04-smoke: | |
| name: Lab 04 — Keycloak OIDC SSO + pgAdmin oauth2-proxy | |
| runs-on: ubuntu-latest | |
| needs: validate | |
| continue-on-error: true | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install tools | |
| run: sudo apt-get install -y postgresql-client netcat-openbsd curl | |
| - name: Start SSO stack (KC + pg-primary + pgAdmin + oauth2-proxy) | |
| run: docker compose -f docker/docker-compose.sso.yml up -d | |
| - name: Wait for Keycloak | |
| run: timeout 200 bash -c 'until curl -sf http://localhost:8080/health/ready | grep -q UP; do sleep 5; done' | |
| - name: Wait for PostgreSQL | |
| run: timeout 60 bash -c 'until pg_isready -h localhost -p 5432 -U labadmin; do sleep 3; done' | |
| - name: Run Lab 03-04 test script | |
| env: | |
| KC_PASS: "Lab04Password!" | |
| run: bash tests/labs/test-lab-03-04.sh | |
| - name: Collect logs on failure | |
| if: failure() | |
| run: docker compose -f docker/docker-compose.sso.yml logs | |
| - name: Cleanup | |
| if: always() | |
| run: docker compose -f docker/docker-compose.sso.yml down -v | |
| lab-05-smoke: | |
| name: Lab 05 -- PG multi-DB + Keycloak + Redis + Traefik integration | |
| runs-on: ubuntu-latest | |
| needs: validate | |
| continue-on-error: true | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install tools | |
| run: sudo apt-get install -y postgresql-client redis-tools curl netcat-openbsd | |
| - name: Start integration stack | |
| run: docker compose -f docker/docker-compose.integration.yml up -d | |
| - name: Wait for Keycloak | |
| run: timeout 200 bash -c 'until curl -sf http://localhost:8080/health/ready | grep -q UP; do sleep 5; done' | |
| - name: Wait for PostgreSQL | |
| run: timeout 60 bash -c 'until pg_isready -h localhost -p 5432 -U postgres; do sleep 3; done' | |
| - name: Run Lab 03-05 test script | |
| env: | |
| PG_PASS: "Lab05Password!" | |
| KC_PASS: "Lab05Password!" | |
| run: bash tests/labs/test-lab-03-05.sh | |
| - name: Collect logs on failure | |
| if: failure() | |
| run: docker compose -f docker/docker-compose.integration.yml logs | |
| - name: Cleanup | |
| if: always() | |
| run: docker compose -f docker/docker-compose.integration.yml down -v | |
| lab-06-smoke: | |
| name: Lab 06 — PostgreSQL Production HA (primary+replica+PgBouncer+exporter) | |
| runs-on: ubuntu-latest | |
| needs: validate | |
| continue-on-error: true | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install tools | |
| run: sudo apt-get install -y postgresql-client curl | |
| - name: Start production stack | |
| run: docker compose -f docker/docker-compose.production.yml up -d | |
| - name: Wait for PG primary | |
| run: timeout 120 bash -c 'until pg_isready -h localhost -p 5432 -U labadmin; do sleep 3; done' | |
| - name: Wait for PG replica | |
| run: timeout 60 bash -c 'until pg_isready -h localhost -p 5433 -U labadmin; do sleep 3; done' | |
| - name: Wait for PgBouncer | |
| run: timeout 60 bash -c 'until pg_isready -h localhost -p 6432 -U labadmin; do sleep 3; done' | |
| - name: Run Lab 03-06 test script | |
| env: | |
| PG_PASS: "Lab06Password!" | |
| run: bash tests/labs/test-lab-03-06.sh | |
| - name: Collect logs on failure | |
| if: failure() | |
| run: docker compose -f docker/docker-compose.production.yml logs | |
| - name: Cleanup | |
| if: always() | |
| run: docker compose -f docker/docker-compose.production.yml down -v |