|
| 1 | +# Deploy coder-k8s and the CloudNativePG example with Argo CD |
| 2 | + |
| 3 | +By the end, your cluster will have: |
| 4 | + |
| 5 | +- the `coder-k8s` operator stack |
| 6 | +- the aggregated API service (`aggregation.coder.com/v1alpha1`) |
| 7 | +- CloudNativePG operator and a `coder-db` PostgreSQL cluster |
| 8 | +- a `CoderControlPlane` named `coder` |
| 9 | +- a live Coder deployment reachable through `svc/coder` |
| 10 | + |
| 11 | +## Prerequisites |
| 12 | + |
| 13 | +- A Kubernetes cluster with `kubectl` access |
| 14 | +- Argo CD installed in namespace `argocd` (with ApplicationSet controller) |
| 15 | +- `kubectl` v1.26+, `jq`, and `curl` |
| 16 | +- `coder` CLI (for optional template + aggregated API verification) |
| 17 | + |
| 18 | +!!! note |
| 19 | + This tutorial assumes Argo CD is already installed and healthy. |
| 20 | + |
| 21 | +## 1) Verify your Argo CD control plane is healthy |
| 22 | + |
| 23 | +```bash |
| 24 | +kubectl -n argocd get deploy |
| 25 | +kubectl -n argocd get pods |
| 26 | +``` |
| 27 | + |
| 28 | +You should see the core Argo CD controllers running (`argocd-application-controller`, `argocd-applicationset-controller`, `argocd-repo-server`, `argocd-server`, etc). |
| 29 | + |
| 30 | +## 2) Apply the ApplicationSet |
| 31 | + |
| 32 | +```bash |
| 33 | +kubectl apply -f https://raw.githubusercontent.com/coder/coder-k8s/main/examples/argocd/applicationset.yaml |
| 34 | +kubectl -n argocd wait --for=create application/coder-k8s-stack --timeout=120s |
| 35 | +``` |
| 36 | + |
| 37 | +!!! note |
| 38 | + The example `ApplicationSet` already includes `syncOptions` for |
| 39 | + `CreateNamespace=true` and `ServerSideApply=true`. |
| 40 | + |
| 41 | +## 3) Wait for the Application to become Synced and Healthy |
| 42 | + |
| 43 | +```bash |
| 44 | +kubectl -n argocd wait --for=jsonpath='{.status.sync.status}'=Synced application/coder-k8s-stack --timeout=20m |
| 45 | +kubectl -n argocd wait --for=jsonpath='{.status.health.status}'=Healthy application/coder-k8s-stack --timeout=20m |
| 46 | +kubectl -n argocd get application coder-k8s-stack \ |
| 47 | + -o jsonpath='{.status.sync.status}{"\n"}{.status.health.status}{"\n"}{.status.operationState.phase}{"\n"}' |
| 48 | +``` |
| 49 | + |
| 50 | +## 4) Validate operator and aggregated API wiring |
| 51 | + |
| 52 | +```bash |
| 53 | +kubectl -n coder-system get deploy coder-k8s -o wide |
| 54 | +kubectl -n coder-system get pods -o wide |
| 55 | + |
| 56 | +kubectl get apiservice v1alpha1.aggregation.coder.com |
| 57 | +kubectl get apiservice v1alpha1.aggregation.coder.com \ |
| 58 | + -o jsonpath='{range .status.conditions[*]}{.type}{"="}{.status}{" reason="}{.reason}{" message="}{.message}{"\n"}{end}' |
| 59 | + |
| 60 | +``` |
| 61 | + |
| 62 | +## 5) Validate database and Coder control plane bring-up |
| 63 | + |
| 64 | +```bash |
| 65 | +kubectl -n coder get cluster.postgresql.cnpg.io coder-db |
| 66 | +kubectl -n coder wait --for=condition=Ready cluster/coder-db --timeout=10m |
| 67 | +kubectl -n coder get secret coder-db-app |
| 68 | + |
| 69 | +kubectl -n coder get codercontrolplane coder -o yaml |
| 70 | +kubectl -n coder rollout status deployment/coder --timeout=10m |
| 71 | +kubectl -n coder get svc coder |
| 72 | +``` |
| 73 | + |
| 74 | +## 6) Complete initial Coder setup from the UI |
| 75 | + |
| 76 | +Port-forward Coder (in a separate terminal, keep it running): |
| 77 | + |
| 78 | +```bash |
| 79 | +kubectl -n coder port-forward svc/coder 3000:80 |
| 80 | +``` |
| 81 | + |
| 82 | +Open the setup page in your browser (`/setup` on the forwarded endpoint). |
| 83 | + |
| 84 | +Create your initial admin user and verify you can reach the templates page. |
| 85 | + |
| 86 | +## 7) (Optional) Create a template directly in Coder |
| 87 | + |
| 88 | +If you want to validate template round-trip behavior: |
| 89 | + |
| 90 | +```bash |
| 91 | +TOKEN=$(curl -sS -X POST http://127.0.0.1:3000/api/v2/users/login \ |
| 92 | + -H 'Content-Type: application/json' \ |
| 93 | + -d '{"email":"<admin-email>","password":"<admin-password>"}' | jq -r '.session_token') |
| 94 | + |
| 95 | +export CODER_URL=http://127.0.0.1:3000 |
| 96 | +export CODER_SESSION_TOKEN="$TOKEN" |
| 97 | + |
| 98 | +coder templates init --id scratch /tmp/coder-template-scratch |
| 99 | +coder templates push starter-scratch --directory /tmp/coder-template-scratch --yes |
| 100 | +coder templates list |
| 101 | +``` |
| 102 | + |
| 103 | +## 8) (Optional) Validate template visibility from aggregated API |
| 104 | + |
| 105 | +```bash |
| 106 | +kubectl get --raw /apis/aggregation.coder.com/v1alpha1 |
| 107 | +kubectl get codertemplates.aggregation.coder.com -A |
| 108 | +kubectl get coderworkspaces.aggregation.coder.com -A |
| 109 | + |
| 110 | +TEMPLATE_FQN="$(kubectl get codertemplates.aggregation.coder.com -A -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' | grep 'starter-scratch' | head -n1)" |
| 111 | +[ -n "$TEMPLATE_FQN" ] |
| 112 | +kubectl -n coder get codertemplates.aggregation.coder.com "$TEMPLATE_FQN" -o yaml |
| 113 | +``` |
| 114 | + |
| 115 | +## Troubleshooting |
| 116 | + |
| 117 | +- **Argo CD sync error: `metadata.annotations: Too long` on CNPG CRDs** |
| 118 | + - Ensure `ServerSideApply=true` is present in `spec.template.spec.syncPolicy.syncOptions` before applying the `ApplicationSet`. |
| 119 | + |
| 120 | +- **CloudNativePG pod crash with `no matches for kind "Pooler"`** |
| 121 | + - This is a downstream effect of failed CRD apply; fix sync options and re-sync the application. |
| 122 | + |
| 123 | +- **`APIService v1alpha1.aggregation.coder.com` not Available** |
| 124 | + - Check `coder-k8s` pod logs and confirm `coder-k8s-apiserver` Service exists in `coder-system`. |
| 125 | + |
| 126 | +- **Coder deployment not rolling out** |
| 127 | + - Verify `coder-db` is Ready and `coder-db-app` secret exists. |
| 128 | + |
| 129 | +## Cleanup |
| 130 | + |
| 131 | +```bash |
| 132 | +kubectl -n argocd delete applicationset coder-k8s-stack |
| 133 | +``` |
| 134 | + |
| 135 | +The generated `Application` has the resources finalizer and will cascade deletion of managed resources. |
0 commit comments