PyPNM on Kubernetes (kind)¶
Note: Kubernetes (kind) workflows are supported on Linux hosts. macOS users should not use this guide.
This walkthrough uses the manifests in deploy/kubernetes/. Start by installing kind and creating a cluster using Local Kubernetes (kind) install.
Repo toolkit usage (recommended)¶
Use the toolkit to create a cluster and deploy from GHCR or local builds:
tools/k8s/pypnm_k8s_toolkit.sh --create --image-source ghcr --tag TAG_VALUE --replicas 1
Add --namespace when you want multiple isolated instances (for example, one PyPNM per CMTS):
tools/k8s/pypnm_k8s_toolkit.sh --create --image-source ghcr --tag TAG_VALUE --replicas 1 --namespace pypnm-cmts-a
If Docker or kubectl permissions require it, the toolkit will re-run itself with sudo.
Script-only deploy (no repo clone)¶
This workflow pulls the manifests from GitHub and deploys the GHCR image directly.
curl -fsSL https://raw.githubusercontent.com/PyPNMApps/PyPNM/main/tools/k8s/pypnm_k8s_remote_deploy.sh \\
-o /tmp/pypnm_k8s_remote_deploy.sh
TAG="v1.1.19.0"
NAMESPACE="pypnm-cmts-a"
bash /tmp/pypnm_k8s_remote_deploy.sh --create --tag "${TAG}" --namespace "${NAMESPACE}" --replicas 1
Local image:
tools/k8s/pypnm_k8s_toolkit.sh --create --image-source local --replicas 1
Teardown:
tools/k8s/pypnm_k8s_toolkit.sh --teardown --delete-cluster
Diagram¶
Build and load a local image¶
docker build -t pypnm:local --build-arg PYTHON_VERSION=3.12 .
kind load docker-image pypnm:local --name pypnm-dev
Apply the manifests¶
kubectl apply -k deploy/kubernetes
kubectl get pods
Health check¶
kubectl port-forward deploy/pypnm-api 8000:8000
curl -i http://127.0.0.1:8000/health
Config overrides (non-interactive)¶
Create a patch configmap:
kubectl create configmap pypnm-config-patch \
--from-file=patch.json=/path/to/patch.json \
--dry-run=client -o yaml | kubectl apply -f -
Then add an initContainer to apply the patch into /app/config/system.json:
initContainers:
- name: config-apply
image: pypnm:local
command: ["python", "/app/tools/system_config/apply_config.py"]
args:
- "--input"
- "/config-patch/patch.json"
- "--config"
- "/config/system.json"
volumeMounts:
- name: config-patch
mountPath: /config-patch
- name: pypnm-config
mountPath: /config
volumes:
- name: config-patch
configMap:
name: pypnm-config-patch
- name: pypnm-config
emptyDir: {}