You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ma...@apache.org on 2022/10/26 13:45:57 UTC

[camel-karavan] branch main updated: Minikube operator deployment

This is an automated email from the ASF dual-hosted git repository.

marat pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git


The following commit(s) were added to refs/heads/main by this push:
     new f82d7fb  Minikube operator deployment
f82d7fb is described below

commit f82d7fbcce42e861751aa5b90de8c9ed86d933ff
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Wed Oct 26 09:45:37 2022 -0400

    Minikube operator deployment
---
 karavan-cloud/MINIKUBE.md                          |  47 +++++----
 .../minikube/karavan-acl-environments.yaml         |  13 ---
 karavan-cloud/minikube/karavan-acl.yaml            | 102 -------------------
 .../minikube/karavan-app-deployment-public.yaml    |  42 --------
 .../minikube/karavan-app-service-node-port.yaml    |  17 ----
 karavan-cloud/minikube/karavan-pvc.yaml            |  35 -------
 .../minikube/karavan-quarkus-pipeline.yaml         |  24 -----
 .../minikube/karavan-quarkus-task-minikube.yaml    | 111 ---------------------
 karavan-cloud/minikube/karavan-secret.yaml         |  18 ++--
 karavan-cloud/minikube/karavan.yaml                |  10 ++
 karavan-cloud/minikube/kustomization.yaml          |  12 ---
 .../minikube/pipeline-service-account.yaml         |  34 -------
 .../apache/camel/karavan/operator/Constants.java   |   5 +
 .../camel/karavan/operator/KaravanReconciler.java  | 110 +++++++++-----------
 .../org/apache/camel/karavan/operator/Utils.java   |  32 ++++++
 .../karavan/operator/resource/KaravanService.java  |  18 ++--
 .../operator/resource/KaravanTektonTask.java       |   9 +-
 .../operator/resource/PipelineRoleBinding.java     |  58 +++++++++++
 .../operator/resource/PipelineRoleDeployer.java    |  62 ++++++++++++
 ...vanService.java => PipelineServiceAccount.java} |  45 +++++----
 ...nCrdWatcher.java => TektonCrdEventHandler.java} |  26 ++---
 ...er.java => TektonSubscriptionEventHandler.java} |  20 ++--
 ...ipt.sh => quarkus-builder-script-kubernetes.sh} |   6 +-
 ...ript.sh => quarkus-builder-script-openshift.sh} |   0
 24 files changed, 320 insertions(+), 536 deletions(-)

diff --git a/karavan-cloud/MINIKUBE.md b/karavan-cloud/MINIKUBE.md
index 68c9880..4fc7f80 100644
--- a/karavan-cloud/MINIKUBE.md
+++ b/karavan-cloud/MINIKUBE.md
@@ -16,40 +16,47 @@
     ```
     kubectl edit configmap feature-flags -n tekton-pipelines
     ```
-2. Create namespace
+2. Install Operator Lifecycle Management
     ```
-    kubectl apply -f karavan-namespace.yaml
+    curl -sL https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.22.0/install.sh | bash -s v0.22.0
     ```
-3. Enable Registry
+    or
+    ```
+    operator-sdk olm install latest
+    ```
+3. Install karavan operator
+    ```
+    kubectl create -f https://operatorhub.io/install/camel-karavan-operator.yaml
+    ```
+    Check operator installation status (PHASE=Succeeded)
+    ```
+    kubectl get csv -n operators
+    ```
+4. Enable Registry addons
     ```
     minikube addons enable registry
     ```
-3. Get IP address of internal registry
+5. Create namespace
+    ```
+    kubectl create namespace karavan
+    ```
+6. Get IP address of internal registry
     ```
     kubectl -n kube-system get svc registry -o jsonpath='{.spec.clusterIP}'
     ```    
-4. Set git parameters
-    Edit `karavan-secret.yaml` and set git repository, username, token and Image Registry IP
-    ```
-    projects-git-repository: https://github.com/xxx
-    projects-git-password: XXXX
-    projects-git-username: XXXX
-    projects-git-main: main
-    kamelets-git-repository: https://github.com/zzz
-    kamelets-git-password: zzz
-    kamelets-git-username: zzz
-    kamelets-git-main: main
-    image-registry: X.X.X.X
+7. Edit Karavan Secret `minikube/karavan-secret.yaml` according to enviroment and apply
     ```
-
-4. Deploy karavan
+    kubectl apply -f minikube/karavan-secret.yaml -n karavan
     ```
-    kubectl apply -k minikube --namespace karavan
+8. Create Karavan Instance and apply
     ```
-6. Expose karavan application service
+    kubectl apply -f minikube/karavan.yaml -n karavan
+    ```
+9. Expose karavan application service
     ```
     minikube service karavan --url --namespace karavan
     ```
+
 ### Optional
 1.  Access Tekton Dashboard 
     ```
diff --git a/karavan-cloud/minikube/karavan-acl-environments.yaml b/karavan-cloud/minikube/karavan-acl-environments.yaml
deleted file mode 100644
index 737d51a..0000000
--- a/karavan-cloud/minikube/karavan-acl-environments.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
-kind: RoleBinding
-apiVersion: rbac.authorization.k8s.io/v1
-metadata:
-  name: karavan-image-puller-test
-  namespace: karavan
-subjects:
-  - kind: ServiceAccount
-    name: default
-    namespace: test
-roleRef:
-  apiGroup: rbac.authorization.k8s.io
-  kind: ClusterRole
-  name: 'system:image-puller'
\ No newline at end of file
diff --git a/karavan-cloud/minikube/karavan-acl.yaml b/karavan-cloud/minikube/karavan-acl.yaml
deleted file mode 100644
index e060c80..0000000
--- a/karavan-cloud/minikube/karavan-acl.yaml
+++ /dev/null
@@ -1,102 +0,0 @@
-# Service account
-apiVersion: v1
-kind: ServiceAccount
-metadata:
-  name: karavan
-  labels:
-    app.kubernetes.io/name: karavan
----
-# Role karavan-app
-apiVersion: rbac.authorization.k8s.io/v1
-kind: Role
-metadata:
-  name: karavan-app
-rules:
-  - apiGroups: [""]
-    resources: ["secrets", "configmaps"]
-    verbs: ["get", "list"]
-  - apiGroups: [""]
-    resources: ["persistentvolumes", "persistentvolumeclaims"]
-    verbs: ["*"]
-  - apiGroups: ["", "apps", "apps.openshift.io"]
-    resources: ["deploymentconfigs", "deployments", "replicationcontrollers"]
-    verbs: ["*"]
----
-# Role tekton run pipeline
-kind: Role
-apiVersion: rbac.authorization.k8s.io/v1
-metadata:
-  name: karavan-tekton-run
-rules:
-  - verbs:
-      - get
-      - list
-      - watch
-      - create
-    apiGroups:
-      - tekton.dev
-    resources:
-      - pipelineruns
----
-# Role bindings
-kind: RoleBinding
-apiVersion: rbac.authorization.k8s.io/v1
-metadata:
-  name: karavan-tekton
-subjects:
-  - kind: ServiceAccount
-    name: karavan
-    namespace: karavan
-roleRef:
-  apiGroup: rbac.authorization.k8s.io
-  kind: Role
-  name: karavan-tekton-run
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: RoleBinding
-metadata:
-  name: karavan-view
-roleRef:
-  kind: ClusterRole
-  apiGroup: rbac.authorization.k8s.io
-  name: view
-subjects:
-  - kind: ServiceAccount
-    name: karavan
-    namespace: karavan
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: RoleBinding
-metadata:
-  name: karavan-app
-roleRef:
-  kind: Role
-  apiGroup: rbac.authorization.k8s.io
-  name: karavan-app
-subjects:
-  - kind: ServiceAccount
-    name: karavan
-    namespace: karavan
----
-# Pipeline should have access to create rolebindings
-kind: Role
-apiVersion: rbac.authorization.k8s.io/v1
-metadata:
-  name: karavan-pipeline-rolebindings
-rules:
-  - apiGroups: ["", "rbac.authorization.k8s.io"]
-    resources: ["rolebindings"]
-    verbs: ["*"]
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: RoleBinding
-metadata:
-  name: karavan-pipeline-rolebindings
-roleRef:
-  kind: Role
-  apiGroup: rbac.authorization.k8s.io
-  name: karavan-pipeline-rolebindings
-subjects:
-  - kind: ServiceAccount
-    name: pipeline
-    namespace: karavan
\ No newline at end of file
diff --git a/karavan-cloud/minikube/karavan-app-deployment-public.yaml b/karavan-cloud/minikube/karavan-app-deployment-public.yaml
deleted file mode 100644
index 11bb8ff..0000000
--- a/karavan-cloud/minikube/karavan-app-deployment-public.yaml
+++ /dev/null
@@ -1,42 +0,0 @@
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  labels:
-    app: karavan
-    app.openshift.io/runtime: quarkus
-    app.kubernetes.io/part-of: karavan
-  name: karavan
-spec:
-  replicas: 1
-  selector:
-    matchLabels:
-      app: karavan
-  template:
-    metadata:
-      labels:
-        app: karavan
-    spec:
-      serviceAccountName: karavan
-      containers:
-        - env:
-            - name: KUBERNETES_NAMESPACE
-              valueFrom:
-                fieldRef:
-                  fieldPath: metadata.namespace
-          image: ghcr.io/apache/camel-karavan:3.18.5
-          imagePullPolicy: Always
-          name: karavan
-          resources:
-            requests:
-              memory: "2048Mi"
-          volumeMounts:
-            - name: karavan-data
-              mountPath: /deployments/karavan-data
-          ports:
-            - containerPort: 8080
-              name: http
-              protocol: TCP
-      volumes:
-        - name: karavan-data
-          persistentVolumeClaim:
-            claimName: karavan-data
\ No newline at end of file
diff --git a/karavan-cloud/minikube/karavan-app-service-node-port.yaml b/karavan-cloud/minikube/karavan-app-service-node-port.yaml
deleted file mode 100644
index 5d86021..0000000
--- a/karavan-cloud/minikube/karavan-app-service-node-port.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-apiVersion: v1
-kind: Service
-metadata:
-  labels:
-    app: karavan
-    app.kubernetes.io/part-of: karavan
-  name: karavan
-spec:
-  selector:
-    app: karavan
-  ports:
-    - name: http
-      port: 80
-      targetPort: 8080
-      nodePort: 30365
-  type: NodePort  
-  
diff --git a/karavan-cloud/minikube/karavan-pvc.yaml b/karavan-cloud/minikube/karavan-pvc.yaml
deleted file mode 100644
index 52bd93b..0000000
--- a/karavan-cloud/minikube/karavan-pvc.yaml
+++ /dev/null
@@ -1,35 +0,0 @@
-apiVersion: v1
-kind: PersistentVolumeClaim
-metadata:
-  name: karavan-data
-spec:
-  resources:
-    requests:
-      storage: 10Gi
-  volumeMode: Filesystem
-  accessModes:
-    - ReadWriteOnce
----
-apiVersion: v1
-kind: PersistentVolumeClaim
-metadata:
-  name: karavan-m2-cache
-spec:
-  resources:
-    requests:
-      storage: 10Gi
-  volumeMode: Filesystem
-  accessModes:
-    - ReadWriteOnce
----
-apiVersion: v1
-kind: PersistentVolumeClaim
-metadata:
-  name: karavan-jbang-cache
-spec:
-  resources:
-    requests:
-      storage: 1Gi
-  volumeMode: Filesystem
-  accessModes:
-    - ReadWriteOnce    
diff --git a/karavan-cloud/minikube/karavan-quarkus-pipeline.yaml b/karavan-cloud/minikube/karavan-quarkus-pipeline.yaml
deleted file mode 100644
index 20b2710..0000000
--- a/karavan-cloud/minikube/karavan-quarkus-pipeline.yaml
+++ /dev/null
@@ -1,24 +0,0 @@
-apiVersion: tekton.dev/v1beta1
-kind: Pipeline
-metadata:
-  name: karavan-quarkus
-spec:
-  params:
-    - name: PROJECT_NAME
-      type: string
-  tasks:
-    - name: karavan-build-deploy
-      params:
-        - name: project
-          value: $(params.PROJECT_NAME)
-      taskRef:
-        kind: Task
-        name: karavan-quarkus-builder
-      workspaces:
-        - name: m2-cache
-          workspace: m2-cache
-        - name: jbang-cache
-          workspace: jbang-cache  
-  workspaces:
-    - name: m2-cache
-    - name: jbang-cache
\ No newline at end of file
diff --git a/karavan-cloud/minikube/karavan-quarkus-task-minikube.yaml b/karavan-cloud/minikube/karavan-quarkus-task-minikube.yaml
deleted file mode 100644
index 48d2cfe..0000000
--- a/karavan-cloud/minikube/karavan-quarkus-task-minikube.yaml
+++ /dev/null
@@ -1,111 +0,0 @@
-apiVersion: tekton.dev/v1beta1
-kind: Task
-metadata:
-  name: karavan-quarkus-builder
-spec:
-  params:
-    - name: project
-      type: string 
-  steps:
-    - name: karavan-build-deploy
-      script: |
-          #!/usr/bin/env bash
-          KAMELETS_DIR="/kamelets"
-          
-          if  [[ $KAMELETS_GIT_REPOSITORY == https* ]] ;
-          then
-              replacer=https://$KAMELETS_GIT_PASSWORD@
-              prefix=https://
-              url="${KAMELETS_GIT_REPOSITORY/$prefix/$replacer}"    
-              git clone --depth 1 --branch ${KAMELETS_GIT_MAIN} $url ${KAMELETS_DIR}
-          else
-              git clone --depth 1 --branch ${KAMELETS_GIT_MAIN} ${KAMELETS_GIT_REPOSITORY} ${KAMELETS_DIR}    
-          fi
-
-          CHECKOUT_DIR="/scripts"
-          
-          if  [[ $PROJECTS_GIT_REPOSITORY == https* ]] ;
-          then
-              replacer=https://$PROJECTS_GIT_PASSWORD@
-              prefix=https://
-              url="${PROJECTS_GIT_REPOSITORY/$prefix/$replacer}"    
-              git clone --depth 1 --branch ${PROJECTS_GIT_MAIN} $url ${CHECKOUT_DIR}
-          else
-              git clone --depth 1 --branch ${PROJECTS_GIT_MAIN} ${PROJECTS_GIT_REPOSITORY} ${CHECKOUT_DIR}    
-          fi
-
-          cd ${CHECKOUT_DIR}/$(inputs.params.project) 
-
-          entrypoint -Dcamel.jbang.version=3.18.2 camel@apache/camel export --local-kamelet-dir=${KAMELETS_DIR}
-
-          export LAST_COMMIT=$(git rev-parse --short HEAD)
-          export DATE=$(date '+%Y%m%d%H%M%S')
-          export TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
-          export NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
-
-          /opt/mvnd/bin/mvnd package \
-            -Dquarkus.container-image.build=true \
-            -Dquarkus.container-image.push=true \
-            -Dquarkus.container-image.insecure=true \
-            -Dquarkus.container-image.username=sa \
-            -Dquarkus.container-image.password=${TOKEN} \
-            -Dquarkus.container-image.registry=${IMAGE_REGISTRY} \
-            -Dquarkus.container-image.builder=jib \
-            -Dquarkus.kubernetes.deploy=true \
-            -Dquarkus.kubernetes.deployment-target=kubernetes \
-            -Dquarkus.kubernetes.add-version-to-label-selectors=false \
-            -Dquarkus.kubernetes.labels.\"app.openshift.io/runtime\"=camel \
-            -Dquarkus.container-image.group=${NAMESPACE} \
-            -Dquarkus.container-image.tag=${DATE}
-      image: ghcr.io/apache/camel-karavan-builder:3.18.5
-      env:
-        - name: PROJECTS_GIT_REPOSITORY
-          valueFrom:
-            secretKeyRef:
-              name: karavan
-              key: projects-git-repository
-        - name: PROJECTS_GIT_USERNAME
-          valueFrom:
-            secretKeyRef:
-              name: karavan
-              key: projects-git-username
-        - name: PROJECTS_GIT_PASSWORD
-          valueFrom:
-            secretKeyRef:
-              name: karavan
-              key: projects-git-password
-        - name: PROJECTS_GIT_MAIN
-          valueFrom:
-            secretKeyRef:
-              name: karavan
-              key: projects-git-main
-        - name: KAMELETS_GIT_REPOSITORY
-          valueFrom:
-            secretKeyRef:
-              name: karavan
-              key: kamelets-git-repository
-        - name: KAMELETS_GIT_USERNAME
-          valueFrom:
-            secretKeyRef:
-              name: karavan
-              key: kamelets-git-username
-        - name: KAMELETS_GIT_PASSWORD
-          valueFrom:
-            secretKeyRef:
-              name: karavan
-              key: kamelets-git-password
-        - name: KAMELETS_GIT_MAIN
-          valueFrom:
-            secretKeyRef:
-              name: karavan
-              key: kamelets-git-main      
-        - name: IMAGE_REGISTRY
-          valueFrom:
-            secretKeyRef:
-              name: karavan
-              key: image-registry
-  workspaces:
-    - mountPath: /root/.m2
-      name: m2-cache
-    - mountPath: /jbang/.jbang/cache
-      name: jbang-cache     
diff --git a/karavan-cloud/minikube/karavan-secret.yaml b/karavan-cloud/minikube/karavan-secret.yaml
index 95b18d1..cea29e4 100644
--- a/karavan-cloud/minikube/karavan-secret.yaml
+++ b/karavan-cloud/minikube/karavan-secret.yaml
@@ -8,12 +8,12 @@ stringData:
   oidc-secret: XXXXX
   oidc-server-url: https://localhost/auth/realms/karavan
   oidc-frontend-url: https://localhost/auth
-  projects-git-repository: https://github.com/mgubaidullin/karavan-demo.git
-  projects-git-password: demo
-  projects-git-username: demo
-  projects-git-main: main
-  kamelets-git-repository: https://github.com/mgubaidullin/karavan-demo-kamelets.git
-  kamelets-git-password: demo
-  kamelets-git-username: demo
-  kamelets-git-main: main
-  image-registry: image-registry.openshift-image-registry.svc:5000
+  projects-git-repository: http://gitea.karavan.svc.cluster.local:3000/karavan/projects.git
+  projects-git-password: karavan
+  projects-git-username: karavan
+  projects-git-branch: main
+  kamelets-git-repository: http://gitea.karavan.svc.cluster.local:3000/karavan/kamelets.git
+  kamelets-git-password: karavan
+  kamelets-git-username: karavan
+  kamelets-git-branch: main
+  image-registry: 10.108.175.208
diff --git a/karavan-cloud/minikube/karavan.yaml b/karavan-cloud/minikube/karavan.yaml
new file mode 100644
index 0000000..3dfd3bb
--- /dev/null
+++ b/karavan-cloud/minikube/karavan.yaml
@@ -0,0 +1,10 @@
+apiVersion: camel.apache.org/v1
+kind: Karavan
+metadata:
+  name: karavan
+  namespace: karavan
+spec:
+  instances: 1
+  auth: public
+  type: dev
+  nodePort: 37777
\ No newline at end of file
diff --git a/karavan-cloud/minikube/kustomization.yaml b/karavan-cloud/minikube/kustomization.yaml
deleted file mode 100644
index f27e373..0000000
--- a/karavan-cloud/minikube/kustomization.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
-apiVersion: kustomize.config.k8s.io/v1beta1
-kind: Kustomization
-
-resources:
-- karavan-acl.yaml
-- karavan-pvc.yaml
-- karavan-quarkus-pipeline.yaml
-- karavan-quarkus-task-minikube.yaml
-- karavan-app-deployment-public.yaml
-- karavan-app-service-node-port.yaml
-- pipeline-service-account.yaml
-- karavan-app-ingress.yaml
\ No newline at end of file
diff --git a/karavan-cloud/minikube/pipeline-service-account.yaml b/karavan-cloud/minikube/pipeline-service-account.yaml
deleted file mode 100644
index e73e68b..0000000
--- a/karavan-cloud/minikube/pipeline-service-account.yaml
+++ /dev/null
@@ -1,34 +0,0 @@
-# Service account
-apiVersion: v1
-kind: ServiceAccount
-metadata:
-  name: pipeline
-  labels:
-    app.kubernetes.io/name: pipeline
----
-# Role deployer
-apiVersion: rbac.authorization.k8s.io/v1
-kind: Role
-metadata:
-  name: deployer
-rules:
-  - apiGroups: [""]
-    resources: ["secrets", "configmaps"]
-    verbs: ["*"]
-  - apiGroups: ["", 'apps']
-    resources: ["deployments", "services"]
-    verbs: ["*"]
----
-# Role bindings
-kind: RoleBinding
-apiVersion: rbac.authorization.k8s.io/v1
-metadata:
-  name: pipeline-deployer
-subjects:
-  - kind: ServiceAccount
-    name: pipeline
-    namespace: karavan
-roleRef:
-  apiGroup: rbac.authorization.k8s.io
-  kind: Role
-  name: deployer
\ No newline at end of file
diff --git a/karavan-operator/src/main/java/org/apache/camel/karavan/operator/Constants.java b/karavan-operator/src/main/java/org/apache/camel/karavan/operator/Constants.java
index 7106f23..9499881 100644
--- a/karavan-operator/src/main/java/org/apache/camel/karavan/operator/Constants.java
+++ b/karavan-operator/src/main/java/org/apache/camel/karavan/operator/Constants.java
@@ -33,4 +33,9 @@ public final class Constants {
 
     public static final String PIPELINE_BUILD_QUARKUS = "karavan-pipeline-build-quarkus";
     public static final String TASK_BUILD_QUARKUS = "karavan-task-build-quarkus";
+
+
+    public static final String ROLE_PIPELINE_DEPLOYER = "deployer";
+    public static final String SERVICEACCOUNT_PIPELINE = "pipeline";
+    public static final String ROLEBINDING_PIPELINE_DEPLOYER = "pipeline-deployer";
 }
\ No newline at end of file
diff --git a/karavan-operator/src/main/java/org/apache/camel/karavan/operator/KaravanReconciler.java b/karavan-operator/src/main/java/org/apache/camel/karavan/operator/KaravanReconciler.java
index 5958bf7..fed42be 100644
--- a/karavan-operator/src/main/java/org/apache/camel/karavan/operator/KaravanReconciler.java
+++ b/karavan-operator/src/main/java/org/apache/camel/karavan/operator/KaravanReconciler.java
@@ -16,10 +16,8 @@
  */
 package org.apache.camel.karavan.operator;
 
-import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition;
-import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinitionList;
 import io.fabric8.kubernetes.client.KubernetesClient;
-import io.fabric8.kubernetes.client.Watch;
+import io.fabric8.kubernetes.client.informers.SharedIndexInformer;
 import io.fabric8.openshift.client.OpenShiftClient;
 import io.javaoperatorsdk.operator.api.reconciler.Context;
 import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
@@ -45,10 +43,13 @@ import org.apache.camel.karavan.operator.resource.KaravanService;
 import org.apache.camel.karavan.operator.resource.KaravanServiceAccount;
 import org.apache.camel.karavan.operator.resource.KaravanTektonPipeline;
 import org.apache.camel.karavan.operator.resource.KaravanTektonTask;
+import org.apache.camel.karavan.operator.resource.PipelineRoleBinding;
+import org.apache.camel.karavan.operator.resource.PipelineRoleDeployer;
+import org.apache.camel.karavan.operator.resource.PipelineServiceAccount;
 import org.apache.camel.karavan.operator.spec.Karavan;
 import org.apache.camel.karavan.operator.spec.KaravanStatus;
-import org.apache.camel.karavan.operator.watcher.TektonCrdWatcher;
-import org.apache.camel.karavan.operator.watcher.TektonSubscriptionWatcher;
+import org.apache.camel.karavan.operator.watcher.TektonCrdEventHandler;
+import org.apache.camel.karavan.operator.watcher.TektonSubscriptionEventHandler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -67,9 +68,8 @@ public class KaravanReconciler implements Reconciler<Karavan>, EventSourceInitia
     static final Logger log = LoggerFactory.getLogger(KaravanReconciler.class);
 
     private boolean isOpenShift = false;
-    private boolean isTektonInstalled = false;
     private KubernetesClient client;
-    private Watch watcher;
+    private SharedIndexInformer informer;
     private Workflow<Karavan> workflow;
 
     private KaravanServiceAccount karavanServiceAccount;
@@ -79,20 +79,22 @@ public class KaravanReconciler implements Reconciler<Karavan>, EventSourceInitia
     private KaravanPvcData karavanPvcData;
     private KaravanPvcM2Cache karavanPvcM2Cache;
     private KaravanPvcJbang karavanPvcJbang;
-    private KaravanTektonTask karavanTektonTask;
-    private KaravanTektonPipeline karavanTektonPipeline;
-    private KaravanDeployment karavanDeployment;
     private KaravanService karavanService;
     private KaravanRoute karavanRoute;
+    private KaravanDeployment karavanDeployment;
+
+    private KaravanTektonPipeline karavanTektonPipeline;
+    private KaravanTektonTask karavanTektonTask;
+    private PipelineServiceAccount pipelineServiceAccount;
+    private PipelineRoleDeployer pipelineRoleDeployer;
+    private PipelineRoleBinding pipelineRoleBinding;
 
     public KaravanReconciler(KubernetesClient client) {
         this.client = client;
-        checkKubernetes();
-        checkTektonInstalled();
-        addSubscriptionWatcher();
+        this.isOpenShift = Utils.isOpenShift(client);
         initDependentResources();
         createWorkflow();
-        System.out.println("isTektonInstalled = " + isTektonInstalled);
+        addSubscriptionWatcher();
     }
 
     @Override
@@ -113,54 +115,18 @@ public class KaravanReconciler implements Reconciler<Karavan>, EventSourceInitia
 
     private void addSubscriptionWatcher() {
         if (this.isOpenShift) {
-            this.watcher = client.adapt(OpenShiftClient.class).operatorHub().subscriptions().watch(new TektonSubscriptionWatcher(this));
+            this.informer = client.adapt(OpenShiftClient.class).operatorHub().subscriptions().inform(new TektonSubscriptionEventHandler(this), 30 * 1000L);
         } else {
-            this.watcher = client.apiextensions().v1().customResourceDefinitions().watch(new TektonCrdWatcher(this));
-        }
-    }
-    private void checkKubernetes() {
-        if (client.isAdaptable(OpenShiftClient.class)) {
-            this.isOpenShift = true;
-        }
-    }
-
-    private void checkTektonInstalled() {
-        CustomResourceDefinitionList list = client.apiextensions().v1().customResourceDefinitions().list();
-        if (list != null) {
-            List<CustomResourceDefinition> items = list.getItems();
-            long crds = items.stream().filter(crd -> crd.getMetadata().getName().equalsIgnoreCase("pipelines.tekton.dev")
-                    || crd.getMetadata().getName().equalsIgnoreCase("tasks.tekton.dev")
-            ).count();
-            if (crds == 2) {
-                if (this.isOpenShift) {
-                    long oper = client.adapt(OpenShiftClient.class).operatorHub().subscriptions().list().getItems().stream()
-                            .filter(sub -> sub.getMetadata().getName().contains("openshift-pipelines-operator")).count();
-                    this.isTektonInstalled = oper > 0;
-                } else {
-                    this.isTektonInstalled = true;
-                }
-            }
+            this.informer = client.apiextensions().v1().customResourceDefinitions().inform(new TektonCrdEventHandler(this), 30 * 1000L);
         }
     }
 
     private void createWorkflow() {
+        log.info("Creating workflow in " + (isOpenShift ? "Openshift" : "Kubernetes"));
         WorkflowBuilder workflowBuilder = new WorkflowBuilder<Karavan>();
-        workflowBuilder.addDependentResource(karavanServiceAccount);
-        workflowBuilder.addDependentResource(karavanRole);
-        workflowBuilder.addDependentResource(karavanRoleBinding);
-        workflowBuilder.addDependentResource(karavanRoleBindingView);
-        workflowBuilder.addDependentResource(karavanPvcData);
-        workflowBuilder.addDependentResource(karavanPvcM2Cache);
-        workflowBuilder.addDependentResource(karavanPvcJbang);
-        workflowBuilder.addDependentResource(karavanDeployment);
-        workflowBuilder.addDependentResource(karavanService);
-        if (isOpenShift){
-            workflowBuilder.addDependentResource(karavanRoute);
-        }
-        if (isTektonInstalled){
-            workflowBuilder.addDependentResource(karavanTektonPipeline);
-            workflowBuilder.addDependentResource(karavanTektonTask);
-        }
+        getResources().forEach(dr -> {
+            workflowBuilder.addDependentResource(dr);
+        });
         this.workflow = workflowBuilder.build();
     }
 
@@ -178,9 +144,13 @@ public class KaravanReconciler implements Reconciler<Karavan>, EventSourceInitia
         if (isOpenShift) {
             this.karavanRoute = new KaravanRoute();
         }
-        if (isTektonInstalled) {
-            this.karavanTektonTask = new KaravanTektonTask();
+
+        if (Utils.isTektonInstalled(client)) {
+            this.karavanTektonTask = new KaravanTektonTask(isOpenShift);
             this.karavanTektonPipeline = new KaravanTektonPipeline();
+            this.pipelineServiceAccount = new PipelineServiceAccount();
+            this.pipelineRoleDeployer = new PipelineRoleDeployer();
+            this.pipelineRoleBinding = new PipelineRoleBinding();
         }
         getResources().forEach(dr -> {
             dr.setKubernetesClient(client);
@@ -189,9 +159,9 @@ public class KaravanReconciler implements Reconciler<Karavan>, EventSourceInitia
     }
 
     public void addTektonResources() {
-        isTektonInstalled = true;
+        log.info("Recreate workflow with Tekton resources");
         if (karavanTektonTask == null) {
-            karavanTektonTask = new KaravanTektonTask();
+            karavanTektonTask = new KaravanTektonTask(isOpenShift);
             karavanTektonTask.setKubernetesClient(client);
             karavanTektonTask.configureWith(new KubernetesDependentResourceConfig());
         }
@@ -200,6 +170,21 @@ public class KaravanReconciler implements Reconciler<Karavan>, EventSourceInitia
             karavanTektonPipeline.setKubernetesClient(client);
             karavanTektonPipeline.configureWith(new KubernetesDependentResourceConfig());
         }
+        if (pipelineServiceAccount == null) {
+            pipelineServiceAccount = new PipelineServiceAccount();
+            pipelineServiceAccount.setKubernetesClient(client);
+            pipelineServiceAccount.configureWith(new KubernetesDependentResourceConfig());
+        }
+        if (pipelineRoleDeployer == null) {
+            pipelineRoleDeployer = new PipelineRoleDeployer();
+            pipelineRoleDeployer.setKubernetesClient(client);
+            pipelineRoleDeployer.configureWith(new KubernetesDependentResourceConfig());
+        }
+        if (pipelineRoleBinding == null) {
+            pipelineRoleBinding = new PipelineRoleBinding();
+            pipelineRoleBinding.setKubernetesClient(client);
+            pipelineRoleBinding.configureWith(new KubernetesDependentResourceConfig());
+        }
         createWorkflow();
     }
 
@@ -218,9 +203,12 @@ public class KaravanReconciler implements Reconciler<Karavan>, EventSourceInitia
         if (isOpenShift) {
             list.add(karavanRoute);
         }
-        if (isTektonInstalled) {
+        if (Utils.isTektonInstalled(client)) {
             list.add(karavanTektonPipeline);
             list.add(karavanTektonTask);
+            list.add(pipelineServiceAccount);
+            list.add(pipelineRoleDeployer);
+            list.add(pipelineRoleBinding);
         }
         return list;
     }
diff --git a/karavan-operator/src/main/java/org/apache/camel/karavan/operator/Utils.java b/karavan-operator/src/main/java/org/apache/camel/karavan/operator/Utils.java
index 14e0316..5a20f59 100644
--- a/karavan-operator/src/main/java/org/apache/camel/karavan/operator/Utils.java
+++ b/karavan-operator/src/main/java/org/apache/camel/karavan/operator/Utils.java
@@ -16,9 +16,14 @@
  */
 package org.apache.camel.karavan.operator;
 
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition;
+import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinitionList;
+import io.fabric8.kubernetes.client.KubernetesClient;
+import io.fabric8.openshift.client.OpenShiftClient;
 import org.eclipse.microprofile.config.ConfigProvider;
 
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 public class Utils {
@@ -33,4 +38,31 @@ public class Utils {
         result.putAll(labels);
         return result;
     }
+
+    public static boolean isTektonInstalled(KubernetesClient client) {
+        CustomResourceDefinitionList list = client.apiextensions().v1().customResourceDefinitions().list();
+        if (list != null) {
+            List<CustomResourceDefinition> items = list.getItems();
+            long crds = items.stream().filter(crd -> crd.getMetadata().getName().equalsIgnoreCase("pipelines.tekton.dev")
+                    || crd.getMetadata().getName().equalsIgnoreCase("tasks.tekton.dev")
+            ).count();
+            if (crds == 2) {
+                if (isOpenShift(client)) {
+                    long oper = client.adapt(OpenShiftClient.class).operatorHub().subscriptions().list().getItems().stream()
+                            .filter(sub -> sub.getMetadata().getName().contains("openshift-pipelines-operator")).count();
+                    return oper > 0;
+                } else {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public static boolean isOpenShift(KubernetesClient client) {
+        if (client.isAdaptable(OpenShiftClient.class)) {
+            return true;
+        }
+        return false;
+    }
 }
diff --git a/karavan-operator/src/main/java/org/apache/camel/karavan/operator/resource/KaravanService.java b/karavan-operator/src/main/java/org/apache/camel/karavan/operator/resource/KaravanService.java
index 5b6a26a..65f60be 100644
--- a/karavan-operator/src/main/java/org/apache/camel/karavan/operator/resource/KaravanService.java
+++ b/karavan-operator/src/main/java/org/apache/camel/karavan/operator/resource/KaravanService.java
@@ -19,6 +19,7 @@ package org.apache.camel.karavan.operator.resource;
 import io.fabric8.kubernetes.api.model.IntOrString;
 import io.fabric8.kubernetes.api.model.Service;
 import io.fabric8.kubernetes.api.model.ServiceBuilder;
+import io.fabric8.kubernetes.api.model.ServicePortBuilder;
 import io.javaoperatorsdk.operator.api.reconciler.Context;
 import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource;
 import org.apache.camel.karavan.operator.Constants;
@@ -36,6 +37,13 @@ public class KaravanService extends CRUDKubernetesDependentResource<Service, Kar
     @Override
     @SuppressWarnings("unchecked")
     public Service desired(Karavan karavan, Context<Karavan> context) {
+
+        ServicePortBuilder portBuilder = new ServicePortBuilder()
+                .withName("http").withPort(80).withProtocol("TCP").withTargetPort(new IntOrString(8080));
+        if (karavan.getSpec().getNodePort() > 0) {
+            portBuilder.withNodePort(karavan.getSpec().getNodePort());
+        }
+
         return new ServiceBuilder()
                 .withNewMetadata()
                 .withName(Constants.NAME)
@@ -43,14 +51,8 @@ public class KaravanService extends CRUDKubernetesDependentResource<Service, Kar
                 .withLabels(Utils.getLabels(Constants.NAME, Map.of()))
                 .endMetadata()
                 .withNewSpec()
-                .withType("NodePort")
-                .addNewPort()
-                .withName(Constants.NAME)
-                .withPort(80)
-                .withTargetPort(new IntOrString(8080))
-                .withNodePort(karavan.getSpec().getNodePort())
-                .withProtocol("TCP")
-                .endPort()
+                .withType(karavan.getSpec().getNodePort() > 0 ? "NodePort" : "ClusterIP")
+                .withPorts(portBuilder.build())
                 .withSelector(Map.of("app", Constants.NAME))
                 .endSpec()
                 .build();
diff --git a/karavan-operator/src/main/java/org/apache/camel/karavan/operator/resource/KaravanTektonTask.java b/karavan-operator/src/main/java/org/apache/camel/karavan/operator/resource/KaravanTektonTask.java
index 4e07b7e..b1eb239 100644
--- a/karavan-operator/src/main/java/org/apache/camel/karavan/operator/resource/KaravanTektonTask.java
+++ b/karavan-operator/src/main/java/org/apache/camel/karavan/operator/resource/KaravanTektonTask.java
@@ -45,8 +45,11 @@ import java.util.stream.Collectors;
 
 public class KaravanTektonTask extends CRUDKubernetesDependentResource<Task, Karavan>  implements Condition<Task, Karavan>  {
 
-    public KaravanTektonTask() {
+    private final boolean isOpenShift;
+
+    public KaravanTektonTask(boolean isOpenShift) {
         super(Task.class);
+        this.isOpenShift = isOpenShift;
     }
 
     @Override
@@ -113,7 +116,9 @@ public class KaravanTektonTask extends CRUDKubernetesDependentResource<Task, Kar
     protected String getScript(Karavan karavan) {
         String imageRegistry = getImageRegistry(karavan);
         try {
-            InputStream inputStream = KaravanTektonTask.class.getResourceAsStream("/karavan-quarkus-builder-script.sh");
+            InputStream inputStream = isOpenShift
+                ? KaravanTektonTask.class.getResourceAsStream("/quarkus-builder-script-openshift.sh")
+                : KaravanTektonTask.class.getResourceAsStream("/quarkus-builder-script-kubernetes.sh");
             String data = new BufferedReader(new InputStreamReader(inputStream))
                     .lines()
                     .map(s -> {
diff --git a/karavan-operator/src/main/java/org/apache/camel/karavan/operator/resource/PipelineRoleBinding.java b/karavan-operator/src/main/java/org/apache/camel/karavan/operator/resource/PipelineRoleBinding.java
new file mode 100644
index 0000000..1916dc5
--- /dev/null
+++ b/karavan-operator/src/main/java/org/apache/camel/karavan/operator/resource/PipelineRoleBinding.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.karavan.operator.resource;
+
+import io.fabric8.kubernetes.api.model.rbac.RoleBinding;
+import io.fabric8.kubernetes.api.model.rbac.RoleBindingBuilder;
+import io.fabric8.kubernetes.api.model.rbac.Subject;
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.dependent.ReconcileResult;
+import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource;
+import org.apache.camel.karavan.operator.Constants;
+import org.apache.camel.karavan.operator.spec.Karavan;
+
+public class PipelineRoleBinding extends CRUDKubernetesDependentResource<RoleBinding, Karavan> {
+
+    public PipelineRoleBinding() {
+        super(RoleBinding.class);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public RoleBinding desired(Karavan karavan, Context<Karavan> context) {
+        return new RoleBindingBuilder()
+                .withNewMetadata()
+                .withName(Constants.ROLEBINDING_PIPELINE_DEPLOYER)
+                .withNamespace(karavan.getMetadata().getNamespace())
+                .endMetadata()
+                .withNewRoleRef("rbac.authorization.k8s.io", "Role", Constants.ROLE_PIPELINE_DEPLOYER)
+                .withSubjects(new Subject("", "ServiceAccount", Constants.SERVICEACCOUNT_PIPELINE, karavan.getMetadata().getNamespace()))
+                .build();
+    }
+
+    @Override
+    public ReconcileResult<RoleBinding> reconcile(Karavan karavan, Context<Karavan> context) {
+        RoleBinding role = getKubernetesClient().rbac().roleBindings().inNamespace(karavan.getMetadata().getNamespace()).withName(Constants.ROLEBINDING_PIPELINE_DEPLOYER).get();
+        if (role == null) {
+            var desired = desired(karavan, context);
+            var createdResource = handleCreate(desired, karavan, context);
+            return ReconcileResult.resourceCreated(createdResource);
+        } else {
+            return ReconcileResult.noOperation(role);
+        }
+    }
+}
diff --git a/karavan-operator/src/main/java/org/apache/camel/karavan/operator/resource/PipelineRoleDeployer.java b/karavan-operator/src/main/java/org/apache/camel/karavan/operator/resource/PipelineRoleDeployer.java
new file mode 100644
index 0000000..8f0b02d
--- /dev/null
+++ b/karavan-operator/src/main/java/org/apache/camel/karavan/operator/resource/PipelineRoleDeployer.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.karavan.operator.resource;
+
+import io.fabric8.kubernetes.api.model.rbac.PolicyRuleBuilder;
+import io.fabric8.kubernetes.api.model.rbac.Role;
+import io.fabric8.kubernetes.api.model.rbac.RoleBuilder;
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.dependent.ReconcileResult;
+import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource;
+import org.apache.camel.karavan.operator.Constants;
+import org.apache.camel.karavan.operator.spec.Karavan;
+
+public class PipelineRoleDeployer extends CRUDKubernetesDependentResource<Role, Karavan> {
+
+    public PipelineRoleDeployer() {
+        super(Role.class);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Role desired(Karavan karavan, Context<Karavan> context) {
+        return new RoleBuilder()
+                .withNewMetadata()
+                .withName(Constants.ROLE_PIPELINE_DEPLOYER)
+                .withNamespace(karavan.getMetadata().getNamespace())
+                .endMetadata()
+                .withRules(
+                        new PolicyRuleBuilder().withApiGroups("").withResources("secrets", "configmaps", "services", "persistentvolumes", "persistentvolumeclaims").withVerbs("*").build(),
+                        new PolicyRuleBuilder().withApiGroups("networking.k8s.io").withResources("ingresses").withVerbs("*").build(),
+                        new PolicyRuleBuilder().withApiGroups("route.openshift.io").withResources( "routes").withVerbs("*").build(),
+                        new PolicyRuleBuilder().withApiGroups("apps").withResources("deployments").withVerbs("*").build()
+                        )
+                .build();
+    }
+
+    @Override
+    public ReconcileResult<Role> reconcile(Karavan karavan, Context<Karavan> context) {
+        Role role = getKubernetesClient().rbac().roles().inNamespace(karavan.getMetadata().getNamespace()).withName(Constants.ROLE_PIPELINE_DEPLOYER).get();
+        if (role == null) {
+            var desired = desired(karavan, context);
+            var createdResource = handleCreate(desired, karavan, context);
+            return ReconcileResult.resourceCreated(createdResource);
+        } else {
+            return ReconcileResult.noOperation(role);
+        }
+    }
+}
diff --git a/karavan-operator/src/main/java/org/apache/camel/karavan/operator/resource/KaravanService.java b/karavan-operator/src/main/java/org/apache/camel/karavan/operator/resource/PipelineServiceAccount.java
similarity index 53%
copy from karavan-operator/src/main/java/org/apache/camel/karavan/operator/resource/KaravanService.java
copy to karavan-operator/src/main/java/org/apache/camel/karavan/operator/resource/PipelineServiceAccount.java
index 5b6a26a..a86bacd 100644
--- a/karavan-operator/src/main/java/org/apache/camel/karavan/operator/resource/KaravanService.java
+++ b/karavan-operator/src/main/java/org/apache/camel/karavan/operator/resource/PipelineServiceAccount.java
@@ -16,43 +16,44 @@
  */
 package org.apache.camel.karavan.operator.resource;
 
-import io.fabric8.kubernetes.api.model.IntOrString;
-import io.fabric8.kubernetes.api.model.Service;
-import io.fabric8.kubernetes.api.model.ServiceBuilder;
+import io.fabric8.kubernetes.api.model.ServiceAccount;
+import io.fabric8.kubernetes.api.model.ServiceAccountBuilder;
 import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.dependent.ReconcileResult;
 import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource;
 import org.apache.camel.karavan.operator.Constants;
-import org.apache.camel.karavan.operator.spec.Karavan;
 import org.apache.camel.karavan.operator.Utils;
+import org.apache.camel.karavan.operator.spec.Karavan;
 
 import java.util.Map;
 
-public class KaravanService extends CRUDKubernetesDependentResource<Service, Karavan> {
+public class PipelineServiceAccount extends CRUDKubernetesDependentResource<ServiceAccount, Karavan> {
 
-    public KaravanService() {
-        super(Service.class);
+    public PipelineServiceAccount() {
+        super(ServiceAccount.class);
     }
 
     @Override
     @SuppressWarnings("unchecked")
-    public Service desired(Karavan karavan, Context<Karavan> context) {
-        return new ServiceBuilder()
+    public ServiceAccount desired(Karavan karavan, Context<Karavan> context) {
+        return new ServiceAccountBuilder()
                 .withNewMetadata()
-                .withName(Constants.NAME)
+                .withName(Constants.SERVICEACCOUNT_PIPELINE)
                 .withNamespace(karavan.getMetadata().getNamespace())
-                .withLabels(Utils.getLabels(Constants.NAME, Map.of()))
+                .withLabels(Utils.getLabels(Constants.SERVICEACCOUNT_PIPELINE, Map.of()))
                 .endMetadata()
-                .withNewSpec()
-                .withType("NodePort")
-                .addNewPort()
-                .withName(Constants.NAME)
-                .withPort(80)
-                .withTargetPort(new IntOrString(8080))
-                .withNodePort(karavan.getSpec().getNodePort())
-                .withProtocol("TCP")
-                .endPort()
-                .withSelector(Map.of("app", Constants.NAME))
-                .endSpec()
                 .build();
     }
+
+    @Override
+    public ReconcileResult<ServiceAccount> reconcile(Karavan karavan, Context<Karavan> context) {
+        ServiceAccount sa = getKubernetesClient().serviceAccounts().inNamespace(karavan.getMetadata().getNamespace()).withName(Constants.SERVICEACCOUNT_PIPELINE).get();
+        if (sa == null) {
+            var desired = desired(karavan, context);
+            var createdResource = handleCreate(desired, karavan, context);
+            return ReconcileResult.resourceCreated(createdResource);
+        } else {
+            return ReconcileResult.noOperation(sa);
+        }
+    }
 }
diff --git a/karavan-operator/src/main/java/org/apache/camel/karavan/operator/watcher/TektonCrdWatcher.java b/karavan-operator/src/main/java/org/apache/camel/karavan/operator/watcher/TektonCrdEventHandler.java
similarity index 60%
rename from karavan-operator/src/main/java/org/apache/camel/karavan/operator/watcher/TektonCrdWatcher.java
rename to karavan-operator/src/main/java/org/apache/camel/karavan/operator/watcher/TektonCrdEventHandler.java
index f38d32a..bfa68ad 100644
--- a/karavan-operator/src/main/java/org/apache/camel/karavan/operator/watcher/TektonCrdWatcher.java
+++ b/karavan-operator/src/main/java/org/apache/camel/karavan/operator/watcher/TektonCrdEventHandler.java
@@ -17,31 +17,33 @@
 package org.apache.camel.karavan.operator.watcher;
 
 import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition;
-import io.fabric8.kubernetes.client.Watcher;
-import io.fabric8.kubernetes.client.WatcherException;
+import io.fabric8.kubernetes.client.informers.ResourceEventHandler;
 import org.apache.camel.karavan.operator.KaravanReconciler;
 
-import java.util.List;
-
-public class TektonCrdWatcher implements Watcher<CustomResourceDefinition> {
+public class TektonCrdEventHandler implements ResourceEventHandler<CustomResourceDefinition> {
 
     private KaravanReconciler karavanReconciler;
 
-    public TektonCrdWatcher(KaravanReconciler karavanReconciler) {
+    public TektonCrdEventHandler(KaravanReconciler karavanReconciler) {
         this.karavanReconciler = karavanReconciler;
     }
 
     @Override
-    public void eventReceived(Action action, CustomResourceDefinition resource) {
-        if (List.of("MODIFIED", "ADDED").contains(action.name())) {
-            if (List.of("ADDED").contains(action.name()) && resource.getMetadata().getName().contains("pipelines.tekton.dev")) {
-                karavanReconciler.addTektonResources();
-            }
+    public void onAdd(CustomResourceDefinition crd) {
+        if (crd.getMetadata().getName().contains("pipelines.tekton.dev")) {
+            karavanReconciler.addTektonResources();
+        }
+    }
+
+    @Override
+    public void onUpdate(CustomResourceDefinition crd1, CustomResourceDefinition crd2) {
+        if (crd2.getMetadata().getName().contains("pipelines.tekton.dev")) {
+            karavanReconciler.addTektonResources();
         }
     }
 
     @Override
-    public void onClose(WatcherException cause) {
+    public void onDelete(CustomResourceDefinition obj, boolean deletedFinalStateUnknown) {
 
     }
 }
diff --git a/karavan-operator/src/main/java/org/apache/camel/karavan/operator/watcher/TektonSubscriptionWatcher.java b/karavan-operator/src/main/java/org/apache/camel/karavan/operator/watcher/TektonSubscriptionEventHandler.java
similarity index 68%
rename from karavan-operator/src/main/java/org/apache/camel/karavan/operator/watcher/TektonSubscriptionWatcher.java
rename to karavan-operator/src/main/java/org/apache/camel/karavan/operator/watcher/TektonSubscriptionEventHandler.java
index d3191b3..5ac485a 100644
--- a/karavan-operator/src/main/java/org/apache/camel/karavan/operator/watcher/TektonSubscriptionWatcher.java
+++ b/karavan-operator/src/main/java/org/apache/camel/karavan/operator/watcher/TektonSubscriptionEventHandler.java
@@ -16,30 +16,32 @@
  */
 package org.apache.camel.karavan.operator.watcher;
 
-import io.fabric8.kubernetes.client.Watcher;
-import io.fabric8.kubernetes.client.WatcherException;
+import io.fabric8.kubernetes.client.informers.ResourceEventHandler;
 import io.fabric8.openshift.api.model.operatorhub.v1alpha1.Subscription;
 import org.apache.camel.karavan.operator.KaravanReconciler;
 
-import java.util.List;
-
-public class TektonSubscriptionWatcher implements Watcher<Subscription> {
+public class TektonSubscriptionEventHandler implements ResourceEventHandler<Subscription> {
 
     private KaravanReconciler karavanReconciler;
 
-    public TektonSubscriptionWatcher(KaravanReconciler karavanReconciler) {
+    public TektonSubscriptionEventHandler(KaravanReconciler karavanReconciler) {
         this.karavanReconciler = karavanReconciler;
     }
 
     @Override
-    public void eventReceived(Action action, Subscription resource) {
-        if (List.of("ADDED").contains(action.name()) && resource.getMetadata().getName().contains("openshift-pipelines-operator")) {
+    public void onAdd(Subscription subscription) {
+        if (subscription.getMetadata().getName().contains("openshift-pipelines-operator")) {
             karavanReconciler.addTektonResources();
         }
     }
 
     @Override
-    public void onClose(WatcherException cause) {
+    public void onUpdate(Subscription oldObj, Subscription newObj) {
+
+    }
+
+    @Override
+    public void onDelete(Subscription obj, boolean deletedFinalStateUnknown) {
 
     }
 }
diff --git a/karavan-operator/src/main/resources/karavan-quarkus-builder-script.sh b/karavan-operator/src/main/resources/quarkus-builder-script-kubernetes.sh
similarity index 88%
copy from karavan-operator/src/main/resources/karavan-quarkus-builder-script.sh
copy to karavan-operator/src/main/resources/quarkus-builder-script-kubernetes.sh
index e8f6861..c1d5ec9 100644
--- a/karavan-operator/src/main/resources/karavan-quarkus-builder-script.sh
+++ b/karavan-operator/src/main/resources/quarkus-builder-script-kubernetes.sh
@@ -43,8 +43,8 @@ export NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
   -Dquarkus.kubernetes-client.master-url=kubernetes.default.svc \
   -Dquarkus.kubernetes-client.token=${TOKEN} \
   -Dquarkus.kubernetes.deploy=true \
-  -Dquarkus.openshift.deployment-kind=Deployment \
-  -Dquarkus.openshift.add-version-to-label-selectors=false \
-  -Dquarkus.openshift.labels.\"app.openshift.io/runtime\"=camel \
+  -Dquarkus.kubernetes.deployment-target=kubernetes \
+  -Dquarkus.kubernetes.add-version-to-label-selectors=false \
+  -Dquarkus.kubernetes.labels.\"app.kubernetes.io/runtime\"=camel \
   -Dquarkus.container-image.group=${NAMESPACE} \
   -Dquarkus.container-image.tag=${DATE}
\ No newline at end of file
diff --git a/karavan-operator/src/main/resources/karavan-quarkus-builder-script.sh b/karavan-operator/src/main/resources/quarkus-builder-script-openshift.sh
similarity index 100%
rename from karavan-operator/src/main/resources/karavan-quarkus-builder-script.sh
rename to karavan-operator/src/main/resources/quarkus-builder-script-openshift.sh