Jalur CD · Tekton di minikube · putaran kustom

Peta Konsep Pipeline — Lab 3 s/d 8

Cara membaca satu pipeline Tekton tumbuh tiap lab: apa yang ditambahkan, fungsi ↔ command yang menjalankannya, sintaks YAML yang menyusunnya, dan mana nama yang bebas dikustom vs terikat (kata baku). Jalur CI (Lab 1–2 di GitHub Actions) adalah jalur terpisah — tak dibahas di sini.

BEBAS — nama saya sendiri TERIKAT — diminta tool, wajib persis Nyata — task asli (bekerja) Placeholder — masih echo
§L3

Pipeline dasar — Task, Pipeline, params

folder labs/01_base_pipeline · pipeline lab3-pipeline

Yang ditambahkan: Task echo & checkout, satu Pipeline, konsep params dan runAfter. Ini fondasi — rantai clone → lint → tests → build → deploy terbentuk, tapi 4 terakhir masih echo (placeholder).

📦 Yang harus di-install — 5 tool (sekali saja)

Baris biru = pilih sesuai mesin: 🖥️ amd64 · Intel/AMD · Windows-WSL 🍎 arm64 · Mac Apple Silicon · VirtualBox
# ⚠️ unduh binary di ~ (HOME), BUKAN /mnt/c — Windows Defender hapus binary Linux
$ cd ~
$ uname -m        # cek dulu: x86_64 = Intel/AMD · aarch64 = ARM (Mac)

# 1) Docker — SAMA untuk semua mesin
$ sudo apt install -y docker.io
$ sudo usermod -aG docker $USER && newgrp docker

# 2) kubectl — pilih SATU baris sesuai arsitektur
$ curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"   # amd64
$ curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/arm64/kubectl"   # ⟵ arm64 (Mac)
$ sudo install kubectl /usr/local/bin/

# 3) minikube — pilih SATU, lalu nyalakan
$ curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64   # amd64
$ curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-arm64   # ⟵ arm64 (Mac)
$ sudo install minikube-linux-* /usr/local/bin/minikube
$ minikube start --driver=docker      # driver 'docker' untuk KEDUA arsitektur

# 4) tkn — $(uname -m) otomatis mengisi x86_64 / aarch64 → 1 baris utk semua
$ V=$(curl -s https://api.github.com/repos/tektoncd/cli/releases/latest | grep -oP '"tag_name":\s*"v\K[^"]+')
$ curl -sLO "https://github.com/tektoncd/cli/releases/download/v$V/tkn_${V}_Linux_$(uname -m).tar.gz"
$ sudo tar xzf tkn_${V}_Linux_$(uname -m).tar.gz -C /usr/local/bin/ tkn

# 5) Tekton DI DALAM cluster (Pipelines + Triggers) — "engine"-nya (SAMA semua)
$ kubectl apply -f https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml
$ kubectl apply -f https://storage.googleapis.com/tekton-releases/triggers/latest/release.yaml
$ kubectl apply -f https://storage.googleapis.com/tekton-releases/triggers/latest/interceptors.yaml
$ kubectl get pods -n tekton-pipelines   # verifikasi: 6 pod 1/1 Running

amd64 vs arm64 = arsitektur CPU, bukan OS. x86_64/amd64 = Intel/AMD (mayoritas Windows-WSL) · aarch64/arm64 = ARM (Mac Apple Silicon M1/M2/M3). Salah arsitektur → binary Exec format error.
VirtualBox di Mac = pengganti WSL — cara Mac menjalankan Ubuntu (host-nya), bukan driver minikube. Di dalam Ubuntu-nya, minikube tetap --driver=docker. Yang berubah cuma arsitektur binary (arm64), bukan cara install-nya.

clonecheckout (git) lintecho testsecho buildecho deployecho

Insight: hasil clone jatuh ke emptyDir pod → hilang saat pod selesai. Makanya lint/tests belum benar-benar memakainya — solusinya Workspace di §L5.

Fungsi ↔ Command

Daftarkan / ubah definisi Task & Pipeline ke clusterkubectl apply -f tasks.yaml
Lihat task apa saja yang sudah terpasangtkn task ls
Jalankan pipeline sambil streaming logtkn pipeline start lab3-pipeline --showlog
Kirim nilai parameter dari luar-p repo-url=... -p branch=main
Lihat riwayat run (Succeeded/Failed)tkn pipelinerun ls

Sintaks YAML — bagian intinya

kind: Task              # satuan kerja = 1 pod
metadata:
  name: echo            # BEBAS
spec:
  params:              # slot input yang bikin task reusable
    - name: message
  steps:
    - name: echo-message
      image: alpine:3   # TERIKAT: tempat step jalan
      args: ["$(params.message)"]  # sisip nilai param
---
kind: Pipeline
spec:
  params:                   # LAPIS 1: param milik pipeline
    - name: repo-url
  tasks:
    - name: clone          # nama task-di-pipeline (BEBAS)
      taskRef: { name: checkout }
      params:               # LAPIS 2: dioper ke task
        - name: repo-url
          value: "$(params.repo-url)"
    - name: lint
      runAfter: [ clone ]      # INI yang menentukan URUTAN

2 lapis params: param pipeline (spec.params, yang kamu kirim via -p) dioper ke param task (tasks[].params). Nama boleh sama, perannya beda lapis. Dan runAfter = satu-satunya yang menentukan urutan jalan.

BEBAS vs TERIKAT di lab ini

BEBAS — nama saya

echocheckout lab3-pipelinemessage repo-urlbranch clone / lint / tests …

TERIKAT — kata baku YAML

apiVersionkind spec / stepsimage command / argsrunAfter $(params.…)
§L4

Trigger — pipeline jalan otomatis dari event

folder labs/02_add_git_trigger · pipeline lab4-pipeline · listener lab4-listener

Yang ditambahkan: EventListener + TriggerBinding + TriggerTemplate, plus ServiceAccount pipeline + RBAC (tak ada di dokumen IBM). Pipeline-nya sama — yang berubah: pemicunya jadi event, bukan tkn start manual. Ini cabang, bukan batang.

📦 Yang harus di-install

Tak ada instalasi baru. Tekton Triggers sudah ikut terpasang di §L3 (langkah 5). Di lab ini kamu cuma membuat objek lewat kubectl apply -f rbac.yaml (SA + RBAC) & 3 file trigger — lihat blok Fungsi ↔ Command di bawah.

⚡ eventcurl / webhook EventListenerlab4-listener PipelineRuntercipta sendiri lab4-pipelineclone→…→deploy

Fungsi ↔ Command

Beri izin listener membuat PipelineRun (SA + RBAC)kubectl apply -f rbac.yaml
Pastikan ServiceAccount sudah adakubectl get sa pipeline
Cek listener sudah AVAILABLEtkn eventlistener ls
Buka jalur ke listener (terminal 1, biarkan hidup)kubectl port-forward service/el-lab4-listener 8090:8080
Kirim event tiruan (terminal 2)curl -X POST http://localhost:8090 -d '{...}'

Sintaks YAML — rantai 3 objek trigger

kind: EventListener
metadata: { name: lab4-listener }
spec:
  serviceAccountName: pipeline   # ← harus cocok dgn rbac.yaml
  triggers:
    - bindings: [{ ref: lab4-binding }]
      template: { ref: lab4-template }
---
kind: TriggerBinding      # AMBIL data dari isi event
spec: { params:
    - name: repository
      value: $(body.repository.url) }
---
kind: TriggerTemplate     # CETAK PipelineRun baru
spec: { resourcetemplates:
    - kind: PipelineRun
      metadata: { generateName: lab4-pipeline-run- }
      spec: { pipelineRef: { name: lab4-pipeline }}}  # ← WAJIB = metadata.name pipeline asli

Kendala nyata yang kamu lewati: pipelines.tekton.dev "lab4-pipeline" not found — TriggerTemplate merujuk lab4-pipeline tapi pipeline.yaml masih bernama cd-pipeline. Ganti nama = ganti di SEMUA tempat yang merujuk (impact map).

BEBAS vs TERIKAT di lab ini

BEBAS — nama saya

lab4-listenerlab4-binding lab4-templategenerateName prefix

TERIKAT — wajib persis

serviceAccountName: pipeline $(body.…)$(tt.params.…) tekton-triggers-eventlistener-roles el-<nama> (nama service otomatis)

Dari mana ClusterRole itu? tekton-triggers-eventlistener-roles/-clusterroles ikut terpasang saat install Tekton Triggers (Lab 3), bukan kamu buat. rbac.yaml cuma menyambungkan SA pipeline ke role itu.

§L5

Catalog + Workspace — hasil clone tersimpan

folder labs/03_use_tekton_catalog · pipeline lab5-pipeline · PVC custom-pvc · workspace ws-source

Yang ditambahkan: ganti checkout buatan sendiri dengan git-clone dari catalog, dan sediakan Workspace + PVC supaya hasil clone tersimpan (bukan hilang di emptyDir). Ini tulang punggung — tanpanya lint & test tak bisa lihat kode.

📦 Yang harus di-install

# git-clone dari catalog — ⚠️ JANGAN `tkn hub install` (server mati)
$ kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/git-clone/0.9/git-clone.yaml
# storageClass 'standard' sudah default di minikube — cukup dicek:
$ kubectl get storageclass
clonegit-clone + PVC lintecho testsecho buildecho deployecho
cloneTULIS kode 🗄️ ws-source → custom-pvcdisk bersama antar-task lint / testsBACA kode

Fungsi ↔ Command

Pasang task git-clone dari catalog (bukan tkn hub)kubectl apply -f .../git-clone/0.9/git-clone.yaml
Buat "tiket pesan disk" (PVC)kubectl apply -f pvc.yaml
Pastikan PVC sudah dapat diskkubectl get pvc # STATUS: Bound
Jalankan sambil menyambung workspace ke PVC-w name=ws-source,claimName=custom-pvc

Sintaks YAML — colokan workspace

kind: PersistentVolumeClaim
metadata: { name: custom-pvc }
spec:
  storageClassName: standard   # minikube; IMMUTABLE (delete dulu utk ubah)
  accessModes: [ ReadWriteOnce ]
---
kind: Pipeline
spec:
  workspaces:
    - name: ws-source        # DEKLARASI colokan (BEBAS)
  tasks:
    - name: clone
      workspaces:
        - name: output      # TERIKAT: git-clone minta "output"
          workspace: ws-source   # sambungkan ke deklarasi di atas
      taskRef: { name: git-clone }
      params:
        - name: url          # TERIKAT: bukan repo-url!
        - name: revision     # TERIKAT: bukan branch!

Bedakan: workspaces: (jamak, header deklarasi) vs workspace: (tunggal, penunjuk ke deklarasi). Satu nama workspace harus identik di 3 tempat: deklarasi spec.workspaces, tiap task workspace:, dan flag -w name=.

BEBAS vs TERIKAT di lab ini

BEBAS — nama saya

lab5-pipelinecustom-pvc ws-source

TERIKAT — diminta git-clone

workspace: output param urlparam revision storageClassName: standard
§L6

Test nyata — flake8 (catalog) + nose (sendiri)

folder labs/04_unit_test_automation · pipeline lab6-pipeline

Yang ditambahkan: ganti placeholder lint/tests jadi task nyataflake8 dari catalog + nose tulis sendiri — yang membaca kode lewat workspace. Muncul juga cleanup/init.

📦 Yang harus di-install

# flake8 dari catalog
$ kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/flake8/0.1/flake8.yaml
# nose = TULIS task sendiri (tak ada yang di-install)
# ⚠️ fix DNS node minikube — task ber-`script:` menarik image dari cgr.dev
$ minikube ssh "printf 'nameserver 8.8.8.8\noptions ndots:0\n' | sudo tee /etc/resolv.conf"
$ minikube ssh "getent hosts cgr.dev"   # keluar IP = DNS beres
initcleanup clonegit-clone lintflake8 testsnose buildecho deployecho

Fungsi ↔ Command

Pasang task flake8 dari catalogkubectl apply -f .../flake8/0.1/flake8.yaml
Perbaiki DNS node (task script: tarik image cgr.dev)minikube ssh "... | sudo tee /etc/resolv.conf"
Pastikan node bisa resolve cgr.devminikube ssh "getent hosts cgr.dev"
Jalankan (tetap kirim workspace)tkn pipeline start lab6-pipeline -w ... --showlog

Sintaks YAML — dua bentuk args yang beda

# TASK LINT (flake8 dari catalog)
- name: lint
  workspaces: [{ name: source, workspace: ws-source }]  # TERIKAT: "source"
  taskRef: { name: flake8 }
  params:
    - name: image            # TERIKAT, huruf kecil
      value: "python:3.9-slim"
    - name: args             # flake8 = bentuk LIST
      value: ["--count","--max-line-length=127"]
# TASK NOSE (tulis sendiri)
- name: nose
  steps: [{ script: |
      pip install -r requirements.txt
      nosetests $(params.args) }]
  # dipanggil pipeline dgn: args (STRING, bukan list!)
  value: "-v --with-spec --spec-color"

Jebakan case-sensitive: flake8 minta args berbentuk LIST ["a","b"]; nose (buatanmu) minta STRING "-v ...". Beda bentuk untuk nama param yang sama.

Kendala nyata: satu nama workspace ditulis 3 versi (ws-sources typo · pipeline-workspace lama · ws-source) → expects workspace "ws-source" but none exists. Samakan SEMUA.

BEBAS vs TERIKAT di lab ini

BEBAS — nama saya

lab6-pipelinenose

TERIKAT — diminta flake8

workspace: source param image (kecil) args LIST (flake8) args STRING (nose)
§L7

Build image — buildah → push DockerHub

folder labs/05_build_an_image · pipeline lab7-pipeline · image docker.io/uyasky/custom-tekton:lab7

Yang ditambahkan: ganti placeholder build jadi buildah — bangun Docker image lalu push ke DockerHub. Butuh param build-image + secret registry regcred.

📦 Yang harus di-install / disiapkan

# buildah dari catalog — Task biasa, ⚠️ BUKAN ClusterTask (sudah dihapus)
$ kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/buildah/0.9/buildah.yaml
# akun DockerHub + Access Token (R/W) → login di WSL (password = token):
$ docker login -u uyasky
# bikin secret registry + sematkan ke ServiceAccount 'default':
$ kubectl create secret generic regcred \
      --from-file=.dockerconfigjson=$HOME/.docker/config.json \
      --type=kubernetes.io/dockerconfigjson
$ kubectl patch serviceaccount default -p '{"secrets":[{"name":"regcred"}]}'
$ kubectl get secret regcred   # verifikasi
init clone lint tests buildbuildah → PUSH deployecho

Fungsi ↔ Command

Pasang task buildah (Task biasa, bukan ClusterTask)kubectl apply -f .../buildah/0.9/buildah.yaml
Login DockerHub di WSL (password = Access Token)docker login -u uyasky
Bikin secret registry untuk clusterkubectl create secret generic regcred --from-file=...
Sematkan secret ke ServiceAccountkubectl patch serviceaccount default -p '{...}'
Jalankan dengan nama image sendiri-p build-image="docker.io/uyasky/custom-tekton:lab7"
Verifikasi image benar ter-pushdocker manifest inspect docker.io/uyasky/custom-tekton:lab7

Sintaks YAML — task build

spec:
  params:
    - name: build-image       # param pipeline (BEBAS) — tambahkan di spec.params!
  tasks:
    - name: build
      workspaces: [{ name: source, workspace: ws-source }]
      taskRef: { name: buildah }   # JANGAN tulis kind: ClusterTask
      params:
        - name: IMAGE          # TERIKAT — HURUF BESAR SEMUA (case-sensitive!)
          value: "$(params.build-image)"
        - name: STORAGE_DRIVER
          value: "vfs"       # adaptasi minikube (overlay gagal)

Kendala nyata: 4 task masih workspace: pipeline-workspace (harus ws-source) + param build-image belum di spec.params. Dua-duanya harus beres.

BEBAS vs TERIKAT di lab ini

BEBAS — nama saya

lab7-pipelinebuild-image nama image (tag)

TERIKAT — wajib persis

param IMAGE (BESAR) tanpa kind: ClusterTask username = DockerHub-mu regcred (nama secret dirujuk SA)

Catatan: nama/tag image bebas, TAPI bagian uyasky/ wajib username DockerHub-mu — kalau bukan, push denied.

§L8

Deploy — tarik image DockerHub, jalankan di minikube

folder labs/06_deploy_to_kubernetes · Deployment + Service surya-counter · di luar dokumen resmi

Yang ditambahkan: manifest Deployment + Service. Bukan build ulang — cukup tarik image Lab 7 dari DockerHub → run di minikube → aplikasi Hit Counter (Flask) hidup & bisa di-curl. Pakai Jalur A: kubectl apply langsung (manifest = infrastruktur).

📦 Yang harus di-install

Tak ada instalasi. Image sudah tersedia di DockerHub dari §L7 (docker.io/uyasky/custom-tekton:lab7). Kamu cuma menulis deploy.yaml lalu kubectl apply — lihat blok Fungsi ↔ Command di bawah.

🐳 DockerHubcustom-tekton:lab7 minikube PULLtarik image Deploymentpod Running terus ServiceNodePort curl /health{"status":"OK"}

Fungsi ↔ Command

Buat Deployment + Servicekubectl apply -f deploy.yaml
Cek pod aplikasi 1/1 Runningkubectl get deploy,svc,pods -l app=surya-counter
Bukti image ditarik dari DockerHubkubectl describe pod -l app=surya-counter | grep -i pull
Cek image sudah ada di gudang minikubeminikube image ls | grep custom-tekton
Dapat URL layananminikube service surya-counter --url
Buktikan aplikasi melayanicurl $(...)/health

Sintaks YAML — aturan label yang WAJIB cocok

kind: Deployment
metadata: { name: surya-counter }
spec:
  selector: { matchLabels: { app: surya-counter }}   # (1)
  template:
    metadata: { labels: { app: surya-counter }}            # (2) WAJIB == (1)
    spec: { containers: [{
        image: docker.io/uyasky/custom-tekton:lab7          # dari DockerHub-mu
        ports: [{ containerPort: 8000 }] }] }          # port gunicorn (TERIKAT)
---
kind: Service
spec:
  selector: { app: surya-counter }                       # (3) WAJIB == (2)
  ports: [{ port: 8000, targetPort: 8000 }]

Aturan keras yang divalidasi Kubernetes: spec.selector.matchLabels = spec.template.metadata.labels, kalau beda → Deployment ditolak (selector does not match template labels). Lalu Service selector juga harus = label pod, kalau tidak curl gagal diam-diam. 3 label app: harus identik. (Ini persis error yang kamu temui: satu label sempat lab8-app.)

Beda pod ini: pod aplikasi Running terus (dijaga Deployment), bukan Completed seperti pod task. Itu sebabnya curl /health tetap menjawab walau pipeline sudah berakhir.

BEBAS vs TERIKAT di lab ini

BEBAS — nama saya

surya-counter (nama app) — asal SAMA di 3 label

TERIKAT — wajib persis

selector == template labels containerPort: 8000 nama image (dari Lab 7)

Kamus BEBAS vs TERIKAT

Ringkasan lintas-lab: mana nama yang bebas kamu tentukan (asal konsisten) vs mana yang wajib persis karena diminta task catalog.

BEBASWajib konsisten di
nama pipelinetkn pipeline start · pipelineRef.name
nama workspacetiap task workspace: · -w name=
nama PVC-w claimName=
param pipeline-p …= · $(params.…)
nama task di pipelinerunAfter: [nama]
nama app (Deploy)3 label app: harus sama
TERIKATDiminta oleh
outputgit-clone (bukan source)
sourceflake8, nose, buildah
url, revisiongit-clone
image (kecil)flake8
IMAGE (BESAR)buildah
args list vs stringflake8 vs nose

Impact map — "kalau ubah X, apa yang ikut?"

Aturan emas seluruh dokumen: ganti satu nama = ganti di SEMUA tempat yang merujuk. Kalau lupa, ini gejalanya.

Yang diubahWajib ikut diubahKalau lupa → gejalanya
Nama pipelinetkn pipeline start · pipelineRefpipelines.tekton.dev "…" not found
Nama workspacesemua workspace: · -w name=workspace … but none exists
Nama PVC-w claimName=pod Pending
Nama param-p …= dan $(params.…)param not found
storageClassNameimmutable → delete PVC duluPVC Pending selamanya
serviceAccountName (EL)rbac.yamlEventListener gagal buat PipelineRun
label app (Deploy)selector = template = Serviceselector does not match template labels

Diagnosa cepat — dari gejala ke tempat mencari

GejalaArtinyaCari di
Failed 0 detikgagal validasi (param/YAML)pesan kubectl apply / tkn logs
Failed di tengahgagal eksekusitkn pipelinerun logs
Log kosong (Pending/ImagePullBackOff)container belum startkubectl describe pod → Events
0/1 CompletedNORMAL — task sekali jalan— (bukan error)