unrip/docs/deployment.md

188 lines
5.1 KiB
Markdown

# 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:
```bash
kubectl apply -f deploy/k8s/base/namespace.yaml
```
Create the app runtime secret required by `near-intents-ingest`:
```bash
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:
```bash
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:
```bash
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:
```bash
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:
```bash
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:
```bash
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
```bash
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:
```bash
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:
```bash
cp .env.example .env
docker compose up -d --build
```
That path is for local testing. Production rollout is Forgejo + Kubernetes.