unrip/docs/deployment.md

5.1 KiB

Deployment

This repository owns the app-side deployment assets for unrip:

  • application source
  • Docker build inputs
  • Kubernetes manifests under deploy/k8s/base/
  • the Forgejo workflow under .forgejo/workflows/deploy.yml

The shared platform bootstrap lives in the separate infra/platform repository. In the current local split, that repo is available as ../unrip3.

Ownership split

Platform repo responsibilities:

  • Hetzner/OpenTofu provisioning
  • cloud-init and k3s bootstrap
  • shared registry
  • Forgejo and the Forgejo runner
  • cert-manager, Traefik, observability, and other cluster services

This repo responsibilities:

  • app image build context
  • app namespace manifests
  • app runtime secret names
  • app deployment workflow

Deployment model

The intended production path is:

  1. bootstrap the shared platform from the platform repo
  2. create the unrip app secrets in the cluster
  3. push this repo to Forgejo
  4. let .forgejo/workflows/deploy.yml build and roll the app in-cluster

The image build happens inside Kubernetes via Kaniko. The operator pushes Git, not Docker images.

Platform prerequisite

Before deploying this repo, the platform repo should already have completed its Hetzner bootstrap flow. From the current local split, the relevant operator docs live in:

  • ../unrip3/deploy/hetzner/README.md
  • ../unrip3/deploy/k8s/README.md
  • ../unrip3/docs/hetzner-self-hosted-ci-runbook.md

After platform bootstrap, you should have:

  • a reachable Forgejo instance
  • a reachable shared registry
  • a running Forgejo runner in the cluster
  • ../unrip3/.state/hetzner/kubeconfig.yaml
  • ../unrip3/.state/hetzner/kubeconfig.incluster.yaml

One-time app namespace setup

Apply the namespace first:

kubectl apply -f deploy/k8s/base/namespace.yaml

Create the app runtime secret required by near-intents-ingest:

kubectl -n unrip create secret generic unrip-secrets \
  --from-literal=NEAR_INTENTS_API_KEY=replace_me

Create the registry auth secret used both for image pulls and the in-cluster Kaniko build job:

kubectl -n unrip create secret docker-registry unrip-registry-creds \
  --docker-server=registry.<your-domain> \
  --docker-username="$REGISTRY_USERNAME" \
  --docker-password="$REGISTRY_PASSWORD"

Then apply the app manifests:

kubectl apply -k deploy/k8s/base

Notes:

  • deploy/k8s/base/unrip.yaml references unrip-secrets and unrip-registry-creds; they are not created by this repo.
  • the checked-in image ghcr.io/example/unrip:bootstrap is only a placeholder. The first real image tag is set by the Forgejo workflow or by a manual kubectl set image.

Required Forgejo repo settings

Required repo secret:

  • KUBECONFIG_B64

Required repo variable:

  • REGISTRY_HOST

Recommended repo variables when you do not want to rely on workflow defaults:

  • PROJECT_NAME
  • PROJECT_NAMESPACE
  • PROJECT_DEPLOYMENTS
  • PROJECT_REGISTRY_SECRET_NAME

Recommended values for this repo:

  • REGISTRY_HOST=registry.<your-domain>
  • PROJECT_NAME=unrip
  • PROJECT_NAMESPACE=unrip
  • PROJECT_DEPLOYMENTS=near-intents-ingest,dummy-reactor,dummy-executor,dummy-consumer
  • PROJECT_REGISTRY_SECRET_NAME=unrip-registry-creds

KUBECONFIG_B64 should be the base64-encoded contents of the in-cluster kubeconfig produced by the platform repo, not the public workstation kubeconfig:

base64 -w0 ../unrip3/.state/hetzner/kubeconfig.incluster.yaml

The current workflow does not read REGISTRY_USERNAME or REGISTRY_PASSWORD from Forgejo directly. Those values are still needed on the operator side when creating the unrip-registry-creds Kubernetes secret.

Seed the repo into Forgejo

Create the repository in Forgejo, add a forgejo remote for this repo, and push main. For example:

git remote add forgejo https://git.<your-domain>/<owner>/$(basename "$PWD").git
git push forgejo HEAD:refs/heads/main

Routine deploy flow

Once the repo exists in Forgejo and the repo settings above are configured:

git push forgejo main

On push to main, .forgejo/workflows/deploy.yml does the following:

  1. loads kubeconfig from KUBECONFIG_B64
  2. applies deploy/k8s/base
  3. creates an in-cluster Kaniko Job in the unrip namespace
  4. builds and pushes REGISTRY_HOST/unrip:<git-sha>
  5. updates the four app deployments and waits for rollout

Observe rollout

kubectl -n unrip get deploy,pods,pvc,job
kubectl -n unrip rollout status deploy/near-intents-ingest
kubectl -n unrip rollout status deploy/dummy-reactor
kubectl -n unrip rollout status deploy/dummy-executor
kubectl -n unrip rollout status deploy/dummy-consumer

Useful logs:

kubectl -n unrip logs deploy/near-intents-ingest -f
kubectl -n unrip logs deploy/dummy-reactor -f
kubectl -n unrip logs deploy/dummy-executor -f
kubectl -n unrip logs deploy/dummy-consumer -f
kubectl -n unrip logs job/redpanda-topic-bootstrap

Local development

Local iteration remains separate from the production path:

cp .env.example .env
docker compose up -d --build

That path is for local testing. Production rollout is Forgejo + Kubernetes.