Back to Deployment Guides
    CI/CD Platform

    Tekton

    Deploy Kubernetes-native CI/CD pipelines on RamNode VPS. Build flexible, cloud-native pipelines with reusable Tasks and Kubernetes primitives.

    Ubuntu 22.04 / Debian 12
    K3s Kubernetes
    Cloud Native

    What is Tekton?

    Tekton is a powerful, Kubernetes-native CI/CD framework that provides a flexible and extensible platform for building continuous integration and delivery systems. Unlike traditional CI/CD tools, Tekton leverages Kubernetes primitives to create cloud-native pipelines that are portable, scalable, and vendor-neutral.

    Cloud-Native

    Built specifically for Kubernetes environments

    Reusable Tasks

    Share pipeline tasks across multiple projects

    Vendor-Neutral

    No lock-in to specific cloud providers

    1

    Prerequisites

    • A RamNode VPS with at least 4GB RAM (8GB recommended)
    • Ubuntu 22.04 LTS or similar Linux distribution
    • Root or sudo access
    • A domain name pointed to your VPS (optional for external access)
    • Basic familiarity with Kubernetes concepts
    2

    Prepare Your VPS

    Update system and install dependencies
    # Update system packages
    sudo apt update && sudo apt upgrade -y
    
    # Install required utilities
    sudo apt install -y curl wget git apt-transport-https ca-certificates gnupg lsb-release
    
    # Disable swap (required for Kubernetes)
    sudo swapoff -a
    sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab

    Configure firewall:

    Configure UFW
    # Install UFW if not already installed
    sudo apt install -y ufw
    
    # Allow SSH
    sudo ufw allow 22/tcp
    
    # Allow Kubernetes API server
    sudo ufw allow 6443/tcp
    
    # Allow NodePort services range
    sudo ufw allow 30000:32767/tcp
    
    # Enable firewall
    sudo ufw --force enable
    3

    Install K3s (Lightweight Kubernetes)

    K3s is ideal for VPS environments - lightweight while maintaining full Kubernetes compatibility.

    Install K3s
    # Install K3s
    curl -sfL https://get.k3s.io | sh -s - --write-kubeconfig-mode 644
    
    # Verify installation
    sudo systemctl status k3s
    
    # Set up kubectl access for non-root user
    mkdir -p ~/.kube
    sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
    sudo chown $(id -u):$(id -g) ~/.kube/config
    export KUBECONFIG=~/.kube/config
    
    # Verify cluster is running
    kubectl get nodes
    4

    Install Tekton Pipelines

    Tekton Pipelines is the core component that provides the CI/CD engine:

    Install Tekton Pipelines
    # Install Tekton Pipelines
    kubectl apply --filename https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml
    
    # Wait for Tekton components to be ready
    kubectl wait --for=condition=Ready pods --all -n tekton-pipelines --timeout=300s
    
    # Verify installation
    kubectl get pods -n tekton-pipelines

    You should see tekton-pipelines-controller and tekton-pipelines-webhook in Running state.

    5

    Install Tekton Triggers (Optional)

    Tekton Triggers enables event-driven pipelines from webhooks:

    Install Tekton Triggers
    kubectl apply --filename https://storage.googleapis.com/tekton-releases/triggers/latest/release.yaml
    
    # Install Tekton Triggers Interceptors
    kubectl apply --filename https://storage.googleapis.com/tekton-releases/triggers/latest/interceptors.yaml
    
    # Wait for components to be ready
    kubectl wait --for=condition=Ready pods --all -n tekton-pipelines --timeout=300s
    
    # Verify installation
    kubectl get pods -n tekton-pipelines
    6

    Install Tekton Dashboard

    Install Dashboard
    kubectl apply --filename https://storage.googleapis.com/tekton-releases/dashboard/latest/release.yaml
    
    # Wait for dashboard to be ready
    kubectl wait --for=condition=Ready pods -l app=tekton-dashboard -n tekton-pipelines --timeout=300s
    
    # Verify dashboard is running
    kubectl get pods -n tekton-pipelines -l app=tekton-dashboard

    Option 1: Port Forward (Quick Access)

    Port forward dashboard
    kubectl port-forward -n tekton-pipelines svc/tekton-dashboard 9097:9097 --address 0.0.0.0
    
    # Access at: http://your-vps-ip:9097

    Option 2: NodePort Service (Persistent)

    Create NodePort service
    cat <<EOF | kubectl apply -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: tekton-dashboard-nodeport
      namespace: tekton-pipelines
    spec:
      type: NodePort
      selector:
        app: tekton-dashboard
      ports:
      - port: 9097
        targetPort: 9097
        nodePort: 30080
    EOF
    
    # Access at: http://your-vps-ip:30080

    Option 3: Ingress with SSL (Production)

    Create Ingress with TLS
    # Install cert-manager
    kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.3/cert-manager.yaml
    kubectl wait --for=condition=Ready pods --all -n cert-manager --timeout=300s
    
    # Create ClusterIssuer
    cat <<EOF | kubectl apply -f -
    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      name: letsencrypt-prod
    spec:
      acme:
        server: https://acme-v02.api.letsencrypt.org/directory
        email: your-email@example.com
        privateKeySecretRef:
          name: letsencrypt-prod
        solvers:
        - http01:
            ingress:
              class: traefik
    EOF
    
    # Create Ingress with TLS
    cat <<EOF | kubectl apply -f -
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: tekton-dashboard-ingress
      namespace: tekton-pipelines
      annotations:
        cert-manager.io/cluster-issuer: letsencrypt-prod
        traefik.ingress.kubernetes.io/router.entrypoints: websecure
    spec:
      tls:
      - hosts:
        - tekton.yourdomain.com
        secretName: tekton-dashboard-tls
      rules:
      - host: tekton.yourdomain.com
        http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: tekton-dashboard
                port:
                  number: 9097
    EOF
    7

    Install Tekton CLI (tkn)

    Install tkn CLI
    # Download and install tkn
    curl -LO https://github.com/tektoncd/cli/releases/download/v0.33.0/tkn_0.33.0_Linux_x86_64.tar.gz
    
    # Extract and install
    sudo tar xvzf tkn_0.33.0_Linux_x86_64.tar.gz -C /usr/local/bin/ tkn
    
    # Verify installation
    tkn version
    
    # Clean up
    rm tkn_0.33.0_Linux_x86_64.tar.gz
    8

    Create Your First Pipeline

    Create a Task (building block of pipelines):

    git-clone-and-list-task.yaml
    cat <<EOF | kubectl apply -f -
    apiVersion: tekton.dev/v1beta1
    kind: Task
    metadata:
      name: git-clone-and-list
    spec:
      params:
      - name: repo-url
        type: string
        description: The Git repository URL to clone
      - name: revision
        type: string
        description: The Git revision to checkout
        default: main
      workspaces:
      - name: source
        description: Workspace to clone repo into
      steps:
      - name: clone
        image: gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init:v0.40.2
        script: |
          #!/usr/bin/env sh
          set -ex
          cd \$(workspaces.source.path)
          git clone \$(params.repo-url) .
          git checkout \$(params.revision)
      - name: list-files
        image: alpine:latest
        script: |
          #!/usr/bin/env sh
          echo "Repository contents:"
          ls -la \$(workspaces.source.path)
    EOF

    Create a Pipeline:

    clone-and-build-pipeline.yaml
    cat <<EOF | kubectl apply -f -
    apiVersion: tekton.dev/v1beta1
    kind: Pipeline
    metadata:
      name: clone-and-build
    spec:
      params:
      - name: repo-url
        type: string
        description: Repository URL to clone
      - name: revision
        type: string
        description: Git revision to checkout
        default: main
      workspaces:
      - name: shared-data
        description: Shared workspace for tasks
      tasks:
      - name: fetch-source
        taskRef:
          name: git-clone-and-list
        params:
        - name: repo-url
          value: \$(params.repo-url)
        - name: revision
          value: \$(params.revision)
        workspaces:
        - name: source
          workspace: shared-data
    EOF

    Run the Pipeline:

    Execute PipelineRun
    cat <<EOF | kubectl apply -f -
    apiVersion: tekton.dev/v1beta1
    kind: PipelineRun
    metadata:
      name: clone-and-build-run-1
    spec:
      pipelineRef:
        name: clone-and-build
      params:
      - name: repo-url
        value: https://github.com/tektoncd/pipeline.git
      - name: revision
        value: main
      workspaces:
      - name: shared-data
        volumeClaimTemplate:
          spec:
            accessModes:
            - ReadWriteOnce
            resources:
              requests:
                storage: 1Gi
    EOF
    
    # Monitor pipeline execution
    tkn pipelinerun logs clone-and-build-run-1 -f
    9

    Build and Push Docker Images

    Create Docker registry secret:

    Create Docker credentials
    kubectl create secret docker-registry docker-credentials \
      --docker-server=https://index.docker.io/v1/ \
      --docker-username=your-dockerhub-username \
      --docker-password=your-dockerhub-password \
      --docker-email=your-email@example.com

    Create build and push Task:

    build-and-push-task.yaml
    cat <<EOF | kubectl apply -f -
    apiVersion: tekton.dev/v1beta1
    kind: Task
    metadata:
      name: build-and-push
    spec:
      params:
      - name: image-name
        type: string
        description: The name of the image to build
      - name: dockerfile
        type: string
        description: Path to the Dockerfile
        default: ./Dockerfile
      workspaces:
      - name: source
        description: Workspace containing the source code
      steps:
      - name: build-and-push
        image: gcr.io/kaniko-project/executor:latest
        env:
        - name: DOCKER_CONFIG
          value: /kaniko/.docker
        command:
        - /kaniko/executor
        args:
        - --dockerfile=\$(params.dockerfile)
        - --context=\$(workspaces.source.path)
        - --destination=\$(params.image-name)
        volumeMounts:
        - name: docker-credentials
          mountPath: /kaniko/.docker
      volumes:
      - name: docker-credentials
        secret:
          secretName: docker-credentials
          items:
          - key: .dockerconfigjson
            path: config.json
    EOF

    Create complete CI/CD Pipeline:

    full-cicd-pipeline.yaml
    cat <<EOF | kubectl apply -f -
    apiVersion: tekton.dev/v1beta1
    kind: Pipeline
    metadata:
      name: full-cicd-pipeline
    spec:
      params:
      - name: repo-url
        type: string
      - name: revision
        default: main
      - name: image-name
        type: string
      workspaces:
      - name: shared-workspace
      tasks:
      - name: clone-repository
        taskRef:
          name: git-clone-and-list
        params:
        - name: repo-url
          value: \$(params.repo-url)
        - name: revision
          value: \$(params.revision)
        workspaces:
        - name: source
          workspace: shared-workspace
      - name: build-push-image
        taskRef:
          name: build-and-push
        runAfter:
        - clone-repository
        params:
        - name: image-name
          value: \$(params.image-name)
        workspaces:
        - name: source
          workspace: shared-workspace
    EOF
    10

    Set Up Webhook Triggers

    Enable automatic pipeline execution from Git webhooks:

    Create EventListener and TriggerBinding
    # Create Service Account
    cat <<EOF | kubectl apply -f -
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: tekton-triggers-sa
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: tekton-triggers-clusterrole
    rules:
    - apiGroups: ["triggers.tekton.dev"]
      resources: ["*"]
      verbs: ["*"]
    - apiGroups: ["tekton.dev"]
      resources: ["*"]
      verbs: ["*"]
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: tekton-triggers-binding
    subjects:
    - kind: ServiceAccount
      name: tekton-triggers-sa
      namespace: default
    roleRef:
      kind: ClusterRole
      name: tekton-triggers-clusterrole
      apiGroup: rbac.authorization.k8s.io
    EOF
    
    # Create TriggerBinding
    cat <<EOF | kubectl apply -f -
    apiVersion: triggers.tekton.dev/v1beta1
    kind: TriggerBinding
    metadata:
      name: github-push-binding
    spec:
      params:
      - name: gitrevision
        value: \$(body.head_commit.id)
      - name: gitrepositoryurl
        value: \$(body.repository.clone_url)
    EOF
    
    # Create TriggerTemplate
    cat <<EOF | kubectl apply -f -
    apiVersion: triggers.tekton.dev/v1beta1
    kind: TriggerTemplate
    metadata:
      name: github-pipeline-template
    spec:
      params:
      - name: gitrevision
      - name: gitrepositoryurl
      resourcetemplates:
      - apiVersion: tekton.dev/v1beta1
        kind: PipelineRun
        metadata:
          generateName: github-run-
        spec:
          pipelineRef:
            name: clone-and-build
          params:
          - name: repo-url
            value: \$(tt.params.gitrepositoryurl)
          - name: revision
            value: \$(tt.params.gitrevision)
          workspaces:
          - name: shared-data
            volumeClaimTemplate:
              spec:
                accessModes:
                - ReadWriteOnce
                resources:
                  requests:
                    storage: 1Gi
    EOF
    
    # Create EventListener
    cat <<EOF | kubectl apply -f -
    apiVersion: triggers.tekton.dev/v1beta1
    kind: EventListener
    metadata:
      name: github-listener
    spec:
      serviceAccountName: tekton-triggers-sa
      triggers:
      - name: github-push
        bindings:
        - ref: github-push-binding
        template:
          ref: github-pipeline-template
    EOF

    Expose EventListener:

    Expose webhook endpoint
    # Get EventListener service
    kubectl get svc el-github-listener
    
    # Expose via NodePort
    kubectl patch svc el-github-listener -p '{"spec":{"type":"NodePort"}}'
    
    # Get the NodePort
    kubectl get svc el-github-listener -o jsonpath='{.spec.ports[0].nodePort}'
    
    # Configure GitHub webhook to: http://your-vps-ip:NODEPORT
    11

    Performance Optimization

    Set resource limits for tasks:

    Task resource limits
    spec:
      steps:
      - name: build
        resources:
          requests:
            memory: 512Mi
            cpu: 250m
          limits:
            memory: 1Gi
            cpu: 500m

    Run independent tasks in parallel:

    Parallel task execution
    tasks:
    - name: test-unit
      taskRef:
        name: run-tests
    - name: test-integration
      taskRef:
        name: run-integration-tests
    # Both run in parallel - no runAfter dependency

    Use persistent workspaces:

    Persistent workspace
    workspaces:
    - name: source
      persistentVolumeClaim:
        claimName: tekton-workspace-pvc
    12

    Security Best Practices

    Create dedicated service accounts:

    Pipeline service account
    kubectl create serviceaccount pipeline-sa
    
    # Bind necessary permissions
    kubectl create rolebinding pipeline-sa-binding \
      --clusterrole=edit \
      --serviceaccount=default:pipeline-sa

    Use Kubernetes secrets for sensitive data:

    Reference secrets in tasks
    # Create secret
    kubectl create secret generic api-key --from-literal=token=your-api-key
    
    # Reference in task
    env:
    - name: API_KEY
      valueFrom:
        secretKeyRef:
          name: api-key
          key: token

    Apply network policies:

    Network policy
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: tekton-pipeline-policy
      namespace: tekton-pipelines
    spec:
      podSelector:
        matchLabels:
          app: tekton-pipelines
      policyTypes:
      - Ingress
      - Egress
      ingress:
      - from:
        - namespaceSelector: {}
      egress:
      - to:
        - namespaceSelector: {}

    Troubleshooting

    Pipeline Fails to Start

    Check pod status and events
    kubectl get pods -n tekton-pipelines
    kubectl describe pod <pod-name> -n tekton-pipelines
    kubectl logs <pod-name> -n tekton-pipelines

    Insufficient Resources

    Monitor resource usage
    kubectl top nodes
    kubectl top pods -n tekton-pipelines
    kubectl describe pod <pod-name> -n tekton-pipelines

    Storage Issues

    Check and clean up PVCs
    kubectl get pvc
    kubectl describe pvc <pvc-name>
    
    # Clean up old PVCs
    kubectl delete pvc --all
    
    # Or delete old pipeline runs (keeps last 5)
    tkn pipelinerun delete --keep 5

    Maintenance Commands

    Tekton maintenance
    # Update Tekton components
    kubectl apply --filename https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml
    
    # Restart components
    kubectl rollout restart deployment -n tekton-pipelines
    
    # List all pipeline runs
    tkn pipelinerun list
    
    # View detailed pipeline run
    tkn pipelinerun describe <pipelinerun-name>
    
    # View pipeline logs
    tkn pipelinerun logs <pipelinerun-name>
    
    # Export for backup
    kubectl get tasks,pipelines,pipelineruns -o yaml > tekton-backup.yaml

    Next Steps

    • Explore Tekton Hub for reusable Tasks and Pipelines
    • Integrate with ArgoCD for GitOps deployments
    • Set up Tekton Chains for supply chain security
    • Configure Prometheus metrics for monitoring