Container Apps
Deploy applications from source code. Basepod builds your Dockerfile and runs it as a container.
Overview
Container apps are built from your source code using a Dockerfile:
- Full control over your runtime environment
- Support for any language or framework
- Persistent storage with volumes
- Environment variable configuration
Quick Start
bash
cd my-project
bp init
bp deploybasepod.yaml:
yaml
name: my-app
type: container
port: 3000
build:
dockerfile: DockerfileDynamic Languages
Node.js
basepod.yaml:
yaml
name: my-node-app
type: container
port: 3000
build:
dockerfile: Dockerfile
env:
NODE_ENV: productionDockerfile:
dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "index.js"]Node.js with Bun
Dockerfile:
dockerfile
FROM oven/bun:1-alpine
WORKDIR /app
COPY package.json bun.lockb ./
RUN bun install --production
COPY . .
EXPOSE 3000
CMD ["bun", "run", "index.ts"]Express.js
Dockerfile:
dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]NestJS
Dockerfile:
dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/main.js"]Nuxt (SSR)
basepod.yaml:
yaml
name: my-nuxt-app
type: container
port: 3000
build:
dockerfile: Dockerfile
env:
NITRO_PRESET: node-serverDockerfile:
dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/.output ./.output
EXPOSE 3000
CMD ["node", ".output/server/index.mjs"]Next.js (SSR)
basepod.yaml:
yaml
name: my-next-app
type: container
port: 3000
build:
dockerfile: DockerfileDockerfile:
dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["npm", "start"]Python / Flask
basepod.yaml:
yaml
name: my-flask-app
type: container
port: 5000
build:
dockerfile: DockerfileDockerfile:
dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["gunicorn", "-b", "0.0.0.0:5000", "app:app"]Python / FastAPI
basepod.yaml:
yaml
name: my-fastapi-app
type: container
port: 8000
build:
dockerfile: Dockerfile
env:
PYTHONUNBUFFERED: "1"Dockerfile:
dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]Python / Django
Dockerfile:
dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN python manage.py collectstatic --noinput
EXPOSE 8000
CMD ["gunicorn", "myproject.wsgi:application", "-b", "0.0.0.0:8000"]Ruby on Rails
basepod.yaml:
yaml
name: my-rails-app
type: container
port: 3000
build:
dockerfile: Dockerfile
env:
RAILS_ENV: production
RAILS_LOG_TO_STDOUT: "true"Dockerfile:
dockerfile
FROM ruby:3.3-slim
RUN apt-get update && apt-get install -y build-essential libpq-dev nodejs
WORKDIR /app
COPY Gemfile Gemfile.lock ./
RUN bundle install --without development test
COPY . .
RUN bundle exec rake assets:precompile
EXPOSE 3000
CMD ["bundle", "exec", "puma", "-C", "config/puma.rb"]PHP / Laravel
basepod.yaml:
yaml
name: my-laravel-app
type: container
port: 80
build:
dockerfile: Dockerfile
env:
APP_ENV: productionDockerfile:
dockerfile
FROM php:8.3-fpm-alpine
RUN apk add --no-cache nginx supervisor
RUN docker-php-ext-install pdo pdo_mysql
WORKDIR /var/www/html
COPY . .
RUN composer install --no-dev --optimize-autoloader
COPY docker/nginx.conf /etc/nginx/nginx.conf
COPY docker/supervisord.conf /etc/supervisord.conf
EXPOSE 80
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]PHP / Symfony
Dockerfile:
dockerfile
FROM php:8.3-fpm-alpine
RUN apk add --no-cache nginx
RUN docker-php-ext-install pdo pdo_mysql opcache
WORKDIR /var/www/html
COPY . .
RUN composer install --no-dev --optimize-autoloader
RUN php bin/console cache:clear --env=prod
EXPOSE 80
CMD ["php-fpm"]Compiled Languages
Go
basepod.yaml:
yaml
name: my-go-app
type: container
port: 8080
build:
dockerfile: DockerfileDockerfile:
dockerfile
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o main .
FROM alpine:latest
RUN apk --no-cache add ca-certificates
COPY --from=builder /app/main /main
EXPOSE 8080
CMD ["/main"]Go / Fiber
Dockerfile:
dockerfile
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o main .
FROM scratch
COPY --from=builder /app/main /main
EXPOSE 3000
CMD ["/main"]Rust
basepod.yaml:
yaml
name: my-rust-app
type: container
port: 8080
build:
dockerfile: DockerfileDockerfile:
dockerfile
FROM rust:1.75-alpine AS builder
RUN apk add --no-cache musl-dev
WORKDIR /app
COPY . .
RUN cargo build --release
FROM alpine:latest
COPY --from=builder /app/target/release/myapp /myapp
EXPOSE 8080
CMD ["/myapp"].NET / ASP.NET Core
basepod.yaml:
yaml
name: my-dotnet-app
type: container
port: 8080
build:
dockerfile: Dockerfile
env:
ASPNETCORE_URLS: http://+:8080
ASPNETCORE_ENVIRONMENT: ProductionDockerfile:
dockerfile
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY *.csproj ./
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY --from=build /app .
EXPOSE 8080
CMD ["dotnet", "MyApp.dll"]Java / Spring Boot
basepod.yaml:
yaml
name: my-spring-app
type: container
port: 8080
build:
dockerfile: Dockerfile
env:
JAVA_OPTS: "-Xmx512m"Dockerfile:
dockerfile
FROM eclipse-temurin:21-jdk-alpine AS builder
WORKDIR /app
COPY . .
RUN ./mvnw package -DskipTests
FROM eclipse-temurin:21-jre-alpine
COPY --from=builder /app/target/*.jar app.jar
EXPOSE 8080
CMD ["java", "-jar", "app.jar"]Elixir / Phoenix
basepod.yaml:
yaml
name: my-phoenix-app
type: container
port: 4000
build:
dockerfile: Dockerfile
env:
MIX_ENV: prod
SECRET_KEY_BASE: ${SECRET_KEY_BASE}Dockerfile:
dockerfile
FROM elixir:1.16-alpine AS builder
RUN apk add --no-cache build-base npm
WORKDIR /app
ENV MIX_ENV=prod
COPY mix.exs mix.lock ./
RUN mix deps.get --only prod
COPY . .
RUN mix assets.deploy
RUN mix release
FROM alpine:latest
RUN apk add --no-cache libstdc++ openssl ncurses-libs
WORKDIR /app
COPY --from=builder /app/_build/prod/rel/myapp ./
EXPOSE 4000
CMD ["bin/myapp", "start"]Configuration Options
Environment Variables
yaml
name: my-app
type: container
port: 3000
env:
DATABASE_URL: postgres://localhost/mydb
API_KEY: ${API_KEY} # From shell
DEBUG: "false"Volumes (Persistent Storage)
yaml
name: my-app
type: container
port: 3000
volumes:
- data:/app/data
- uploads:/app/uploadsResource Limits
yaml
name: my-app
type: container
port: 3000
resources:
memory: 512m
cpus: 1.0Build Arguments
yaml
name: my-app
type: container
port: 3000
build:
dockerfile: Dockerfile
args:
NODE_ENV: production
API_URL: https://api.example.comIgnored Files
These are automatically excluded from uploads:
.git/node_modules/.env,.env.local__pycache__/,*.pycvendor/(PHP)target/(Rust, Java).next/,.nuxt/,.output/
Add custom ignores in .basepodignore:
*.log
tmp/
coverage/Deploying Updates
bash
# Make changes
git add . && git commit -m "Update"
# Deploy
bp deployBasepod will:
- Build a new image
- Stop the old container
- Start the new container
- Clean up old images