Command-line tools for converting container application definitions into Debian packages.
container-packaging-tools automates the creation of Debian packages from simple container app definitions. It transforms Docker Compose configurations, metadata, and configuration schemas into production-ready Debian packages with systemd integration, eliminating the need to understand Debian packaging internals.
- Automated Package Generation: Convert app definitions to complete Debian packages
- CasaOS Converter: Import applications from CasaOS app store format
- Template-Based: Uses Jinja2 templates for all packaging files
- Comprehensive Validation: Validates metadata, Docker Compose, and configuration schemas
- systemd Integration: Automatically generates systemd service units
- Cockpit Ready: Generates web UI metadata for Cockpit integration
- AppStream Support: Creates AppStream metadata for software centers
- Standards Compliant: Follows Debian packaging standards and best practices
- Package marine applications (Signal K, OpenCPN, AvNav) for HaLOS
- Create container-based Debian packages for any Docker application
- Standardize packaging across multiple applications
- Automate CI/CD pipelines for container app deployment
- Debian 13 (Trixie) or newer - Required for Python 3.11+ and Pydantic v2.0+
- Raspberry Pi OS (Trixie-based) is also supported
- Ubuntu 24.04+ or other Debian-based distributions with compatible package versions
Note: Older distributions like Ubuntu 22.04 or Debian 12 (Bookworm) do not have Pydantic v2.0+ available in their repositories.
For development with AI assistants, use the halos workspace for full context:
# Clone the workspace
git clone https://github.com/halos-org/halos.git
cd halos
# Get all sub-repositories including container-packaging-tools
./run repos:clone
# Work from workspace root for AI-assisted development
# Claude Code gets full context across all reposSee halos/docs/ for development workflows:
LIFE_WITH_CLAUDE.md- Quick start guideIMPLEMENTATION_CHECKLIST.md- Development checklistDEVELOPMENT_WORKFLOW.md- Detailed workflows
# From APT repository (when available)
sudo apt install container-packaging-tools
# Or build from source
git clone https://github.com/halos-org/container-packaging-tools.git
cd container-packaging-tools
./run build
sudo dpkg -i ../container-packaging-tools_*.debCreate a directory with three required files:
mkdir my-app
cd my-appmetadata.yaml - Package metadata:
name: My Web Application
package_name: my-app-container
version: 1.0.0
upstream_version: 1.0.0
description: A simple web application
long_description: |
This is my container application packaged as a Debian package.
homepage: https://example.com/my-app
maintainer: Your Name <your.email@example.com>
license: MIT
tags:
- role::container-app
- implemented-in::docker
debian_section: web
architecture: all
web_ui:
enabled: true
path: /
port: 8080
protocol: http
default_config:
APP_PORT: "8080"
LOG_LEVEL: "info"docker-compose.yml - Container definition:
version: '3.8'
services:
app:
image: nginx:alpine
container_name: my-app
ports:
- "${APP_PORT:-8080}:80"
environment:
- LOG_LEVEL=${LOG_LEVEL:-info}
volumes:
- /var/lib/container-apps/my-app-container/data:/usr/share/nginx/html:rw
restart: "no"Note: Non-Root Containers If your container runs as a non-root user (like Grafana UID 472), add
user: "472"to docker-compose.yml. This ensures the tool generates correct directory ownership in the postinst script. See EXAMPLES.md - Pattern 6 for details.
config.yml - Configuration schema:
version: "1.0"
groups:
- id: general
label: General Settings
description: Basic application configuration
fields:
- id: APP_PORT
label: Application Port
type: integer
default: 8080
required: true
min: 1024
max: 65535
description: Port for the web interface
- id: LOG_LEVEL
label: Log Level
type: enum
default: info
required: false
options: [debug, info, warning, error]
description: Logging verbosity# Generate Debian package structure
generate-container-packages my-app/ build/
# Build the Debian package
cd build/my-app-container
dpkg-buildpackage -us -uc
# Install the package
sudo dpkg -i ../my-app-container_1.0.0_all.deb# Start the service
sudo systemctl start my-app-container
# Check status
sudo systemctl status my-app-container
# View logs
sudo journalctl -u my-app-container -f
# Access the web interface
curl http://localhost:8080/
# Configure the application
sudo nano /etc/container-apps/my-app-container/env
sudo systemctl restart my-app-containerFor more examples and detailed documentation, see EXAMPLES.md.
The CasaOS converter allows you to import applications from the CasaOS app store format and convert them to the container-packaging-tools format. This is useful for leveraging the large CasaOS app ecosystem.
# Convert a single CasaOS app definition
generate-container-packages convert-casaos casaos-app.yml output/
# Convert in batch mode (entire directory)
generate-container-packages convert-casaos --batch casaos-apps/ output/
# Convert with asset download (icons, screenshots)
generate-container-packages convert-casaos --download-assets casaos-app.yml output/
# Sync mode - only update changed files
generate-container-packages convert-casaos --batch --sync casaos-apps/ output/- Automatic Mapping: Converts CasaOS metadata to container-packaging-tools format
- Category Translation: Maps CasaOS categories to Debian package sections
- Field Type Detection: Intelligently converts configuration field types
- Asset Download: Optional download of icons and screenshots
- Batch Processing: Convert multiple apps in parallel
- Sync Mode: Only update files when source has changed (preserves manual edits to generated files, skips unchanged conversions)
# 1. Clone a CasaOS app store
git clone https://github.com/IceWhaleTech/CasaOS-AppStore.git
# 2. Convert CasaOS apps to container-packaging-tools format
generate-container-packages convert-casaos --batch \
CasaOS-AppStore/Apps/ \
converted-apps/
# 3. Review and customize converted apps (optional)
# The converter creates metadata.yaml, docker-compose.yml, and config.yml
# You can manually edit these files before packaging
ls converted-apps/*/
# 4. Generate Debian package structures and build .deb files
for app in converted-apps/*/; do
generate-container-packages "$app" build/
cd "build/$(basename "$app")" && dpkg-buildpackage -us -uc && cd ../..
done
# The .deb files are now in build/
ls -lh build/*.debFor detailed converter documentation, see the converter module documentation.
- EXAMPLES.md - Comprehensive examples and usage patterns
- docs/SPEC.md - Technical specification and requirements
- docs/ARCHITECTURE.md - System architecture and design
- docs/DESIGN.md - High-level design documentation
Each application definition directory must contain:
| File | Required | Description |
|---|---|---|
metadata.yaml |
Yes | Package metadata (name, version, description, etc.) |
docker-compose.yml |
Yes | Docker Compose configuration |
config.yml |
Yes | User-configurable parameters schema |
icon.png or icon.svg |
No | Application icon |
screenshot*.png |
No | Screenshots for AppStream metadata |
Every key in metadata.yaml must be one the tool knows. An unrecognised key fails the build and names itself:
ERROR: Validation failed
- Validation errors in metadata.yaml:
- routing -> mdsn: Extra inputs are not permitted
The usual cause is a container-packaging-tools pin older than the field you declared. Raise the pin (CONTAINER_TOOLS_REF in the consumer repo's tools/build-all.sh) to a release that carries the field. The other cause is a typo or a retired key, and the message says which line to delete.
This applies from 0.13.0 onward. An older tool does not know the rule, so it drops the key and reports success: that is the failure this rule exists to prevent, and it is why the pin matters. See halos-marine-containers issue 253.
source_metadata is the deliberate exception. It carries whatever an upstream catalogue such as CasaOS puts in it, so extra keys there are kept, not rejected.
The rule covers metadata.yaml only. Unknown keys in config.yml are still dropped silently; that gap is tracked in container-packaging-tools issue 253.
The tool generates a complete Debian package structure:
<package-name>/
├── debian/
│ ├── control # Package metadata
│ ├── rules # Build rules
│ ├── install # File installation
│ ├── postinst # Post-installation script
│ ├── prerm # Pre-removal script
│ ├── postrm # Post-removal script
│ ├── changelog # Package changelog
│ ├── copyright # License information
│ └── compat # Debhelper compatibility
├── systemd/
│ └── service # systemd service unit
├── appstream/
│ └── metainfo.xml # AppStream metadata
└── files/
├── docker-compose.yml
├── config.yml
└── env.template # Environment file template
# Clone the repository
git clone https://github.com/halos-org/container-packaging-tools.git
cd container-packaging-tools
# Build the development Docker container
./run docker:build
# Run tests
./run test
# Run linter
./run lint
# Check formatting
./run format:check
# Run type checker
./run typecheckAll development happens in Docker containers to ensure consistent Debian Trixie environment:
# Run all tests
./run test
# Run specific test categories
./run test:unit # Unit tests only
./run test:integration # Integration tests only
# Run with coverage
./run test:coverage # Requires 80% coverage
# Open interactive shell
./run docker:shellThis project uses lefthook for pre-commit hooks to run lint checks locally before commits.
# Install lefthook (one-time)
brew install lefthook
# Enable hooks in this repo
./run hooks-installWhat it checks:
ruff check src/ tests/- Linting
Skip hooks when needed:
git commit --no-verify -m "WIP: message"Before submitting changes, ensure all checks pass:
# Run all quality checks
./run check
# Individual checks
./run lint # Ruff linter
./run format # Code formatting
./run typecheck # Type checking with tyFor faster iteration on Debian/Ubuntu systems:
# Install build dependencies
sudo apt install dpkg-dev debhelper dh-python python3-all
# Install Python dependencies
uv sync --dev
# Run tests locally
uv run pytest
# Note: Some tests require dpkg-buildpackage and will fail on non-Debian systemsContributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Run all quality checks (
./run check) - Run all tests (
./run test) - Commit your changes following Conventional Commits
- Push to your branch
- Open a Pull Request
- All commits must follow conventional commit format
- PRs must have passing CI checks before merge
- Code coverage must be maintained at 80% or higher
- All code must pass linting, formatting, and type checking
- halos-marine-containers - Marine application definitions using this tool
- halos - HaLOS workspace and distribution
- cockpit-apt - APT package manager for Cockpit
- halos-pi-gen - HaLOS image builder
MIT License - see debian/copyright for full details.
- Issues: GitHub Issues
- Documentation: EXAMPLES.md and docs/
- HaLOS Project: hatlabs.github.io/halos