DEV Community

Gus
Gus

Posted on

CapsuleBay: Hybrid CI/CD for People Who Like Their Containers a Little Too Much

“Where each service carries its own deployment logic.”

Build once. Scan everywhere. Deploy with confidence.

CapsuleBay Diagram


💡 The Short Version

CapsuleBay is a self-contained hybrid CI/CD framework I built because I got tired of my homelab breaking every time I breathed near it.

Instead of having one giant deployment script or cloud pipeline that does everything (and fails spectacularly), CapsuleBay lets each service carry its own deployment logic.

Every app becomes a deployment capsule — a small Docker image that contains its own docker-compose.yml, configuration, and brain.

You push your code → CapsuleBay builds it, scans it for vulnerabilities, fetches secrets just-in-time, deploys it to your self-hosted environment, and even pings you on Discord when it’s done.


🧠 The Core Idea

In most setups, you’ve got a big centralized CI/CD pipeline trying to handle multiple apps at once — full of conditionals, shared scripts, and “if environment == prod” nightmares.

CapsuleBay flips that model.

Each app lives in its own folder (called a capsule) with:

  • A Dockerfile
  • A docker-compose.yml

That capsule knows how to build and deploy itself, wherever you throw it — like a portable mini-infrastructure.

No shared scripts. No tangled YAMLs. No “why does this only work on staging?” energy.


☁️ The Hybrid CI/CD Setup

CapsuleBay runs across two layers — one in the cloud for validation, one local for deployment.

1️⃣ GitHub Actions – Cloud Validation

This stage makes sure everything’s safe to deploy.

  • Builds each capsule image
  • Runs Trivy and Snyk scans for vulnerabilities
  • Uploads scan reports to GitHub for traceability

2️⃣ Jenkins – Self-Hosted Deployment

This stage actually does the heavy lifting.

  • Builds and pushes verified images to a local registry
  • Fetches secrets Just-In-Time from HashiCorp Vault (no stored .env files!)
  • Wakes target VMs using the Proxmox API
  • Deploys the capsule using its embedded docker-compose.yml
  • Sends status updates to Discord with timestamps and duration

🔐 What “Just-In-Time” Secrets Mean

CapsuleBay doesn’t keep secrets around — it borrows them.

When a deployment starts, Jenkins asks HashiCorp Vault for the credentials needed by that app (like API tokens or DB passwords). Vault hands them over temporarily — Jenkins injects them into the container, then deletes them the moment deployment finishes.

The token Vault gives Jenkins also expires immediately after use, so even if someone snoops around later, there’s nothing left to find.

Think of it like a one-time key that unlocks the door, lets you deploy, then melts in your hand.


🐾 Explained by Cats

Imagine you have three cats:

  • N8N
  • Portainer
  • WhoAmI

In a normal setup, you’d have to chase each cat around the house with a brush, food, and collar every time it’s feeding time (that’s you writing endless bash scripts).

With CapsuleBay, each cat carries its own backpack:

  • Bowl (Dockerfile)
  • Meal plan (docker-compose.yml)
  • Key to the house (Vault secret, fetched only when needed)

When dinner time (deployment) comes, Jenkins yells:

“Alright, everyone to your stations.”

Each cat runs to its corner, fetches its one-time key, eats, and texts you on Discord when it’s full.

CapsuleBay Deployment notification

When done, the key evaporates — no one else can reuse it.

That’s CapsuleBay. 🐱💻


🧰 What’s Under the Hood

Layer What It Does Tool
GitHub Actions Validates builds & runs security scans Trivy + Snyk
Jenkins Handles self-hosted deployments Jenkinsfile
Vault Issues one-time, Just-In-Time secrets HashiCorp Vault
Proxmox API Powers on target VMs automatically Proxmox
Discord Webhook Sends real-time notifications Discord

Flowchart:
CapsuleBay Flowchart


🧩 Why It’s Cool

Problem CapsuleBay’s Fix
Shared pipeline chaos Each service carries its own logic
Rebuilding the same image repeatedly Immutable capsule images
Leaky .env files Vault injects secrets JIT
Manual server babysitting Jenkins powers on VMs automatically
No deployment visibility Discord notifications with time and status

🧪 Real Example

n8n/Dockerfile

FROM docker:27.0.3-cli-alpine3.20
RUN apk add --no-cache docker-cli-compose bash
WORKDIR /app
COPY . /app
ARG LAN_IP
ENV LAN_IP=$LAN_IP
CMD ["docker", "compose", "up", "-d"]
Enter fullscreen mode Exit fullscreen mode

n8n/docker-compose.yml

version: "3.9"
services:
  n8n:
    image: n8nio/n8n:latest
    ports:
      - "5678:5678"
    env_file:
      - .env
Enter fullscreen mode Exit fullscreen mode

When the image is built, it contains its own compose file — so it can deploy itself anywhere, anytime.

The .env file gets injected at runtime from Vault and is wiped immediately after use.


🪶 Adding a New Capsule

Adding a new service is simple:

  1. Create a folder like myservice/
  2. Add a Dockerfile and docker-compose.yml
  3. Add the folder name to Jenkins parameters

That’s it. CapsuleBay takes care of the rest — build, scan, and deploy — automatically.


🧭 Why It Actually Works

CapsuleBay quietly blends solid DevOps principles with homelab practicality:

  • Immutable builds (every image is versioned)
  • Just-in-Time secrets (no long-term credentials)
  • Auditable deploys (Discord logs every step)
  • Offline-friendly (no cloud dependency)

It’s basically Kubernetes for people who don’t want Kubernetes.


🚀 TL;DR

CapsuleBay makes deployments behave like collectible trading cards.

Each capsule has everything it needs to play itself — I just tell Jenkins which ones to summon.

It’s not corporate-scale DevOps. It’s homelab discipline meets automation freedom.


Built by @gustav0thethird

“Hold my beer, I am deploying.”

Top comments (0)