ops-demo/docs/04-tekton-pipeline.md

668 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Oefening 04 — Tekton Pipeline
**Tijd**: ~45 minuten
**Doel**: Een pipeline bouwen die automatisch de image-tag in Git aanpast en ArgoCD de update laat uitrollen — de
volledige GitOps CI/CD-loop.
---
## Wat je leert
- Tekton-concepten: Task, Pipeline, PipelineRun, Workspace
- Hoe een pipeline via een Git-commit een GitOps-deployment triggert (geen container registry nodig)
- De volledige loop: pipeline push → ArgoCD detecteert → rolling update → nieuwe versie in browser
---
## De loop
```
Jij triggert een PipelineRun
Task 1: clone repo
Task 2: valideer manifests (kubectl dry-run)
Task 3: pas image-tag aan → deployment.yaml: 6.6.2 → 6.7.0
Task 4: git commit + push
ArgoCD detecteert de commit
ArgoCD synchroniseert de podinfo Deployment
Rolling update → podinfo v6.7.0 in je browser
```
---
## Vereisten
Oefeningen 0103 afgerond. podinfo is bereikbaar via **http://podinfo.192.168.56.200.nip.io** en toont versie **6.6.2**.
Je hebt nodig:
- Een GitHub Personal Access Token (PAT) met **repo**-scope (lezen + schrijven)
---
## Stappen
### 1. Tekton installeren via ArgoCD
**`manifests/ci/tekton/kustomization.yaml`**
```yaml
resources:
- https://storage.googleapis.com/tekton-releases/pipeline/previous/v0.65.1/release.yaml
patches:
- path: namespace-podsecurity-patch.yaml
target:
kind: Namespace
name: tekton-pipelines
```
Waarom dit:
- `release.yaml` installeert Tekton Pipelines (controller, webhook, CRDs).
- De `patches` regel past de namespace aan die al in de upstream release zit.
- Zonder patch faalt de eerste TaskRun vaak op Pod Security admission.
- Pod Security Admission is een Kubernetes-mechanisme dat per namespace bepaalt hoe streng pod-beveiliging wordt
afgedwongen.
- In deze oefening zet de upstream Tekton install de namespace effectief op `restricted`; dat profiel eist o.a.
`runAsNonRoot`, `seccompProfile` en `allowPrivilegeEscalation=false`.
- Tekton runtime-pods (zoals `prepare` en `step-*`) voldoen in deze setup niet altijd aan die eisen, waardoor je direct
`PodAdmissionFailed` krijgt voordat je pipeline-logica start.
**`manifests/ci/tekton/namespace-podsecurity-patch.yaml`**
```yaml
apiVersion: v1
kind: Namespace
metadata:
name: tekton-pipelines
labels:
pod-security.kubernetes.io/enforce: privileged
```
Waarom dit:
- Tekton maakt zelf tijdelijke pods aan per TaskRun (`prepare`, `step-*`).
- Met `enforce=restricted` worden die pods in deze workshop-setup afgewezen.
- Deze patch maakt de oefening reproduceerbaar op de single-node VM.
- `enforce=privileged` betekent hier niet "alles in je cluster is onveilig", maar alleen dat deze ene namespace niet
door PSA wordt geblokkeerd.
- We kiezen dit bewust als workshop trade-off: focus op GitOps/Tekton-flow, niet op PSA-hardening.
- In productie kies je meestal niet `privileged`, maar harden je de Tekton setup zodat hij onder `baseline`/`restricted`
draait.
**`apps/ci/tekton.yaml`**
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: tekton
namespace: argocd
annotations:
argocd.argoproj.io/sync-wave: "5"
spec:
project: workshop
source:
repoURL: JOUW_FORK_URL
targetRevision: HEAD
path: manifests/ci/tekton
destination:
server: https://kubernetes.default.svc
namespace: tekton-pipelines
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ServerSideApply=true
```
> **HOST**
> ```bash
> git add apps/ci/tekton.yaml manifests/ci/tekton/
> git commit -m "feat: installeer Tekton via ArgoCD"
> git push
> ```
Wacht tot Tekton draait (~35 minuten):
> **VM**
> ```bash
> kubectl get pods -n tekton-pipelines
> # tekton-pipelines-controller-xxx 1/1 Running
> # tekton-pipelines-webhook-xxx 1/1 Running
> ```
Wat je hier valideert:
- De Tekton controller verwerkt Pipeline/Task resources.
- De Tekton webhook default/valideert objecten bij `kubectl apply`.
- Als deze pods niet `Running` zijn, heeft het geen zin om door te gaan.
---
### 2. Pipeline-resources aanmaken
**`manifests/ci/pipeline/serviceaccount.yaml`**
```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: pipeline-runner
namespace: tekton-pipelines
```
Waarom dit:
- Deze serviceaccount draait de pipeline pods.
- Alle permissies voor `validate` en eventuele cluster-calls hangen aan dit account.
**`manifests/ci/pipeline/pipeline.yaml`** — zie de solution branch voor de volledige inhoud, of kopieer uit
`reference-solution`:
> **HOST**
> ```bash
> git show origin/solution/04-tekton-pipeline:manifests/ci/pipeline/pipeline.yaml
> ```
Wat er in die pipeline zit:
- `clone`: clonet jouw repo met credentials uit `git-credentials`.
- `validate`: doet client-side manifestvalidatie op de podinfo manifests.
- `bump-image-tag`: wijzigt de image tag in `deployment.yaml`.
- `git-commit-push`: commit + push naar `main`, waarna ArgoCD de wijziging oppakt.
**`manifests/ci/pipeline/pipelinerun.yaml`**
```yaml
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
name: bump-podinfo-to-670
namespace: tekton-pipelines
spec:
pipelineRef:
name: gitops-image-bump
taskRunTemplate:
serviceAccountName: pipeline-runner
params:
- name: repo-url
value: JOUW_FORK_URL
- name: new-tag
value: "6.7.0"
workspaces:
- name: source
volumeClaimTemplate:
spec:
accessModes: [ ReadWriteOnce ]
resources:
requests:
storage: 1Gi
- name: git-credentials
secret:
secretName: git-credentials
```
Waarom deze velden belangrijk zijn:
- `pipelineRef`: kiest welke pipeline je start.
- `params`: bepaalt repo en doelversie zonder de pipeline-definitie te wijzigen.
- `workspaces.source`: tijdelijk werkvolume voor clone/edit/commit.
- `workspaces.git-credentials`: secret mount voor Git auth.
**`apps/ci/pipeline.yaml`**
Belangrijk:
- Dit bestand is alleen de ArgoCD `Application` wrapper.
- Daarom is het klein en zie je hier geen Tekton-steps.
- De echte pipeline-steps staan in `manifests/ci/pipeline/pipeline.yaml`
(clone, validate, bump-image-tag, git-commit-push).
- ArgoCD beheert dus alleen Tekton resources; de pipeline runtime gebeurt in Tekton zelf.
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: workshop-pipeline
namespace: argocd
annotations:
argocd.argoproj.io/sync-wave: "7"
spec:
project: workshop
source:
repoURL: JOUW_FORK_URL
targetRevision: HEAD
path: manifests/ci/pipeline
destination:
server: https://kubernetes.default.svc
namespace: tekton-pipelines
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
```
> **HOST**
> ```bash
> git add apps/ci/pipeline.yaml manifests/ci/pipeline/
> git commit -m "feat: voeg pipeline-resources toe"
> git push
> ```
---
### 3. Tekton Dashboard zichtbaar maken (UI)
Maak een aparte Tekton Dashboard app, met Ingress zodat je PipelineRuns in de browser ziet.
**`manifests/ci/dashboard/kustomization.yaml`**
```yaml
resources:
- https://storage.googleapis.com/tekton-releases/dashboard/latest/release-full.yaml
- ingress.yaml
```
Waarom dit:
- `release-full.yaml` installeert de dashboard backend + service.
- `ingress.yaml` maakt de UI bereikbaar via dezelfde ingress-nginx die je in oefening 03 bouwde.
**`manifests/ci/dashboard/ingress.yaml`**
```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tekton-dashboard
namespace: tekton-pipelines
spec:
ingressClassName: nginx
rules:
- host: tekton.192.168.56.200.nip.io
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: tekton-dashboard
port:
number: 9097
```
**`apps/ci/tekton-dashboard.yaml`**
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: tekton-dashboard
namespace: argocd
annotations:
argocd.argoproj.io/sync-wave: "6"
spec:
project: workshop
source:
repoURL: JOUW_FORK_URL
targetRevision: HEAD
path: manifests/ci/dashboard
destination:
server: https://kubernetes.default.svc
namespace: tekton-pipelines
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
```
> **HOST**
> ```bash
> git add apps/ci/tekton-dashboard.yaml manifests/ci/dashboard/
> git commit -m "feat: voeg Tekton Dashboard met ingress toe"
> git push
> ```
Open daarna: **http://tekton.192.168.56.200.nip.io**
---
### 4. Git-credentials instellen
Dit is een verplichte stap vóór je de PipelineRun triggert.
Zonder `git-credentials` secret faalt de `clone` task direct.
De pipeline moet kunnen pushen naar jouw fork.
Maak een GitHub PAT aan met `repo`-scope en voer daarna een van deze opties uit:
> **VM**
> ```bash
> /vagrant/scripts/vm/set-git-credentials.sh <jouw-github-gebruikersnaam> <jouw-pat>
> ```
Dit maakt een Kubernetes Secret aan in het cluster — **het PAT komt niet in Git**.
Tip:
- Bij GitHub PAT over HTTPS kun je als username je GitHub username gebruiken.
- `x-access-token` als username werkt vaak ook, zolang password de PAT is.
---
### 5. Pipeline triggeren
Controleer eerst dat stap 3 gelukt is.
Pas daarna de PipelineRun starten:
> **VM**
> ```bash
> kubectl apply -f manifests/ci/pipeline/pipelinerun.yaml
> ```
Volg de voortgang:
> **VM**
> ```bash
> kubectl get pipelinerun -n tekton-pipelines -w
> ```
Of per pod:
> **VM**
> ```bash
> kubectl get pods -n tekton-pipelines -w
> ```
De PipelineRun duurt ~23 minuten.
Wat je zou moeten zien:
- eerst `clone`,
- daarna `validate`,
- dan `bump-image-tag`,
- en als laatste `git-commit-push`.
---
### 6. Controleer de commit
> **HOST**
> ```bash
> git fetch origin
> git log origin/main --oneline -3
> # Je ziet: chore(pipeline): bump podinfo to 6.7.0
> ```
---
### 7. ArgoCD laten synchroniseren
Klik **Refresh** op de **podinfo** application in ArgoCD, of wacht op het automatische poll-interval.
> **VM**
> ```bash
> kubectl rollout status deployment/podinfo -n podinfo
> ```
Waarom dit nodig is:
- De pipeline praat niet direct met de podinfo Deployment.
- De pipeline pusht alleen Git; ArgoCD voert de daadwerkelijke rollout uit.
---
### 8. Controleer in de browser
Open **http://podinfo.192.168.56.200.nip.io** — je ziet nu versie **6.7.0**.
> **HOST**
> ```bash
> curl http://podinfo.192.168.56.200.nip.io | jq .version
> # "6.7.0"
> ```
---
## Pipeline opnieuw uitvoeren
De naam van een PipelineRun moet uniek zijn:
> **VM**
> ```bash
> kubectl delete pipelinerun bump-podinfo-to-670 -n tekton-pipelines
> kubectl apply -f manifests/ci/pipeline/pipelinerun.yaml
> ```
---
## Bonus: triggeren via Git webhook (optioneel)
Wil je dat Tekton automatisch runt bij een `git push`?
Dan gebruik je **Tekton Triggers** met een webhook endpoint.
Als je **GitHub** gebruikt, kun je onderstaande manifests direct volgen.
Gebruik je GitLab/Gitea/Bitbucket, dan blijft het patroon hetzelfde maar de interceptor/payload-mapping kan verschillen.
> [!IMPORTANT]
> In deze workshop draait de cluster op een VirtualBox host-only netwerk (`192.168.56.x`).
> Dat endpoint is niet publiek bereikbaar vanaf GitHub.
> Dus: GitHub kan `tekton-webhook.192.168.56.200.nip.io` niet direct aanroepen.
>
> Voor echte GitHub webhooks heb je een brug nodig, bijvoorbeeld:
> - een publieke tunnel (`ngrok`, `cloudflared tunnel`)
> - een webhook relay (`smee.io`)
> - of een publiek bereikbare cluster endpoint (geen host-only-only setup)
### 1. Triggers resources toevoegen
**`manifests/ci/triggers/kustomization.yaml`**
```yaml
resources:
- https://storage.googleapis.com/tekton-releases/triggers/latest/release.yaml
- https://storage.googleapis.com/tekton-releases/triggers/latest/interceptors.yaml
- triggerbinding.yaml
- triggertemplate.yaml
- eventlistener.yaml
- ingress.yaml
```
**`manifests/ci/triggers/triggerbinding.yaml`**
```yaml
apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerBinding
metadata:
name: github-push-binding
namespace: tekton-pipelines
spec:
params:
- name: repo-url
value: $(body.repository.clone_url)
```
**`manifests/ci/triggers/triggertemplate.yaml`**
```yaml
apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerTemplate
metadata:
name: github-push-template
namespace: tekton-pipelines
spec:
params:
- name: repo-url
default: https://github.com/JOUW_USERNAME/JOUW_REPO.git
resourcetemplates:
- apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
generateName: webhook-bump-
namespace: tekton-pipelines
spec:
pipelineRef:
name: gitops-image-bump
taskRunTemplate:
serviceAccountName: pipeline-runner
params:
- name: repo-url
value: $(tt.params.repo-url)
- name: new-tag
value: "6.7.0"
- name: git-user-name
value: "Workshop Pipeline"
- name: git-user-email
value: "pipeline@workshop.local"
workspaces:
- name: source
volumeClaimTemplate:
spec:
accessModes: [ ReadWriteOnce ]
resources:
requests:
storage: 1Gi
- name: git-credentials
secret:
secretName: git-credentials
```
**`manifests/ci/triggers/eventlistener.yaml`**
```yaml
apiVersion: triggers.tekton.dev/v1beta1
kind: EventListener
metadata:
name: github-push-listener
namespace: tekton-pipelines
spec:
serviceAccountName: pipeline-runner
triggers:
- name: on-push
interceptors:
- ref:
name: github
params:
- name: secretRef
value:
secretName: github-webhook-secret
secretKey: secretToken
- name: eventTypes
value:
- push
bindings:
- ref: github-push-binding
template:
ref: github-push-template
```
**`manifests/ci/triggers/ingress.yaml`**
```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tekton-triggers
namespace: tekton-pipelines
spec:
ingressClassName: nginx
rules:
- host: tekton-webhook.192.168.56.200.nip.io
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: el-github-push-listener
port:
number: 8080
```
**`apps/ci/tekton-triggers.yaml`**
```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: tekton-triggers
namespace: argocd
annotations:
argocd.argoproj.io/sync-wave: "8"
spec:
project: workshop
source:
repoURL: JOUW_FORK_URL
targetRevision: HEAD
path: manifests/ci/triggers
destination:
server: https://kubernetes.default.svc
namespace: tekton-pipelines
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
```
> **HOST**
> ```bash
> git add apps/ci/tekton-triggers.yaml manifests/ci/triggers/
> git commit -m "feat: voeg Tekton Triggers webhook flow toe"
> git push
> ```
### 2. Webhook secret zetten
> **VM**
> ```bash
> kubectl -n tekton-pipelines create secret generic github-webhook-secret \
> --from-literal=secretToken='kies-een-sterke-random-string' \
> --dry-run=client -o yaml | kubectl apply -f -
> ```
### 3. GitHub webhook registreren
- In GitHub: **Settings → Webhooks → Add webhook**
- Payload URL: `http://tekton-webhook.192.168.56.200.nip.io`
- Content type: `application/json`
- Secret: dezelfde waarde als `secretToken`
- Event: **Just the push event**
Zonder tunnel/relay of publiek endpoint zal GitHub deze URL niet kunnen bereiken.
Met zo'n brug maakt elke push een nieuwe `PipelineRun` aan.
---
## Probleemoplossing
| Symptoom | Oplossing |
|--------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| PipelineRun blijft "Running" | `kubectl describe pipelinerun -n tekton-pipelines bump-podinfo-to-670` |
| Secret `git-credentials` niet gevonden | Run in VM: `./scripts/vm/set-git-credentials.sh ...` (na `vagrant ssh` + `cd /vagrant`) of vanaf host: `vagrant ssh -c \"/vagrant/scripts/vm/set-git-credentials.sh ...\"` |
| Push mislukt: 403 Forbidden | PAT heeft onvoldoende rechten — `repo`-scope vereist |
| ArgoCD synchroniseert niet | Klik **Refresh** in de UI |
| `root` blijft OutOfSync op app `tekton` | Verwijder de lege `kustomize: {}` uit `apps/ci/tekton.yaml` (Argo normaliseert deze weg in live state) |
| PipelineRun faalt met `PodAdmissionFailed` | Controleer dat `tekton-pipelines` label `pod-security.kubernetes.io/enforce=privileged` heeft (via `manifests/ci/tekton/namespace-podsecurity-patch.yaml`) |
| Tekton Dashboard toont standaard Nginx/404 | Controleer `apps/ci/tekton-dashboard.yaml` en `manifests/ci/dashboard/ingress.yaml` host/service/poort |
| Webhook maakt geen PipelineRun aan | Check `kubectl get eventlistener -n tekton-pipelines` en controleer GitHub webhook URL/secret/eventtype |
---
## Volgende stap
In Oefening 05 kijk je terug op wat je gebouwd hebt en experimenteer je met drift detection.