-
Notifications
You must be signed in to change notification settings - Fork 2
Get Started Run In Kubernetes
A Kubernetes Deployment running the codeQ image is the same shape as the Docker container in Run In Docker, wrapped in a Service, a ConfigMap, and a PersistentVolumeClaim. The repository ships a Helm chart at helm/codeq/ that does the wiring. This page walks through installing it, verifying the Pod is healthy, port-forwarding to test, and the values that matter for a real environment.
The chart targets two topologies. A single-replica Deployment with a PVC is the Kubernetes-native equivalent of one Docker container; that is what helm install gives you out of the box. A multi-replica cluster — with three Pods participating in raft — requires replicaCount: 3 plus the same RAFT_* environment variables that drive the compose template, surfaced through extraEnv. This page covers the single-replica install in detail and points at the values you need to flip for the cluster path.
The chart files live at helm/codeq/ and have the following structure:
helm/codeq/
Chart.yaml # apiVersion, version, appVersion
values.yaml # default values
README.md # the chart's own short docs
templates/
deployment.yaml
service.yaml
configmap.yaml
secret.yaml
pvc.yaml
hpa.yaml
ingress.yaml
serviceaccount.yaml
_helpers.tpl
NOTES.txt
The Chart.yaml declares the chart name codeq, version 0.2.0, app version 0.1.0. The image defaults to ghcr.io/osvaldoandrade/codeq-service:0.1.0 — the same image you pulled in the Docker walkthrough, pinned to a release tag rather than latest. Override image.tag in your values to follow a different release.
The Deployment runs the codeQ container with the ConfigMap mounted as environment variables and the optional Secret mounted likewise. The Service exposes port 80 (service.port) on top of the container's :8080 (service.targetPort). The PVC is conditional on persistence.artifacts.enabled for the artifacts directory; the Pebble store path is set via config keys that flow into env vars.
Read helm/codeq/values.yaml once before installing — the inline keys are the API the chart exposes to you, and they document themselves with a default.
If you do not have a Kubernetes cluster handy, kind or minikube gives you one in two commands:
kind create cluster --name codeq
kubectl cluster-infoClone the repo and install the chart from the local path:
git clone https://github.com/osvaldoandrade/codeq
cd codeq
helm install codeq ./helm/codeq \
--namespace codeq --create-namespaceThat is the smallest viable install: default image, single replica, ClusterIP service, no ingress, no autoscaling. Verify the Pod is running:
kubectl -n codeq get pods
kubectl -n codeq get svcYou should see one Pod with two ready containers transitioning to Running and one Service of type ClusterIP exposing port 80. The Pod takes a couple of seconds to start; the image pull dominates first-time latency.
The default Service is ClusterIP — not externally reachable. Port-forward to talk to it from your laptop:
kubectl -n codeq port-forward svc/codeq 8080:80In another terminal, the same three calls as every other Get Started page:
AUTH='Authorization: Bearer dev-token'
JSON='Content-Type: application/json'
TASK_ID=$(curl -s -X POST http://localhost:8080/v1/codeq/tasks -H "$AUTH" -H "$JSON" -d '{"command":"PROCESS_ORDER","payload":{"orderId":"42"},"priority":5}' | jq -r '.id')
echo "$TASK_ID"
curl -s -X POST http://localhost:8080/v1/codeq/tasks/claim -H "$AUTH" -H "$JSON" -d '{"commands":["PROCESS_ORDER"],"leaseSeconds":60,"waitSeconds":5}' | jq
curl -s -X POST "http://localhost:8080/v1/codeq/tasks/${TASK_ID}/result" -H "$AUTH" -H "$JSON" -d '{"status":"COMPLETED","result":{"ok":true}}'
curl -s "http://localhost:8080/v1/codeq/tasks/${TASK_ID}" -H "$AUTH" | jq '.status'If the last line prints "COMPLETED", the install is working. The auth token here is dev-token because the default chart values do not configure real authentication; for a real install you must override the auth provider (see "Production values" below).
flowchart LR
C[Client] -- ":80" --> SVC[Service<br/>codeq.codeq.svc]
SVC -- ":8080" --> POD[Pod codeq-xxxxx]
POD --> CM[(ConfigMap<br/>env vars)]
POD --> SEC[(Secret<br/>auth)]
POD --> PV[(PersistentVolumeClaim<br/>artifacts)]
One Pod with the codeQ container. One Service routing traffic on port 80 to the container's :8080. A ConfigMap holding the non-secret configuration. An optional Secret carrying webhookHmacSecret and any auth secrets. An optional PersistentVolumeClaim for the local artifacts directory.
The Pebble store path is set via the config values in values.yaml. By default the chart's values.yaml does not enable a PVC for the Pebble store itself — for a single-replica development install that is acceptable because the Pod uses the node's local disk. For a real install you must add a PVC for Pebble; see the "Production values" section.
The values.yaml schema is large because the chart wraps many knobs. The values that matter for any install are below; the rest are documented inline in helm/codeq/values.yaml.
The image block sets the container image. Override image.tag to follow a specific release.
image:
repository: ghcr.io/osvaldoandrade/codeq-service
tag: "0.1.0"
pullPolicy: IfNotPresentreplicaCount controls how many Pods the Deployment runs. 1 for a single-instance install; 3 for the raft-cluster path with the right environment overrides.
service controls the Service shape. type: ClusterIP is the default; switch to LoadBalancer or front it with an Ingress (ingress.enabled: true) for external traffic.
config controls the application configuration that flows into the Pod as environment variables via the ConfigMap. Keys mirror the YAML config schema in pkg/config/config.go. The two you almost certainly want to set explicitly are the auth provider URLs:
config:
port: 8080
logLevel: info
logFormat: json
workerJwksUrl: "https://issuer.example.com/.well-known/jwks.json"
workerAudience: "codeq-worker"
workerIssuer: "https://issuer.example.com"secrets.enabled: true provisions a Kubernetes Secret with the named fields. secrets.webhookHmacSecret is the HMAC secret used to sign result webhooks; if you use the webhook delivery feature, set this.
secrets:
enabled: true
webhookHmacSecret: "redacted-secret-here"autoscaling.enabled flips on a HorizontalPodAutoscaler. Useful when the workload is unevenly distributed across the day. The default targets 80% CPU.
ingress.enabled switches on an Ingress object. Configure ingress.className for your controller (nginx, traefik, etc.) and ingress.hosts for the hostnames.
The chart's values.yaml carries legacy keys from earlier versions of codeQ that referenced an external store. Recent codeQ releases position Pebble as the sole storage engine — every other path is deprecated. The chart will be refactored to surface Pebble as a first-class top-level block in an upcoming release. Until then, configure Pebble through the extraEnv escape hatch and disable any legacy substructure:
extraEnv:
- name: PERSISTENCE_PROVIDER
value: pebble
- name: PERSISTENCE_CONFIG
value: '{"path":"/var/lib/codeq/pebble"}'A reasonable production install pins the image, enables Pebble persistence with a PVC, configures real auth, and turns on TLS via an Ingress.
# values-prod.yaml
image:
repository: ghcr.io/osvaldoandrade/codeq-service
tag: "0.1.0"
pullPolicy: IfNotPresent
replicaCount: 1
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 2000m
memory: 4Gi
service:
type: ClusterIP
port: 80
targetPort: 8080
config:
port: 8080
logLevel: info
logFormat: json
defaultLeaseSeconds: 300
workerJwksUrl: "https://issuer.example.com/.well-known/jwks.json"
workerAudience: "codeq-worker"
workerIssuer: "https://issuer.example.com"
identityServiceUrl: "https://issuer.example.com"
secrets:
enabled: true
webhookHmacSecret: "..."
extraEnv:
- name: PERSISTENCE_PROVIDER
value: pebble
- name: PERSISTENCE_CONFIG
value: '{"path":"/var/lib/codeq/pebble"}'
- name: PRODUCER_AUTH_PROVIDER
value: jwks
- name: WORKER_AUTH_PROVIDER
value: jwks
extraVolumes:
- name: pebble
persistentVolumeClaim:
claimName: codeq-pebble
extraVolumeMounts:
- name: pebble
mountPath: /var/lib/codeq/pebble
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: codeq.example.com
paths:
- path: /v1/codeq
pathType: Prefix
tls:
- secretName: codeq-tls
hosts:
- codeq.example.comThe PVC codeq-pebble is provisioned separately (kubectl apply -f pvc.yaml) — the chart's built-in PVC template covers the artifacts directory; the Pebble directory uses extraVolumes so you keep control over the StorageClass, access mode, and size.
Install with the values file:
helm upgrade --install codeq ./helm/codeq \
-f values-prod.yaml \
--namespace codeq --create-namespaceupgrade --install is idempotent — same command for first install and subsequent upgrades.
The single-replica install gives durability against Pod restarts but not against node loss. For high availability you want raft. The chart does not (yet) ship a first-class raft block; you assemble it via extraEnv. Set replicaCount: 3, give each Pod a stable identity, and surface the RAFT_* variables.
For a stable identity you generally migrate from a Deployment to a StatefulSet so each Pod has a predictable hostname (codeq-0, codeq-1, codeq-2) and a per-Pod PVC. The codeQ chart currently ships a Deployment; a StatefulSet-shaped chart is on the roadmap. For the moment, the supported path to a clustered Kubernetes install is to write a small companion chart (or raw manifests) that uses the same image with the raft envs from the Run With Docker Compose page. The compose file is the canonical reference for the environment variables.
In a Kubernetes raft cluster the per-Pod stable hostnames go into RAFT_PEERS and RAFT_PEER_HTTP_ADDRS:
RAFT_PEERS=codeq-0=codeq-0.codeq:7000,codeq-1=codeq-1.codeq:7000,codeq-2=codeq-2.codeq:7000
RAFT_PEER_HTTP_ADDRS=codeq-0=http://codeq-0.codeq:8080,codeq-1=http://codeq-1.codeq:8080,codeq-2=http://codeq-2.codeq:8080
RAFT_SELF_ID=$(hostname)
RAFT_BIND_ADDR=:7000
RAFT_ENABLED=true
RAFT_MUX_ENABLED=true
RAFT_BOOTSTRAP=true # only on codeq-0
The headless Service (clusterIP: None) backing the StatefulSet gives the *.codeq DNS that the peer list relies on.
The Deployment in the chart wires both a readiness probe and a liveness probe against /metrics (or a dedicated /healthz if your version of the chart includes one — check helm/codeq/templates/deployment.yaml). The metrics endpoint is unauthenticated and returns 200 once the application has booted, which is a sufficient liveness signal.
For richer health, expose the Prometheus dashboard documented in Metrics and alert on the application-specific signals (queue depth, lease-reap rate, raft commit latency).
The chart ships a short verification block in templates/NOTES.txt that prints after helm install. The relevant manual commands:
helm -n codeq status codeq
kubectl -n codeq get all
kubectl -n codeq logs deploy/codeq --tail=50
kubectl -n codeq port-forward svc/codeq 8080:80 &
curl -sSf http://localhost:8080/metrics | headThe Pod logs should show an HTTP listener on :8080, a Pebble open, and (in dev mode) static auth providers registered. The metrics endpoint should return Prometheus output.
helm upgrade re-renders the templates with your new values and updates the Deployment. Because the Pod has a single Pebble volume, an upgrade is effectively a serial restart: the new Pod starts, the old Pod terminates, and the volume re-attaches to the new one. Expect a few seconds of downtime per restart in the single-replica topology. In the clustered topology, raft handles the leader rotation transparently.
helm upgrade codeq ./helm/codeq -f values-prod.yaml -n codeq
helm rollback codeq 1 -n codeq # roll back to revision 1
helm history codeq -n codeq # see all revisionsPebble's on-disk format is stable across minor codeQ versions — a chart upgrade that bumps the image tag does not require a state migration. Major version upgrades follow the release notes, which call out any migration step.
If the chart suits you, the next reading is operational. Observability Overview wires up Prometheus and the dashboards. Tuning Knobs covers the config values that affect throughput (lease seconds, backoff policy, requeue inspect limit). Cost of HA tells you what to budget if you move to the three-replica raft topology.
If you want a deeper view into what the application is doing inside the Pod, Concepts Overview opens the architecture chapter. The path from POST /v1/codeq/tasks through the route handler, through the scheduler, through the persistence engine, through (optionally) raft, and back is documented page by page.
If you want a Go service that produces and consumes against this install, Sous Functions Get Started walks through the typed SDK — one stream per process, multiplexed sequence numbers, typed handlers.
Source: github.com/osvaldoandrade/codeq.
- Overview
- Tasks and Results
- Queue Model
- Sharding
- Leases and Ownership
- Multi-Tenancy
- Authentication and Authorization
- Persistence Engine
- Consensus and Replication
- Cluster-Level Failover
- Deployment Modes
- Architecture Overview