Why Containerize an Existing App?
Most containerization guides assume you're starting fresh. In reality, you're more likely to have an existing application — a Node.js API, a Python Flask service, a Ruby on Rails app — that you need to package into a Docker container so it can run consistently across environments and deploy to modern cloud platforms.
This guide walks you through the process systematically, covering the most common languages and pitfalls.
Step 1: Understand What Your App Needs
Before writing a Dockerfile, answer these questions:
- What runtime does it need? (Node.js 20, Python 3.12, Ruby 3.3...)
- What system dependencies does it have? (ImageMagick, libpq, ffmpeg...)
- What ports does it listen on?
- What environment variables does it expect?
- Does it write to the local filesystem? (uploads, caches, logs)
- How do you start it in production? (
node server.js,gunicorn app:app...)
Document the answers — your Dockerfile is essentially the answer to all these questions in code.
Step 2: Choose a Base Image
Pick an official base image matching your runtime. Prefer Alpine variants for smaller images:
| Runtime | Recommended Base Image |
|---|---|
| Node.js | node:20-alpine |
| Python | python:3.12-alpine |
| Ruby | ruby:3.3-alpine |
| Go | golang:1.22-alpine (builder) + scratch (runtime) |
| PHP | php:8.3-fpm-alpine |
Step 3: Write the Dockerfile
Node.js Application
FROM node:20-alpine
# Install system deps if needed (e.g., for canvas, sharp, etc.)
RUN apk add --no-cache libc6-compat
WORKDIR /app
# Copy and install dependencies first (cache optimization)
COPY package*.json ./
RUN npm ci --only=production
# Copy application source
COPY . .
# Create a non-root user and switch to it
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
EXPOSE 3000
CMD ["node", "server.js"]Python (Flask/FastAPI) Application
FROM python:3.12-alpine
RUN apk add --no-cache gcc musl-dev libffi-dev
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
EXPOSE 8000
CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:8000", "--workers", "4"]Step 4: Create .dockerignore
Always create this before your first build:
# Node.js
node_modules
npm-debug.log
# Python
__pycache__
*.pyc
.venv
venv
# Common
.git
.env
*.env
.DS_Store
*.log
coverage
.pytest_cache
dist
buildStep 5: Build and Test Locally
# Build the image
docker build -t my-existing-app:local .
# Run it with environment variables from your .env file
docker run -d -p 3000:3000 --env-file .env --name my-app-test my-existing-app:local
# Check logs
docker logs -f my-app-test
# Test it
curl http://localhost:3000/healthStep 6: Handle Common Issues
"Module not found" / "Package not installed"
Your .dockerignore might be excluding files needed for the build, or you have platform-specific native modules compiled on your host.
# Rebuild inside the container to ensure platform compatibility
docker run --rm -v $(pwd):/app -w /app node:20-alpine npm ciApp can't connect to the database
Inside a container, localhost refers to the container itself, not your host machine. Use host.docker.internal (Docker Desktop) or a Docker Compose service name:
# Development: reach host machine's database
DATABASE_URL=postgres://user:pass@host.docker.internal:5432/mydbFile permission errors
When switching to a non-root user, ensure your app's directories are owned correctly:
RUN mkdir -p /app/uploads && chown appuser:appgroup /app/uploads
USER appuserStep 7: Deploy to PandaStack
Once your container runs locally, push your code to GitHub and deploy:
npm install -g @pandastack/cli
panda login
panda deploy --type container --repo your-org/your-repoPandaStack builds your image directly from the Dockerfile in your repository — no need to push to an external registry. Set your environment variables from [dashboard.pandastack.io](https://dashboard.pandastack.io) and connect to managed databases (PostgreSQL, MySQL, Redis, MongoDB) provisioned by the platform.
Your containerized app goes from a GitHub push to a live HTTPS endpoint. For the full deployment guide, visit [docs.pandastack.io](https://docs.pandastack.io).