Package System¶
HaLOS packages container applications as standard Debian .deb packages. This means Docker apps are installed, updated, and removed with APT -- the same package manager used for all other system software.
Why Debian Packages?¶
Packaging containers as .deb files provides several advantages over Docker Compose files alone:
- Single install command:
sudo apt install marine-grafana-container - Dependency management: APT resolves dependencies automatically (e.g., Docker)
- Clean removal:
apt removestops containers and cleans up - Automatic updates: Standard
apt upgradeworkflow - System integration: systemd services, icons, mDNS, dashboard tiles -- all in one package
- Repository distribution: Published to
apt.hatlabs.filike any APT package
What's in a Container App Package?¶
Each container app package contains:
/var/lib/container-apps/{app-name}/
├── docker-compose.yml # Docker Compose definition
├── runtime.env # Environment variables
└── icon.png # Application icon
/etc/systemd/system/
└── {app-name}-container.service # systemd service unit
/usr/share/pixmaps/
└── {app-name}.png # Icon for store and dashboard
The systemd service runs docker compose up -d on start and docker compose down on stop.
App Definition Format¶
Developers define container apps using three files:
metadata.yaml¶
The central definition file. Contains package metadata, version, tags, routing configuration, and Docker labels.
name: Grafana
app_id: grafana
version: 12.3.2-1
upstream_version: 12.3.2
description: Data visualization and monitoring platform
homepage: https://grafana.com/
maintainer: Hat Labs <support@hatlabs.fi>
license: AGPL-3.0
tags:
- role::container-app
- field::marine
- category::visualization
- category::monitoring
- interface::web
routing:
subdomain: grafana
auth:
mode: forward_auth
web_ui:
enabled: true
port: 3000
protocol: http
See the Container Metadata Reference for the full schema.
docker-compose.yml¶
Standard Docker Compose file. The container-packaging-tools adds Traefik labels, mDNS labels, and Homarr labels automatically based on metadata.yaml.
config.yml (optional)¶
User-configurable settings that are exposed as environment variables in runtime.env.
container-packaging-tools¶
The generate-container-packages command converts app definitions into Debian packages:
apps/grafana/ generate-container-packages
├── metadata.yaml ──────────────────────────► grafana-container_12.3.2-1_all.deb
├── docker-compose.yml
├── config.yml
└── icon.png
The tool:
- Validates the metadata against the schema
- Generates Traefik routing labels from the
routingconfiguration - Generates Homarr dashboard labels from the metadata
- Generates mDNS publisher labels from the subdomain
- Creates Debian packaging files (control, rules, postinst, prerm, postrm)
- Builds the
.debpackage withdpkg-buildpackage
Tag-Based Categorization¶
Packages use a tag-based categorization system with debtag facets. This enables domain-specific stores to organize packages meaningfully.
Key Facets¶
| Facet | Purpose | Examples |
|---|---|---|
field:: |
Application domain | field::marine, field::core |
category:: |
User-facing store category | category::navigation, category::monitoring |
role:: |
Package type | role::container-app |
interface:: |
UI type | interface::web |
How Store Filtering Works¶
- A store configuration defines filter rules (e.g.,
include_tags: [field::marine]) - The backend filters all packages matching those tags
- Categories are auto-discovered from
category::*tags on matched packages - The store UI displays packages organized by category
# store/marine.yaml
id: marine
name: Marine Navigation & Monitoring
filters:
include_tags:
- field::marine
category_metadata:
- id: navigation
label: Navigation & Charts
icon: MapIcon
New categories appear automatically when a package uses a new category::* tag -- no store configuration update needed.
APT Repository¶
Container app packages are published to apt.hatlabs.fi:
| Channel | Purpose | Tag format |
|---|---|---|
trixie-stable |
Production releases | v{version}+{N} |
trixie-unstable |
Pre-release testing | v{version}+{N}_pre |
The CI/CD pipeline builds packages on push to main, publishes to unstable, and promotes to stable when a GitHub release is published.
Install Lifecycle¶
Installation¶
apt install marine-grafana-container
→ dpkg extracts files
→ postinst creates data directories, generates secrets
→ systemd starts grafana-container.service
→ docker compose up -d
→ Traefik detects labels, creates route
→ mDNS publisher advertises grafana.halos.local
→ Homarr adapter adds dashboard tile
Removal¶
apt remove marine-grafana-container
→ prerm stops grafana-container.service
→ docker compose down
→ Traefik removes route
→ mDNS publisher removes advertisement
→ Homarr adapter detects removal
→ dpkg removes package files
Updates¶
apt upgrade
→ dpkg extracts updated files
→ systemd restarts the service
→ docker compose pulls new image and recreates container
→ Persistent data in /var/lib/container-apps/{app}/ is preserved
Version Management¶
Container app packages use a two-part version scheme:
- Upstream version: The application version (e.g.,
12.3.2) - Revision: Auto-incremented by CI (e.g.,
-1,-2)
The full Debian version is {upstream}-{revision} (e.g., 12.3.2-1). Revisions increment automatically on each CI build, even if the upstream version hasn't changed.