kubectl and plain
manifests, no Helm. The application itself is installed afterwards, either
by the Helm chart or with kubectl alone
(Install without Helm), once the cluster passes the
checks below.
The files cited below live in the hosting repository. Run the commands from a
clone of it:
What you need before starting
1. Reach the cluster
Ready. kubectl version should show a client at most one
minor version away from the server; further apart, some commands fail in
puzzling ways.
2. Storage
Check first — this is the single most common reason nothing starts.No resources found means no volume can ever be created: PostgreSQL and the
data volume would stay Pending forever, and the pods with them. Managed
clusters differ wildly here; some ship a class, some only offer object storage
(which does not suit PostgreSQL).
If the list is empty, local-path-provisioner gives you node-local volumes in
one manifest:
local-path (default).
Prove it works before going further — and mind that the check needs a pod,
not just a claim (Trap 1):
Bound, and ok in the logs. Anything else, stop here: the rest cannot work.
3. Ingress controller
Needed only for a public address; skip it if you will useport-forward.
Install Traefik or ingress-nginx — most managed Kubernetes offerings
have both as a one-click add-on, which is the simplest path since the
provider then also wires the load balancer. Then:
traefik, nginx…) and the EXTERNAL-IP of the
controller’s service: that address is what your DNS record will point to.
4. cert-manager and an issuer
Installing cert-manager is not enough — it issues nothing until an issuer exists.https://acme-v02.api.letsencrypt.org/directory and its own key secret name.
Both are ready-made in the hosting repository under
k8s/cert-manager/cluster-issuer-letsencrypt.yaml. Replace the email: of
both issuers with a mailbox you read before applying it: the file ships
with a maintainer’s address.
READY: True on both means cert-manager registered with the ACME servers.
5. HTTPS redirect (Traefik)
A certificate does not close the clear-text entrance: once the site is public,http:// keeps serving it unless something redirects. With Traefik, that
something is a Middleware, cluster-side, ready-made in the hosting repository:
ssl-redirect acts as soon as the Ingress has a TLS
section.
The manifests in k8s/
The hosting repository’s k8s/ folder holds four sets of manifests. Those
under k8s/apowerb/ are rendered from the chart, so both install paths deploy
the same stack.
Install without Helm
Running and apowerb-th2etl-seed Completed. Back up
k8s/secret.yaml and never regenerate it: a new ENCRYPT_KEY makes every
connected integration unreadable. Reach the interface with
kubectl -n apowerb port-forward svc/apowerb-frontend 13000:3000.
Public address. Copy apowerb-public/, put your domain in, apply the copy:
READY, switch the
cert-manager.io/cluster-issuer annotation to letsencrypt-prod and delete
the apowerb-tls secret.
Upgrade. Keep the same secret.yaml. The seed Job is immutable: delete it
first.
k8s/apowerb/backend-deployment.yaml and apply
my-public/ instead: the plain backend has no public URL, and CORS and OAuth
callbacks break until the public copy is back.
Remove. kubectl delete -f k8s/apowerb/ deletes the namespace and both
volumes, the database included. Nothing protects them, unlike the chart.
Next: install with Helm
Helm chart
Secrets, install, checks, public address, first administrator, upgrades.
Traps
Trap 1: a PVC that stays Pending on purpose
Symptom. You create a claim to test the storage; it staysPending. It
looks like the storage is broken.
Cause. Storage classes with volumeBindingMode: WaitForFirstConsumer —
local-path among them — only create the volume when a pod needs it. This
is by design: the volume is placed on the node the pod is scheduled to.
Remedy. Test with a claim and a pod, as in step 2.
kubectl get storageclass shows the mode.
Trap 2: no storage class at all
Symptom. SamePending, but with a pod waiting too, and
kubectl describe pvc says: no persistent volumes available for this claim and no storage class is set.
Cause. The cluster has no default storage class — common on lean managed
clusters.
Remedy. Step 2. Check kubectl get storageclass before
installing, not after wondering why nothing starts.
Trap 3: a certificate stuck at Ready: False
Symptom.kubectl get certificate shows READY: False and stays there,
without an obvious error.
Causes, in the order worth checking.
- The DNS name does not resolve to the ingress load balancer yet, or port 80 is closed — the HTTP-01 challenge needs both.
- The issuer uses
classinstead ofingressClassName(see step 4). - The Let’s Encrypt rate limit has been hit — five failures in an hour blocks the account for a week. This is what the staging issuer is for.
Challenge object names the real reason.