Install through an Aetheus pipeline
Once you run one Aetheus, it can install the next one. This page describes the smallest pipeline that does the job: build, deploy, record a release. No QA, no quality gate, no security scan.
This is a second installation, not the first
You need a working Aetheus to run the pipeline. Install the first one with Docker or from binaries.
What you need before writing any YAML
-
A project
Everything else hangs off it: the repository, the pipeline, the releases and the artefacts.
-
A Git repository linked to that project
The pipeline definition is read from the repository at every launch, and the run checks out a pinned revision from it. A pipeline that needs a workspace is refused before the run is even created if its source repository is missing or ambiguous, so link it explicitly when the project holds more than one.
-
An online agent on the target host
The pipeline runs on the machine you are deploying to. Register that machine as a server and let its agent come online first; a stage with no eligible runner waits rather than deploying somewhere else.
The host also needs whatever the build uses. For the layout below, that is Docker with the Compose plugin.
-
A variable library for the non-secret values
Host names, ports, web roots, deployment paths. A pipeline only sees a library it lists explicitly, so declaring it in the YAML is part of the setup, not an afterthought.
-
A vault for the secrets
Database password, JWT key, encryption key and salt, initial admin password. A vault the pipeline cannot resolve fails the run, which is the behaviour you want: the alternative would be deploying with blank secrets.
The minimal pipeline
Commit this as .pipeline/aetheus-install.yaml in the linked repository. Three stages: build the images, hand the payload to the deploy stage, then record what was published.
name: aetheus-install
trigger: manual
variable_libraries:
- aetheus-target-host
vaults:
- aetheus-target-secrets
variables:
APP_VERSION: "1.0.$(BUILD_PIPELINE_RUNNUMBER)"
COMPOSE_PROJECT: "aetheus"
DEPLOY_DIR: "/srv/aetheus"
stages:
- name: Build
os: linux
group: Deploy
steps:
- name: Build the production images
checkout: true
working_directory: "$(WORKSPACE)"
timeout_seconds: 3600
shell: |
set -eu
SOURCE_COMMIT="$(git rev-parse HEAD)"
docker build \
--load \
--build-arg "APP_VERSION=$(APP_VERSION)" \
--file deploy/docker/Dockerfile.back \
--tag "aetheus-back:${SOURCE_COMMIT}" .
docker build \
--load \
--file deploy/docker/Dockerfile.front \
--tag "aetheus-front:${SOURCE_COMMIT}" .
docker image inspect \
"aetheus-back:${SOURCE_COMMIT}" \
"aetheus-front:${SOURCE_COMMIT}" >/dev/null
mkdir -p .pipeline-artifacts
printf '%s' "${SOURCE_COMMIT}" > .pipeline-artifacts/source-commit
- name: Deploy
os: linux
group: Deploy
depends_on:
- Build
steps:
- name: Bring the stack up
checkout: true
working_directory: "$(WORKSPACE)"
timeout_seconds: 1800
shell: |
set -eu
SOURCE_COMMIT="$(git rev-parse HEAD)"
export AETHEUS_BACK_IMAGE="aetheus-back:${SOURCE_COMMIT}"
export AETHEUS_FRONT_IMAGE="aetheus-front:${SOURCE_COMMIT}"
export APP_VERSION="$(APP_VERSION)"
cd "$(DEPLOY_DIR)"
docker compose up -d
# Refuse to call this a success until the database is actually reachable.
for attempt in $(seq 1 30); do
if curl -sf http://127.0.0.1:10026/health/ready; then exit 0; fi
sleep 5
done
echo "The backend never became ready." >&2
exit 1
- name: Release
os: linux
group: Deploy
depends_on:
- Deploy
steps:
- name: Record the deployed release
type: release
version: "$(APP_VERSION)"
changelog: true
deployed: true
timeout_seconds: 300
Reading that pipeline
checkout: trueclones the pinned revision into$(WORKSPACE). Without it the stage runs on an empty directory.depends_onis what serialises the three stages. Remove it and they would be dispatched in parallel.- The deploy step polls
/health/readyrather than/health/live, because the process answers "live" before its database connection is usable. Polling the wrong endpoint is the classic way to declare a broken deployment successful. - The
releasestep is a native type, not a script: the backend then knows the version, the commit and the artefacts, which is what makes a later rollback point at something precise.
Version numbers
1.0.$(BUILD_PIPELINE_RUNNUMBER) yields 1.0.1, 1.0.2 and so on, counting every launch of this pipeline including the failed ones. It is a build counter, not a semantic version.
First run
Push the YAML to the default branch of the linked repository. The definition is read from Git at launch, so there is nothing to synchronise in the UI.
Create the pipeline in the project, pointing at that slug, and attach the variable library and the vault.
Launch it, and watch the run timeline. A stage stuck in a waiting state almost always means no eligible agent is online for its
os.When it goes green, the run's overview carries the release it produced and the commit it was built from.
What this pipeline deliberately leaves out
The pipelines the project runs on itself add a great deal on top of this skeleton: immutable candidate artefacts, blue-green colour switching so the control plane never goes down while deploying itself, a rollback stage that runs only when the release fails, and retention. Add them when you need them; none of it is required to get an instance installed.