The v2.18 image's entrypoint runs the setup wizard on first boot. Without the SEMAPHORE_ADMIN_* variables it prompts on stdin, fails with 'Username cannot be empty', and the container exits — leading to a crash loop. Set: SEMAPHORE_ADMIN=admin SEMAPHORE_ADMIN_NAME=Administrator SEMAPHORE_ADMIN_EMAIL=admin@local.mk-labs.cloud SEMAPHORE_ADMIN_PASSWORD={{ vault_semaphore_admin_password }} SEMAPHORE_PLAYBOOK_PATH=/var/lib/semaphore/playbooks The env-var bootstrap path is stable in v2.x; only the legacy 'semaphore user add' CLI invocation was unreliable. Drop the manual user-add step from the README.
118 lines
4.7 KiB
Markdown
118 lines
4.7 KiB
Markdown
# semaphore
|
|
|
|
Deploys [SemaphoreUI](https://semaphoreui.com) with a PostgreSQL backend on
|
|
the mk-labs `imagineering` VM (`figment`) via rootful Podman Quadlets.
|
|
|
|
## Architecture
|
|
|
|
```
|
|
┌─────────────────────┐
|
|
user ─── HTTPS ─── Traefik ──▶│ figment (10.1.71.37) │
|
|
│ │
|
|
│ ┌─────────────────┐ │
|
|
│ │ semaphore │ │
|
|
│ │ :3000 │──┼──┐
|
|
│ └─────────────────┘ │ │ semaphore-net
|
|
│ │ │ (podman)
|
|
│ ┌─────────────────┐ │ │
|
|
│ │ semaphore- │◀─┼──┘
|
|
│ │ postgres :5432 │ │
|
|
│ └─────────────────┘ │
|
|
│ │
|
|
│ /etc/containers/ │
|
|
│ systemd/*.container│
|
|
└───────────────────────┘
|
|
```
|
|
|
|
- Both containers run as **rootful** Podman services, managed by
|
|
systemd-generated units from Quadlet files in `/etc/containers/systemd/`.
|
|
- The two containers share a user-defined Podman network
|
|
(`semaphore-net`) so Semaphore can address PostgreSQL by container name.
|
|
- Data persists on two named Podman volumes (`semaphore_data`,
|
|
`semaphore_postgres_data`) so container recreation is non-destructive.
|
|
- Image tags are **pinned** — no floating `:latest`.
|
|
|
|
## Required vault variables
|
|
|
|
| Variable | Purpose |
|
|
|-----------------------------------------|---------------------------------------------------------|
|
|
| `vault_semaphore_database_password` | PostgreSQL role password for the `semaphore` DB user. |
|
|
| `vault_semaphore_admin_password` | Initial admin password (used during manual user-add). |
|
|
| `vault_semaphore_access_key_encryption` | 32-byte key for Semaphore-stored access keys. |
|
|
|
|
Generate the access-key encryption value with:
|
|
|
|
```bash
|
|
head -c 32 /dev/urandom | base64
|
|
```
|
|
|
|
## Usage
|
|
|
|
```yaml
|
|
- name: Deploy SemaphoreUI
|
|
hosts: semaphore_server
|
|
become: true
|
|
roles:
|
|
- semaphore
|
|
```
|
|
|
|
Or via the dedicated playbook:
|
|
|
|
```bash
|
|
ansible-playbook -i inventory.yml playbooks/day1_deploy_semaphore.yml
|
|
```
|
|
|
|
## First-run admin user
|
|
|
|
The container provisions the initial admin user from the
|
|
`SEMAPHORE_ADMIN_*` environment variables on first boot. Credentials:
|
|
|
|
| Field | Value |
|
|
|----------|------------------------------------------------|
|
|
| Login | `admin` |
|
|
| Name | `Administrator` |
|
|
| Email | `admin@local.mk-labs.cloud` |
|
|
| Password | `vault_semaphore_admin_password` (in vault) |
|
|
|
|
The admin env vars are only consulted on first boot when no admin
|
|
exists in the database. Subsequent password rotations should be done
|
|
through the web UI, not by re-running this role.
|
|
|
|
## Pinned versions
|
|
|
|
- **Semaphore**: `docker.io/semaphoreui/semaphore:v2.18.5-ansible2.16.5`
|
|
(bundles Ansible 2.16.5 inside the container, matching our controller)
|
|
- **PostgreSQL**: `docker.io/library/postgres:16-alpine`
|
|
|
|
To bump versions, update `semaphore_image` / `semaphore_postgres_image`
|
|
in `defaults/main.yml`. Test against figment, snapshot first.
|
|
|
|
## Verification
|
|
|
|
The role completes with an HTTP health check against
|
|
`http://127.0.0.1:3000/api/ping`. If Semaphore doesn't respond within
|
|
~60 seconds, the role fails loudly rather than reporting green-but-broken.
|
|
|
|
## Troubleshooting
|
|
|
|
```bash
|
|
# Container status
|
|
sudo systemctl status semaphore semaphore-postgres
|
|
sudo podman ps -a
|
|
|
|
# Logs
|
|
sudo journalctl -u semaphore -f
|
|
sudo journalctl -u semaphore-postgres -f
|
|
sudo podman logs semaphore --tail 100
|
|
|
|
# Network
|
|
sudo podman network inspect semaphore-net
|
|
|
|
# Wipe and redeploy (destructive — destroys all Semaphore data)
|
|
sudo systemctl stop semaphore semaphore-postgres
|
|
sudo podman volume rm semaphore_data semaphore_postgres_data
|
|
sudo rm /etc/containers/systemd/semaphore.container /etc/containers/systemd/semaphore-postgres.container
|
|
sudo systemctl daemon-reload
|
|
# then re-run the playbook
|
|
```
|