Part 5 — Deploy & verify
Everything’s wired. This part is the dress rehearsal: push, watch, verify, and learn the commands you’ll lean on when something goes sideways.
1. Point DNS at the Reserved IP
Section titled “1. Point DNS at the Reserved IP”From part 2 you have a Reserved IP. At your DNS provider, add the A records you used in values/<env>.yaml:
dev.example.com. IN A 134.209.xx.xxexample.com. IN A 134.209.xx.xx # if values/prod.yaml uses the apexVerify before pushing — ACME’s HTTP-01 challenge fails fast when DNS isn’t ready:
dig +short dev.example.com# → 134.209.xx.xx2. Trigger the deploy
Section titled “2. Trigger the deploy”If you’ve followed part 4, every push to main deploys automatically. To kick off the first run without a code change:
git commit --allow-empty -m "ci: trigger first deploy"git push origin mainWatch it live:
gh run watchOr open the Actions tab in GitHub.
3. Verify on the server
Section titled “3. Verify on the server”While CI is casting, on your laptop:
rune get services -n dev# NAME NAMESPACE GEN DESIRED READY AGE# web dev 1 1 1 45s
rune get instances -n devrune health web -n dev --checksrune logs web -n dev --tail 50 --followThe first cast pulls the image from GHCR — first pull on a fresh droplet can take 30-60s depending on image size. Subsequent rollouts are seconds.
4. Confirm TLS
Section titled “4. Confirm TLS”If you used tls.mode: auto, watch the certificate get issued:
rune get ingresses -n dev# NAME HOST TLS STATUS READY AGE# web dev.example.com auto Issued true 90sThen hit the URL:
curl -sI https://dev.example.com# HTTP/2 200# server: CaddyIf STATUS stays Pending for more than ~5 minutes, see Expose a service → Troubleshooting — usually it’s a DNS record that hasn’t propagated.
5. Iterate
Section titled “5. Iterate”A typical change loop now looks like this:
# make a code change in apps/web/git add apps/web/git commit -m "web: tweak homepage"git pushCI rebuilds + redeploys web only (because apps/web/** is the path glob in deploy-config.yml). The runner streams the rollout in the cast job; on your laptop:
rune get instances -n dev -w# Watch instances cycle: old Terminating, new Running.rune cast is idempotent — no diff, no work. Re-running it with the same inputs is a safe no-op.
6. The eight commands you’ll actually use
Section titled “6. The eight commands you’ll actually use”Bookmark these. They cover ~95% of day-to-day operation:
| Command | Use case |
|---|---|
rune cast <file> -n <env> | Apply a service / configmap / secret. |
rune get services -n <env> | List services + readiness. |
rune get instances -n <env> | The actual containers running. |
rune logs <svc> -n <env> -f | Tail logs across all instances. |
rune exec <svc> -n <env> sh | Open a shell inside an instance. |
rune restart <svc> -n <env> | Roll instances (e.g. after secret update). |
rune scale <svc> N -n <env> | Quick scale without re-casting. |
rune health <svc> -n <env> --checks | Why is a probe failing? |
For everything else, CLI overview.
7. When CI is broken but you need to deploy
Section titled “7. When CI is broken but you need to deploy”You can always cast manually from your laptop using the admin token from part 2:
rune login myapp-dev --server $(terraform -chdir=infra/terraform/do output -raw grpc_endpoint) \ --token-file infra/terraform/do/rune-admin.token \ --default-namespace dev
# Same templating CI does, just run locally:rune cast infra/runeset/casts/web.yaml \ --values infra/runeset/values/dev.yaml \ --set app.tag=sha-$(git rev-parse --short HEAD) \ -n dev8. When things break — first three places to look
Section titled “8. When things break — first three places to look”rune logs <svc> -n <env> --tail 200— app-level errors. 80% of issues stop here.rune get instances -n <env>+rune get instance <id> -o yaml— restart count, last termination reason, image pull errors.ssh root@$RESERVED_IP 'journalctl -u runed -n 200 --no-pager'— server-level issues (registry auth, ACME, networking). The runed operations doc lists log markers.
For specific failure modes, the Errors reference maps exit codes and error messages to their fix.
9. Tear down (when you’re done playing)
Section titled “9. Tear down (when you’re done playing)”# Drop everything in the namespacerune delete services --all -n dev
# Or destroy the droplet entirely (the Reserved IP and volume survive# unless you remove the `prevent_destroy` lifecycle blocks first)cd infra/terraform/doterraform destroyWhat’s next
Section titled “What’s next”You now have a working pipeline. Pick what to harden next based on where the project is heading:
- More than one service: add another entry to
deploy-config.yml+ anothercasts/<name>.yaml. The detect/build/cast matrix scales without workflow changes. - Production environment: repeat parts 2 & 4 with
environment = "prod", a separate droplet, and a per-env GitHub Environment. - Persistent storage / databases: Persistent storage + Storage resources.
- Stricter networking: Network policy.
- Multi-replica scaling and rollouts: Scale & restart and Health checks.
- Service-to-service dependencies / init steps: Dependencies and Init steps.
If you want to know how runed works under the covers, start with Concepts → Architecture.
Back: Part 4 — CI/CD · Up: Tutorial overview