← NCP-CN 6.10 Study Hub

BlueAlly SA Training Package

Hands-on Labs (local, no Nutanix)

No NKP cluster, no Prism Central, no online lab access required. NKP is a curated bundle of upstream CNCF projects, so you can build the muscle memory for most of the exam's hands-on objectives on your own laptop with kind and free tooling. Every command here was run on macOS (Apple Silicon) with colima before publishing.

What these labs cover, and what they cannot.

Covered (the upstream mechanics NKP is built on): Kubernetes architecture and kubectl, RBAC, the Cluster API object model, GitOps with Flux, OPA Gatekeeper admission policy, the Prometheus monitoring stack, and Velero backup and restore. That is roughly 70% of the exam's hands-on territory, taught with the exact tools NKP ships.

Not covered (stays book-knowledge from the study guides and NKPA videos): the Nutanix infrastructure provider parameters (Prism Central endpoint, subnets, KIB images), the Kommander UI and its workspaces, projects, and platform-app catalog, and the NKP licensing flow. Those need a real NKP estate. The labs build the foundation; the guides carry the product specifics.

Watch first

Three verified primers, in order, before you start. Basics, then exam-grade Kubernetes, then the NKP product itself.

TechWorld with Nana · 1:12
Kubernetes Crash Course
Architecture, pods, services, config, deployments. The foundation.
freeCodeCamp · 2:06
CKA Exam Prep (2026)
CKA-level depth: RBAC, storage, networking, troubleshooting.
Nutanix University · 0:57
Kubernetes in Production with NKP
The product tour: fleet, workspaces, GitOps, CAPI, observability.

Setup (once)

Install the toolchain, start a container runtime, and create a local cluster. The cluster you create is a kind (Kubernetes in Docker) cluster, which is exactly what NKP uses for its temporary bootstrap cluster (Section 1).

# install the toolchain (Homebrew)
brew install colima docker kind helm clusterctl fluxcd/tap/flux velero kubectl

# start a container runtime (no Docker Desktop license needed)
colima start --cpu 6 --memory 12 --disk 60

# create the lab cluster, then confirm the node is Ready
kind create cluster --name ncpcn-lab
kubectl --context kind-ncpcn-lab get nodes

The labs

  1. kind and kubectl: the control plane
  2. RBAC: Role and RoleBinding
  3. Cluster API: the object model
  4. Flux: GitOps continuous delivery
  5. Gatekeeper: admission policy
  6. Prometheus: the monitoring stack
  7. Velero: backup and restore

Lab 0 · kind and kubectl: the control plane validated

Maps to Section 1 / 2 · the bootstrap cluster (Q5, Q6), NotReady troubleshooting (Q22)

Deploy and expose an app, then look at what is actually running. The kube-system namespace shows the control plane the exam keeps testing sideways: etcd, kube-apiserver, kube-scheduler, kube-controller-manager, kube-proxy.

kubectl --context kind-ncpcn-lab create namespace demo
kubectl -n demo create deployment web --image=nginx:stable --replicas=2
kubectl -n demo expose deployment web --port=80 --type=ClusterIP
kubectl -n demo rollout status deployment/web

# the control plane, live
kubectl -n kube-system get pods

// Observe: kind is Kubernetes in Docker. No container runtime, no kind cluster, no NKP install. That is the literal reason the install host needs a runtime (Q6).

Lab 1 · RBAC: Role and RoleBinding validated

Maps to Section 3 · in-cluster RBAC vs fleet RBAC (Q34, Q35)

Grant a service account read-only pod access in one namespace, then prove the boundary with kubectl auth can-i. This is the in-cluster Kubernetes RBAC side of the distinction; the Kommander workspace and project roles are the fleet-plane side that federates downward.

kubectl create namespace team-a
kubectl -n team-a create serviceaccount dev
kubectl -n team-a create role pod-reader --verb=get,list,watch --resource=pods
kubectl -n team-a create rolebinding dev-pod-reader --role=pod-reader --serviceaccount=team-a:dev

kubectl auth can-i list pods   --as=system:serviceaccount:team-a:dev -n team-a    # yes
kubectl auth can-i list pods   --as=system:serviceaccount:team-a:dev -n default   # no  (Role is namespaced)
kubectl auth can-i delete pods --as=system:serviceaccount:team-a:dev -n team-a    # no  (verb not granted)

// Note: kubectl auth can-i exits non-zero on a "no". Handy in scripts, and a small detail worth knowing.

Lab 2 · Cluster API: the object model validated

Maps to Section 2 · management cluster (Q7), KubeadmControlPlane vs MachineDeployment (Q21, Q23), the generate/dry-run workflow (Q20)

Install the Cluster API controllers with the Docker provider. The exam tests the CAPI object model, which is provider-agnostic: the Nutanix provider swaps in for Docker, but the objects are identical. After init, the management cluster manages itself, exactly as NKP pivots CAPI state into the management cluster.

clusterctl init --infrastructure docker

# the CAPI object model, now live as CRDs:
kubectl get crds | grep cluster.x-k8s.io
#  clusters                  -> the top-level cluster object
#  kubeadmcontrolplanes      -> owns control-plane replicas + k8s version (Q21)
#  machinedeployments        -> one per worker pool, owns worker replicas (Q23)
#  machinesets / machines    -> the layers beneath a MachineDeployment
#  dockermachinetemplates    -> machine shapes (NutanixMachineTemplate on real NKP)

# the provider controllers (management cluster is self-managing, Q7):
kubectl get deploy -A | grep -E 'capi-|capd-'

# the customization workflow (Q20): render editable manifests instead of applying
clusterctl generate cluster my-cluster --kubernetes-version v1.31.0 \
  --control-plane-machine-count=1 --worker-machine-count=2 > my-cluster.yaml

// Note: on a default kind cluster the Docker provider will not boot real worker nodes without mounting the host Docker socket, which is a Docker-provider quirk, not exam content. The exam tests the object model and the generate-then-apply workflow, which is what this lab makes concrete. On real NKP the same clusterctl and CAPI objects drive Nutanix nodes through Prism Central.

Lab 3 · Flux: GitOps continuous delivery validated

Maps to Section 4 · GitOps CD (Q72), Flux reconciliation and HelmReleases (Q29)

Install Flux, point it at a Git repo, and watch it reconcile the manifests into the cluster automatically. This is exactly the project-level Continuous Delivery mechanism NKP exposes, and the Flux HelmReleases you inspect when Kommander platform apps misbehave.

flux install

flux create source git podinfo \
  --url=https://github.com/stefanprodan/podinfo --branch=master --interval=1m

flux create kustomization podinfo \
  --source=GitRepository/podinfo --path="./kustomize" --prune=true \
  --interval=5m --target-namespace=default --wait

flux get kustomizations
kubectl -n default get deploy podinfo     # deployed straight from Git

Lab 4 · Gatekeeper: admission policy validated

Maps to Section 3 · OPA Gatekeeper "no privileged containers" admission rule (Q37)

Install Gatekeeper, write a constraint that forbids privileged containers, and watch the admission webhook block one. Scope it to a single namespace so it cannot interfere with system pods.

kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/v3.22.2/deploy/gatekeeper.yaml
kubectl -n gatekeeper-system rollout status deploy/gatekeeper-controller-manager

# the policy: a ConstraintTemplate (the rule) + a Constraint (where it applies)
kubectl apply -f - <<'EOF'
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8sdenyprivileged
spec:
  crd:
    spec:
      names:
        kind: K8sDenyPrivileged
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8sdenyprivileged
        violation[{"msg": msg}] {
          c := input.review.object.spec.containers[_]
          c.securityContext.privileged == true
          msg := sprintf("Privileged container not allowed: %v", [c.name])
        }
EOF
kubectl wait --for condition=established crd/k8sdenyprivileged.constraints.gatekeeper.sh --timeout=90s

kubectl create namespace policy-demo
kubectl apply -f - <<'EOF'
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sDenyPrivileged
metadata:
  name: no-privileged
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaces: ["policy-demo"]
EOF

# this is DENIED by the admission webhook:
kubectl -n policy-demo run priv --image=nginx:stable --restart=Never \
  --overrides='{"spec":{"containers":[{"name":"priv","image":"nginx:stable","securityContext":{"privileged":true}}]}}'
# Error: admission webhook "validation.gatekeeper.sh" denied the request:
#        [no-privileged] Privileged container not allowed: priv

# a normal pod is ALLOWED:
kubectl -n policy-demo run ok --image=nginx:stable --restart=Never

Lab 5 · Prometheus: the monitoring stack validated

Maps to Section 3 · the monitoring trio (Q47), ServiceMonitor (Q49), vs the logging stack

Install kube-prometheus-stack and confirm the trio the exam loves to swap with logging components: Prometheus collects metrics, Alertmanager routes alerts, Grafana shows dashboards. Logging is the other stack (Loki stores, Grafana views, the Logging Operator collects).

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm install kps prometheus-community/kube-prometheus-stack -n monitoring --create-namespace

# the trio, live
kubectl -n monitoring get pods | grep -E 'prometheus-kps|grafana|alertmanager'

# the CRD behind scraping a custom app's metrics (Q49)
kubectl get crd servicemonitors.monitoring.coreos.com

// Note: install without a blocking --wait and poll readiness instead; this chart pulls many images and a blocking wait can stall.

Lab 6 · Velero: backup and restore validated

Maps to Section 3 · backup to object storage (Q41), velero backup (Q44), velero restore (Q45)

Stand up MinIO as S3-compatible object storage, install Velero against it, then back up a namespace, delete it, and restore it. Backups land in object storage with working credentials, which is one of Velero's two foundational dependencies.

kubectl apply -f https://raw.githubusercontent.com/vmware-tanzu/velero/main/examples/minio/00-minio-deployment.yaml
kubectl -n velero rollout status deploy/minio

printf '[default]\naws_access_key_id = minio\naws_secret_access_key = minio123\n' > minio-creds

velero install --provider aws --plugins velero/velero-plugin-for-aws:v1.12.0 \
  --bucket velero --secret-file minio-creds --use-volume-snapshots=false \
  --backup-location-config region=minio,s3ForcePathStyle=true,s3Url=http://minio.velero.svc:9000

# back up the demo namespace from Lab 0, delete it, restore it
velero backup create demo-bak --include-namespaces demo --wait
kubectl delete ns demo
velero restore create demo-restore --from-backup demo-bak --wait
kubectl -n demo get deploy web      # back from the backup
Honest scope on Velero: this lab validates resource-level backup and restore to object storage (Q41, Q44, Q45). Velero's second dependency, snapshotting persistent-volume data via CSI VolumeSnapshotClasses (Q43, Q46), needs the external-snapshotter controller plus a snapshot-capable CSI driver, which a default kind cluster does not ship. The PV-snapshot path is real and on the exam; it is just not exercised in this minimal local setup. Understand it from the study guide.

Cleanup

kind delete cluster --name ncpcn-lab
colima stop          # frees the VM; colima start brings it back