Skip to main content
Docker provides a consistent way to package and deploy your mock APIs. This guide shows you how to containerize Apicentric services for local development, CI/CD, and production environments.

Why use Docker

  • Consistency: Same environment across development, testing, and production
  • Isolation: Services run independently without conflicting dependencies
  • Portability: Easy to share and deploy across different machines
  • CI/CD integration: Simple to run in automated pipelines

Quick start

The fastest way to run Apicentric in Docker:
docker run -p 8080:8080 -v $(pwd)/services:/app/services apicentric/apicentric:latest

Basic Dockerfile

Create a Dockerfile for your mock services:
Dockerfile
FROM debian:bookworm-slim

# Install runtime dependencies
RUN apt-get update && apt-get install -y \
    ca-certificates \
    libssl3 \
    curl \
    && rm -rf /var/lib/apt/lists/*

# Install Apicentric
RUN curl -fsSL https://raw.githubusercontent.com/pmaojo/apicentric/main/scripts/install.sh | sh

# Create directories
WORKDIR /app
RUN mkdir -p /app/services /app/data

# Copy service definitions
COPY services/ /app/services/

# Set environment variables
ENV APICENTRIC_PORT=8080
ENV APICENTRIC_HOST=0.0.0.0
ENV RUST_LOG=info,apicentric=debug

# Expose port
EXPOSE 8080

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:8080/health || exit 1

# Start simulator
CMD ["apicentric", "simulator", "start", "--services-dir", "/app/services"]
1
Create your service directory
2
mkdir -p services
cat > services/api.yaml << EOF
name: my-api
server:
  port: 8080
  base_path: /api
endpoints:
  - method: GET
    path: /health
    responses:
      200:
        content_type: application/json
        body: '{"status": "healthy"}'
EOF
3
Build the image
4
docker build -t my-mock-api .
5
Run the container
6
docker run -p 8080:8080 my-mock-api
7
Test it
8
curl http://localhost:8080/api/health

Multi-stage build

For production deployments, use a multi-stage build to include both the Rust backend and WebUI:
Dockerfile.production
# Stage 1: Build Frontend
FROM node:22-alpine AS frontend-builder
WORKDIR /app/webui

# Copy package files
COPY webui/package*.json ./
RUN npm ci

# Copy frontend source
COPY webui/ ./

# Build Next.js application
RUN npm run build

# Stage 2: Build Backend
FROM rust:1.92-bookworm AS backend-builder
WORKDIR /app

# Install build dependencies
RUN apt-get update && apt-get install -y \
    pkg-config \
    libssl-dev \
    && rm -rf /var/lib/apt/lists/*

# Copy Cargo files
COPY Cargo.toml Cargo.lock ./

# Copy source code
COPY src/ ./src/
COPY examples/ ./examples/

# Build with default features
RUN cargo build --release --bin apicentric

# Stage 3: Runtime
FROM debian:bookworm-slim
WORKDIR /app

# Install runtime dependencies
RUN apt-get update && apt-get install -y \
    ca-certificates \
    libssl3 \
    curl \
    && rm -rf /var/lib/apt/lists/*

# Copy backend binary
COPY --from=backend-builder /app/target/release/apicentric /usr/local/bin/apicentric

# Copy frontend build
COPY --from=frontend-builder /app/webui/.next/standalone ./webui
COPY --from=frontend-builder /app/webui/.next/static ./webui/.next/static
COPY --from=frontend-builder /app/webui/public ./webui/public

# Create directories for data and services
RUN mkdir -p /app/data /app/services

# Copy service definitions
COPY services/ /app/services/

# Set environment variables
ENV APICENTRIC_PORT=8080
ENV APICENTRIC_HOST=0.0.0.0
ENV APICENTRIC_DATA_DIR=/app/data
ENV APICENTRIC_SERVICES_DIR=/app/services
ENV RUST_LOG=info,apicentric=debug

# Expose ports
EXPOSE 8080 3000

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:8080/health || exit 1

# Start cloud server
CMD ["apicentric", "cloud"]
Build it:
docker build -f Dockerfile.production -t my-mock-api:prod .

Docker Compose

Manage multiple services with Docker Compose:
docker-compose.yml
version: '3.8'

services:
  apicentric:
    build: .
    ports:
      - "8080:8080"
    volumes:
      - ./services:/app/services
      - ./data:/app/data
    environment:
      - APICENTRIC_PORT=8080
      - APICENTRIC_HOST=0.0.0.0
      - RUST_LOG=info,apicentric=debug
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 3s
      retries: 3
      start_period: 5s
    restart: unless-stopped

  # Additional service for different API
  users-api:
    build: .
    ports:
      - "9001:9001"
    volumes:
      - ./services/users:/app/services
    environment:
      - APICENTRIC_PORT=9001
    restart: unless-stopped

  # Another mock API
  products-api:
    build: .
    ports:
      - "9002:9002"
    volumes:
      - ./services/products:/app/services
    environment:
      - APICENTRIC_PORT=9002
    restart: unless-stopped
Start all services:
docker-compose up -d
Stop all services:
docker-compose down

Volume mounting

Mount service definitions for hot-reloading during development:
docker run -p 8080:8080 \
  -v $(pwd)/services:/app/services \
  -v $(pwd)/data:/app/data \
  my-mock-api
Changes to service files will be detected automatically, and services will reload without restarting the container.

Environment variables

Configure Apicentric using environment variables:
docker run -p 8080:8080 \
  -e APICENTRIC_PORT=8080 \
  -e APICENTRIC_HOST=0.0.0.0 \
  -e APICENTRIC_SERVICES_DIR=/app/services \
  -e APICENTRIC_DATA_DIR=/app/data \
  -e RUST_LOG=info,apicentric=debug \
  -v $(pwd)/services:/app/services \
  my-mock-api
Or use an .env file with Docker Compose:
.env
APICENTRIC_PORT=8080
APICENTRIC_HOST=0.0.0.0
RUST_LOG=info,apicentric=debug
Reference it in docker-compose.yml:
services:
  apicentric:
    build: .
    env_file: .env
    volumes:
      - ./services:/app/services

CI/CD integration

GitHub Actions

.github/workflows/docker.yml
name: Build and Push Docker Image

on:
  push:
    branches: [main]

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2
      
      - name: Build image
        run: docker build -t my-mock-api:${{ github.sha }} .
      
      - name: Test services
        run: |
          docker run -d -p 8080:8080 --name test-api my-mock-api:${{ github.sha }}
          sleep 5
          curl -f http://localhost:8080/api/health || exit 1
          docker stop test-api
      
      - name: Push to registry
        if: success()
        run: |
          echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
          docker tag my-mock-api:${{ github.sha }} my-mock-api:latest
          docker push my-mock-api:latest

GitLab CI

.gitlab-ci.yml
stages:
  - build
  - test
  - deploy

build:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

test:
  stage: test
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker run -d -p 8080:8080 --name test-api $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
    - sleep 5
    - apk add curl
    - curl -f http://localhost:8080/api/health

Production best practices

1
Use specific versions
2
Avoid latest tags in production:
3
FROM debian:bookworm-slim@sha256:...
4
Minimize image size
5
Use minimal base images:
6
FROM gcr.io/distroless/base-debian12
COPY --from=builder /usr/local/bin/apicentric /apicentric
CMD ["/apicentric", "simulator", "start"]
7
Run as non-root user
8
RUN useradd -m -u 1000 apicentric
USER apicentric
9
Enable health checks
10
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD curl -f http://localhost:8080/health || exit 1
11
Use secrets management
12
docker run -p 8080:8080 \
  --secret api_key \
  -e API_KEY_FILE=/run/secrets/api_key \
  my-mock-api

Kubernetes deployment

Deploy to Kubernetes:
k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: apicentric
spec:
  replicas: 2
  selector:
    matchLabels:
      app: apicentric
  template:
    metadata:
      labels:
        app: apicentric
    spec:
      containers:
      - name: apicentric
        image: my-mock-api:latest
        ports:
        - containerPort: 8080
        env:
        - name: APICENTRIC_PORT
          value: "8080"
        - name: RUST_LOG
          value: "info,apicentric=debug"
        volumeMounts:
        - name: services
          mountPath: /app/services
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 10
          periodSeconds: 30
        readinessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 10
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "512Mi"
            cpu: "500m"
      volumes:
      - name: services
        configMap:
          name: apicentric-services
---
apiVersion: v1
kind: Service
metadata:
  name: apicentric
spec:
  selector:
    app: apicentric
  ports:
  - port: 80
    targetPort: 8080
  type: LoadBalancer
Apply it:
kubectl apply -f k8s/deployment.yaml

Troubleshooting

Container exits immediately

Check logs:
docker logs <container-id>

Services not loading

Verify volume mount:
docker exec -it <container-id> ls /app/services

Port conflicts

Use different host ports:
docker run -p 9090:8080 my-mock-api

Permission issues

Ensure proper file permissions:
chmod -R 755 services/
When mounting volumes on Windows, use absolute paths and ensure Docker Desktop has access to the directory.

Next steps

Contract testing

Run contract tests in Docker

Digital twin setup

Containerize IoT device twins

Creating mocks

Learn about service definitions

Import specs

Import existing API specifications

Build docs developers (and LLMs) love