Skip to content

PeiDocker Documentation

PeiDocker generates Docker configurations from YAML files to build reproducible Docker images without writing Dockerfiles directly.

Overview

PeiDocker provides: - Two-stage build system (stage-1 for system packages, stage-2 for applications) - CLI and web GUI interfaces - Automatic docker-compose.yml generation from user_config.yml - Storage strategy switching between volumes, host mounts, and in-image storage - Custom script execution at build, first-run, every-run, and user-login - SSH server configuration with multiple authentication methods - Environment variable substitution using Docker Compose syntax

Installation

From PyPI

pip install pei-docker

# For pixi users
pixi global install pipx
pipx install pei-docker

From Source

git clone https://github.com/igamenovoer/PeiDocker.git
cd PeiDocker
pip install -e .

Quick Start

Web GUI

# Start GUI with auto-selected port
pei-docker-gui start

# Specify port
pei-docker-gui start --port 8080

# Load existing project
pei-docker-gui start --project-dir /path/to/project

# Jump to specific configuration page
pei-docker-gui start --project-dir /path/to/project --jump-to-page ssh

# Native desktop mode (requires pywebview)
pei-docker-gui start --native

The GUI provides tabs for: - Project settings (base image, output naming) - SSH configuration (users, keys, authentication) - Network configuration (ports, proxy) - Storage management (volumes, bind mounts) - Script automation - Environment variables

Command Line

# Create new project
pei-docker-cli create -p /your/build/dir

# Generate docker-compose.yml
pei-docker-cli configure -p /your/build/dir

# Build images
cd /your/build/dir
docker compose build stage-1 --progress=plain
docker compose build stage-2 --progress=plain

# Run container
docker compose up stage-2

# SSH into container (if configured)
ssh me@127.0.0.1 -p 2222

Project Structure

project_dir/
├── user_config.yml         # Main configuration file
├── docker-compose.yml      # Generated by configure command
├── stage-1.Dockerfile      # Generated stage-1 Dockerfile
├── stage-2.Dockerfile      # Generated stage-2 Dockerfile
├── compose-template.yml    # Template file (do not modify)
└── installation/           # Copied to /pei-from-host in image
    ├── stage-1/
    │   ├── custom/        # Custom scripts for stage-1
    │   ├── tmp/           # Downloaded packages
    │   └── system/        # System configuration files
    └── stage-2/
        ├── custom/        # Custom scripts for stage-2
        ├── tmp/           # Downloaded packages
        └── system/        # System configuration files

Configuration Reference

Two-Stage Build System

  • stage-1: Base image with system packages installed via apt
  • stage-2: Application image built on stage-1 with custom packages

Storage Strategy

Stage-2 provides three directories with dynamic storage: - /soft/app: Application installations - /soft/data: Data files - /soft/workspace: Working files

These symlink to either: - /hard/volume/xxx: When external volume is mounted - /hard/image/xxx: When using in-image storage

Storage types: - auto-volume: Docker manages volume automatically - manual-volume: User-specified volume name - host: Bind mount from host directory - image: Store inside Docker image

SSH Configuration

ssh:
  enable: true
  port: 22              # Container SSH port
  host_port: 2222       # Host mapped port
  users:
    username:
      password: 'pass'
      uid: 1000         # Optional, auto-assigned if not set
      # Choose one authentication method:
      pubkey_file: 'path/to/key.pub'      # Public key file
      pubkey_text: 'ssh-rsa AAAA...'      # Inline public key
      privkey_text: '-----BEGIN...'       # Inline private key
      privkey_file: 'path/to/private.key' # Private key file

Script Execution Hooks

Scripts execute at four stages: - on_build: During image build - on_first_run: First container start - on_every_run: Every container start - on_user_login: User SSH login

Scripts support parameters:

on_build:
  - 'script.sh --param=value --flag'

Environment Variables

Supports Docker Compose variable substitution:

environment:
  - 'VAR_NAME=value'
  - 'API_URL=${API_URL:-http://localhost:8080}'

Port Mapping

Separate port configurations for each stage:

stage_1:
  ports:
    - "5432:5432"  # Database ports
stage_2:
  ports:
    - "8080:8080"  # Application ports

Proxy Configuration

proxy:
  address: host.docker.internal
  port: 7890
  enable_globally: false      # Apply to all shell commands
  remove_after_build: false   # Remove after build
  use_https: false            # Use HTTPS proxy

APT Repository

apt:
  repo_source: 'tuna'        # Or: 'aliyun', '163', 'ustc', 'cn'
  keep_repo_after_build: true
  use_proxy: false
  keep_proxy_after_build: false

CLI Commands

create

Creates new PeiDocker project.

pei-docker-cli create -p DIRECTORY [OPTIONS]

Options: - -p, --project-dir: Project directory (required) - -e, --with-examples: Include example files (default: true) - --with-contrib: Include contrib directory (default: true)

configure

Generates docker-compose.yml from user_config.yml.

pei-docker-cli configure [OPTIONS]

Options: - -p, --project-dir: Project directory (default: current) - -c, --config: Config file name (default: user_config.yml) - -f, --full-compose: Generate extended compose file - --with-merged: Generate merged.Dockerfile, merged.env, and build-merged.sh for building without docker compose

Build Without Docker Compose (Merged Build)

If you prefer a single docker build flow without docker compose:

# Generate merged artifacts
pei-docker-cli configure --with-merged

# Build the final stage-2 image using merged.Dockerfile and merged.env
./build-merged.sh

# Override output image name:tag on the fly
./build-merged.sh --output-image myorg/myapp:dev
./build-merged.sh -o myorg/myapp:dev

This produces: - merged.Dockerfile: stand-alone multi-stage Dockerfile (stage-1 + stage-2) - merged.env: all build-time args as KEY='value' - build-merged.sh: one-shot build script that sources merged.env and runs docker build - Supports --output-image/-o <name:tag> to override the final image tag

Complete Configuration Example

stage_1:
  image:
    base: ubuntu:24.04
    output: myapp:stage-1

  ssh:
    enable: true
    port: 22
    host_port: 2222
    users:
      me:
        password: '123456'
        uid: 1000

  apt:
    repo_source: ''
    keep_repo_after_build: true

  proxy:
    address: host.docker.internal
    port: 7890
    enable_globally: false

  environment:
    - 'STAGE=development'

  ports:
    - "5432:5432"

  device:
    type: cpu

  mount:
    apt_cache:
      type: auto-volume
      dst_path: /var/cache/apt

  custom:
    on_build:
      - 'stage-1/custom/setup.sh'

stage_2:
  image:
    base: null  # Uses stage-1 output
    output: myapp:stage-2

  storage:
    app:
      type: auto-volume
    data:
      type: host
      host_path: /data
    workspace:
      type: auto-volume

  mount:
    home_me:
      type: auto-volume
      dst_path: /home/me

  custom:
    on_build:
      - 'stage-2/custom/install.sh'

Troubleshooting

Docker Registry Connection Issues

If unable to connect to docker.io:

# Pull base image manually
docker pull ubuntu:24.04

# Tag with local name
docker tag ubuntu:24.04 local-ubuntu:24.04

# Use local-ubuntu:24.04 in user_config.yml

Converting to docker run

Use Decomposerize to convert docker-compose.yml to docker run commands.

Persistent Changes

For on_first_run scripts, commit the container after first run to save changes:

docker commit <container_id> <new_image_name>