# Namespace, image ref, and storage class confirmed against this cluster # (microk8s, 2026-09-04). Image is pushed to Nexus for a durable, off-node # copy (docker push localhost:30892/... — see README), but the Deployment # below pulls it from the *node's local containerd image store* instead of # over the network: kubelet's image pulls run in the host network namespace, # which uses this node's public DNS resolver, not cluster CoreDNS, so # `nexus-service.nexus.svc.cluster.local` is NOT resolvable for a plain pull # (only for in-cluster builders like Kaniko, whose *build* pod runs in pod # netns). The `microk8s-hostpath` PVC below also pins every pod to whichever # node created it (`ai-workstation`, confirmed via the PV's nodeAffinity), so # a single local `ctr image import` of the pushed tar is enough — see # vote-service/README.md for the import command. `imagePullPolicy: Never` # enforces that: no accidental network pull attempt, no ImagePullBackOff. # `ai-for-dummies` did not exist yet as a namespace, so it is created below, # matching the one-namespace-per-app pattern every other small app in this # cluster uses (judge0, minio, pragent, …). No storageClassName set: # microk8s's `hostpath-storage` addon is the default. apiVersion: v1 kind: Namespace metadata: name: ai-for-dummies --- apiVersion: apps/v1 kind: Deployment metadata: name: ai-for-dummies-vote namespace: ai-for-dummies labels: app: ai-for-dummies-vote spec: replicas: 1 # single replica: the store is one JSON file on one PVC, not a shared DB selector: matchLabels: app: ai-for-dummies-vote strategy: type: Recreate # avoid two pods writing the same PVC-backed file at once template: metadata: labels: app: ai-for-dummies-vote spec: # Pinned to `kubernets`: the image is imported straight into that node's # containerd store (see README) and `microk8s-hostpath` PVs carry a # nodeAffinity for whichever node first binds them, so scheduling and # storage must agree on one node. `kubernets` is the control-plane node # that hosts the rest of this cluster's workloads. nodeSelector: kubernetes.io/hostname: kubernets securityContext: fsGroup: 65532 # matches distroless "nonroot" uid/gid; without it the PVC mounts root-owned and the container can't write votes.json containers: - name: vote-service image: localhost:30892/ai-for-dummies-vote-service:latest imagePullPolicy: Never # image is side-loaded via `ctr image import`; never fetch over the network ports: - containerPort: 8080 env: - name: PORT value: "8080" - name: VOTE_DB_PATH value: /data/votes.json - name: ALLOWED_ORIGIN value: https://netcracker.pages.marcospaulo.dev.br resources: requests: { cpu: 10m, memory: 16Mi } limits: { cpu: 100m, memory: 64Mi } readinessProbe: httpGet: { path: /healthz, port: 8080 } initialDelaySeconds: 2 livenessProbe: httpGet: { path: /healthz, port: 8080 } initialDelaySeconds: 5 volumeMounts: - name: data mountPath: /data securityContext: runAsNonRoot: true readOnlyRootFilesystem: true allowPrivilegeEscalation: false volumes: - name: data persistentVolumeClaim: claimName: ai-for-dummies-vote-data --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: ai-for-dummies-vote-data namespace: ai-for-dummies spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 100Mi --- apiVersion: v1 kind: Service metadata: name: ai-for-dummies-vote namespace: ai-for-dummies spec: selector: app: ai-for-dummies-vote ports: - port: 80 targetPort: 8080