7.7 KiB
7.7 KiB
name, description
| name | description |
|---|---|
| update-compositions | Use when updating, upgrading, or bumping Docker container images, tags, and composition services across one or more APEX fleet nodes. |
Updating APEX Compositions
This skill guides the safe, structured update of container images and compose definitions across nodes in the APEX fleet.
Core Rules
- Verify access first: Never execute commands against a node without confirming SSH connectivity and credentials.
- Hold critical services: Always ask the user which services or compositions must NOT be touched before discovering or updating images.
- Classify update scope: Separate updates into Minor/Patch (non-breaking) and Major (breaking / schema migration risks).
- Gate major updates: Never apply a Major version bump without in-depth migration research and explicit user approval.
- Verify health post-recreation: An update is not complete until containers reach
Upandhealthystatus with clean logs.
Workflow Steps
Step 1: Confirm Node Access
- Identify the target nodes from the user request (e.g.,
icarus,daedalus,morpheus). - If access credentials, custom SSH ports, or key paths are not declared in the environment's SSH configuration, ask the user:
- SSH hostname / IP
- SSH port (APEX default:
2222) - SSH user (APEX default:
adam) - Identity file / key
- Test connectivity to each node before proceeding:
ssh -p <port> <user>@<node_fqdn> "hostname && uptime" - Completion check: All target nodes return exit code 0 on the connectivity probe.
Step 2: Inquire About Critical Services & Holds
- Prompt the user explicitly before inspecting or modifying any services:
"Which critical services or compositions on these nodes should NOT be updated during this run (e.g. databases, SSO/Authelia, Mail, Vaultwarden, Matrix)?"
- Record the freeze list (held services/compositions).
- Ensure all subsequent steps skip services on the freeze list.
- Completion check: User response received, and the list of excluded services is confirmed.
Step 3: Inventory Running Services and Images
For each target node:
- List active containers, current images, and status:
ssh <node> "docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'" - Locate the compose files on the node:
- Shared core:
/srv/<node_fqdn>/compositions/apex/docker-compose.yml - Node applications:
/srv/<node_fqdn>/compositions/*/docker-compose.yml - Overrides:
docker-compose.override.ymlin each composition folder
- Shared core:
- Map every running container to its compose declaration:
- Image repository (e.g.
authelia/authelia,postgres,jellyfin/jellyfin) - Pinned tag / SHA digest (e.g.
:4,:16-alpine,:v1.37.1) - Whether the image is locally built (
build:context present)
- Image repository (e.g.
- Exclude any services identified on the freeze list from Step 2.
- Completion check: A complete table of non-held compositions, running tags, and compose file locations is constructed.
Step 4: Seek Latest Tags and Classify Update Types
For each candidate service:
- Query the container registry (Docker Hub, GitHub Container Registry
ghcr.io, Quay, etc.) for available release tags. Refer to references/registry-queries.md for registry API patterns. - Determine the latest stable versioned tag:
- Prefer semantic versioned tags (e.g.
1.38.0,16.4-alpine) matching the existing packaging flavor. - Ignore pre-release, alpha, beta, or release-candidate (
-rc) tags unless the running container already pins one. - Do not replace a pinned version tag with bare
:latest.
- Prefer semantic versioned tags (e.g.
- Compare the current tag with the latest tag using Semantic Versioning (SemVer:
MAJOR.MINOR.PATCH):
| Tag Transition | Classification | Action Path |
|---|---|---|
1.37.1 -> 1.37.2 |
Patch | Proceed to Step 6 |
1.37.1 -> 1.38.0 |
Minor | Proceed to Step 6 |
Floating tag (e.g. :4 or :16) with new digest |
Minor / In-place | Proceed to Step 6 |
16 -> 17 or 1.x -> 2.x |
Major | Route to Step 5 (Strict Gate) |
Locally built image (build:) |
Local Build | Git update + build (Step 6) |
- Completion check: Every eligible service has a determined target tag and is classified as Major or Minor/Patch.
Step 5: Major Update Protocol (Strict Gating)
For each service classified as Major:
- Research Update Strategy:
- Check upstream release notes, migration guides, and changelogs.
- Identify:
- Breaking configuration changes (renamed environment variables, CLI flags).
- Storage schema migrations (e.g., PostgreSQL major version pg_upgrade requirements).
- Deprecated dependencies or protocol changes.
- Formulate Migration Plan:
- Outline pre-upgrade steps (e.g., explicit database dump
pg_dump/mysqldumpbeyond normal snapshots). - Outline required compose file changes (volumes, environment).
- Outline fallback/rollback steps if the upgrade fails.
- Outline pre-upgrade steps (e.g., explicit database dump
- Request Explicit User Approval:
- Present the findings to the user:
- Target service and node.
- Current version vs New major version.
- Summary of breaking changes and migration strategy.
- Ask: "Do you approve proceeding with the major update for
<service>on<node>under this strategy?"
- Present the findings to the user:
- Gate:
- If approved: Proceed to Step 6 for this service.
- If rejected or deferred: Add service to the freeze list and leave it untouched.
- Completion check: Every Major update either has documented strategy + user approval or is explicitly skipped.
Step 6: Apply Updates and Recreate Containers
Follow node rollout order to minimize blast radius:
- Application nodes / workers first (e.g.,
icarus). - Communications / data nodes next (e.g.,
morpheus). - Core edge / gateway / SSO nodes last (e.g.,
daedalus), ensuring routing and auth remain stable during earlier rollouts.
For each node:
- Pre-upgrade backup:
- Trigger a backup of stateful volumes:
ssh <node> "apex backup/run" - For database services being updated, execute an in-container logical export to host storage.
- Trigger a backup of stateful volumes:
- Update image tags in compose files:
- Modify the target
docker-compose.ymlordocker-compose.override.ymlwith the new version tag.
- Modify the target
- Pull images:
ssh <node> "cd /srv/<node_fqdn>/compositions/<service> && docker compose pull" - Recreate services:
ssh <node> "cd /srv/<node_fqdn>/compositions/<service> && docker compose up -d" - Completion check: Compose commands finish with exit code 0.
Step 7: Verify Service Health & Stability
Immediately after recreation on each node:
- Inspect container state:
ssh <node> "docker ps -a --filter name=<container_name> --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'"- Verify status is
Up. - If a healthcheck is configured, verify it transitions to
(healthy)and does NOT get stuck in(unhealthy)or(starting).
- Verify status is
- Inspect recent logs:
ssh <node> "docker logs --tail 50 <container_name>"- Check for crash loops, panic traces, connection refused, or migration errors.
- Verify HTTP/network response (if edge/web service):
curl -IfsS -k https://<service_fqdn> || true - Rollback protocol:
- If a container enters a crash loop (
Restarting,Exit 1):- Capture failure logs.
- Revert the image tag in
docker-compose.ymlto the prior tag. - Re-run
docker compose up -d. - Notify user immediately with logs and root cause.
- If a container enters a crash loop (
- Completion check: All updated containers are confirmed
Upandhealthywith clean logs.