DevOps Server Deployer
Ansible automation that deploys every service on the DevOps server host: a PyPI package mirror, the platform's shared PostgreSQL server, and the self-hosted DevOps server itself (source code hosting, artifact delivery, and CI/CD pipelines).
Each service runs as Docker containers on one remote Linux host, and the platform's internal Root CA signs every internal TLS certificate. Secrets and per-host config come from the Vault KV store over mTLS (API key plus client certificate), so nothing secret lives in this repo. Backups go through Restic.
The playbooks run Ansible under Python managed by uv, with this
repo's own plugins and modules in lookup_plugins/, action_plugins/, and library/.
Quick start
# Set required environment variables, or put them in a .env file in the project root.
export CS_PROJECT_CODE="<project-code>"
export VAULT_API_ENDPOINT="https://<host>:8083"
export VAULT_API_KEY="<api-key>"
export VAULT_CA_CERT_BASE64="<base64-encoded-ca-cert>"
export VAULT_CLIENT_CERT_BASE64="<base64-encoded-client-cert>"
export VAULT_CLIENT_KEY_BASE64="<base64-encoded-client-key>"
# Install dependencies
uv sync --all-extras --all-packages --no-progress
uv --offline run --no-sync --no-progress ansible-galaxy install -r requirements.yml
# Run a deployment (example: deploy the SCM service).
uv --offline run --no-sync --no-progress ansible-playbook playbook.yml --tags scm
Every task carries the never tag, so a run without --tags does nothing.
Ordered services
Deployed top to bottom; later rows may depend on earlier ones (e.g. scm on database). The PyPI
mirror comes first because every uv-based repo on the platform, this one included, installs its
Python packages from it. The SCM service connects to the database as a client, so the database has
to be up and its downstream credentials seeded before SCM runs.
| Service | Group | Description |
|---|---|---|
| Prerequisites | - | Tools, Vault access, and shared variables |
| PyPI Mirror | pypi_mirror | Pull-through cache for upstream Python packages |
| Database | database | Shared PostgreSQL server with mutual TLS; seeds Vault with downstream DB credentials |
| SCM | scm | Code hosting, artifact registries, and CI/CD runners |
Project structure
devops-server-deployer/
├── playbook.yml # Main Ansible playbook, one play per service
├── inventory.yml # Hosts, service groups, and host-specific variables
├── ansible.cfg # Ansible configuration
├── requirements.yml # Ansible collection and role dependencies
├── group_vars/ # Per-service variable definitions
├── host_vars/ # Per-host variable overrides
├── tasks/ # Ansible task files per service
├── files/ # Docker build contexts per service
├── templates/ # Jinja2 templates per service
├── library/ # Custom Ansible modules
├── lookup_plugins/ # Custom Ansible lookup plugins
├── action_plugins/ # Custom Ansible action plugins
├── src/ # Python package with the Vault client
└── docs/ # Per-service documentation
Development
See DEVELOPMENT.md for git hooks, lint, and syntax-check commands.