Nauval Firmansyah
Nauval Firmansyah
Published on 2026-01-19 / 53 Visits
1
1

Training Survival K9ADM

Pada bagian awal blog ini, saya akan membagikan berbagai error yang saya temui dari para peserta selama training, termasuk proses analisis dan problem solving yang dilakukan. Selanjutnya, artikel ini akan membahas penyelesaian quiz 1 sampai quiz 3.

Error

Dial tcp 127.0.0.1:8080: connect: connection refused

Error seperti ini didapatkan ketika mencoba mengoperasikan command kubectl seperti kubectl get node dan lain-lain. Hal pertama yang di perlukan adalah pastikan file kubeconfig tersedia pada folder .kube di user yang akan menjalankan kubectl.

  1. Check folder .kube dan kubeconfig

ls -a ~/ # Jika folder .kube ada check file config
ls -l ~/.kube/config # Jika folder dan config tidak ada lanjut step 2
  1. Copy kubeconfig ke .kube

mkdir ~/.kube
sudo cp /etc/kubernetes/admin.conf ~/.kube/config
sudo chown $(id -u):$(id -g) ~/.kube/config
  1. Verifikasi dengan check node dan pod

kubectl get node
kubectl get pod -n kube-system

Selalu copy kubeconfig pada instance yang ingin terhubung dengan cluster

Error: Calico-node failed not intilialized

Ketika menginstall calico sebagai cni ada beberapa case yang gagal sehingga node state nya akan berubah menjadi NotReady karena komunikasi cluster akan mendapati gangguan. Disini saya akan menjelaskan untuk proses troubleshooting untuk calico:

  1. Check logs pod calico-node

  • Get pod error calico-node

kubectl get pod -n kube-system -k k8s-app=calico-node
  • Describe pod calico-node

kubectl describe -n kube-system pod calico-node-xxxx <- paste your pod error
  • Check logs pod calico-node

kubectl logs -n kube-system calico-node-xxxx -c install-cni
---
Get https://[10.96.0.1]:443/apis/crd.projectcalico.org/v1/clusterinformations/default: dial tcp 10.96.0.1:443: i/o timeout
  1. Create configmap

kubectl create cm -n kube-system kubernetes-services-endpoint\
--from-literal=KUBERNETES_SERVICE_HOST=k9adm-master\
--from-literal=KUBERNETES_SERVICE_PORT=6443
  1. Jangan lupa untuk semua node di mapping hosts master

nano /etc/hosts
---
172.1.1.10      k9adm-master
  1. Restart daemonset calico-node

kubectl rollout restart daemonset -n kube-system calico-node

Error: Metrics Not Available Yet

Error ini biasa terjadi ketika menginstall metrics-server berhasil namun saat ingin verifikasi menggunakan kubectl top gagal mendapatkan usage resource pod atau node.

Cara memperbaiki seperti di bawah ini:

  1. Check heatlh-check api

kubectl get apiservices v1beta1.metrics.k8s.io
---
NAME                     SERVICE                      AVAILABLE   AGE
v1beta1.metrics.k8s.io   kube-system/metrics-server   False       6d5h
  1. Check penyebab api false

  • Check pod metrics-server pastikan running

kubectl get pod -n kube-system -l k8s-app=metrics-server -o wide
  • Check logs pod metrics-server

kubectl logs -n kube-system metrics-server-xxxxx-xxxxx
  • Describe apiservice metrics-server

kubectl describe apiservices v1beta1.metrics.k8s.io

Jika terdapat error ke api kubernetes dapat dicoba dengan delete kube-proxy pada node master

  1. Delete pod kube-proxy di node-master

  • Check name pod kube-proxy yang ada master

kubectl get pod -n kube-system -l k8s-app=kube-proxy -o wide
  • Delete pod kube-proxy-h9kgm

kubectl delete pod -n kube-system kube-proxy-h9kgm
  1. Verifikasi kubectl top node dan kubectl top pod

kubectl top node
kubectl top pod -n kube-system

Error: Can't Hit ClusterIP Service

Pada saat pengetesan hit clusterip mengalami timeout yang dimana ekspetasinya adalah ketika hit akan success 200. Cara ini bisa solve dengan mencoba delete pod kube-proxy node master atau bisa juga dengan restart daemonset kube-proxy tapi restart kube-proxy tidak disarankan pada level production karena cluster akan mengalami intermitten ketika proses restart berlangsung.

  1. Opsi 1 delete pod kube-proxy node master dapat mereferensi pada artikel sebelumnya

  2. Opsi 2 restart daemonset kube-proxy

kubectl rollout restart daemonset -n kube-system kube-proxy

Tips To Debug

  1. Check status pod

kubectl get pod -n {namespace}
  1. Describe pod agar mengetahui lebih jelas state yang berjalan

kubectl describe pod -n {namespace}
  1. Check logs apabila pod gagal di jalankan

kubectl logs -n {namespace} {name-pod}
  1. Check logs per container apabila pods memiliki lebih dari satu container

kubectl logs -n {namespace} {name-pod} -c {name-container}
  1. Check service komponen kubernetes pastikan running

kubectl get pod -n kube-system

# check setiap node
systemctl status kubelet
  1. Check hostname pastikan setiap ip node cluster sudah di mapping pada hostname

#Jika tidak ada hostname di /etc/hosts

NODE_LIST=$(kubectl get nodes -o wide --no-headers | awk '{print $1,$6}')

ALL_NODES=$(kubectl get nodes --no-headers | awk '{print $1}')

for node in $ALL_NODES; do
  echo "Updating /etc/hosts on $node"

  for entry in "$NODE_LIST"; do
    NODE_NAME=$(echo $entry | awk '{print $1}')
    NODE_IP=$(echo $entry | awk '{print $2}')

    ssh $node "grep -q '$NODE_NAME' /etc/hosts || \
      echo '$NODE_IP $NODE_NAME' | sudo tee -a /etc/hosts > /dev/null"
  done
done

Quiz

Quiz 1

Namespace Requirements:

  • Create namespace: nginx

  • Create namespace: httpd

Pod & Image Requirements:

  • Nginx Deployment (Namespace: nginx):

    • Create 2 Pods named: {username}-pod-nginx-1 and {username}-pod-nginx-2

    • Image: registry.adinusa.id/adinusa/nginx:alpine

    • Label: app=nginx

  • HTTPD Deployment (Namespace: httpd):

    • Create 2 Pods named: {username}-pod-httpd-1 and {username}-pod-httpd-2

    • Image: registry.adinusa.id/adinusa/httpd:2.4

    • Label: app=httpd


  1. Create namespace

kubectl create ns httpd
kubectl create ns nginx
  1. Create manifest pod nginx dan httpd

nano quiz1-pods.yaml
apiVersion: v1
kind: Pod
metadata:
  name: valansy-pod-nginx-1
  namespace: nginx
  labels:
    app: nginx
spec:
  containers:
  - name: nginx-container
    image: registry.adinusa.id/adinusa/nginx:alpine
    ports:
    - containerPort: 80
---
apiVersion: v1
kind: Pod
metadata:
  name: valansy-pod-nginx-2
  namespace: nginx
  labels:
    app: nginx
spec:
  containers:
  - name: nginx-container
    image: registry.adinusa.id/adinusa/nginx:alpine
    ports:
    - containerPort: 80
---
apiVersion: v1
kind: Pod
metadata:
  name: valansy-pod-httpd-1
  namespace: httpd
  labels:
    app: httpd
spec:
  containers:
  - name: httpd-container
    image: registry.adinusa.id/adinusa/httpd:2.4
    ports:
    - containerPort: 80
---
apiVersion: v1
kind: Pod
metadata:
  name: valansy-pod-httpd-2
  namespace: httpd
  labels:
    app: httpd
spec:
  containers:
  - name: httpd-container
    image: registry.adinusa.id/adinusa/httpd:2.4
    ports:
    - containerPort: 80
  1. Apply manifeset nginx dan httpd

kubectl apply -f quiz1-pods.yaml
  1. Verifikasi pod nginx dan httpd

kubectl get pod -n nginx
kubectl get pod -n httpd

Quiz 2

1. Configuration:

  • ConfigMap: Create a ConfigMap named {username}-config containing a custom nginx.conf

2. Storage Requirements (PV & PVC):

  • PersistentVolume (PV): - Name: {username}-pv

    • Capacity: 1Gi,

    • Access Mode: ReadWriteMany

    • HostPath: /opt/data, This folder with file already on k9adm-worker1 and k9adm-worker2, after run nusactl start, You can verify

  • PersistentVolumeClaim (PVC):

    • Name: {username}-pvc

    • Request: 1Gi

    • Access Mode: ReadWriteMany

3. Workload (Deployment):

  • Name: {username}-nginx-quiz

  • Replicas: 2

  • Image: registry.adinusa.id/adinusa/nginx:alpine

  • Storage Attachment: Mount the PVC to directory /usr/share/nginx/html inside the container.

  • Volume: Reference the {username}-config within the deployment spec. Attach to /etc/nginx/nginx.conf

4. Service NodePort

  • Name: {username}-svc-quiz

  • Port: 30001

5. Ingress

  • Name: {username}-ing-quiz

  • Domain: {username}-quiz.id

  • Attach into svc: {username}-svc-quiz

  • Make sure can access with curl from Workstation


  1. Create configmap nginx.conf

  • Buat file nginx.conf

nano nginx.conf
---
user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}
  • Create configmap dari file nginx.conf

kubectl create configmap valansy-config --from-file nginx.conf
  1. Create PV dan PVC

  • Create manifest pv dan pvc

nano quiz2-storage.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-valansy
spec:
  capacity:
    storage: 1Gi
  accessModes:
  - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  hostPath:
    path: "/opt/data"

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-valansy
spec:
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
  • Apply file storage

kubectl apply -f quiz2-storage.yaml
  1. Create deployent nginx

  • Create manifest

nano quiz2-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
  generation: 1
  name: valansy-nginx-quiz
  labels:
    app: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: registry.adinusa.id/adinusa/nginx:alpine
        imagePullPolicy: Always
        name: nginx
        volumeMounts:
        - name: vol
          mountPath: /usr/share/nginx/html
        - name: vol-cm
          mountPath: /etc/nginx/nginx.conf
          subPath: nginx.conf
        ports:
        - containerPort: 80
          protocol: TCP
      volumes:
      - name: vol
        persistentVolumeClaim:
          claimName: pvc-valansy
      - name: vol-cm
        configMap:
          name: valansy-config
  • Apply manifest

kubectl apply -f quiz2-deployment.yaml
  1. Create service from deployment

  • create service

kubectl expose deployment valansy-nginx-quiz --name=valansy-svc-quiz --type NodePort --port 80
# Format penulisan
# kubectl expose {nama-deployment} --name={nama-service} --type NodePort --port 80 --node-port 30001
  • patching nodeport ke 30001

kubectl patch svc valansy-svc-quiz \
  --type='json' \
  -p='[
    {
      "op": "replace",
      "path": "/spec/ports/0/nodePort",
      "value": 30001
    }
  ]'
  1. Create ingress

kubectl create ingress valansy-ing-quiz --rule="valansy-quiz.id/=valansy-svc-quiz:80"
  1. Tambahkan domain pada mapping ip loadbalancer

nano /etc/hosts
---
172.1.1.100     valansy-quiz.id
# ip-loadbalancer-ingress    domain
  1. Verifikasi

curl valansy-quiz.id

Quiz 3

1. Environment Setup:

  • Namespace: Create and use a namespace named quiz for all subsequent resources.

  • Node Labeling:

    • Label k9adm-worker1 with node-environment=production

    • Label k9adm-worker2 with node-environment=staging

2. Database Workload (Pod & Service):

  • Database Pod:

    • Name: {username}-db

    • Image: mysql:8.0 (Environment variables for DB initialization are optional for this task).

    • Mysql env:

      • MYSQL_ROOT_PASSWORD: rootpwquiz

      • MYSQL_DATABASE: quiz-db

  • Database Service:

    • Name: db-svc-quiz

    • Type: ClusterIP

3. Application Workloads (Deployments):

  • Deployment V1 (Production):

    • Name: {username}-quiz-v1

    • Replicas: 2

    • Image: mysql:8.0

    • Node Selection: Must run only on nodes with node-environment=production.

    • Service: Create prod-svc-quiz (NodePort: 32701) pointing to this deployment.

  • Deployment V2 (Staging):

    • Name: {username}-quiz-v2

    • Replicas: 1

    • Image: mysql:8.0

    • Node Selection: Must run only on nodes with node-environment=staging.

    • Service: Create stg-svc-quiz (NodePort: 32702) pointing to this deployment.

4. Network Security (NetworkPolicy):

  • Name: {username}-net-quiz

  • Requirement: Apply a policy to the {username}-db pod.

  • Rule: Allow traffic ONLY from pods located on nodes labeled node-environment:production. You can use labels that you want.

  • Connectivity: Ensure the database is accessed only via the service name db-svc-quiz.


  1. Enviroment Setup

  • Create namespace quiz

kubectl create ns quiz
  • Labeling node

kubectl label nodes k9adm-worker1 node-environment=production
kubectl label nodes k9adm-worker2 node-environment=staging
  1. Setup database

  • Create pod

kubectl run {username}-db --image=mysql:8.0 -n quiz \
  --env=MYSQL_ROOT_PASSWORD=rootpwquiz \
  --env=MYSQL_DATABASE=quiz-db
  • Create service

kubectl expose pod -n quiz valansy-db --port 3306 --name db-svc-quiz -n quiz
  1. Setup deployment

  • Create manifest prod

nano quiz3-prod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: valansy-quiz-v1
  namespace: quiz
spec:
  replicas: 2
  selector:
    matchLabels:
      app: quiz-v1
      env: prod
  template:
    metadata:
      labels:
        app: quiz-v1
        env: prod
    spec:
      nodeSelector:
        node-environment: production
      containers:
        - name: mysql
          image: mysql:8.0
          env:
            - name: MYSQL_ROOT_PASSWORD
              value: rootpwquiz
            - name: MYSQL_DATABASE
              value: quiz-db
          ports:
            - containerPort: 3306
---
apiVersion: v1
kind: Service
metadata:
  name: prod-svc-quiz
  namespace: quiz
spec:
  type: NodePort
  selector:
    app: quiz-v1
    env: prod
  ports:
    - port: 3306
      targetPort: 3306
      nodePort: 32701
  • Apply manifest prod

kubectl apply -f quiz3-prod.yaml
  • Create manifest staging

nano quiz3-stag.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: valansy-quiz-v2
  namespace: quiz
spec:
  replicas: 1
  selector:
    matchLabels:
      app: quiz-v2
      env: stag
  template:
    metadata:
      labels:
        app: quiz-v2
        env: stag
    spec:
      nodeSelector:
        node-environment: staging
      containers:
        - name: mysql
          image: mysql:8.0
          env:
            - name: MYSQL_ROOT_PASSWORD
              value: rootpwquiz
            - name: MYSQL_DATABASE
              value: quiz-db
          ports:
            - containerPort: 3306
---
apiVersion: v1
kind: Service
metadata:
  name: stg-svc-quiz
  namespace: quiz
spec:
  type: NodePort
  selector:
    app: quiz-v2
    env: stag
  ports:
    - port: 3306
      targetPort: 3306
      nodePort: 32702
  • Apply manifest staging

kubectl apply -f quiz3-stag.yaml
  • Verifikasi pod dan service

kubectl get pod -n quiz -o wide
kubectl get svc -n quiz
  1. Creaete Network Policy

  • Create manifest network policy

nano quiz3-netpol.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: valansy-net-quiz
  namespace: quiz
spec:
  podSelector:
    matchLabels:
      run: valansy-db
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          env: prod
    ports:
    - protocol: TCP
      port: 3306
  • Apply manifest

kubectl apply -f quiz3-netpol.yaml
  • Verifikasi netpol access mysql via pod quiz-v1 (production) dengan ekspetasi berhasil mengakses database

# Access via pod node 1
kubectl exec -n quiz -it valansy-quiz-v1-xxxxx-xxxx -- bash
bash-5.1# mysql -u root -h db-svc-quiz -prootpwquiz
  • Verifikasi netpol access mysql via pod quiz-v2 (staging) dengan ekspetasi gagal akses database

# Access via pod node 2
kubectl exec -n quiz -it valansy-quiz-v2-xxxxx-xxxx -- bash
bash-5.1# mysql -u root -h db-svc-quiz -prootpwquiz


Comment