Skip to main content
CleanStart

Knowledge Hub

Migrating from Bitnami to CleanStart

Drop-in replacement guide for smooth migration from Bitnami to CleanStart container images.

Why Migrate from Bitnami?

Security Improvements

CleanStart offers faster patching with CVEs addressed in days rather than weeks, a minimal footprint with a smaller attack surface and fewer packages, transparent sourcing with supply chain clarity and verification, and compliance-ready variants including FIPS support for regulated environments.

Cost Reduction

Smaller images enable faster pulls and consume less storage, lower resource usage optimizes for container environments, reduced egress decreases bandwidth costs, and community-driven open-source eliminates the need for commercial licenses.

Operational Simplicity

All CleanStart images follow consistent patterns and conventions, better documentation provides language and framework-specific guides, language-native tooling works with npm, pip, Maven, cargo, and other package managers, and Kubernetes-friendly design is optimized for cloud-native deployments.

Quick Comparison

Aspect

Bitnami

CleanStart

CVE patching

7-14 days

1-3 days

Image size

400-800 MB

150-400 MB

Non-root user

Yes

Yes

Health checks

Basic

Pre-configured

FIPS support

Extra fee

Variant available

Cost

Subscription

Free

Community

Commercial

Open

The 30-Second Swap: Helm Charts

If you're using Bitnami Helm charts, the migration is trivial. The following diagram illustrates the Helm-based Bitnami to CleanStart migration flow:

graph TD    A["Running Bitnami<br/>Helm Release<br/>postgres:15"] -->|Current| B["docker.io/<br/>bitnami/<br/>postgresql:15"]     A -->|Upgrade| C["Update values.yaml"]     C -->|Change| D["image.repository<br/>bitnami/postgresql →<br/>cleanstart/postgresql"]     C -->|Update| E["image.tag<br/>15 → 16<br/>Optional"]     D -->|Execute| F["helm upgrade<br/>my-release<br/>my-chart"]     E -->|Execute| F     F -->|Pull| G["docker.io/<br/>cleanstart/<br/>postgresql:16"]     G -->|Replace| H["Rolling Update<br/>Old Pod"]     H -->|Drain| I["Pod Evicted"]     I -->|New| J["New Pod<br/>CleanStart<br/>Image"]     J -->|Ready| K["Pod Running<br/>CleanStart"]     K -->|Verify| L["Health Check<br/>Database Ready"]     L -->|Success| M["Migration<br/>Complete<br/>30 seconds"]     B -->|Compare| N["Bitnami<br/>400-800 MB<br/>7-14 day patches<br/>Commercial"]     G -->|Compare| O["CleanStart<br/>150-400 MB<br/>1-3 day patches<br/>Free"]     M -->|Benefits| P["Smaller Size<br/>Faster Patching<br/>Lower Cost"]     style A fill:#ffcccc    style C fill:#ffff99    style F fill:#ffff99    style G fill:#ccffcc    style M fill:#99ff99    style P fill:#99ff99

If you're using Bitnami Helm charts, the migration is trivial.

Step 1: Update values.yaml

# Before (Bitnami)image:  registry: docker.io  repository: bitnami/postgresql  tag: "15" # After (CleanStart)image:  registry: docker.io  repository: cleanstart/postgresql  tag: "16"

Step 2: Deploy

helm upgrade my-release my-chart \    -f values.yaml

That's it! The Helm chart is compatible.

Language-Specific Migrations

Node.js Migration

Before (Bitnami):

FROM bitnami/node:18 COPY . .RUN npm install --production

After (CleanStart):

FROM cleanstart/node:20 COPY . .RUN npm install --production

Test:

docker build -t myapp:new .docker run --rm myapp:new node -v          # Check versiondocker run --rm myapp:new npm -v           # Check npm

Python Migration

Before (Bitnami):

FROM bitnami/python:3.11 COPY requirements.txt .RUN pip install -r requirements.txtCOPY . .

After (CleanStart):

FROM cleanstart/python:3.12 COPY requirements.txt .RUN pip install -r requirements.txtCOPY . .

Java Migration

Before (Bitnami):

FROM bitnami/java:17 COPY target/*.jar app.jar

After (CleanStart):

FROM cleanstart/java:21 COPY target/*.jar app.jar

PostgreSQL Migration

Before (Bitnami):

docker run -d \    -e POSTGRESQL_USERNAME=user \    -e POSTGRESQL_PASSWORD=password \    -e POSTGRESQL_DATABASE=mydb \    bitnami/postgresql:15

After (CleanStart):

docker run -d \    -e POSTGRES_USER=user \    -e POSTGRES_PASSWORD=password \    -e POSTGRES_DB=mydb \    cleanstart/postgresql:16

Redis Migration

Before (Bitnami):

docker run -d \    -e REDIS_PASSWORD=password \    bitnami/redis:7

After (CleanStart):

docker run -d \    -e REDIS_PASSWORD=password \    cleanstart/redis:7.2

Environment Variable Mapping

CleanStart uses standard environment variables (not Bitnami's custom ones):

PostgreSQL

Bitnami

CleanStart

Usage

POSTGRESQL_USERNAME

POSTGRES_USER

DB user

POSTGRESQL_PASSWORD

POSTGRES_PASSWORD

DB password

POSTGRESQL_DATABASE

POSTGRES_DB

Default database

MySQL

Bitnami

CleanStart

Usage

MYSQL_ROOT_PASSWORD

MYSQL_ROOT_PASSWORD

Root password

MYSQL_USER

MYSQL_USER

Regular user

MYSQL_PASSWORD

MYSQL_PASSWORD

User password

MYSQL_DATABASE

MYSQL_DATABASE

Default database

MongoDB

Bitnami

CleanStart

Usage

MONGODB_USERNAME

MONGO_INITDB_ROOT_USERNAME

Root user

MONGODB_PASSWORD

MONGO_INITDB_ROOT_PASSWORD

Root password

MONGODB_DATABASE

MONGO_INITDB_DATABASE

Default database

Step-by-Step Migration

Phase 1: Testing (1-2 days)

# Step 1: Create test container with CleanStart imagedocker pull cleanstart/postgresql:16docker run -d --name postgres-test \    -e POSTGRES_USER=testuser \    -e POSTGRES_PASSWORD=testpass \    -e POSTGRES_DB=testdb \    cleanstart/postgresql:16 # Step 2: Wait for startupsleep 5 # Step 3: Test connectivitydocker exec postgres-test psql -U testuser -d testdb -c "SELECT version();" # Step 4: Verify data restoration (if migrating existing data)docker exec postgres-test pg_restore -U testuser -d testdb /backup/dump.sql # Step 5: Run queriesdocker exec postgres-test psql -U testuser -d testdb -c "SELECT COUNT(*) FROM users;" # Step 6: Check disk usagedocker inspect postgres-test | jq '.[0].Size'

Phase 2: Staging Deployment (3-5 days)

Create docker-compose.yml for staging:

version: '3.9'services:  postgres:    image: cleanstart/postgresql:16    container_name: postgres-staging    environment:      POSTGRES_USER: ${DB_USER}      POSTGRES_PASSWORD: ${DB_PASSWORD}      POSTGRES_DB: ${DB_NAME}    ports:      - "5433:5432"    volumes:      - postgres-staging-data:/var/lib/postgresql/data      - ./init.sql:/docker-entrypoint-initdb.d/init.sql    healthcheck:      test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"]      interval: 10s      timeout: 5s      retries: 5 volumes:  postgres-staging-data:

Deploy and validate:

docker-compose -f docker-compose.yml up -d# Run integration tests against staging./integration-tests.sh --environment staging

Phase 3: Production Migration (1 day)

For RDB (Redis) or In-Memory Caches

# No data persistence neededdocker stop redis-olddocker rm redis-olddocker run -d \    --name redis-new \    -p 6379:6379 \    cleanstart/redis:7.2

For Databases with Persistent Data

# Step 1: Create backup of Bitnami databasedocker exec bitnami-postgres pg_dump -U user mydb > backup.sql # Step 2: Start CleanStart containerdocker run -d \    --name postgres-new \    -e POSTGRES_USER=user \    -e POSTGRES_PASSWORD=password \    -e POSTGRES_DB=mydb \    -v postgres-new-data:/var/lib/postgresql/data \    cleanstart/postgresql:16 # Step 3: Wait for startupsleep 10 # Step 4: Restore datadocker exec -i postgres-new psql -U user -d mydb < backup.sql # Step 5: Verify data integritydocker exec postgres-new psql -U user -d mydb -c "SELECT COUNT(*) FROM users;" # Step 6: Switch traffic (update connection strings)# Update app config to point to postgres-new # Step 7: Stop old containerdocker stop bitnami-postgres

Zero-Downtime Migration with Replication

For critical databases, use replication:

# Step 1: Configure Bitnami as masterdocker exec bitnami-postgres psql -U user -c \    "ALTER USER replicator WITH REPLICATION PASSWORD 'reppassword';" # Step 2: Start CleanStart as replicadocker run -d \    --name postgres-replica \    -e PGUSER=replicator \    -e PGPASSWORD=reppassword \    cleanstart/postgresql:16 \    pg_basebackup -h bitnami-postgres-ip -D /var/lib/postgresql/data -U replicator # Step 3: Monitor replication lagdocker exec postgres-replica psql -U replicator -c \    "SELECT slot_name, slot_type, active FROM pg_replication_slots;" # Step 4: Promote replica to masterdocker exec postgres-replica psql -U postgres -c "SELECT pg_promote();" # Step 5: Update connection strings and stop old master

Troubleshooting Migration Issues

Issue: Connection Refused

Problem: Application can't connect to new CleanStart container

Solution:

# Verify container is runningdocker ps | grep cleanstart # Check port mappingdocker inspect mydb | jq '.[0].NetworkSettings.Ports' # Test connectivitydocker exec mydb nc -zv localhost 5432

Issue: Data Corruption

Problem: Data doesn't match between Bitnami and CleanStart

Solution:

# Export data from both containersdocker exec bitnami-db pg_dump -U user mydb > bitnami.sqldocker exec cleanstart-db pg_dump -U user mydb > cleanstart.sql # Compare schemasdiff <(grep "^CREATE" bitnami.sql) <(grep "^CREATE" cleanstart.sql) # Compare row countsdocker exec bitnami-db psql -U user -d mydb -c "SELECT COUNT(*) FROM users;"docker exec cleanstart-db psql -U user -d mydb -c "SELECT COUNT(*) FROM users;"

Issue: Performance Degradation

Problem: CleanStart container runs slower than Bitnami

Solution:

# Check resource limitsdocker inspect cleanstart-db | jq '.[0].HostConfig.Memory' # Monitor CPU and memorydocker stats cleanstart-db # Compare performance# Bitnami testdocker exec bitnami-db psql -U user -d mydb -c "EXPLAIN ANALYZE SELECT * FROM large_table;" # CleanStart testdocker exec cleanstart-db psql -U user -d mydb -c "EXPLAIN ANALYZE SELECT * FROM large_table;"

Issue: Configuration Incompatibility

Problem: Bitnami config options don't work with CleanStart

Solution:

# Check available environment variablesdocker run --rm cleanstart/postgresql:16 env | grep POSTGRES # Compare with Bitnami documentation# Use standard PostgreSQL configuration instead of Bitnami's custom vars # For advanced config, mount postgresql.confdocker run -d \    -v ./postgresql.conf:/etc/postgresql/postgresql.conf \    cleanstart/postgresql:16 \    postgres -c config_file=/etc/postgresql/postgresql.conf

Kubernetes Migration

Update Deployments

# Current Bitnami deploymentkubectl set image deployment/postgres \    postgres=docker.io/bitnami/postgresql:15 # Migrate to CleanStartkubectl set image deployment/postgres \    postgres=docker.io/cleanstart/postgresql:16 --record

Update StatefulSets

# BeforeapiVersion: apps/v1kind: StatefulSetmetadata:  name: postgresspec:  template:    spec:      containers:      - name: postgres        image: bitnami/postgresql:15 # AfterapiVersion: apps/v1kind: StatefulSetmetadata:  name: postgresspec:  template:    spec:      containers:      - name: postgres        image: cleanstart/postgresql:16

Apply changes:

kubectl apply -f statefulset.yamlkubectl rollout status statefulset/postgres

Helm Chart Update

# Update values for Bitnami chart to use CleanStart imagehelm upgrade my-release bitnami/postgresql \    --set image.repository=cleanstart/postgresql \    --set image.tag=16 \    --set image.registry=docker.io # Or use custom valuescat > values.yaml <<EOFimage:  registry: docker.io  repository: cleanstart/postgresql  tag: "16"EOF helm upgrade my-release bitnami/postgresql -f values.yaml

Post-Migration Validation

# Verify imagedocker inspect myservice | grep -i image # Confirm versiondocker exec myservice postgres --versiondocker exec myservice redis-server --version # Check userdocker exec myservice id# Should output: uid=1000(appuser) gid=1000(appuser)... # Verify persistent volumedocker volume ls | grep myservice # Monitor logsdocker logs -f myservice # Load testing./load-test.sh myservice 1000 requests

Rollback Plan

If issues occur after migration:

# Quick rollbackdocker stop postgres-newdocker run -d --name postgres-old \    -v postgres-old-data:/var/lib/postgresql/data \    bitnami/postgresql:15 # Or for Kuberneteskubectl rollout undo deployment/postgres

Cost Comparison

Before (Bitnami)

Bitnami license:     $1,000/yearImage size (500 MB × 3 services):  Large egress costsLarger containers:   More memory/CPU neededStorage overhead:    5 GB total

After (CleanStart)

CleanStart license:  Free (open source)Image size (200 MB × 3 services):  Reduced egressSmaller containers:  Less memory/CPUStorage overhead:    2 GB total Total savings: $1,000+ year, 30% reduced resource usage

Migration Timeline

Phase

Duration

Tasks

Planning

3-5 days

Assess services, create plan

Testing

3-5 days

Local and staging testing

Staging

3-5 days

Deploy to staging, validate

Production

1-2 days

Execute migration, monitor

Validation

7 days

Monitor metrics, resolve issues

Total

2-3 weeks

Complete migration of 5-10 services

Support Resources

Language Getting Started Guides. Application Setup Guides. Troubleshooting Guide. Bitnami Helm Values Reference — Comprehensive mapping of Bitnami chart values for configuration compatibility.

Next Steps

  1. Choose your first service for migration
  2. Follow the language-specific getting-started guide
  3. Test thoroughly in staging
  4. Execute production migration
  5. Monitor for 7 days
  6. Document lessons learned