惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

MongoDB | Blog
MongoDB | Blog
大猫的无限游戏
大猫的无限游戏
H
Help Net Security
V
Visual Studio Blog
G
Google Developers Blog
Blog — PlanetScale
Blog — PlanetScale
Last Week in AI
Last Week in AI
C
Check Point Blog
D
Docker
M
MIT News - Artificial intelligence
P
Proofpoint News Feed
博客园 - 叶小钗
博客园 - 聂微东
The Cloudflare Blog
云风的 BLOG
云风的 BLOG
Martin Fowler
Martin Fowler
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
酷 壳 – CoolShell
酷 壳 – CoolShell
MyScale Blog
MyScale Blog
WordPress大学
WordPress大学
Engineering at Meta
Engineering at Meta
腾讯CDC
S
SegmentFault 最新的问题
博客园 - 【当耐特】

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
From Docker Compose on My Laptop to OKE in Production — S...
Pavan Maddur · 2026-05-12 · via DEV Community

I have a rule: if I can't run the full stack on my laptop with docker compose up, the architecture is too complicated.

But then you need to deploy to production, and suddenly you're rewriting everything as Kubernetes manifests. The Compose file that worked on your machine is useless. Config lives in two places and they drift apart.

Here's the workflow I settled on after trying a bunch of things that didn't work well.

The Local Stack

Standard web app — API, Redis, Postgres. Three services.

# docker-compose.yml
services:
  api:
    build: .
    ports:
      - "8080:8080"
    environment:
      - DATABASE_URL=postgres://app:secret@db:5432/myapp
      - REDIS_URL=redis://cache:6379
    depends_on:
      db:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 10s

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: myapp
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "app"]

  cache:
    image: redis:7-alpine

volumes:
  pgdata:

Enter fullscreen mode Exit fullscreen mode

docker compose up and the full stack is running. No external dependencies, fast iteration.

What I Tried and Abandoned

Komposekompose convert technically works but the output is ugly. Tons of annotations, weird formatting, needs so much cleanup I might as well write the YAML by hand.

Docker Compose on Kubernetes — Various tools that try to run Compose files directly on K8s. They all add complexity and break in subtle ways.

Trying to share one config — I wasted a weekend trying to make the same file work for both. Local dev and production have genuinely different requirements. Pretending otherwise creates worse problems.

What Actually Works: Convention Over Tooling

I keep two config sets, aligned by convention:

project/
├── docker-compose.yml          # Local dev
├── Dockerfile
├── k8s/
│   ├── base/
│   │   ├── deployment.yaml
│   │   ├── service.yaml
│   │   └── kustomization.yaml
│   └── overlays/
│       ├── staging/
│       └── production/
└── Makefile

Enter fullscreen mode Exit fullscreen mode

Same image names, same env var names, same port numbers in both places. When I change a port in Compose, I grep for it in k8s/ and update it. Manual, but nothing breaks silently.

The key differences between local and OKE:

  • Database — Container locally, OCI managed service in production. I don't run databases on K8s.
  • Secrets — Plain text in Compose, OCI Vault via External Secrets Operator on OKE.
  • Scaling — One replica locally, HPA on OKE.

The K8s Side

# k8s/base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
spec:
  replicas: 2
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
        - name: api
          image: iad.ocir.io/mytenancy/myapp:latest
          ports:
            - containerPort: 8080
          envFrom:
            - secretRef:
                name: app-secrets
          readinessProbe:
            httpGet:
              path: /health
              port: 8080
            periodSeconds: 10

Enter fullscreen mode Exit fullscreen mode

Kustomize overlays handle the per-environment differences:

# k8s/overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: production
resources:
  - ../../base
images:
  - name: iad.ocir.io/mytenancy/myapp
    newTag: v1.2.3

Enter fullscreen mode Exit fullscreen mode

The Alignment Check I Actually Use

# Makefile
dev:
    docker compose up --build

build:
    docker build -t iad.ocir.io/$(TENANCY)/myapp:$(TAG) .
    docker push iad.ocir.io/$(TENANCY)/myapp:$(TAG)

deploy-staging:
    kubectl apply -k k8s/overlays/staging

check-alignment:
    @echo "=== Compose ports ===" && grep -A1 "ports:" docker-compose.yml
    @echo "=== K8s ports ===" && grep "containerPort" k8s/base/deployment.yaml
    @echo "=== Compose health ===" && grep "test:" docker-compose.yml
    @echo "=== K8s health ===" && grep "path:" k8s/base/deployment.yaml

Enter fullscreen mode Exit fullscreen mode

make check-alignment is dumb but it catches drift. I run it before every deploy. It's saved me twice already from deploying with mismatched health check paths.

The Honest Take

This isn't elegant. I'd love a single config file that works everywhere. But every tool I tried to achieve that added more complexity than it removed.

The current setup is boring and it works. Compose for local, Kustomize for OKE, same Docker image, same env var names, a Makefile to keep me honest. I understand every piece of it, and when something breaks at 2am, that matters more than elegance.


Pavan Madduri — Oracle ACE Associate, CNCF Golden Kubestronaut. GitHub | LinkedIn | Website | Google Scholar | ResearchGate