Skip to content

pasunboneleve/gcp-rust-blog-public

Repository files navigation

GCP Rust Blog CI/CD

From Commit to Production, Automatically

This repository is a small Rust web application designed so that every change flows from commit to production without manual intervention.

Infrastructure, CI/CD, and security are defined alongside the code and evolve with it as a single system. There are no hidden steps and no out-of-band processes.

The focus is not the technology itself, but the shape of the system: making correct change the path of least resistance.

Quick Start

Prerequisites

  • Rust for building and running the app locally. Install with rustup, which provides cargo and rustc.
  • devloop for the primary local development workflow. Install with cargo install --git https://github.com/pasunboneleve/devloop.git.
  • cloudflared for the shareable public tunnel used to validate social cards during local development. Install it from Cloudflare's package or binary distribution for your platform.
  • Node.js or Bun to install the Tailwind CLI.
  • Tailwind CLI for CSS compilation during local development. Install with npm install -g @tailwindcss/cli or the equivalent Bun workflow.
  • direnv to auto-load repo environment variables. Install it from your system package manager and run direnv allow in the repo.
  • bacon only if you want the fallback direct-repo workflow instead of devloop. Install with cargo install bacon.
  • Docker for containerization
  • gcloud CLI configured with your GCP project
  • OpenTofu/Terraform for infrastructure management

Configuration Setup

  1. Prepare deployment variables if you need them locally:

    cp .env.template .env
    # Edit .env with your actual GCP project values

    The checked-in .envrc does not automatically load .env. Use this file as a template for manual exports or extend your local direnv setup if you want it loaded automatically.

  2. Configure infrastructure variables:

    cp infra/prod.tfvars.template infra/prod.tfvars
    # Edit infra/prod.tfvars with your GCP project details

    📝 Template file: infra/prod.tfvars.template

  3. Create GitHub Personal Access Token:

    ⚠️ Important: Store this token securely - GitHub won't show it again!

Local Development

Recommended:

Primary local workflow:

direnv allow
devloop run

That gives you one supervised loop for Rust rebuilds, content-triggered server restarts, CSS recompilation, browser refresh notifications, and copy/paste-ready public post URLs for card validation.

Fallback direct-repo workflow:

# Terminal 1: Rust server with restart-on-change
bacon run

# Terminal 2: one-shot CSS build when needed
./scripts/build-css.sh

# Check and format code
cargo check
cargo fmt
cargo clippy

Content Management

  • Blog posts: Add Markdown files in content/posts/ as <slug>.md
  • Access posts: Visit /posts/<slug> in your browser
  • Site header: Customize content/banner.html for navigation and branding

Project Structure

├── src/                     # Axum app, content loading, markdown, metadata
├── content/
│   ├── banner.html          # Site header with navigation
│   ├── layout.html          # Shared page shell
│   ├── home.md              # Home page content
│   └── posts/
│       └── <slug>.md        # Blog post content
├── infra/                   # OpenTofu/Terraform infrastructure
├── .github/workflows/       # CI/CD automation
└── Dockerfile               # Multi-stage container build

Architecture

This project implements a cloud-native, security-first architecture:

  • Application: Modular Rust web server using Axum
  • Content: File-based blog posts in Markdown format
  • Rendering: Markdown, KaTeX math, Mermaid diagrams, and social metadata
  • Infrastructure: Fully managed with OpenTofu/Terraform
  • Deployment: Automated CI/CD with GitHub Actions and Workload Identity Federation
  • Security: Least-privilege service accounts and non-root containers
  • DNS: Managed through Google Cloud DNS with OpenTofu

At startup, the app loads site configuration, HTML templates, the home page, the 404 page, and post Markdown from content/. Requests are served from that loaded content plus static assets under content/static/.

Getting Started

To deploy your own instance:

  1. Fork this repository
  2. Configure infrastructure:
    cp infra/prod.tfvars.template infra/prod.tfvars
    # Edit infra/prod.tfvars with your GCP project details and GitHub token
  3. Deploy infrastructure:
    cd infra
    tofu init
    tofu apply -var-file="prod.tfvars"
    This automatically:
    • Sets up GCP Workload Identity Federation
    • Configures all required GitHub repository secrets
    • Provisions infrastructure components
  4. Deploy: Push to main branch triggers automatic deployment

CI/CD Build Modes

The deploy workflow uses two build modes:

  • Full build: Runs when application/infrastructure code changes. Builds and pushes:
    • :${GITHUB_SHA} (deploy image)
    • :app-base (binary/runtime base image)
  • Content-only build: Runs when all changed files are under content/.
    • Reuses :app-base
    • Builds a lightweight overlay image that only updates /app/content
    • Pushes :${GITHUB_SHA} and deploys it

If :app-base does not exist yet, the workflow automatically falls back to a full build and publishes it for future content-only deployments.

Documentation

Key Features

Infrastructure as Code - Everything managed with OpenTofu
Secure CI/CD - GitHub Actions with Workload Identity Federation
Least Privilege - Dedicated service accounts with minimal permissions
Automated DNS - Domain management through code
Container Security - Multi-stage builds, non-root containers
Observability - Structured logging with tracing
Faster content deploys - Content-only changes reuse a prebuilt app base image

Environment Configuration

  • PORT - Server port (default: 8080, required for Cloud Run)
  • RUST_LOG - Log level (default: "info")

License

This project is open source and available under the MIT License.

About

This isn’t a blog about systems. It’s a system that happens to be a blog.

Topics

Resources

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors