Skip to content
Open
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
3 changes: 0 additions & 3 deletions .devcontainer/postAttach.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,3 @@
# postCreate.sh - Script executed after the dev container is attached to the host

set -euo pipefail

gcloud auth application-default login
gcloud auth application-default set-quota-project data-warehouse-492522
4 changes: 3 additions & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ updates:
labels:
- "dependencies"
- package-ecosystem: "docker"
directory: "/.devcontainer"
directories:
- "/.devcontainer"
- "/metabase"
schedule:
interval: "weekly"
commit-message:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Terraform Apply
name: Deploy

on:
workflow_dispatch:
Expand All @@ -21,6 +21,7 @@ concurrency:
permissions:
contents: write
id-token: write
packages: write
pull-requests: write

jobs:
Expand Down Expand Up @@ -61,15 +62,44 @@ jobs:
terraform-apply:
runs-on: ubuntu-latest
needs: [setup]
# this convoluted syntax allows skipped and successful prerequisite runs and disallows failures
if: (always() && !cancelled() && !failure())
environment: ${{ needs.setup.outputs.env_name }}
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Docker Login to GitHub Container Registry
uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # v4.7.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1

- name: Cache Parameters
id: cache_params
working-directory: .
run: |
CACHE_SCOPE="compiler"
MAIN_BRANCH_REF="refs/heads/main"
echo "cache_from_args=type=gha,scope=${CACHE_SCOPE},ref=${MAIN_BRANCH_REF}" >> $GITHUB_OUTPUT
echo "cache_to_args=type=gha,scope=${CACHE_SCOPE},mode=max,ref=${MAIN_BRANCH_REF}" >> $GITHUB_OUTPUT

- name: Build, tag, and push image to GitHub Container Registry
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
with:
builder: ${{ steps.buildx.outputs.name }}
build-args: GIT-SHA=${{ github.sha }}
cache-from: ${{ steps.cache_params.outputs.cache_from_args }}
cache-to: ${{ steps.cache_params.outputs.cache_to_args }}
context: .
file: metabase/Dockerfile
push: true
tags: ghcr.io/${{ github.repository }}/metabase:${{ github.sha }}

- name: Install Terraform
uses: hashicorp/setup-terraform@dfe3c3f87815947d99a8997f908cb6525fc44e9e # v4.0.1
with:
Expand All @@ -85,9 +115,13 @@ jobs:
run: ./init.sh "${{ needs.setup.outputs.env_name }}"

- name: Terraform Plan
env:
TF_VAR_metabase_container_tag: ${{ github.sha }}
run: terraform plan -out=tfplan -lock-timeout=5m

- name: Terraform Apply
env:
TF_VAR_metabase_container_tag: ${{ github.sha }}
run: terraform apply -lock-timeout=5m tfplan

- name: Attach detailed summary to job
Expand All @@ -98,21 +132,20 @@ jobs:
skip-comment: true

release:
needs: [terraform-apply]
needs: [setup, terraform-apply]
if: ${{ needs.setup.outputs.is_release =='true' }}
runs-on: ubuntu-latest
permissions:
# https://github.com/softprops/action-gh-release#permissions
contents: write

steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0

- name: Release
uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3
uses: softprops/action-gh-release@e598afbe1493e6b1bafb1f389cabb956eab91231 # v3.0.3
with:
prerelease: false
generate_release_notes: true
38 changes: 23 additions & 15 deletions .github/workflows/terraform-plan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,39 +7,47 @@ on:
- "terraform/**"
- ".github/workflows/terraform-plan.yml"

defaults:
run:
shell: bash
working-directory: terraform

permissions:
id-token: write
contents: read
id-token: write
pull-requests: write

jobs:
terraform-plan:
runs-on: ubuntu-latest
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
defaults:
run:
working-directory: terraform

steps:
- name: Checkout
- name: Check out the repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Install Terraform
uses: hashicorp/setup-terraform@dfe3c3f87815947d99a8997f908cb6525fc44e9e # v4.0.1
- name: Get head SHA of main
id: get_main_sha
run: |
git fetch origin main --depth=1
MAIN_SHA=$(git rev-parse origin/main)
echo "sha=${MAIN_SHA}" >> $GITHUB_OUTPUT

- name: Authenticate to GCP
uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
with:
workload_identity_provider: ${{ secrets.GCP_WIF_PROVIDER }}
service_account: ${{ secrets.GCP_WIF_SERVICE_ACCOUNT }}

- name: Terraform Init
run: terraform init
- name: Setup Terraform
uses: hashicorp/setup-terraform@dfe3c3f87815947d99a8997f908cb6525fc44e9e # v4.0.1
with:
terraform_version: 1.16.6 # should match TF_VERSION in .devcontainer/Dockerfile

- name: Initialize Terraform and select workspace
run: ./init.sh prod

- name: Terraform Plan
run: terraform plan -out=tfplan
env:
TF_VAR_metabase_container_tag: ${{ steps.get_main_sha.outputs.sha }}
run: terraform plan -out=tfplan -lock-timeout=5m

- name: Setup tf-summarize
uses: kishaningithub/setup-tf-summarize@1596bb06f9509eb36b71bc1b304407cc111059c0 # v3.0.0
Expand All @@ -49,12 +57,12 @@ jobs:

- name: Check for existing comment
uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad # v4.0.0
id: fc
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: "github-actions[bot]"
body-includes: CHANGE
direction: last
id: fc

- name: Create or update PR comment with course-grained plan summary
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*.tfstate.*
*.tfvars
!terraform.tfvars.example
tfplan

# Python
__pycache__/
Expand Down
10 changes: 10 additions & 0 deletions bin/gcloud-auth.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
# auth to gcloud

set -euo pipefail

gcloud auth application-default login
gcloud auth application-default set-quota-project data-warehouse-492522

gcloud auth login
gcloud config set project data-warehouse-492522
6 changes: 3 additions & 3 deletions compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ services:
volumes:
- "./:/home/compiler/src"
metabase:
image: "metabase/metabase:v0.65.x"
container_name: "metabase"
build:
context: "./metabase"
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
Expand All @@ -48,7 +49,6 @@ services:
restart: "unless-stopped"
postgres:
image: "postgres:18-alpine"
container_name: "postgres"
environment:
POSTGRES_DB: "metabase"
POSTGRES_USER: "metabase"
Expand Down
4 changes: 2 additions & 2 deletions docs/explanation/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ flowchart TD
end

subgraph CloudRun ["Application Runtime"]
MB["Metabase OSS Container<br/>(metabase/metabase:vX.Y.Z)<br/>Min Instances: 1 | 2 GiB RAM"]
MB["Metabase Custom Container<br/>(socat TCP bridge)<br/>Min Instances: 1 | 2 GiB RAM"]
end

subgraph Storage_State ["Application State & Secrets"]
Expand All @@ -58,7 +58,7 @@ flowchart TD
GCS --> dbtRun
dbtRun -->|SQL Transformation| BQ

MB -->|Cloud SQL Connection Unix Socket| CSQL
MB -->|TCP localhost:5432 → socat bridge| CSQL
MB -.->|Fetch Secrets on Boot| SM
MB -->|Native IAM Auth / Zero Keys| BQ
SA -.->|Attached Identity| MB
Expand Down
5 changes: 4 additions & 1 deletion docs/reference/structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
├── .env.example # Sample local environment variables
├── .pre-commit-config.yaml # Conventional commits & file hygiene hooks
├── plan.md # Full architectural design & implementation plan
├── dbt/ # dbt project (models, macros, snapshots, profiles)
├── dbt/ # dbt project (models, macros, snapshots, profiles)
├── metabase/ # Custom Metabase image (socat TCP bridge)
│ ├── Dockerfile
│ └── entrypoint.sh
├── terraform/ # Infrastructure as Code (GCP Cloud Run & Cloud SQL)
└── README.md
```
8 changes: 8 additions & 0 deletions metabase/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FROM metabase/metabase:v0.65.2

RUN apk add --no-cache socat

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]
14 changes: 14 additions & 0 deletions metabase/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash
set -e

# Only start socat bridge if CLOUD_SQL_CONNECTION_NAME is set
if [ -n "$CLOUD_SQL_CONNECTION_NAME" ]; then
echo "Starting socat bridge: localhost:5432 → /cloudsql/$CLOUD_SQL_CONNECTION_NAME"
socat TCP-LISTEN:5432,fork,reuseaddr UNIX-CONNECT:/cloudsql/$CLOUD_SQL_CONNECTION_NAME &
sleep 1
else
echo "CLOUD_SQL_CONNECTION_NAME not set, skipping socat bridge"
fi

# Execute the original command (Metabase startup)
exec /app/run_metabase.sh "$@"
23 changes: 5 additions & 18 deletions plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,9 @@ Refer to [docs/reference/structure.md](docs/reference/structure.md) for the deta

---

## 4. Phase 1: Dev Container & Local Development
## 4. Production Configuration Details

Following the `compilerla` pattern:

- **`compose.yml`** orchestrates three services:
1. `dev`: VS Code developer container mounting the repository at `/home/compiler/src`, running as user `compiler`.
2. `metabase`: Official Metabase Docker container connected to local Postgres.
3. `postgres`: PostgreSQL 16 backing Metabase application state.
- **`.devcontainer/devcontainer.json`** configures VS Code extensions (`hashicorp.terraform`, `gitlens`, `prettier`, etc.) and sets the default terminal profile.
- **`.devcontainer/Dockerfile`** installs developer tools: Terraform/OpenTofu, Google Cloud CLI (`gcloud`), `pre-commit`, and Postgres client utilities.

---

## 5. Production Configuration Details

### 5.1 Cloud Run Sizing & Environment Variables
### 4.1 Cloud Run Sizing & Environment Variables

- **CPU & Memory**: 1 vCPU, 2 GiB RAM (can scale to 2 vCPU / 4 GiB if user concurrency grows).
- **Scaling Rules**: `min_instances = 1`, `max_instances = 3`.
Expand All @@ -68,15 +55,15 @@ Following the `compilerla` pattern:
- `MB_SITE_URL`: `https://dashboards.compiler.la`
- `JAVA_OPTS`: `"-Xmx1536m -Xms512m -XX:+UseG1GC"` (Allocates appropriate JVM heap within the 2 GiB container limit).

### 5.2 BigQuery Authentication
### 4.2 BigQuery Authentication

- Dedicated Service Account: `metabase-runner@data-warehouse-492522.iam.gserviceaccount.com`.
- IAM roles granted:
- `roles/bigquery.jobUser` (permits executing queries).
- `roles/bigquery.dataViewer` (permits reading analytical datasets/tables).
- `roles/cloudsql.client` (permits connecting to Cloud SQL via unix domain socket).

### 5.3 Ingress & Cloudflare DNS
### 4.3 Ingress & Cloudflare DNS

1. In GCP Cloud Run, configure Custom Domain Mapping for `dashboards.compiler.la`.
2. In Cloudflare DNS:
Expand All @@ -85,7 +72,7 @@ Following the `compilerla` pattern:

---

## 6. Phased Implementation Roadmap
## 5. Phased Implementation Roadmap

1. **Phase 1: Dev Container & Local Development**:
- Set up `.devcontainer/devcontainer.json`, `.devcontainer/Dockerfile`, `compose.yml`, and `.env.example`.
Expand Down
Loading
Loading