Skip to main content
mastering ckad certified kubernetes application developer

Lab Setup Solutions

6 min read Chapter 8 of 87
Summary

Step-by-step solutions for Exercises 1 and 2: creating...

Step-by-step solutions for Exercises 1 and 2: creating a 3-node Kind cluster with ingress port mappings, and configuring shell aliases with bash completion.

Lab Setup Solutions

Solution: Exercise 1 — Spin Up a 3-Node Kind Cluster

Step 1: Write the Cluster Configuration

Create a directory for your lab files and write the configuration:

mkdir -p ~/ckad-lab
cat > ~/ckad-lab/kind-cluster.yaml << 'EOF'
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
  - role: control-plane
    kubeadmConfigPatches:
      - |
        kind: InitConfiguration
        nodeRegistration:
          kubeletExtraArgs:
            node-labels: "ingress-ready=true"
    extraPortMappings:
      - containerPort: 80
        hostPort: 80
      - containerPort: 443
        hostPort: 443
  - role: worker
  - role: worker
EOF

The heredoc (<< 'EOF') writes the file content exactly as shown. Using single quotes around EOF prevents bash from interpreting any special characters inside the block.

Step 2: Create the Cluster

kind create cluster --config ~/ckad-lab/kind-cluster.yaml --name ckad-practice

Expected output:

Creating cluster "ckad-practice" ...
 ✓ Ensuring node image (kindest/node:v1.30.0) 🖼
 ✓ Preparing nodes 📦 📦 📦
 ✓ Writing configuration 📜
 ✓ Starting control-plane 🕹️
 ✓ Installing CNI 🔌
 ✓ Installing StorageClass 💾
 ✓ Joining worker nodes 🚜
Set kubectl context to "kind-ckad-practice"
You can now use your cluster with:

kubectl cluster-info --context kind-ckad-practice

If the image pull takes a long time on the first run, that is normal — the kindest/node image is approximately 900 MB. Subsequent cluster creations reuse the cached image.

Step 3: Verify All Nodes Are Ready

kubectl get nodes

Expected output:

NAME                          STATUS   ROLES           AGE   VERSION
ckad-practice-control-plane   Ready    control-plane   60s   v1.30.0
ckad-practice-worker          Ready    <none>          45s   v1.30.0
ckad-practice-worker2         Ready    <none>          45s   v1.30.0

All three nodes must show Ready in the STATUS column. If a node shows NotReady, wait 30 seconds and run the command again. Kind’s CNI plugin (kindnet) takes a few seconds to configure networking on each node.

Step 4: Verify the Ingress Label

kubectl get nodes --show-labels | grep ingress-ready

Expected output (labels are a long comma-separated list — look for ingress-ready=true):

ckad-practice-control-plane   Ready    control-plane   90s   v1.30.0   beta.kubernetes.io/arch=amd64,...,ingress-ready=true,...

An alternative way to verify, which is cleaner:

kubectl get nodes -l ingress-ready=true

Expected output:

NAME                          STATUS   ROLES           AGE   VERSION
ckad-practice-control-plane   Ready    control-plane   90s   v1.30.0

Only the control-plane node should appear, because only that node has the ingress-ready=true label.

Step 5: Verify Port Mappings

Check that Docker is forwarding ports 80 and 443 to the control-plane container:

docker port ckad-practice-control-plane

Expected output:

80/tcp -> 0.0.0.0:80
443/tcp -> 0.0.0.0:443

This confirms that traffic reaching your host on ports 80 and 443 will be forwarded to the control-plane container.

Troubleshooting

Problem: ERROR: failed to create cluster: node(s) already exist for a cluster with the name "ckad-practice"

Fix: A cluster with that name already exists. Delete it first:

kind delete cluster --name ckad-practice

Then rerun the create command.

Problem: Cannot connect to the Docker daemon

Fix: Docker is not running. Start it:

sudo systemctl start docker

Or on macOS, open Docker Desktop.

Problem: Port 80 or 443 already in use.

Fix: Another process (web server, reverse proxy) is bound to those ports. Find it:

sudo lsof -i :80
sudo lsof -i :443

Stop the conflicting process or change the hostPort values in your Kind configuration to different ports (e.g., 8080 and 8443).


Solution: Exercise 2 — Configure All Aliases and Verify Bash Completion

Step 1: Add the Configuration to .bashrc

Open ~/.bashrc in your preferred editor and add the following block at the end:

cat >> ~/.bashrc << 'BASHEOF'

# ============================================
# CKAD Kubernetes Shell Configuration
# ============================================

# Core aliases
alias k=kubectl
alias kaf='kubectl apply -f'
export do='--dry-run=client -o yaml'
export now='--force --grace-period 0'

# Resource shortcuts
alias kgp='kubectl get pods'
alias kgd='kubectl get deployments'
alias kgs='kubectl get services'
alias kgn='kubectl get nodes'
alias kgi='kubectl get ingress'
alias kdp='kubectl describe pod'
alias kdd='kubectl describe deployment'
alias kl='kubectl logs'
alias klf='kubectl logs -f'
alias kdel='kubectl delete'
alias kw='kubectl get pods -w'
alias kga='kubectl get all'
alias kns='kubectl config set-context --current --namespace'

# Bash completion
source <(kubectl completion bash)
complete -F __start_kubectl k

# Editor for kubectl edit
export KUBE_EDITOR="vim"

# kubectl output formatting
export COLUMNS=200
BASHEOF

Important: Using >> (append) rather than > (overwrite) prevents destroying your existing .bashrc content. Always double-check this before running the command.

Step 2: Source the Configuration

source ~/.bashrc

This reloads the configuration in your current terminal session. New terminal windows will load it automatically.

If you see any errors during sourcing, the most common cause is a syntax error in the aliases or a missing kubectl binary. Verify kubectl is on your PATH:

which kubectl

Step 3: Verify the k Alias

k get nodes

Expected output — identical to kubectl get nodes:

NAME                          STATUS   ROLES           AGE    VERSION
ckad-practice-control-plane   Ready    control-plane   5m     v1.30.0
ckad-practice-worker          Ready    <none>          4m     v1.30.0
ckad-practice-worker2         Ready    <none>          4m     v1.30.0

Step 4: Verify Bash Completion

Type the following and press Tab twice (do not press Enter):

k get p

Then press <TAB><TAB>. You should see a list including:

persistentvolumeclaims   poddisruptionbudgets     pods
persistentvolumes        podtemplates             priorityclasses

If no completions appear, ensure bash-completion is installed:

# Check if bash-completion is installed
dpkg -l | grep bash-completion

# Install if missing
sudo apt-get install -y bash-completion

Then re-source your .bashrc.

Step 5: Verify the Dry-Run Variable

k run verify --image=nginx $do

Expected output — a valid YAML manifest printed to the terminal, with no resource created in the cluster:

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: verify
  name: verify
spec:
  containers:
  - image: nginx
    name: verify
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

Verify that no Pod was created:

k get pod verify

Expected output:

Error from server (NotFound): pods "verify" not found

This confirms the --dry-run=client flag worked — the command generated YAML without sending it to the API server.

Step 6: Verify Namespace Switching

# Switch to kube-system namespace
kns kube-system

Expected output:

Context "kind-ckad-practice" modified.

Now list Pods without specifying a namespace:

k get pods

Expected output — system Pods:

NAME                                                  READY   STATUS    RESTARTS   AGE
coredns-7db6d8ff4d-xxxxx                              1/1     Running   0          10m
coredns-7db6d8ff4d-yyyyy                              1/1     Running   0          10m
etcd-ckad-practice-control-plane                      1/1     Running   0          10m
kube-apiserver-ckad-practice-control-plane             1/1     Running   0          10m
kube-controller-manager-ckad-practice-control-plane    1/1     Running   0          10m
kube-proxy-xxxxx                                       1/1     Running   0          10m
kube-scheduler-ckad-practice-control-plane             1/1     Running   0          10m

Switch back to default:

kns default

Verification Checklist

Run these commands in sequence. All should succeed:

#CommandExpected Result
1k get nodesThree nodes, all Ready
2k run test --image=nginx $do | head -3apiVersion: v1 / kind: Pod / metadata:
3kns kube-system && k get pods | wc -lAt least 8 lines (header + 7 system Pods)
4kns defaultContext modified
5echo $KUBE_EDITORvim

If all five pass, Exercise 2 is complete.