From d141e7699ef85ed7f17f57c459d4a7e4c0df3f41 Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Mon, 6 May 2024 14:24:40 +0800
Subject: [PATCH 01/37] fix(charts): charts name

---
 .woodpecker/publish-charts.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.woodpecker/publish-charts.yml b/.woodpecker/publish-charts.yml
index c4610c9a..cde37f3f 100644
--- a/.woodpecker/publish-charts.yml
+++ b/.woodpecker/publish-charts.yml
@@ -10,8 +10,8 @@ steps:
   - export IMAGE_TAG=$([ ! -z $CI_COMMIT_TAG ] && echo \"$VERSION\" || echo \"canary\")
   - export APP_VERSION=$([ -z $CI_COMMIT_TAG ] && echo $CI_COMMIT_SHA || echo $VERSION)
   - export CHART_VERSION=$([ -z $CI_COMMIT_TAG ] && echo 1.0.0 || echo $VERSION)
-  - sed -i s#{{repository}}#oci://$DRYCC_REGISTRY/$([ -z $CI_COMMIT_TAG ] && echo charts-testing || echo charts)#g charts/workflow/Chart.yaml
-  - helm dependency update charts/workflow
+  - sed -i s#{{repository}}#oci://$DRYCC_REGISTRY/$([ -z $CI_COMMIT_TAG ] && echo charts-testing || echo charts)#g charts/$${CI_REPO_NAME}/Chart.yaml
+  - helm dependency update charts/$${CI_REPO_NAME}
   - helm package -u charts/$${CI_REPO_NAME} --version $CHART_VERSION --app-version $APP_VERSION
   - echo $CONTAINER_PASSWORD | helm registry login $DRYCC_REGISTRY -u $CONTAINER_USERNAME --password-stdin
   - helm push $${CI_REPO_NAME}-$CHART_VERSION.tgz oci://$DRYCC_REGISTRY/$([ -z $CI_COMMIT_TAG ] && echo charts-testing || echo charts)

From 3aa8b31fb831be271f98ee6447f020cdee4a86f6 Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Mon, 15 Jul 2024 11:31:15 +0800
Subject: [PATCH 02/37] chore(woodpecker): add cron event

---
 .woodpecker/publish-charts.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.woodpecker/publish-charts.yml b/.woodpecker/publish-charts.yml
index cde37f3f..3dd59123 100644
--- a/.woodpecker/publish-charts.yml
+++ b/.woodpecker/publish-charts.yml
@@ -24,3 +24,4 @@ steps:
     event:
     - tag
     - push
+    - cron

From 94f7f0057a2d39ca4a1723a55c29d368b69c90a7 Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@users.noreply.github.com>
Date: Fri, 15 Nov 2024 11:58:16 +0800
Subject: [PATCH 03/37] docs(timeseries): add docs

---
 README.md | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 94ec8ba7..d866579f 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,8 @@ Please see below for links and descriptions of each component:
 - [registry](https://github.com/drycc/registry) - The Container registry
 - [logger](https://github.com/drycc/logger) - The (in-memory) log buffer for `drycc logs`
 - [monitor](https://github.com/drycc/monitor) - The platform monitoring components
-- [prometheus](https://github.com/drycc/prometheus) - The monitor database
+- [timeseries](https://github.com/drycc/timeseries) - The monitor database for telegraf
+- [prometheus](https://github.com/drycc/prometheus) - The monitor database for drycc component
 - [rabbitmq](https://github.com/drycc/rabbitmq) - RabbitMQ is a message broker used with controller celery
 - [storage](https://github.com/drycc/storage) - The in-cluster, kubernetes storage, s3 api compatible, hybrid storage system.
 - [workflow-cli](https://github.com/drycc/workflow-cli) - Workflow CLI `drycc`

From 8dc8fda5bedb6b7a7421fc69bca252b7828eae6e Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Mon, 18 Nov 2024 18:02:29 +0800
Subject: [PATCH 04/37] chore(charts): remove timeseries

---
 README.md                  | 7 +++----
 charts/workflow/Chart.yaml | 5 +----
 2 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/README.md b/README.md
index d866579f..48f9f93e 100644
--- a/README.md
+++ b/README.md
@@ -17,12 +17,11 @@ Please see below for links and descriptions of each component:
 - [builder](https://github.com/drycc/builder) - Git server and source-to-image component
 - [imagebuilder](https://github.com/drycc/imagebuilder) - The builder for Container Image and [CNCF Buildpacks](https://buildpacks.io/) based applications
 - [fluentbit](https://github.com/drycc/fluentbit) - Backend log shipping mechanism for `drycc logs`
-- [postgres](https://github.com/drycc/postgres) - The central database
+- [database](https://github.com/drycc/database) - Central database based on PostgreSQL
 - [registry](https://github.com/drycc/registry) - The Container registry
 - [logger](https://github.com/drycc/logger) - The (in-memory) log buffer for `drycc logs`
-- [monitor](https://github.com/drycc/monitor) - The platform monitoring components
-- [timeseries](https://github.com/drycc/timeseries) - The monitor database for telegraf
-- [prometheus](https://github.com/drycc/prometheus) - The monitor database for drycc component
+- [grafana](https://github.com/drycc/grafana) - Central monitor grafana
+- [prometheus](https://github.com/drycc/prometheus) - The monitor database
 - [rabbitmq](https://github.com/drycc/rabbitmq) - RabbitMQ is a message broker used with controller celery
 - [storage](https://github.com/drycc/storage) - The in-cluster, kubernetes storage, s3 api compatible, hybrid storage system.
 - [workflow-cli](https://github.com/drycc/workflow-cli) - Workflow CLI `drycc`
diff --git a/charts/workflow/Chart.yaml b/charts/workflow/Chart.yaml
index 559ee331..14d55759 100755
--- a/charts/workflow/Chart.yaml
+++ b/charts/workflow/Chart.yaml
@@ -13,9 +13,6 @@ dependencies:
 - name: database
   repository: {{repository}}
   version: x.x.x
-- name: timeseries
-  repository: {{repository}}
-  version: x.x.x
 - name: fluentbit
   repository: {{repository}}
   version: x.x.x
@@ -31,7 +28,7 @@ dependencies:
 - name: storage
   repository: {{repository}}
   version: x.x.x
-- name: monitor
+- name: grafana
   repository: {{repository}}
   version: x.x.x
 - name: registry

From 146b35cbb4e23660a09637044752fe51b46b8587 Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Tue, 19 Nov 2024 11:34:42 +0800
Subject: [PATCH 05/37] chore(valkey): use valkey replace redis

---
 charts/workflow/Chart.yaml  |  2 +-
 charts/workflow/values.yaml | 16 ++++++++--------
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/charts/workflow/Chart.yaml b/charts/workflow/Chart.yaml
index 14d55759..6792657c 100755
--- a/charts/workflow/Chart.yaml
+++ b/charts/workflow/Chart.yaml
@@ -19,7 +19,7 @@ dependencies:
 - name: gateway
   repository: {{repository}}
   version: x.x.x
-- name: redis
+- name: valkey
   repository: {{repository}}
   version: x.x.x
 - name: logger
diff --git a/charts/workflow/values.yaml b/charts/workflow/values.yaml
index 59fc3e00..0af32369 100644
--- a/charts/workflow/values.yaml
+++ b/charts/workflow/values.yaml
@@ -34,12 +34,12 @@ global:
   # - off-cluster: Run PostgreSQL outside the Kubernetes cluster
   timeseriesLocation: "on-cluster"
 
-  # Set the location of Workflow's Redis instance
+  # Set the location of Workflow's Valkey instance
   #
   # Valid values are:
-  # - on-cluster: Run Redis within the Kubernetes cluster
-  # - off-cluster: Run Redis outside the Kubernetes cluster (configure in redis section)
-  redisLocation: "on-cluster"
+  # - on-cluster: Run Valkey within the Kubernetes cluster
+  # - off-cluster: Run Valkey outside the Kubernetes cluster (configure in valkey section)
+  valkeyLocation: "on-cluster"
   # Set the location of Workflow's rabbitmq instance
   # Valid values are:
   # - on-cluster: Run Rabbitmq within the Kubernetes cluster
@@ -230,11 +230,11 @@ timeseries:
     ## If the PV uses a different storage class, specify that here.
     storageClass: ""
 
-redis:
-  # The addrs parameters are configured only when using an off-cluster Redis instance
+valkey:
+  # The addrs parameters are configured only when using an off-cluster Valkey instance
   addrs: "" # A list of clusters: "127.0.0.1:7001/1,127.0.0.2:7002/1"
-  password: "redis password" # "" == no password
-  # The following parameters are configured only when using an on-cluster Redis instance
+  password: "valkey password" # "" == no password
+  # The following parameters are configured only when using an on-cluster Valkey instance
   replicas: 1
   persistence:
     enabled: false # Set to true to enable persistence

From 4c39cae34aa56f9974c3dacd10c1018ce44e7745 Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Fri, 22 Nov 2024 21:43:11 +0800
Subject: [PATCH 06/37] chore(workflow): remove rabbitmq

---
 README.md                   |  1 -
 charts/workflow/Chart.yaml  |  3 ---
 charts/workflow/values.yaml | 28 ----------------------------
 3 files changed, 32 deletions(-)

diff --git a/README.md b/README.md
index 48f9f93e..6604ed3f 100644
--- a/README.md
+++ b/README.md
@@ -22,7 +22,6 @@ Please see below for links and descriptions of each component:
 - [logger](https://github.com/drycc/logger) - The (in-memory) log buffer for `drycc logs`
 - [grafana](https://github.com/drycc/grafana) - Central monitor grafana
 - [prometheus](https://github.com/drycc/prometheus) - The monitor database
-- [rabbitmq](https://github.com/drycc/rabbitmq) - RabbitMQ is a message broker used with controller celery
 - [storage](https://github.com/drycc/storage) - The in-cluster, kubernetes storage, s3 api compatible, hybrid storage system.
 - [workflow-cli](https://github.com/drycc/workflow-cli) - Workflow CLI `drycc`
 
diff --git a/charts/workflow/Chart.yaml b/charts/workflow/Chart.yaml
index 6792657c..70313124 100755
--- a/charts/workflow/Chart.yaml
+++ b/charts/workflow/Chart.yaml
@@ -37,9 +37,6 @@ dependencies:
 - name: registry-proxy
   repository: {{repository}}
   version: x.x.x
-- name: rabbitmq
-  repository: {{repository}}
-  version: x.x.x
 - name: passport
   repository: {{repository}}
   version: x.x.x
diff --git a/charts/workflow/values.yaml b/charts/workflow/values.yaml
index 0af32369..d8013904 100644
--- a/charts/workflow/values.yaml
+++ b/charts/workflow/values.yaml
@@ -1,7 +1,6 @@
 # This is the global configuration file for Workflow
 
 # If the service is used by a component alone, it needs to be configured inside the component.
-# Refer to rabbitmqUrl and databaseUrl of the controller component. 
 # If the service is dependent on multiple components and there is state synchronization,
 # it needs to be configured separately, such as storage.
 
@@ -40,11 +39,6 @@ global:
   # - on-cluster: Run Valkey within the Kubernetes cluster
   # - off-cluster: Run Valkey outside the Kubernetes cluster (configure in valkey section)
   valkeyLocation: "on-cluster"
-  # Set the location of Workflow's rabbitmq instance
-  # Valid values are:
-  # - on-cluster: Run Rabbitmq within the Kubernetes cluster
-  # - off-cluster: Run Rabbitmq outside the Kubernetes cluster (configure in controller section)
-  rabbitmqLocation: "on-cluster"
   # Set the location of Workflow's prometheus cluster
   #
   # Valid values are:
@@ -177,8 +171,6 @@ controller:
   ## databaseUrl and databaseReplicaUrl are will no longer use the built-in database component
   databaseUrl: ""
   databaseReplicaUrl: ""
-  # Configuring this will no longer use the built-in rabbitmq component
-  rabbitmqUrl: ""
 
 database:
   # The following parameters are configured only when using an on-cluster Database instance
@@ -241,26 +233,6 @@ valkey:
     size: 5Gi
     storageClass: ""
 
-rabbitmq:
-  # The following parameters are configured only when using an on-cluster Rabbitmq instance
-  # If left empty they will be generated using randAlphaNum
-  username: ""
-  password: ""
-  # GCP PDs and EBS volumes are supported only
-  persistence:
-    enabled: false # Set to true to enable persistence
-    size: 5Gi # PVC size
-    ## rabbitmq data Persistent Volume Storage Class
-    ## If defined, storageClassName: <storageClass>
-    ## If set to "-", storageClassName: "", which disables dynamic provisioning
-    ## If undefined (the default) or set to null, no storageClassName spec is
-    ##   set, choosing the default provisioner.  (gp2 on AWS, standard on
-    ##   GKE, AWS & OpenStack)
-    ##
-    ## Storage class of PV to bind. By default it looks for standard storage class.
-    ## If the PV uses a different storage class, specify that here.
-    storageClass: ""
-
 fluentbit:
   # Interval to flush output (seconds)
   flush: 5

From 6d9c670c9d52c300b6834e20933d2e9050c5bc4c Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Tue, 26 Nov 2024 18:21:34 +0800
Subject: [PATCH 07/37] chore(workflow): remove monitor

---
 charts/workflow/values.yaml | 72 ++++++++++---------------------------
 1 file changed, 18 insertions(+), 54 deletions(-)

diff --git a/charts/workflow/values.yaml b/charts/workflow/values.yaml
index d8013904..e03f54e1 100644
--- a/charts/workflow/values.yaml
+++ b/charts/workflow/values.yaml
@@ -23,16 +23,6 @@ global:
   #   configured above)
   # - off-cluster: Run PostgreSQL outside the Kubernetes cluster
   databaseLocation: "on-cluster"
-
-  # Set the location of Workflow's Timeseries database
-  #
-  # Valid values are:
-  # - on-cluster: Run PostgreSQL within the Kubernetes cluster (credentials are generated
-  #   automatically; backups are sent to object storage
-  #   configured above)
-  # - off-cluster: Run PostgreSQL outside the Kubernetes cluster
-  timeseriesLocation: "on-cluster"
-
   # Set the location of Workflow's Valkey instance
   #
   # Valid values are:
@@ -197,31 +187,6 @@ database:
     ## If the PV uses a different storage class, specify that here.
     storageClass: ""
 
-timeseries:
-  # The following parameters are configured only when using an on-cluster Database instance
-  # The username and password to be used by the on-cluster database.
-  # If left empty they will be generated
-  # The user name should be set to lowercase letters 
-  superuser: "postgres"
-  superuserPassword: ""
-  replicator: "standby"
-  replicatorPassword: ""
-  user: ""
-  password: ""
-  persistence:
-    enabled: false # Set to true to enable persistence
-    size: 5Gi # PVC size
-    ## database data Persistent Volume Storage Class
-    ## If defined, storageClassName: <storageClass>
-    ## If set to "-", storageClassName: "", which disables dynamic provisioning
-    ## If undefined (the default) or set to null, no storageClassName spec is
-    ##   set, choosing the default provisioner.  (gp2 on AWS, standard on
-    ##   GKE, AWS & OpenStack)
-    ##
-    ## Storage class of PV to bind. By default it looks for standard storage class.
-    ## If the PV uses a different storage class, specify that here.
-    storageClass: ""
-
 valkey:
   # The addrs parameters are configured only when using an off-cluster Valkey instance
   addrs: "" # A list of clusters: "127.0.0.1:7001/1,127.0.0.2:7002/1"
@@ -237,25 +202,24 @@ fluentbit:
   # Interval to flush output (seconds)
   flush: 5
 
-monitor:
-  grafana:
-    # Configure the following ONLY if you want persistence for on-cluster grafana
-    # GCP PDs and EBS volumes are supported only
-    persistence:
-      enabled: false # Set to true to enable persistence
-      accessMode: ReadWriteOnce
-      size: 5Gi # PVC size
-      ## grafana data Persistent Volume Storage Class
-      ## If defined, storageClassName: <storageClass>
-      ## If set to "-", storageClassName: "", which disables dynamic provisioning
-      ## If undefined (the default) or set to null, no storageClassName spec is
-      ##   set, choosing the default provisioner.  (gp2 on AWS, standard on
-      ##   GKE, AWS & OpenStack)
-      ##
-      ## Storage class of PV to bind. By default it looks for standard storage class.
-      ## If the PV uses a different storage class, specify that here.
-      storageClass: ""
-      volumeName: ""
+grafana:
+  # Configure the following ONLY if you want persistence for on-cluster grafana
+  # GCP PDs and EBS volumes are supported only
+  persistence:
+    enabled: false # Set to true to enable persistence
+    accessMode: ReadWriteOnce
+    size: 5Gi # PVC size
+    ## grafana data Persistent Volume Storage Class
+    ## If defined, storageClassName: <storageClass>
+    ## If set to "-", storageClassName: "", which disables dynamic provisioning
+    ## If undefined (the default) or set to null, no storageClassName spec is
+    ##   set, choosing the default provisioner.  (gp2 on AWS, standard on
+    ##   GKE, AWS & OpenStack)
+    ##
+    ## Storage class of PV to bind. By default it looks for standard storage class.
+    ## If the PV uses a different storage class, specify that here.
+    storageClass: ""
+    volumeName: ""
 
 registry:
   # The host parameters is configured only when using an off-cluster Registry instance

From bf24e9642db1471b3afbae45c37e1f45fa70337c Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Wed, 27 Nov 2024 09:23:43 +0800
Subject: [PATCH 08/37] chore(valkey): change valkey replicas to 3

---
 charts/workflow/values.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/charts/workflow/values.yaml b/charts/workflow/values.yaml
index e03f54e1..f02a2c34 100644
--- a/charts/workflow/values.yaml
+++ b/charts/workflow/values.yaml
@@ -192,7 +192,7 @@ valkey:
   addrs: "" # A list of clusters: "127.0.0.1:7001/1,127.0.0.2:7002/1"
   password: "valkey password" # "" == no password
   # The following parameters are configured only when using an on-cluster Valkey instance
-  replicas: 1
+  replicas: 3
   persistence:
     enabled: false # Set to true to enable persistence
     size: 5Gi

From 6b6332f9c1ad6517b3d58c1a9b07523dc9730898 Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Mon, 23 Dec 2024 13:53:50 +0800
Subject: [PATCH 09/37] fix(wooddpecker): secsets are deprecated

---
 .woodpecker/publish-charts.yml | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/.woodpecker/publish-charts.yml b/.woodpecker/publish-charts.yml
index 3dd59123..f5226f3d 100644
--- a/.woodpecker/publish-charts.yml
+++ b/.woodpecker/publish-charts.yml
@@ -16,10 +16,13 @@ steps:
   - echo $CONTAINER_PASSWORD | helm registry login $DRYCC_REGISTRY -u $CONTAINER_USERNAME --password-stdin
   - helm push $${CI_REPO_NAME}-$CHART_VERSION.tgz oci://$DRYCC_REGISTRY/$([ -z $CI_COMMIT_TAG ] && echo charts-testing || echo charts)
   - bash _scripts/generate_cache.sh 
-  secrets:
-  - drycc_registry
-  - container_username
-  - container_password
+  environment:
+    DRYCC_REGISTRY:
+      from_secret: drycc_registry
+    CONTAINER_USERNAME:
+      from_secret: container_username
+    CONTAINER_PASSWORD:
+      from_secret: container_password
   when:
     event:
     - tag

From 7807db8f84f147ad6f58a8b8fb3f3dbdd0bd5902 Mon Sep 17 00:00:00 2001
From: lijianguo <lijianguo1991@outlook.com>
Date: Thu, 24 Apr 2025 09:29:05 +0800
Subject: [PATCH 10/37] chore(charts): update values (#63)

---
 charts/workflow/values.yaml | 43 ++-----------------------------------
 1 file changed, 2 insertions(+), 41 deletions(-)

diff --git a/charts/workflow/values.yaml b/charts/workflow/values.yaml
index f02a2c34..7405cc97 100644
--- a/charts/workflow/values.yaml
+++ b/charts/workflow/values.yaml
@@ -81,47 +81,8 @@ global:
   passportLocation: "on-cluster"
 
 storage:
-  # The following parameters are configured only when using an on-cluster Storage instance
-  csi:
-    storageClassName: drycc-storage
-    statefulset:
-      replicas: 1
-  mainnode:
-    tipd:
-      replicas: 3
-      persistence:
-        enabled: false
-        size: 5Gi
-        storageClass: ""
-    weed:
-      replicas: 3
-      persistence:
-        enabled: false
-        size: 5Gi
-        storageClass: ""
-  metanode:
-    tikv:
-      replicas: 3
-      persistence:
-        enabled: false
-        size: 5Gi
-        storageClass: ""
-    weed:
-      replicas: 3
-      persistence:
-        enabled: false
-        size: 5Gi
-        storageClass: ""
-  datanode:
-    weed:
-      replicas: 3
-      persistence:
-        enabled: false
-        size: 5Gi
-        storageClass: ""
   # The following parameters are configured only when using an off-cluster Storage instance
   lookup: path
-  health: ""
   endpoint: ""
   builderBucket: ""
   registryBucket: ""
@@ -153,7 +114,7 @@ controller:
   # admin_only - allows for registration by an admin only.
   registrationMode: "admin_only"
   # Set storageClassName, It is used for application mount.
-  appStorageClass: "{{ .Values.storage.csi.storageClassName }}"
+  appStorageClass: "longhorn"
   # Set controller deployment  replicas
   replicas: 1
   # Set celery replicas
@@ -245,7 +206,7 @@ passport:
 prometheus:
   ## prometheus-server configuration##
   prometheus-server:
-    replicas: 1
+    replicas: 2
     retention: 15d
     # persistence config
     persistence:

From e3a8392e8bc591643dd0a363461530a28ac6b61d Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Wed, 7 May 2025 08:48:15 +0800
Subject: [PATCH 11/37] chore(registry): change proxy port location

---
 charts/workflow/values.yaml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/charts/workflow/values.yaml b/charts/workflow/values.yaml
index 7405cc97..bfa03328 100644
--- a/charts/workflow/values.yaml
+++ b/charts/workflow/values.yaml
@@ -50,8 +50,6 @@ global:
   registryLocation: "on-cluster"
   # Prefix for the imagepull secret created when using private registry
   registrySecretPrefix: "private-registry"
-  # The host port to which registry proxy binds to
-  registryProxyPort: 5555
 
   # Enable usage of RBAC authorization mode
   #
@@ -194,6 +192,8 @@ registry:
   # The subsection provides configuration for managing redirects from content backends.
   # For backends that support it, redirecting is disabled by default.
   redirect: "false"
+  # host port for the registry proxy in the daemonset
+  proxyPort: 5555
 
 passport:
   # The following parameters are configured only when using an on-cluster passport

From 26d6d11b46043efe59874a7371d3a4465212cbdf Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Wed, 7 May 2025 09:05:20 +0800
Subject: [PATCH 12/37] chore(charts): remove rbac

---
 charts/workflow/values.yaml | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/charts/workflow/values.yaml b/charts/workflow/values.yaml
index bfa03328..e8e5a9ed 100644
--- a/charts/workflow/values.yaml
+++ b/charts/workflow/values.yaml
@@ -50,13 +50,6 @@ global:
   registryLocation: "on-cluster"
   # Prefix for the imagepull secret created when using private registry
   registrySecretPrefix: "private-registry"
-
-  # Enable usage of RBAC authorization mode
-  #
-  # Valid values are:
-  # - true: all RBAC-related manifests will be installed (in case your cluster supports RBAC)
-  # - false: no RBAC-related manifests will be installed
-  rbac: true
   # GatewayClass is cluster-scoped resource defined by the infrastructure provider.
   # This resource represents a class of Gateways that can be instantiated.
   gatewayClass: ""

From e6bb73f996b8d4d83794173f7682cb15d5a54129 Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Wed, 7 May 2025 18:05:37 +0800
Subject: [PATCH 13/37] chore(charts): use condition

---
 charts/workflow/Chart.yaml  |  18 ++--
 charts/workflow/values.yaml | 167 ++++++++++++------------------------
 2 files changed, 64 insertions(+), 121 deletions(-)

diff --git a/charts/workflow/Chart.yaml b/charts/workflow/Chart.yaml
index 70313124..6c7116f0 100755
--- a/charts/workflow/Chart.yaml
+++ b/charts/workflow/Chart.yaml
@@ -10,39 +10,43 @@ dependencies:
 - name: controller
   repository: {{repository}}
   version: x.x.x
-- name: database
-  repository: {{repository}}
-  version: x.x.x
 - name: fluentbit
   repository: {{repository}}
   version: x.x.x
 - name: gateway
   repository: {{repository}}
   version: x.x.x
-- name: valkey
+- name: logger
   repository: {{repository}}
   version: x.x.x
-- name: logger
+- name: valkey
   repository: {{repository}}
   version: x.x.x
+  condition: valkey.enabled
 - name: storage
   repository: {{repository}}
   version: x.x.x
+  condition: storage.enabled
 - name: grafana
   repository: {{repository}}
   version: x.x.x
-- name: registry
+  condition: grafana.enabled
+- name: database
   repository: {{repository}}
   version: x.x.x
-- name: registry-proxy
+  condition: database.enabled
+- name: registry
   repository: {{repository}}
   version: x.x.x
+  condition: registry.enabled
 - name: passport
   repository: {{repository}}
   version: x.x.x
+  condition: passport.enabled
 - name: prometheus
   repository: {{repository}}
   version: x.x.x
+  condition: prometheus.enabled
 description: Drycc Workflow
 home: https://github.com/drycc/workflow
 maintainers:
diff --git a/charts/workflow/values.yaml b/charts/workflow/values.yaml
index e8e5a9ed..924139b3 100644
--- a/charts/workflow/values.yaml
+++ b/charts/workflow/values.yaml
@@ -7,49 +7,6 @@
 global:
   # Admin email, used for each component to send email to administrator
   email: "drycc@drycc.cc"
-
-  # Set the location of Workflow's Object Storage
-  #
-  # Valid values are:
-  # - on-cluster: Run drycc storage within the Kubernetes cluster
-  # - off-cluster: Run Storage outside the Kubernetes cluster (Compatible with s3 API)
-  storageLocation: "on-cluster"
-
-  # Set the location of Workflow's PostgreSQL database
-  #
-  # Valid values are:
-  # - on-cluster: Run PostgreSQL within the Kubernetes cluster (credentials are generated
-  #   automatically; backups are sent to object storage
-  #   configured above)
-  # - off-cluster: Run PostgreSQL outside the Kubernetes cluster
-  databaseLocation: "on-cluster"
-  # Set the location of Workflow's Valkey instance
-  #
-  # Valid values are:
-  # - on-cluster: Run Valkey within the Kubernetes cluster
-  # - off-cluster: Run Valkey outside the Kubernetes cluster (configure in valkey section)
-  valkeyLocation: "on-cluster"
-  # Set the location of Workflow's prometheus cluster
-  #
-  # Valid values are:
-  # - on-cluster: Run prometheus within the Kubernetes cluster
-  # - off-cluster: prometheus is running outside of the cluster and credentials and connection information will be provided.
-  prometheusLocation: "on-cluster"
-  # Set the location of Workflow's grafana instance
-  #
-  # Valid values are:
-  # - on-cluster: Run Grafana within the Kubernetes cluster
-  # - off-cluster: Grafana is running outside of the cluster
-  grafanaLocation: "on-cluster"
-
-  # Set the location of Workflow's Registry
-  #
-  # Valid values are:
-  # - on-cluster: Run registry within the Kubernetes cluster
-  # - off-cluster: Use registry outside the Kubernetes cluster (example: drycc registry,self-hosted)
-  registryLocation: "on-cluster"
-  # Prefix for the imagepull secret created when using private registry
-  registrySecretPrefix: "private-registry"
   # GatewayClass is cluster-scoped resource defined by the infrastructure provider.
   # This resource represents a class of Gateways that can be instantiated.
   gatewayClass: ""
@@ -64,32 +21,7 @@ global:
   platformDomain: ""
   # Whether certManagerEnabled is true to automatically generate drycc certificates
   certManagerEnabled: false
-  # Set the location of Workflow's passport
-  #
-  # Valid values are:
-  # - on-cluster: Run passport within the Kubernetes cluster
-  # - off-cluster: Use passport outside the Kubernetes cluster
-  passportLocation: "on-cluster"
-
-storage:
-  # The following parameters are configured only when using an off-cluster Storage instance
-  lookup: path
-  endpoint: ""
-  builderBucket: ""
-  registryBucket: ""
-  # The following parameters are general parameters
-  accesskey: ""
-  secretkey: ""
 
-# Set the default (global) way of how Application (your own) images are
-# pulled from within the Controller.
-# This can be configured per Application as well in the Controller.
-#
-# This affects pull apps and git push apps
-#
-# Values values are:
-# - Always
-# - IfNotPresent
 builder:
   service:
     # Service type default to ClusterIP, the entrance will be taken over by router.
@@ -97,6 +29,20 @@ builder:
     # If service.type is not set to NodePort, the following statement will be ignored.
     nodePort: ""
 
+# Drycc Gateway is a gateway chart that integrates cert-manager.
+gateway:
+  # acme configuration takes effect if and only if certManagerEnabled is true
+  acme:
+    server: https://acme-v02.api.letsencrypt.org/directory
+    #  EAB credentials
+    externalAccountBinding:
+      keyID: ""
+      keySecret: ""
+
+fluentbit:
+  # Interval to flush output (seconds)
+  flush: 5
+
 controller:
   appImagePullPolicy: "IfNotPresent"
   # Possible values are:
@@ -114,32 +60,8 @@ controller:
   databaseUrl: ""
   databaseReplicaUrl: ""
 
-database:
-  # The following parameters are configured only when using an on-cluster Database instance
-  # The username and password to be used by the on-cluster database.
-  # If left empty they will be generated
-  # The user name should be set to lowercase letters 
-  superuser: "postgres"
-  superuserPassword: ""
-  replicator: "standby"
-  replicatorPassword: ""
-  user: ""
-  password: ""
-  persistence:
-    enabled: false # Set to true to enable persistence
-    size: 5Gi # PVC size
-    ## database data Persistent Volume Storage Class
-    ## If defined, storageClassName: <storageClass>
-    ## If set to "-", storageClassName: "", which disables dynamic provisioning
-    ## If undefined (the default) or set to null, no storageClassName spec is
-    ##   set, choosing the default provisioner.  (gp2 on AWS, standard on
-    ##   GKE, AWS & OpenStack)
-    ##
-    ## Storage class of PV to bind. By default it looks for standard storage class.
-    ## If the PV uses a different storage class, specify that here.
-    storageClass: ""
-
 valkey:
+  enabled: true
   # The addrs parameters are configured only when using an off-cluster Valkey instance
   addrs: "" # A list of clusters: "127.0.0.1:7001/1,127.0.0.2:7002/1"
   password: "valkey password" # "" == no password
@@ -150,11 +72,17 @@ valkey:
     size: 5Gi
     storageClass: ""
 
-fluentbit:
-  # Interval to flush output (seconds)
-  flush: 5
+storage:
+  enabled: true
+  # The following parameters are configured only when using an off-cluster Storage instance
+  lookup: path
+  endpoint: ""
+  # The following parameters are general parameters
+  accesskey: ""
+  secretkey: ""
 
 grafana:
+  enabled: true
   # Configure the following ONLY if you want persistence for on-cluster grafana
   # GCP PDs and EBS volumes are supported only
   persistence:
@@ -174,11 +102,7 @@ grafana:
     volumeName: ""
 
 registry:
-  # The host parameters is configured only when using an off-cluster Registry instance
-  host: ""
-  # The following organization parameters are valid only in cluster-off
-  # In the case of cluster-on, the value is app name, which is dynamically assigned by builder.
-  organization: ""
+  enabled: true
   username: ""
   password: ""
   # The redirect parameters is configured only when using an on-cluster Registry instance
@@ -189,6 +113,7 @@ registry:
   proxyPort: 5555
 
 passport:
+  enabled: true
   # The following parameters are configured only when using an on-cluster passport
   # Set passport deployment replicas
   replicas: 1
@@ -196,7 +121,34 @@ passport:
   databaseUrl: ""
   databaseReplicaUrl: ""
 
+database:
+  enabled: true
+  # The following parameters are configured only when using an on-cluster Database instance
+  # The username and password to be used by the on-cluster database.
+  # If left empty they will be generated
+  # The user name should be set to lowercase letters 
+  superuser: "postgres"
+  superuserPassword: ""
+  replicator: "standby"
+  replicatorPassword: ""
+  user: ""
+  password: ""
+  persistence:
+    enabled: false # Set to true to enable persistence
+    size: 5Gi # PVC size
+    ## database data Persistent Volume Storage Class
+    ## If defined, storageClassName: <storageClass>
+    ## If set to "-", storageClassName: "", which disables dynamic provisioning
+    ## If undefined (the default) or set to null, no storageClassName spec is
+    ##   set, choosing the default provisioner.  (gp2 on AWS, standard on
+    ##   GKE, AWS & OpenStack)
+    ##
+    ## Storage class of PV to bind. By default it looks for standard storage class.
+    ## If the PV uses a different storage class, specify that here.
+    storageClass: ""
+
 prometheus:
+  enabled: true
   ## prometheus-server configuration##
   prometheus-server:
     replicas: 2
@@ -214,19 +166,6 @@ prometheus:
   ##
   kube-state-metrics:
     enabled: true
-  # Configure the following ONLY if using an off-cluster prometheus database
-  # URL configuration is only available in off-cluster prometheus database
-  url: "http://my.prometheus.url:9090"
   # The username and password to be used by the on-cluster database.
   username: "admin"
   password: "admin"
-
-# Drycc Gateway is a gateway chart that integrates cert-manager.
-gateway:
-  # acme configuration takes effect if and only if certManagerEnabled is true
-  acme:
-    server: https://acme-v02.api.letsencrypt.org/directory
-    #  EAB credentials
-    externalAccountBinding:
-      keyID: ""
-      keySecret: ""

From 5d924b95dda5d4bf846ea8af04b03ebcb57515ba Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Tue, 13 May 2025 11:55:00 +0800
Subject: [PATCH 14/37] feat(victoriametrics): use victoriametrics replace
 prometheus

---
 charts/workflow/Chart.yaml  |  4 +--
 charts/workflow/values.yaml | 62 +++++++++++++++++++++++--------------
 2 files changed, 41 insertions(+), 25 deletions(-)

diff --git a/charts/workflow/Chart.yaml b/charts/workflow/Chart.yaml
index 6c7116f0..7147caa5 100755
--- a/charts/workflow/Chart.yaml
+++ b/charts/workflow/Chart.yaml
@@ -43,10 +43,10 @@ dependencies:
   repository: {{repository}}
   version: x.x.x
   condition: passport.enabled
-- name: prometheus
+- name: victoriametrics
   repository: {{repository}}
   version: x.x.x
-  condition: prometheus.enabled
+  condition: victoriametrics.enabled
 description: Drycc Workflow
 home: https://github.com/drycc/workflow
 maintainers:
diff --git a/charts/workflow/values.yaml b/charts/workflow/values.yaml
index 924139b3..3eba7630 100644
--- a/charts/workflow/values.yaml
+++ b/charts/workflow/values.yaml
@@ -7,9 +7,6 @@
 global:
   # Admin email, used for each component to send email to administrator
   email: "drycc@drycc.cc"
-  # GatewayClass is cluster-scoped resource defined by the infrastructure provider.
-  # This resource represents a class of Gateways that can be instantiated.
-  gatewayClass: ""
   # A domain name consists of one or more parts.
   # Periods (.) are used to separate these parts.
   # Each part must be 1 to 63 characters in length and can contain lowercase letters, digits, and hyphens (-).
@@ -31,6 +28,8 @@ builder:
 
 # Drycc Gateway is a gateway chart that integrates cert-manager.
 gateway:
+  # GatewayClass is cluster-scoped resource defined by the infrastructure provider.
+  gatewayClass: ""
   # acme configuration takes effect if and only if certManagerEnabled is true
   acme:
     server: https://acme-v02.api.letsencrypt.org/directory
@@ -50,6 +49,8 @@ controller:
   # disabled - turns off open registration
   # admin_only - allows for registration by an admin only.
   registrationMode: "admin_only"
+  # Set app gateway, It is used for application gateway.
+  appGatewayClass: ""
   # Set storageClassName, It is used for application mount.
   appStorageClass: "longhorn"
   # Set controller deployment  replicas
@@ -110,7 +111,8 @@ registry:
   # For backends that support it, redirecting is disabled by default.
   redirect: "false"
   # host port for the registry proxy in the daemonset
-  proxyPort: 5555
+  proxy:
+    port: 5555
 
 passport:
   enabled: true
@@ -147,25 +149,39 @@ database:
     ## If the PV uses a different storage class, specify that here.
     storageClass: ""
 
-prometheus:
+victoriametrics:
   enabled: true
-  ## prometheus-server configuration##
-  prometheus-server:
-    replicas: 2
-    retention: 15d
-    # persistence config
+  ## victoriametrics vmagent configuration
+  ##
+  vmagent:
+    replicas: 3
+
+  ## victoriametrics vminsert configuration
+  ##
+  vminsert:
+    replicas: 3
+
+  ## victoriametrics vmselect configuration
+  ##
+  vmselect:
+    replicas: 3
+
+  ## victoriametrics vmstorage configuration
+  ##
+  vmstorage:
+    replicas: 3
+    temporary:
+      enabled: false
+      size: 5Gi
+      storageClass: ""
     persistence:
-      enabled: true
-      accessMode: ReadWriteOnce
-      size: 10Gi
+      enabled: false
+      size: 5Gi
       storageClass: ""
-  ## node-exporter configuration##
-  node-exporter:
-    enabled: true
-  ## kube-state-metrics configuration
-  ##
-  kube-state-metrics:
-    enabled: true
-  # The username and password to be used by the on-cluster database.
-  username: "admin"
-  password: "admin"
+    ## node-exporter configuration##
+    node-exporter:
+      enabled: true
+    ## kube-state-metrics configuration
+    ##
+    kube-state-metrics:
+      enabled: true

From 0b2139ee48b7bf4b44367ce205575baa3d42b5d0 Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Mon, 19 May 2025 09:10:56 +0800
Subject: [PATCH 15/37] docs(readme): change prometheus to victoriametrics

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 6604ed3f..eaac8013 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@ Please see below for links and descriptions of each component:
 - [registry](https://github.com/drycc/registry) - The Container registry
 - [logger](https://github.com/drycc/logger) - The (in-memory) log buffer for `drycc logs`
 - [grafana](https://github.com/drycc/grafana) - Central monitor grafana
-- [prometheus](https://github.com/drycc/prometheus) - The monitor database
+- [victoriametrics](https://github.com/drycc/victoriametrics) - The monitor database
 - [storage](https://github.com/drycc/storage) - The in-cluster, kubernetes storage, s3 api compatible, hybrid storage system.
 - [workflow-cli](https://github.com/drycc/workflow-cli) - Workflow CLI `drycc`
 

From aac9c1ff4ca820705365e5104e3432dfe13465c9 Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Mon, 19 May 2025 10:40:27 +0800
Subject: [PATCH 16/37] chore(scripts): add install scripts

---
 .../{publish-charts.yml => publish.yml}       |  24 +
 install-cli.sh                                |  73 ++
 install.sh                                    | 738 ++++++++++++++++++
 uninstall.sh                                  |  37 +
 4 files changed, 872 insertions(+)
 rename .woodpecker/{publish-charts.yml => publish.yml} (65%)
 create mode 100755 install-cli.sh
 create mode 100755 install.sh
 create mode 100755 uninstall.sh

diff --git a/.woodpecker/publish-charts.yml b/.woodpecker/publish.yml
similarity index 65%
rename from .woodpecker/publish-charts.yml
rename to .woodpecker/publish.yml
index f5226f3d..f3e76f2a 100644
--- a/.woodpecker/publish-charts.yml
+++ b/.woodpecker/publish.yml
@@ -28,3 +28,27 @@ steps:
     - tag
     - push
     - cron
+
+- name: publish-scripts
+  image: bash
+  commands:
+  - podman run --rm
+      -e CI_FORGE_TYPE=github
+      -e CI_PIPELINE_EVENT=tag
+      -e CI_REPO_OWNER="$CI_REPO_OWNER"
+      -e CI_REPO_NAME="$CI_REPO_NAME"
+      -e CI_COMMIT_REF="refs/tags/$CI_COMMIT_TAG"
+      -e PLUGIN_API_KEY="$GITHUB_TOKEN"
+      -e PLUGIN_BASE_URL="https://api.github.com/"
+      -e PLUGIN_UPLOAD_URL="https://uploads.github.com/"
+      -e PLUGIN_OVERWRITE="true"
+      -e PLUGIN_FILES="*.sh"
+      -v $(pwd):$(pwd)
+      -w $(pwd)
+      docker.io/woodpeckerci/plugin-release
+  environment:
+    GITHUB_TOKEN:
+      from_secret: github_token
+  when:
+    event:
+    - tag
diff --git a/install-cli.sh b/install-cli.sh
new file mode 100755
index 00000000..882aa6c3
--- /dev/null
+++ b/install-cli.sh
@@ -0,0 +1,73 @@
+#!/usr/bin/env bash
+set -eo pipefail
+shopt -s expand_aliases
+
+check_platform_arch() {
+  local supported="darwin-amd64 darwin-arm64 linux-amd64 linux-386 linux-arm linux-arm64 windows-386 windows-amd64"
+
+  if ! echo "${supported}" | tr ' ' '\n' | grep -q "${PLATFORM}-${ARCH}"; then
+    cat <<EOF
+
+The Drycc Workflow CLI (drycc) is not currently supported on ${PLATFORM}-${ARCH}.
+
+See https://github.com/drycc/workflow-cli for more information.
+
+EOF
+  fi
+}
+
+PLATFORM="$(uname | tr '[:upper:]' '[:lower:]')"
+if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then
+    DRYCC_BIN_URL_BASE="https://github.com/drycc/workflow-cli/releases"
+else
+    DRYCC_BIN_URL_BASE="https://github.com/drycc/workflow-cli/releases"
+fi
+
+# initArch discovers the architecture for this system.
+init_arch() {
+  ARCH=$(uname -m)
+  case $ARCH in
+    armv5*) ARCH="armv5";;
+    armv6*) ARCH="armv6";;
+    armv7*) ARCH="arm";;
+    aarch64) ARCH="arm64";;
+    x86) ARCH="386";;
+    x86_64) ARCH="amd64";;
+    i686) ARCH="386";;
+    i386) ARCH="386";;
+  esac
+}
+
+init_latest_version() {
+  VERSION=$(curl -Ls $DRYCC_BIN_URL_BASE|grep /drycc/workflow-cli/releases/tag/ | sed -E 's/.*\/drycc\/workflow-cli\/releases\/tag\/(v[0-9\.]+)".*/\1/g' | head -1)
+}
+
+init_arch
+init_latest_version
+check_platform_arch
+
+DRYCC_CLI="drycc-${VERSION}-${PLATFORM}-${ARCH}"
+DRYCC_CLI_PATH="${DRYCC_CLI}"
+if [ "${VERSION}" != 'stable' ]; then
+  DRYCC_CLI_PATH="${VERSION}/${DRYCC_CLI_PATH}"
+fi
+
+echo "Downloading ${DRYCC_CLI} From Google Cloud Storage..."
+echo "Downloading binary from here: ${DRYCC_BIN_URL_BASE}/download/${DRYCC_CLI_PATH}"
+curl -fsSL -o drycc "${DRYCC_BIN_URL_BASE}/download/${DRYCC_CLI_PATH}"
+
+chmod +x drycc
+
+cat <<EOF
+
+The Drycc Workflow CLI (drycc) is now available in your current directory.
+
+To learn more about Drycc Workflow, execute:
+
+    $ ./drycc --help
+
+You can also move it to other directories, such as:
+
+   $ mv $PWD/drycc /usr/local/bin
+
+EOF
diff --git a/install.sh b/install.sh
new file mode 100755
index 00000000..c9339ccb
--- /dev/null
+++ b/install.sh
@@ -0,0 +1,738 @@
+#!/usr/bin/env bash
+set -eo pipefail
+shopt -s expand_aliases
+
+# default vars
+GATEWAY_CLASS="istio"
+CLUSTER_CIDR=${CLUSTER_CIDR:-"10.42.0.0/16"}
+SERVICE_CIDR=${SERVICE_CIDR:-"10.43.0.0/16"}
+CLUSTER_DOMAIN=${CLUSTER_DOMAIN:-"cluster.local"}
+CERT_MANAGER_ENABLED="${CERT_MANAGER_ENABLED:-false}"
+DRYCC_REGISTRY="${DRYCC_REGISTRY:-registry.drycc.cc}"
+CHARTS_URL=oci://registry.drycc.cc/$([ "$CHANNEL" == "stable" ] && echo charts || echo charts-testing)
+CONTAINERD_RUNTIMES="${CONTAINERD_RUNTIMES:-runc}"
+CONTAINERD_CONFIG_PATH="${CONTAINERD_CONFIG_PATH:-/var/lib/rancher/k3s/agent/etc/containerd}"
+mkdir -p "${CONTAINERD_CONFIG_PATH}"
+CONTAINERD_CONFIG_FILE="${CONTAINERD_CONFIG_PATH}/config.toml.tmpl"
+REGISTRY_CONFIG_PATH="${REGISTRY_CONFIG_PATH:-/etc/rancher/k3s/}"
+mkdir -p "${REGISTRY_CONFIG_PATH}"
+REGISTRY_CONFIG_FILE="${REGISTRY_CONFIG_PATH}/registries.yaml"
+
+# initArch discovers the architecture for this system.
+init_arch() {
+  ARCH=$(uname -m)
+  case $ARCH in
+    armv5*) ARCH="armv5";;
+    armv6*) ARCH="armv6";;
+    armv7*) ARCH="arm";;
+    aarch64) ARCH="arm64";;
+    x86) ARCH="386";;
+    x86_64) ARCH="amd64";;
+    i686) ARCH="386";;
+    i386) ARCH="386";;
+  esac
+}
+
+function clean_before_exit {
+    # delay before exiting, so stdout/stderr flushes through the logging system
+    rm -rf /tmp/drycc-values.yaml
+    sleep 3
+}
+trap clean_before_exit EXIT
+init_arch
+
+urlencode() {
+  # urlencode <string>
+
+  old_lang=$LANG
+  LANG=C
+  
+  old_lc_collate=$LC_COLLATE
+  LC_COLLATE=C
+
+  local length="${#1}"
+  for (( i = 0; i < length; i++ )); do
+      local c="${1:i:1}"
+      case $c in
+          [a-zA-Z0-9.~_-]) printf "$c" ;;
+          *) printf '%%%02X' "'$c" ;;
+      esac
+  done
+
+  LANG=$old_lang
+  LC_COLLATE=$old_lc_collate
+}
+
+function install_helm {
+  if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then
+    version=$(curl -Ls https://github.com/helm/helm/releases|grep /helm/helm/releases/tag/ | sed -E 's/.*\/helm\/helm\/releases\/tag\/(v[0-9\.]{1,}(-rc.[0-9]{1,})?)".*/\1/g' | head -1)
+    tar_name="helm-${version}-linux-${ARCH}.tar.gz"
+    helm_download_url="https://github.com/helm/${tar_name}"
+  else
+    version=$(curl -Ls https://github.com/helm/helm/releases|grep /helm/helm/releases/tag/ | sed -E 's/.*\/helm\/helm\/releases\/tag\/(v[0-9\.]{1,}(-rc.[0-9]{1,})?)".*/\1/g' | head -1)
+    tar_name="helm-${version}-linux-${ARCH}.tar.gz"
+    helm_download_url="https://get.helm.sh/${tar_name}"
+  fi
+  curl -fsSL -o "${tar_name}" "${helm_download_url}"
+  tar -zxvf "${tar_name}"
+  mv "linux-${ARCH}/helm" /usr/local/bin/helm
+  rm -rf "${tar_name}" "linux-${ARCH}"
+}
+
+function configure_os {
+  echo -e "\\033[32m---> Start configuring kernel parameters\\033[0m"
+  if [[ "$(command -v iptables)" != "" ]] ; then
+    iptables -F
+    iptables -X
+    iptables -F -t nat
+    iptables -X -t nat
+    iptables -P FORWARD ACCEPT
+  else
+    # Kube hostport depends on iptables
+    echo -e "\\033[33m---> The iptables does not exist...\\033[0m"
+    exit 1
+  fi
+  swapoff -a
+  sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
+  mount bpffs -t bpf /sys/fs/bpf
+  rmem_max=$(sysctl -ne net.core.rmem_max)
+  if [ ! -n "$rmem_max" ] || [ 2500000 -gt $rmem_max ] ;then
+    echo 'net.core.rmem_max = 2500000' >> /etc/sysctl.conf
+  fi
+  nr_hugepages=$(sysctl -ne vm.nr_hugepages)
+  if [ ! -n "$nr_hugepages" ] || [ 1024 -gt $nr_hugepages ] ;then
+    echo 'vm.nr_hugepages = 1024' >> /etc/sysctl.conf
+  fi
+  max_user_instances=$(sysctl -ne fs.inotify.max_user_instances)
+  if [ ! -n "$max_user_instances" ] || [ 65535 -gt $max_user_instances ] ;then
+    echo 'fs.inotify.max_user_instances = 65535' >> /etc/sysctl.conf
+  fi
+  sysctl -p
+  
+  cpufreq=$(ls /sys/devices/system/cpu/cpu*/cpufreq >/dev/null 2>&1 || echo "false")
+  if [[ $cpufreq != "false" ]]; then
+    for cpu in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do
+      echo performance > $cpu
+    done
+  fi
+  echo -e "\\033[32m---> Configuring kernel parameters finish\\033[0m"
+}
+
+function install_crun_runtime {
+  echo -e "\\033[32m---> Start install crun runtime\\033[0m"
+  if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then
+    crun_base_url="https://github.com/containers"
+  else
+    crun_base_url="https://github.com/containers"
+  fi
+  crun_version=$(curl -Ls ${crun_base_url}/crun/releases|grep /containers/crun/releases/tag/ | sed -E 's/.*\/containers\/crun\/releases\/tag\/([0-9\.]{1,}(-rc.[0-9]{1,})?)".*/\1/g' | head -1)
+  crun_download_url=${crun_base_url}/crun/releases/download/${crun_version}/crun-${crun_version}-linux-${ARCH}
+  curl -sfL "${crun_download_url}" -o /usr/local/bin/crun
+  chmod a+rx /usr/local/bin/crun
+  echo -e "\\033[32m---> crun runtime install completed!\\033[0m"
+}
+
+function install_kata_runtime {
+  echo -e "\\033[32m---> Start install kata runtime\\033[0m"
+  if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then
+    kata_base_url="https://github.com/kata-containers"
+  else
+    kata_base_url="https://github.com/kata-containers"
+  fi
+
+  kata_version=$(curl -Ls ${kata_base_url}/kata-containers/releases|grep /kata-containers/kata-containers/releases/tag/ | sed -E 's/.*\/kata-containers\/kata-containers\/releases\/tag\/([0-9\.]{1,}(-rc.[0-9]{1,})?)".*/\1/g' | head -1)
+  kata_package=kata-static-${kata_version}-${ARCH}.tar.xz
+  kata_download_url=${kata_base_url}/kata-containers/releases/download/${kata_version}/${kata_package}
+
+  curl -sfL "${kata_download_url}" -o ${kata_package}
+  tar xvf ${kata_package} -C /
+  ln -s /opt/kata/bin/containerd-shim-kata-v2 /usr/local/bin/containerd-shim-kata-v2
+  ln -s /opt/kata/bin/kata-collect-data.sh /usr/local/bin/kata-collect-data.sh
+  ln -s /opt/kata/bin/kata-runtime /usr/local/bin/kata-runtime
+  rm -rf ${kata_package}
+  echo -e "\\033[32m---> Kata runtime install completed!\\033[0m"
+}
+
+function install_runtime {
+  readarray -d , -t containerd_runtimes <<<"$CONTAINERD_RUNTIMES"
+  if [[ "$CONTAINERD_RUNTIMES" =~ "crun" ]]; then
+    containerd_default_runtime="crun"
+  else
+    containerd_default_runtime="runc"
+  fi
+  cat << EOF > "${CONTAINERD_CONFIG_FILE}"
+{{ template "base" . }}
+
+[plugins.cri.containerd]
+  snapshotter = "overlayfs"
+  default_runtime_name = "${containerd_default_runtime}"
+  disable_snapshot_annotations = true
+EOF
+
+  for (( n=0; n < ${#containerd_runtimes[*]}; n++ ))
+  do
+    if [[ "${containerd_runtimes[n]}" == "kata" ]]; then
+      install_kata_runtime
+      sed -i s/sandbox_cgroup_only=false/sandbox_cgroup_only=true/g /opt/kata/share/defaults/kata-containers/configuration.toml
+      cat << EOF >> "${CONTAINERD_CONFIG_FILE}"
+[plugins.cri.containerd.runtimes.kata]
+  runtime_type = "io.containerd.kata.v2"
+  privileged_without_host_devices = true
+  pod_annotations = ["io.katacontainers.*"]
+  container_annotations = ["io.katacontainers.*"]
+[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata.options]
+  ConfigPath = "/opt/kata/share/defaults/kata-containers/configuration.toml"
+EOF
+    elif [[ "${containerd_runtimes[n]}" == "crun" ]]; then
+      install_crun_runtime
+      cat << EOF >> "${CONTAINERD_CONFIG_FILE}"
+[plugins.cri.containerd.runtimes.crun]
+  runtime_type = "io.containerd.runc.v2"
+[plugins.cri.containerd.runtimes.crun.options]
+  SystemdCgroup = true
+EOF
+    else
+      cat << EOF >> "${CONTAINERD_CONFIG_FILE}"
+[plugins.cri.containerd.runtimes.runc]
+  runtime_type = "io.containerd.runc.v2"
+[plugins.cri.containerd.runtimes.runc.options]
+  SystemdCgroup = true
+EOF
+    fi
+  done
+}
+
+function configure_registry {
+  if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]]; then
+    cat << EOF >> "${REGISTRY_CONFIG_FILE}"
+mirrors:
+  docker.io:
+    endpoint:
+    - "https://docker.m.daocloud.io"
+    - "https://docker-mirror.drycc.cc"
+    - "https://registry-1.docker.io"
+  quay.io:
+    endpoint:
+    - "https://quay.m.daocloud.io"
+    - "https://quay-mirror.drycc.cc"
+    - "https://quay.io"
+  gcr.io:
+    endpoint:
+    - "https://gcr.m.daocloud.io"
+    - "https://quay-mirror.drycc.cc"
+    - "https://gcr.io"
+  registry.k8s.io:
+    endpoint:
+    - "https://k8s.m.daocloud.io"
+    - "https://k8s-mirror.drycc.cc"
+    - "https://registry.k8s.io"
+EOF
+  fi
+}
+
+function configure_k3s_mirrors {
+  echo -e "\\033[32m---> Start configuring k3s mirrors\\033[0m"
+  if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then
+    INSTALL_K3S_MIRROR="${INSTALL_DRYCC_MIRROR}"
+    k3s_install_url="https://github.com/get-k3s/"
+    K3S_RELEASE_URL=https://github.com/k3s-io/k3s/releases
+    export INSTALL_K3S_MIRROR
+  else
+    k3s_install_url="https://get.k3s.io"
+    K3S_RELEASE_URL=github.com/k3s-io/k3s/releases
+  fi
+  if [ -z "${INSTALL_K3S_VERSION}" ]; then
+    INSTALL_K3S_VERSION=$(curl -Ls "$K3S_RELEASE_URL" | grep /k3s-io/k3s/releases/tag/ | sed -E 's/.*\/k3s-io\/k3s\/releases\/tag\/(v[0-9\.]{1,}[rc0-9\-]{0,}%2Bk3s[0-9])".*/\1/g' | head -1)
+  else 
+    INSTALL_K3S_VERSION=$(urlencode "$INSTALL_K3S_VERSION")
+  fi
+  export INSTALL_K3S_VERSION
+  echo -e "\\033[32m---> Configuring k3s mirrors finish\\033[0m"
+}
+
+function install_k3s_server {
+  configure_os
+  install_runtime
+  configure_registry
+  configure_k3s_mirrors
+  INSTALL_K3S_EXEC="server ${INSTALL_K3S_EXEC} --embedded-registry --flannel-backend=none  --disable-network-policy --disable=traefik --disable=servicelb --disable-kube-proxy --cluster-cidr=${CLUSTER_CIDR} --service-cidr=${SERVICE_CIDR} --cluster-domain=${CLUSTER_DOMAIN}"
+  if [[ -n "${K3S_DATA_DIR}" ]] ; then
+    INSTALL_K3S_EXEC="$INSTALL_K3S_EXEC --data-dir=${K3S_DATA_DIR}/rancher/k3s"
+  fi
+  if [[ -z "${K3S_URL}" ]] ; then
+    INSTALL_K3S_EXEC="$INSTALL_K3S_EXEC --cluster-init"
+  fi
+  curl -sfL "${k3s_install_url}" |INSTALL_K3S_EXEC="$INSTALL_K3S_EXEC" sh -s -
+
+  readarray -d , -t containerd_runtimes <<<"$CONTAINERD_RUNTIMES"
+  for (( n=0; n < ${#containerd_runtimes[*]}; n++ ))
+  do
+    kubectl apply -f - <<EOF
+apiVersion: node.k8s.io/v1
+kind: RuntimeClass
+metadata:
+  name: ${containerd_runtimes[n]}
+handler: ${containerd_runtimes[n]}
+EOF
+  done
+}
+
+function install_k3s_agent {
+  configure_os
+  install_runtime
+  configure_registry
+  configure_k3s_mirrors
+  if [[ -n "${K3S_DATA_DIR}" ]] ; then
+    INSTALL_K3S_EXEC="$INSTALL_K3S_EXEC --embedded-registry --data-dir=${K3S_DATA_DIR}/rancher/k3s"
+  fi
+  curl -sfL "${k3s_install_url}" |INSTALL_K3S_EXEC="$INSTALL_K3S_EXEC" sh -s -
+}
+
+function install_longhorn {
+  options=${1:-""}
+  helm repo add longhorn https://github.com/longhorn-charts
+  helm repo update
+  if [[ -z "${LONGHORN_CONFIG_FILE}" ]] ; then
+    echo -e "\\033[32m---> Longhorn using the default configuration.\\033[0m"
+    helm upgrade --install longhorn longhorn/longhorn \
+      --set csi.attacherReplicaCount=1 \
+      --set csi.provisionerReplicaCount=1 \
+      --set csi.resizerReplicaCount=1 \
+      --set csi.snapshotterReplicaCount=1 \
+      --set persistence.defaultClass=false \
+      --set longhornUI.replicas=1 \
+      --set persistence.defaultClassReplicaCount=1 \
+      --namespace longhorn-system \
+      --create-namespace $options --wait
+  else
+    helm upgrade --install longhorn longhorn/longhorn -f "${LONGHORN_CONFIG_FILE}" --wait
+  fi
+  echo -e "\\033[32m---> Longhorn install completed!\\033[0m"
+}
+
+function install_mountpoint {
+  options=${1:-""}
+  helm repo add aws-mountpoint-s3-csi-driver https://github.com/mountpoint-charts
+  helm repo update
+
+  if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then
+    mountpoint_api_url=https://github.com/drycc-addons/mountpoint-s3-csi-driver
+  else
+    mountpoint_api_url=https://github.com/drycc-addons/mountpoint-s3-csi-driver
+  fi
+  version=$(curl -Ls $mountpoint_api_url/releases|grep /drycc-addons/mountpoint-s3-csi-driver/releases/tag/ | sed -E 's/.*\/drycc-addons\/mountpoint-s3-csi-driver\/releases\/tag\/v([0-9\.]{1,}(-rc.[0-9]{1,})?)".*/\1/g' | head -1)
+
+  helm upgrade --install aws-mountpoint-s3-csi-driver aws-mountpoint-s3-csi-driver/aws-mountpoint-s3-csi-driver \
+    --set experimental.podMounter=true \
+    --set image.repository=registry.drycc.cc/drycc-addons/mountpoint-s3-csi-driver \
+    --set image.tag=${version} \
+    --namespace kube-system $options --wait
+  echo -e "\\033[32m---> Longhorn install completed!\\033[0m"
+}
+
+function check_metallb {
+  if [[ "${METALLB_CONFIG_FILE}" && ! -f "${METALLB_CONFIG_FILE}" ]] ; then
+    echo -e "\\033[33m---> The path ${METALLB_CONFIG_FILE} does not exist...\\033[0m"
+    exit 1
+  fi
+}
+
+# Best practices
+#
+# 1. Jumbo frames, change MTU(9000).
+# 2. Big tcp, enableIPv6BIGTCP/enableIPv4BIGTCP.
+# 3. Set `routingMode=native` and `ipv4NativeRoutingCIDR`.
+# 4. Change `loadBalancer.mode` to dsr(requires `routingMode=native`).
+# 5. Set `loadBalancer.acceleration=native`(requires hardware support).
+#
+# The following is a general configuration without optimization.
+function install_network() {
+  options=${1:-""}
+  echo -e "\\033[32m---> Start install network...\\033[0m"
+  kubernetes_service_host=(`ip -o route get to 8.8.8.8 | sed -n 's/.*src \([0-9.]\+\).*/\1/p'`)
+  helm upgrade --install cilium $CHARTS_URL/cilium \
+    --set endpointHealthChecking.enabled=false \
+    --set healthChecking=false \
+    --set operator.replicas=1 \
+    --set sysctlfix.enabled=true \
+    --set bpf.masquerade=true \
+    --set bandwidthManager.enabled=true \
+    --set bandwidthManager.bbr=true \
+    --set kubeProxyReplacement=true \
+    --set hubble.enabled=false \
+    --set hostPort.enabled=true \
+    --set k8sServiceHost=${KUBERNETES_SERVICE_HOST:-$kubernetes_service_host} \
+    --set k8sServicePort=${KUBERNETES_SERVICE_PORT:-6443} \
+    --set prometheus.enabled=true \
+    --set operator.prometheus.enabled=true \
+    --set envoy.enabled=false \
+    --namespace kube-system $options --wait
+  echo -e "\\033[32m---> Network install completed!\\033[0m"
+}
+
+function install_metallb() {
+  check_metallb
+  options=${1:-""}
+  echo -e "\\033[32m---> Start install metallb...\\033[0m"
+  helm upgrade --install metallb $CHARTS_URL/metallb \
+    --set speaker.frr.enabled=true \
+    --namespace metallb \
+    --create-namespace $options --wait
+
+  if [[ -z "${METALLB_CONFIG_FILE}" ]] ; then
+    echo -e "\\033[32m---> Metallb using the default configuration.\\033[0m"
+    kubectl apply -n metallb -f - <<EOF
+apiVersion: metallb.io/v1beta1
+kind: IPAddressPool
+metadata:
+  name: public
+spec:
+  addresses:
+  - $(ip -o route get to 8.8.8.8 | sed -n 's/.*src \([0-9.]\+\).*/\1/p')/32
+  serviceAllocation:
+    priority: 50
+    namespaces:
+    - drycc
+
+---
+apiVersion: metallb.io/v1beta1
+kind: IPAddressPool
+metadata:
+  name: default
+spec:
+  addresses:
+  - 192.168.254.0/24
+
+---
+apiVersion: metallb.io/v1beta1
+kind: L2Advertisement
+metadata:
+  name: drycc-l2-advertisement
+  namespace: metallb
+spec:
+  ipAddressPools:
+  - public
+  - default
+EOF
+  else
+    kubectl apply -n metallb -f ${METALLB_CONFIG_FILE}
+  fi
+  echo -e "\\033[32m---> Metallb install completed!\\033[0m"
+}
+
+function install_gateway() {
+  options=${1:-""}
+  echo -e "\\033[32m---> Start install gateway...\\033[0m"
+  if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then
+    gateway_api_url=https://github.com/kubernetes-sigs/gateway-api
+  else
+    gateway_api_url=https://github.com/kubernetes-sigs/gateway-api
+  fi
+  version=$(curl -Ls $gateway_api_url/releases|grep /kubernetes-sigs/gateway-api/releases/tag/ | sed -E 's/.*\/kubernetes-sigs\/gateway-api\/releases\/tag\/(v[0-9\.]{1,}(-rc.[0-9]{1,})?)".*/\1/g' | head -1)
+
+  helm repo add istio https://github.com/istio-charts
+  helm repo update
+  kubectl apply -f $gateway_api_url/releases/download/${version}/experimental-install.yaml
+  helm upgrade --install istio-base istio/base -n istio-system --set defaultRevision=default --create-namespace --wait $options
+  helm upgrade --install istio-istiod istio/istiod -n istio-system \
+    --set pilot.env.PILOT_ENABLE_ALPHA_GATEWAY_API=true \
+    --set pilot.env.PILOT_ENABLE_QUIC_LISTENERS=true \
+    --wait $options
+  helm upgrade --install istio-gateway istio/gateway -n istio-gateway --create-namespace --wait $options
+  echo -e "\\033[32m---> Gateway install completed!\\033[0m"
+}
+
+function install_cert_manager() {
+  options=${1:-""}
+  echo -e "\\033[32m---> Start install cert-manager...\\033[0m"
+  helm upgrade --install cert-manager $CHARTS_URL/cert-manager \
+    --namespace cert-manager \
+    --create-namespace \
+    --set clusterResourceNamespace=drycc \
+    --set "extraArgs={--feature-gates=ExperimentalGatewayAPISupport=true}" \
+    --set crds.enabled=true --wait $options
+  echo -e "\\033[32m---> Cert-manager install completed!\\033[0m"
+}
+
+function install_catalog() {
+  options=${1:-""}
+  echo -e "\\033[32m---> Start install catalog...\\033[0m"
+  helm upgrade --install catalog $CHARTS_URL/catalog \
+    --set asyncBindingOperationsEnabled=true \
+    --set image=registry.drycc.cc/drycc-addons/service-catalog:canary \
+    --namespace catalog \
+    --create-namespace --wait $options
+  echo -e "\\033[32m---> Catalog install completed!\\033[0m"
+}
+
+function install_components {
+  install_network
+  install_metallb
+  install_gateway
+  install_cert_manager
+  install_catalog
+}
+
+function check_drycc {
+  if [[ -z "${PLATFORM_DOMAIN}" ]] ; then
+    echo -e "\\033[33m---> Please set the PLATFORM_DOMAIN variable.\\033[0m"
+    echo -e "\\033[33m---> For example:\\033[0m"
+    echo -e "\\033[33m---> export PLATFORM_DOMAIN=drycc.cc\\033[0m"
+    echo -e "\\033[33m---> And confirm that wildcard domain name resolution has been set.\\033[0m"
+    echo -e "\\033[33m---> For example, the current server IP is 8.8.8.8\\033[0m"
+    echo -e "\\033[33m---> Please point *.drycc.cc to 8.8.8.8\\033[0m"
+    exit 1
+  fi
+
+  if [[ -z "${DRYCC_ADMIN_USERNAME}" || -z "${DRYCC_ADMIN_PASSWORD}" ]] ; then
+    echo -e "\\033[33m---> Please set the DRYCC_ADMIN_USERNAME and DRYCC_ADMIN_PASSWORD variable.\\033[0m"
+    echo -e "\\033[33m---> For example:\\033[0m"
+    echo -e "\\033[33m---> export DRYCC_ADMIN_USERNAME=admin\\033[0m"
+    echo -e "\\033[33m---> export DRYCC_ADMIN_PASSWORD=admin\\033[0m"
+    echo -e "\\033[33m---> This password is used by end users to log in and manage drycc.\\033[0m"
+    echo -e "\\033[33m---> Please set a high security string!!!\\033[0m"
+    exit 1
+  fi
+}
+
+function install_drycc {
+  check_drycc
+  options=${1:-""}
+  echo -e "\\033[32m---> Start install workflow...\\033[0m"
+  if [[ "$CHANNEL" == "stable" ]]; then
+    if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then
+      FILER_VERSION=$(curl -Ls https://github.com/drycc/filer/releases|grep /drycc/filer/releases/tag/ | sed -E 's/.*\/drycc\/filer\/releases\/tag\/(v[0-9\.]{1,}(-rc.[0-9]{1,})?)".*/\1/g' | head -1)
+    else
+      FILER_VERSION=$(curl -Ls https://github.com/drycc/filer/releases|grep /drycc/filer/releases/tag/ | sed -E 's/.*\/drycc\/filer\/releases\/tag\/(v[0-9\.]{1,}(-rc.[0-9]{1,})?)".*/\1/g' | head -1)
+    fi
+    FILER_IMAGE=${DRYCC_REGISTRY}/drycc/filer:$(sed 's#v##' <<< $FILER_VERSION)
+    FILER_IMAGE_PULL_POLICY="IfNotPresent"
+  else
+    FILER_IMAGE=${DRYCC_REGISTRY}/drycc/filer:canary
+    FILER_IMAGE_PULL_POLICY="Always"
+  fi
+
+cat << EOF > "/tmp/drycc-values.yaml"
+global:
+  clusterDomain: ${CLUSTER_DOMAIN}
+  platformDomain: ${PLATFORM_DOMAIN}
+  certManagerEnabled: ${CERT_MANAGER_ENABLED}
+
+builder:
+  replicas: ${BUILDER_REPLICAS:-1}
+  imageRegistry: ${DRYCC_REGISTRY}
+
+gateway:
+  gatewayClass: ${GATEWAY_CLASS}
+
+database:
+  imageRegistry: ${DRYCC_REGISTRY}
+  resources:
+    limits:
+      memory: 2512Mi
+      hugepages-2Mi: 256Mi
+  persistence:
+    enabled: true
+    size: ${DATABASE_PERSISTENCE_SIZE:-5Gi}
+    storageClass: ${DATABASE_PERSISTENCE_STORAGE_CLASS:-""}
+
+fluentbit:
+  imageRegistry: ${DRYCC_REGISTRY}
+
+controller:
+  apiReplicas: ${CONTROLLER_API_REPLICAS:-1}
+  celeryReplicas: ${CONTROLLER_CELERY_REPLICAS:-1}
+  webhookReplicas: ${CONTROLLER_WEBHOOK_REPLICAS:-1}
+  imageRegistry: ${DRYCC_REGISTRY}
+  appRuntimeClass: ${CONTROLLER_APP_RUNTIME_CLASS:-""}
+  appGatewayClass: ${CONTROLLER_APP_GATEWAY_CLASS:-$GATEWAY_CLASS}
+  appStorageClass: ${CONTROLLER_APP_STORAGE_CLASS:-"longhorn"}
+  filerImage: ${FILER_IMAGE}
+  filerImagePullPolicy: ${FILER_IMAGE_PULL_POLICY}
+
+valkey:
+  imageRegistry: ${DRYCC_REGISTRY}
+  persistence:
+    enabled: true
+    size: ${VALKEY_PERSISTENCE_SIZE:-5Gi}
+    storageClass: ${VALKEY_PERSISTENCE_STORAGE_CLASS:-""}
+
+storage:
+  zones: 1
+  drives: 1
+  replicas: 4
+  imageRegistry: ${DRYCC_REGISTRY}
+  persistence:
+    enabled: true
+    size: ${STORAGE_PERSISTENCE_SIZE:-5Gi}
+    storageClass: ${STORAGE_PERSISTENCE_STORAGE_CLASS:-""}
+
+imagebuilder:
+  imageRegistry: ${DRYCC_REGISTRY}
+
+logger:
+  replicas: ${LOGGER_REPLICAS:-1}
+  imageRegistry: ${DRYCC_REGISTRY}
+
+grafana:
+  imageRegistry: ${DRYCC_REGISTRY}
+  persistence:
+    enabled: true
+    size: ${MONITOR_GRAFANA_PERSISTENCE_SIZE:-5Gi}
+    storageClass: ${MONITOR_GRAFANA_PERSISTENCE_STORAGE_CLASS:-""}
+
+passport:
+  replicas: ${PASSPORT_REPLICAS:-1}
+  imageRegistry: ${DRYCC_REGISTRY}
+  adminUsername: ${DRYCC_ADMIN_USERNAME}
+  adminPassword: ${DRYCC_ADMIN_PASSWORD}
+
+registry:
+  replicas: ${REGISTRY_REPLICAS:-1}
+  imageRegistry: ${DRYCC_REGISTRY}
+
+acme:
+  server: ${ACME_SERVER:-"https://acme-v02.api.letsencrypt.org/directory"}
+  externalAccountBinding:
+    keyID: ${ACME_EAB_KEY_ID:-""}
+    keySecret: ${ACME_EAB_KEY_SECRET:-""}
+EOF
+
+  if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then
+    cat << EOF > "/tmp/drycc-mirror-values.yaml"
+imagebuilder:
+  container_registries: |
+    unqualified-search-registries = ["docker.io"]
+    short-name-mode="permissive"
+    [[registry]]
+    prefix = "docker.io"
+    location = "registry-1.docker.io"
+    [[registry.mirror]]
+    prefix = "docker.io"
+    location = "hub-mirror.c.163.com"
+EOF
+  else
+    cat << EOF > "/tmp/drycc-mirror-values.yaml"
+imagebuilder:
+  container_registries: |
+    unqualified-search-registries = ["docker.io"]
+    short-name-mode="permissive"
+EOF
+  fi
+  if [[ -z "${VICTORIAMETRICS_CONFIG_FILE}" ]] ; then
+    VICTORIAMETRICS_CONFIG_FILE="/tmp/drycc-storage-values.yaml"
+    cat << EOF > "${VICTORIAMETRICS_CONFIG_FILE}"
+victoriametrics:
+  enabled: true
+  vmagent:
+    replicas: 1
+  vminsert:
+    replicas: 1
+  vmselect:
+    replicas: 1
+  vmstorage:
+    replicas: 1
+    persistence:
+      enabled: true
+      size: ${VICTORIAMETRICS_PERSISTENCE_SIZE:-10Gi}
+      storageClass: ${VICTORIAMETRICS_PERSISTENCE_STORAGE_CLASS:-""}
+EOF
+    export VICTORIAMETRICS_CONFIG_FILE
+  fi
+
+  helm upgrade --install drycc $CHARTS_URL/workflow \
+    --namespace drycc \
+    --values /tmp/drycc-values.yaml \
+    --values /tmp/drycc-mirror-values.yaml \
+    --values ${VICTORIAMETRICS_CONFIG_FILE} \
+    --create-namespace --wait --timeout 30m0s $options
+  echo -e "\\033[32m---> Workflow install completed!\\033[0m"
+}
+
+function install_helmbroker {
+  if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then
+    addons_url="https://github.com/drycc-addons/addons/releases/download/latest/index.yaml"
+  else
+    addons_url="https://github.com/drycc-addons/addons/releases/download/latest/index.yaml"
+  fi
+  options=${1:-""}
+  local VALKEY_PASSWORD=$(kubectl get secrets -n drycc valkey-creds -o jsonpath="{.data.password}"| base64 -d)
+  local HELMBROKER_USERNAME=${HELMBROKER_USERNAME:-$(cat /proc/sys/kernel/random/uuid)}
+  local HELMBROKER_PASSWORD=${HELMBROKER_PASSWORD:-$(cat /proc/sys/kernel/random/uuid)}
+
+  echo -e "\\033[32m---> Start install helmbroker...\\033[0m"
+
+  helm upgrade --install helmbroker $CHARTS_URL/helmbroker \
+    --set valkey.enabled=false \
+    --set gateway.gatewayClass=${GATEWAY_CLASS} \
+    --set global.clusterDomain=${CLUSTER_DOMAIN} \
+    --set global.platformDomain=${PLATFORM_DOMAIN} \
+    --set global.certManagerEnabled=${CERT_MANAGER_ENABLED} \
+    --set persistence.size=${HELMBROKER_PERSISTENCE_SIZE:-5Gi} \
+    --set persistence.storageClass=${HELMBROKER_PERSISTENCE_STORAGE_CLASS:-"longhorn"} \
+    --set username=${HELMBROKER_USERNAME} \
+    --set password=${HELMBROKER_PASSWORD} \
+    --set replicas=${HELMBROKER_REPLICAS} \
+    --set valkeyUrl=redis://:${VALKEY_PASSWORD}@drycc-valkey.drycc.svc.${CLUSTER_DOMAIN}:16379/11 \
+    --set celeryReplicas=${HELMBROKER_CELERY_REPLICAS} \
+    --namespace drycc-helmbroker --create-namespace $options --wait -f - <<EOF
+repositories:
+- name: drycc-helmbroker
+  url: ${addons_url}
+EOF
+
+  kubectl apply -f - <<EOF
+apiVersion: servicecatalog.k8s.io/v1beta1
+kind: ClusterServiceBroker
+metadata:
+  finalizers:
+  - kubernetes-incubator/service-catalog
+  generation: 1
+  labels:
+    app.kubernetes.io/managed-by: Helm
+    heritage: Helm
+  name: helmbroker
+spec:
+  relistBehavior: Duration
+  relistRequests: 5
+  url: http://${HELMBROKER_USERNAME}:${HELMBROKER_PASSWORD}@drycc-helmbroker.drycc-helmbroker.svc.${CLUSTER_DOMAIN}
+EOF
+
+  echo -e "\\033[32m---> Helmbroker username: $HELMBROKER_USERNAME\\033[0m"
+  echo -e "\\033[32m---> Helmbroker password: $HELMBROKER_PASSWORD\\033[0m"
+  echo -e "\\033[32m---> Helmbroker install completed!\\033[0m"
+}
+
+function upgrade {
+  install_network --reset-then-reuse-values
+  install_metallb --reset-then-reuse-values
+  install_gateway --reset-then-reuse-values
+  install_cert_manager --reset-then-reuse-values
+  install_catalog --reset-then-reuse-values
+  install_longhorn --reset-then-reuse-values
+  install_mountpoint --reset-then-reuse-values
+  install_drycc --reset-then-reuse-values
+  install_helmbroker --reset-then-reuse-values
+  echo -e "\\033[32m---> Upgrade complete, enjoy life...\\033[0m"
+}
+
+export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
+
+if [[ -z "$@" ]] ; then
+  check_drycc
+  check_metallb
+  install_k3s_server
+  install_helm
+  install_components
+  install_longhorn
+  install_mountpoint
+  install_drycc
+  install_helmbroker
+  echo -e "\\033[32m---> Installation complete, enjoy life...\\033[0m"
+else
+  for command in "$@"
+  do
+    $command
+    echo -e "\\033[32m---> Execute $command complete, enjoy life...\\033[0m"
+  done
+fi
diff --git a/uninstall.sh b/uninstall.sh
new file mode 100755
index 00000000..334cb9d7
--- /dev/null
+++ b/uninstall.sh
@@ -0,0 +1,37 @@
+#!/usr/bin/env bash
+set -eo pipefail
+shopt -s expand_aliases
+
+# clean cilium
+ip link delete cilium_host > /dev/null 2>&1 || true
+ip link delete cilium_net > /dev/null 2>&1 || true
+ip link delete cilium_vxlan > /dev/null 2>&1 || true
+ip link delete nodelocaldns > /dev/null 2>&1 || true
+iptables-save | grep -iv cilium | iptables-restore || true
+ip6tables-save | grep -iv cilium | ip6tables-restore || true
+
+if [[ -x /usr/local/bin/k3s-killall.sh ]] ; then
+    /usr/local/bin/k3s-killall.sh
+fi
+
+if [[ -x /usr/local/bin/k3s-uninstall.sh ]] ; then
+    /usr/local/bin/k3s-uninstall.sh
+fi
+
+if [[ -x /usr/local/bin/k3s-agent-uninstall.sh ]] ; then
+    /usr/local/bin/k3s-agent-uninstall.sh
+fi
+
+if [[ -n "${K3S_DATA_DIR}" ]] ; then
+    rm -rf  "${K3S_DATA_DIR}/rancher"
+fi
+
+iptables -F && iptables -X && iptables -F -t nat && iptables -X -t nat && iptables -P FORWARD ACCEPT
+
+rm -rf /etc/cni
+rm -rf /etc/rancher
+rm -rf /var/lib/rancher
+rm -rf /usr/local/bin/crun
+rm -rf /usr/local/bin/helm ~/.config/helm
+
+rm -rf /opt/kata /usr/local/bin/containerd-shim-kata-v2 /usr/local/bin/kata-collect-data.sh /usr/local/bin/kata-runtime

From 29bd50a7ec67334d3d18198e19a7c295a3a5634a Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Mon, 19 May 2025 15:23:21 +0800
Subject: [PATCH 17/37] fix(install): catalog version

---
 install.sh | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)

diff --git a/install.sh b/install.sh
index c9339ccb..f734cc5b 100755
--- a/install.sh
+++ b/install.sh
@@ -455,11 +455,21 @@ function install_cert_manager() {
 }
 
 function install_catalog() {
+  service_catalog_version="canary"
+  if [[ "$CHANNEL" == "stable" ]]; then
+    if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then
+      service_catalog_url=https://github.com/drycc-addons/service-catalog
+    else
+      service_catalog_url=https://github.com/drycc-addons/service-catalog
+    fi
+    service_catalog_version=$(curl -Ls $service_catalog_url/releases|grep /drycc-addons/service-catalog/releases/tag/ | sed -E 's/.*\/drycc-addons\/service-catalog\/releases\/tag\/(v[0-9\.]{1,}(-rc.[0-9]{1,})?)".*/\1/g' | head -1)
+  fi
+
   options=${1:-""}
   echo -e "\\033[32m---> Start install catalog...\\033[0m"
   helm upgrade --install catalog $CHARTS_URL/catalog \
     --set asyncBindingOperationsEnabled=true \
-    --set image=registry.drycc.cc/drycc-addons/service-catalog:canary \
+    --set image=registry.drycc.cc/drycc-addons/service-catalog:${service_catalog_version} \
     --namespace catalog \
     --create-namespace --wait $options
   echo -e "\\033[32m---> Catalog install completed!\\033[0m"
@@ -651,10 +661,20 @@ EOF
 
 function install_helmbroker {
   if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then
-    addons_url="https://github.com/drycc-addons/addons/releases/download/latest/index.yaml"
+    addons_base_url="https://github.com/drycc-addons/addons"
   else
-    addons_url="https://github.com/drycc-addons/addons/releases/download/latest/index.yaml"
+    addons_base_url="https://github.com/drycc-addons/addons"
   fi
+  version="latest"
+  if [[ "$CHANNEL" == "stable" ]]; then
+    for version in $(curl -Ls "${addons_base_url}"/releases|grep /drycc-addons/addons/releases/tag/ | sed -E 's/.*\/drycc-addons\/addons\/releases\/tag\/(v[0-9]{1,})".*/\1/g'); do
+      if [[ "$version" != "latest" ]]; then
+        break
+      fi
+    done
+  fi
+  addons_url="${addons_base_url}/releases/download/${version}/index.yaml"
+
   options=${1:-""}
   local VALKEY_PASSWORD=$(kubectl get secrets -n drycc valkey-creds -o jsonpath="{.data.password}"| base64 -d)
   local HELMBROKER_USERNAME=${HELMBROKER_USERNAME:-$(cat /proc/sys/kernel/random/uuid)}

From 0eee60bb62426ee0e936479b71c418919c0a46ec Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Wed, 21 May 2025 11:52:16 +0800
Subject: [PATCH 18/37] chore(install): add victoriametrics env

---
 charts/workflow/values.yaml | 23 ++++++++++++-----------
 install.sh                  | 18 +++++++++++-------
 2 files changed, 23 insertions(+), 18 deletions(-)

diff --git a/charts/workflow/values.yaml b/charts/workflow/values.yaml
index 3eba7630..d1091e87 100644
--- a/charts/workflow/values.yaml
+++ b/charts/workflow/values.yaml
@@ -155,6 +155,10 @@ victoriametrics:
   ##
   vmagent:
     replicas: 3
+    persistence:
+      enabled: false
+      size: 5Gi
+      storageClass: ""
 
   ## victoriametrics vminsert configuration
   ##
@@ -170,18 +174,15 @@ victoriametrics:
   ##
   vmstorage:
     replicas: 3
-    temporary:
-      enabled: false
-      size: 5Gi
-      storageClass: ""
     persistence:
       enabled: false
       size: 5Gi
       storageClass: ""
-    ## node-exporter configuration##
-    node-exporter:
-      enabled: true
-    ## kube-state-metrics configuration
-    ##
-    kube-state-metrics:
-      enabled: true
+
+  ## node-exporter configuration##
+  nodeExporter:
+    enabled: true
+  ## kube-state-metrics configuration
+  ##
+  kubeStateMetrics:
+    enabled: true
diff --git a/install.sh b/install.sh
index f734cc5b..38d33930 100755
--- a/install.sh
+++ b/install.sh
@@ -46,7 +46,7 @@ urlencode() {
 
   old_lang=$LANG
   LANG=C
-  
+
   old_lc_collate=$LC_COLLATE
   LC_COLLATE=C
 
@@ -108,7 +108,7 @@ function configure_os {
     echo 'fs.inotify.max_user_instances = 65535' >> /etc/sysctl.conf
   fi
   sysctl -p
-  
+
   cpufreq=$(ls /sys/devices/system/cpu/cpu*/cpufreq >/dev/null 2>&1 || echo "false")
   if [[ $cpufreq != "false" ]]; then
     for cpu in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do
@@ -243,7 +243,7 @@ function configure_k3s_mirrors {
   fi
   if [ -z "${INSTALL_K3S_VERSION}" ]; then
     INSTALL_K3S_VERSION=$(curl -Ls "$K3S_RELEASE_URL" | grep /k3s-io/k3s/releases/tag/ | sed -E 's/.*\/k3s-io\/k3s\/releases\/tag\/(v[0-9\.]{1,}[rc0-9\-]{0,}%2Bk3s[0-9])".*/\1/g' | head -1)
-  else 
+  else
     INSTALL_K3S_VERSION=$(urlencode "$INSTALL_K3S_VERSION")
   fi
   export INSTALL_K3S_VERSION
@@ -469,7 +469,7 @@ function install_catalog() {
   echo -e "\\033[32m---> Start install catalog...\\033[0m"
   helm upgrade --install catalog $CHARTS_URL/catalog \
     --set asyncBindingOperationsEnabled=true \
-    --set image=registry.drycc.cc/drycc-addons/service-catalog:${service_catalog_version} \
+    --set image=registry.drycc.cc/drycc-addons/service-catalog:${service_catalog_version#v} \
     --namespace catalog \
     --create-namespace --wait $options
   echo -e "\\033[32m---> Catalog install completed!\\033[0m"
@@ -630,12 +630,16 @@ imagebuilder:
 EOF
   fi
   if [[ -z "${VICTORIAMETRICS_CONFIG_FILE}" ]] ; then
-    VICTORIAMETRICS_CONFIG_FILE="/tmp/drycc-storage-values.yaml"
+    VICTORIAMETRICS_CONFIG_FILE="/tmp/drycc-victoriametrics-values.yaml"
     cat << EOF > "${VICTORIAMETRICS_CONFIG_FILE}"
 victoriametrics:
   enabled: true
   vmagent:
     replicas: 1
+    persistence:
+      enabled: true
+      size: ${VICTORIAMETRICS_VMAGENT_PERSISTENCE_SIZE:-10Gi}
+      storageClass: ${VICTORIAMETRICS_VMAGENT_PERSISTENCE_STORAGE_CLASS:-""}
   vminsert:
     replicas: 1
   vmselect:
@@ -644,8 +648,8 @@ victoriametrics:
     replicas: 1
     persistence:
       enabled: true
-      size: ${VICTORIAMETRICS_PERSISTENCE_SIZE:-10Gi}
-      storageClass: ${VICTORIAMETRICS_PERSISTENCE_STORAGE_CLASS:-""}
+      size: ${VICTORIAMETRICS_VMSTORAGE_PERSISTENCE_SIZE:-10Gi}
+      storageClass: ${VICTORIAMETRICS_VMSTORAGE_PERSISTENCE_STORAGE_CLASS:-""}
 EOF
     export VICTORIAMETRICS_CONFIG_FILE
   fi

From 27eaaceed751de6a68ed3dd7f66665d145337049 Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Thu, 26 Jun 2025 11:52:19 +0800
Subject: [PATCH 19/37] chore(charts): remove logger

---
 README.md                  | 1 -
 charts/workflow/Chart.yaml | 3 ---
 install.sh                 | 4 ----
 3 files changed, 8 deletions(-)

diff --git a/README.md b/README.md
index eaac8013..af2b2ba4 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,6 @@ Please see below for links and descriptions of each component:
 - [fluentbit](https://github.com/drycc/fluentbit) - Backend log shipping mechanism for `drycc logs`
 - [database](https://github.com/drycc/database) - Central database based on PostgreSQL
 - [registry](https://github.com/drycc/registry) - The Container registry
-- [logger](https://github.com/drycc/logger) - The (in-memory) log buffer for `drycc logs`
 - [grafana](https://github.com/drycc/grafana) - Central monitor grafana
 - [victoriametrics](https://github.com/drycc/victoriametrics) - The monitor database
 - [storage](https://github.com/drycc/storage) - The in-cluster, kubernetes storage, s3 api compatible, hybrid storage system.
diff --git a/charts/workflow/Chart.yaml b/charts/workflow/Chart.yaml
index 7147caa5..e71d464a 100755
--- a/charts/workflow/Chart.yaml
+++ b/charts/workflow/Chart.yaml
@@ -16,9 +16,6 @@ dependencies:
 - name: gateway
   repository: {{repository}}
   version: x.x.x
-- name: logger
-  repository: {{repository}}
-  version: x.x.x
 - name: valkey
   repository: {{repository}}
   version: x.x.x
diff --git a/install.sh b/install.sh
index 38d33930..a59aa61d 100755
--- a/install.sh
+++ b/install.sh
@@ -580,10 +580,6 @@ storage:
 imagebuilder:
   imageRegistry: ${DRYCC_REGISTRY}
 
-logger:
-  replicas: ${LOGGER_REPLICAS:-1}
-  imageRegistry: ${DRYCC_REGISTRY}
-
 grafana:
   imageRegistry: ${DRYCC_REGISTRY}
   persistence:

From 2370abb7b14efc3711aa4336382677b97e07d574 Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Fri, 4 Jul 2025 14:53:12 +0800
Subject: [PATCH 20/37] chore(workflow): add quickwit

---
 charts/workflow/Chart.yaml | 3 +++
 install.sh                 | 3 +++
 2 files changed, 6 insertions(+)

diff --git a/charts/workflow/Chart.yaml b/charts/workflow/Chart.yaml
index e71d464a..41910932 100755
--- a/charts/workflow/Chart.yaml
+++ b/charts/workflow/Chart.yaml
@@ -16,6 +16,9 @@ dependencies:
 - name: gateway
   repository: {{repository}}
   version: x.x.x
+- name: quickwit
+  repository: {{repository}}
+  version: x.x.x
 - name: valkey
   repository: {{repository}}
   version: x.x.x
diff --git a/install.sh b/install.sh
index a59aa61d..a816949c 100755
--- a/install.sh
+++ b/install.sh
@@ -535,6 +535,9 @@ builder:
 gateway:
   gatewayClass: ${GATEWAY_CLASS}
 
+quickwit:
+  imageRegistry: ${DRYCC_REGISTRY}
+
 database:
   imageRegistry: ${DRYCC_REGISTRY}
   resources:

From 4027e15d8b030370af5f1eb6052f316dae75ca22 Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Tue, 15 Jul 2025 23:08:51 +0800
Subject: [PATCH 21/37] chore(workflow): remove cluster domain

---
 charts/workflow/values.yaml | 5 -----
 install.sh                  | 9 +++------
 2 files changed, 3 insertions(+), 11 deletions(-)

diff --git a/charts/workflow/values.yaml b/charts/workflow/values.yaml
index d1091e87..f5628430 100644
--- a/charts/workflow/values.yaml
+++ b/charts/workflow/values.yaml
@@ -7,11 +7,6 @@
 global:
   # Admin email, used for each component to send email to administrator
   email: "drycc@drycc.cc"
-  # A domain name consists of one or more parts.
-  # Periods (.) are used to separate these parts.
-  # Each part must be 1 to 63 characters in length and can contain lowercase letters, digits, and hyphens (-).
-  # It must start and end with a lowercase letter or digit.
-  clusterDomain: "cluster.local"
   # The publicly resolvable hostname to build your cluster with.
   #
   # This will be the hostname that is used to build endpoints such as "drycc.$HOSTNAME"
diff --git a/install.sh b/install.sh
index a816949c..b523dc4e 100755
--- a/install.sh
+++ b/install.sh
@@ -6,7 +6,6 @@ shopt -s expand_aliases
 GATEWAY_CLASS="istio"
 CLUSTER_CIDR=${CLUSTER_CIDR:-"10.42.0.0/16"}
 SERVICE_CIDR=${SERVICE_CIDR:-"10.43.0.0/16"}
-CLUSTER_DOMAIN=${CLUSTER_DOMAIN:-"cluster.local"}
 CERT_MANAGER_ENABLED="${CERT_MANAGER_ENABLED:-false}"
 DRYCC_REGISTRY="${DRYCC_REGISTRY:-registry.drycc.cc}"
 CHARTS_URL=oci://registry.drycc.cc/$([ "$CHANNEL" == "stable" ] && echo charts || echo charts-testing)
@@ -255,7 +254,7 @@ function install_k3s_server {
   install_runtime
   configure_registry
   configure_k3s_mirrors
-  INSTALL_K3S_EXEC="server ${INSTALL_K3S_EXEC} --embedded-registry --flannel-backend=none  --disable-network-policy --disable=traefik --disable=servicelb --disable-kube-proxy --cluster-cidr=${CLUSTER_CIDR} --service-cidr=${SERVICE_CIDR} --cluster-domain=${CLUSTER_DOMAIN}"
+  INSTALL_K3S_EXEC="server ${INSTALL_K3S_EXEC} --embedded-registry --flannel-backend=none  --disable-network-policy --disable=traefik --disable=servicelb --disable-kube-proxy --cluster-cidr=${CLUSTER_CIDR} --service-cidr=${SERVICE_CIDR}"
   if [[ -n "${K3S_DATA_DIR}" ]] ; then
     INSTALL_K3S_EXEC="$INSTALL_K3S_EXEC --data-dir=${K3S_DATA_DIR}/rancher/k3s"
   fi
@@ -524,7 +523,6 @@ function install_drycc {
 
 cat << EOF > "/tmp/drycc-values.yaml"
 global:
-  clusterDomain: ${CLUSTER_DOMAIN}
   platformDomain: ${PLATFORM_DOMAIN}
   certManagerEnabled: ${CERT_MANAGER_ENABLED}
 
@@ -688,7 +686,6 @@ function install_helmbroker {
   helm upgrade --install helmbroker $CHARTS_URL/helmbroker \
     --set valkey.enabled=false \
     --set gateway.gatewayClass=${GATEWAY_CLASS} \
-    --set global.clusterDomain=${CLUSTER_DOMAIN} \
     --set global.platformDomain=${PLATFORM_DOMAIN} \
     --set global.certManagerEnabled=${CERT_MANAGER_ENABLED} \
     --set persistence.size=${HELMBROKER_PERSISTENCE_SIZE:-5Gi} \
@@ -696,7 +693,7 @@ function install_helmbroker {
     --set username=${HELMBROKER_USERNAME} \
     --set password=${HELMBROKER_PASSWORD} \
     --set replicas=${HELMBROKER_REPLICAS} \
-    --set valkeyUrl=redis://:${VALKEY_PASSWORD}@drycc-valkey.drycc.svc.${CLUSTER_DOMAIN}:16379/11 \
+    --set valkeyUrl=redis://:${VALKEY_PASSWORD}@drycc-valkey.drycc.svc:16379/11 \
     --set celeryReplicas=${HELMBROKER_CELERY_REPLICAS} \
     --namespace drycc-helmbroker --create-namespace $options --wait -f - <<EOF
 repositories:
@@ -718,7 +715,7 @@ metadata:
 spec:
   relistBehavior: Duration
   relistRequests: 5
-  url: http://${HELMBROKER_USERNAME}:${HELMBROKER_PASSWORD}@drycc-helmbroker.drycc-helmbroker.svc.${CLUSTER_DOMAIN}
+  url: http://${HELMBROKER_USERNAME}:${HELMBROKER_PASSWORD}@drycc-helmbroker.drycc-helmbroker.svc
 EOF
 
   echo -e "\\033[32m---> Helmbroker username: $HELMBROKER_USERNAME\\033[0m"

From 347f4c40b6331860ad3d729863d093989b33a628 Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@users.noreply.github.com>
Date: Thu, 24 Jul 2025 17:01:45 +0800
Subject: [PATCH 22/37] chore(install): change controller component replicas

---
 install.sh | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/install.sh b/install.sh
index b523dc4e..e5821edc 100755
--- a/install.sh
+++ b/install.sh
@@ -551,8 +551,6 @@ fluentbit:
   imageRegistry: ${DRYCC_REGISTRY}
 
 controller:
-  apiReplicas: ${CONTROLLER_API_REPLICAS:-1}
-  celeryReplicas: ${CONTROLLER_CELERY_REPLICAS:-1}
   webhookReplicas: ${CONTROLLER_WEBHOOK_REPLICAS:-1}
   imageRegistry: ${DRYCC_REGISTRY}
   appRuntimeClass: ${CONTROLLER_APP_RUNTIME_CLASS:-""}
@@ -560,6 +558,14 @@ controller:
   appStorageClass: ${CONTROLLER_APP_STORAGE_CLASS:-"longhorn"}
   filerImage: ${FILER_IMAGE}
   filerImagePullPolicy: ${FILER_IMAGE_PULL_POLICY}
+  api:
+    replicas: ${CONTROLLER_API_REPLICAS:-1}
+  celery:
+    replicas: ${CONTROLLER_CELERY_REPLICAS:-1}
+  metric:
+    replicas: ${CONTROLLER_METRIC_REPLICAS:-1}
+  mutate:
+    replicas: ${CONTROLLER_MUTATE_REPLICAS:-1}
 
 valkey:
   imageRegistry: ${DRYCC_REGISTRY}

From 7b83a07660be2a33e3684cb4316789a0135f1716 Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Fri, 25 Jul 2025 17:22:54 +0800
Subject: [PATCH 23/37] chore(charts): optimize values

---
 charts/workflow/values.yaml | 37 ++++++++-----------------------------
 1 file changed, 8 insertions(+), 29 deletions(-)

diff --git a/charts/workflow/values.yaml b/charts/workflow/values.yaml
index f5628430..3bd11487 100644
--- a/charts/workflow/values.yaml
+++ b/charts/workflow/values.yaml
@@ -70,32 +70,20 @@ valkey:
 
 storage:
   enabled: true
-  # The following parameters are configured only when using an off-cluster Storage instance
-  lookup: path
-  endpoint: ""
   # The following parameters are general parameters
   accesskey: ""
   secretkey: ""
+  persistence:
+    enabled: false
+    size: 5Gi
+    storageClass: ""
 
 grafana:
   enabled: true
-  # Configure the following ONLY if you want persistence for on-cluster grafana
-  # GCP PDs and EBS volumes are supported only
   persistence:
-    enabled: false # Set to true to enable persistence
-    accessMode: ReadWriteOnce
-    size: 5Gi # PVC size
-    ## grafana data Persistent Volume Storage Class
-    ## If defined, storageClassName: <storageClass>
-    ## If set to "-", storageClassName: "", which disables dynamic provisioning
-    ## If undefined (the default) or set to null, no storageClassName spec is
-    ##   set, choosing the default provisioner.  (gp2 on AWS, standard on
-    ##   GKE, AWS & OpenStack)
-    ##
-    ## Storage class of PV to bind. By default it looks for standard storage class.
-    ## If the PV uses a different storage class, specify that here.
+    enabled: false
+    size: 5Gi
     storageClass: ""
-    volumeName: ""
 
 registry:
   enabled: true
@@ -131,17 +119,8 @@ database:
   user: ""
   password: ""
   persistence:
-    enabled: false # Set to true to enable persistence
-    size: 5Gi # PVC size
-    ## database data Persistent Volume Storage Class
-    ## If defined, storageClassName: <storageClass>
-    ## If set to "-", storageClassName: "", which disables dynamic provisioning
-    ## If undefined (the default) or set to null, no storageClassName spec is
-    ##   set, choosing the default provisioner.  (gp2 on AWS, standard on
-    ##   GKE, AWS & OpenStack)
-    ##
-    ## Storage class of PV to bind. By default it looks for standard storage class.
-    ## If the PV uses a different storage class, specify that here.
+    enabled: false
+    size: 5Gi
     storageClass: ""
 
 victoriametrics:

From 742bb2880dad2da7049d347c1a6be53fad9e17d6 Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Wed, 3 Sep 2025 11:35:06 +0800
Subject: [PATCH 24/37] chore(charts): change replicas location

---
 install.sh | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/install.sh b/install.sh
index e5821edc..a28af20d 100755
--- a/install.sh
+++ b/install.sh
@@ -700,7 +700,8 @@ function install_helmbroker {
     --set password=${HELMBROKER_PASSWORD} \
     --set replicas=${HELMBROKER_REPLICAS} \
     --set valkeyUrl=redis://:${VALKEY_PASSWORD}@drycc-valkey.drycc.svc:16379/11 \
-    --set celeryReplicas=${HELMBROKER_CELERY_REPLICAS} \
+    --set api.replicas=${HELMBROKER_API_REPLICAS} \
+    --set celery.replicas=${HELMBROKER_CELERY_REPLICAS} \
     --namespace drycc-helmbroker --create-namespace $options --wait -f - <<EOF
 repositories:
 - name: drycc-helmbroker

From fca1f2c65e721422bff0dff4698ffa2155224b21 Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Tue, 14 Oct 2025 15:14:32 +0800
Subject: [PATCH 25/37] fix(install): install helm error

---
 install.sh | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/install.sh b/install.sh
index a28af20d..e738f26f 100755
--- a/install.sh
+++ b/install.sh
@@ -63,12 +63,23 @@ urlencode() {
 }
 
 function install_helm {
+  echo -e "\\033[32m---> Start install helm\\033[0m"
   if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then
-    version=$(curl -Ls https://github.com/helm/helm/releases|grep /helm/helm/releases/tag/ | sed -E 's/.*\/helm\/helm\/releases\/tag\/(v[0-9\.]{1,}(-rc.[0-9]{1,})?)".*/\1/g' | head -1)
+    version=$(curl -Ls https://github.com/helm/helm/releases \
+      | grep -o 'href="/helm/helm/releases/tag/v[^"]*"' \
+      | sed 's|href="/helm/helm/releases/tag/||; s/"$//' \
+      | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' \
+      | sort -Vr \
+      | head -1)
     tar_name="helm-${version}-linux-${ARCH}.tar.gz"
     helm_download_url="https://github.com/helm/${tar_name}"
   else
-    version=$(curl -Ls https://github.com/helm/helm/releases|grep /helm/helm/releases/tag/ | sed -E 's/.*\/helm\/helm\/releases\/tag\/(v[0-9\.]{1,}(-rc.[0-9]{1,})?)".*/\1/g' | head -1)
+    version=$(curl -Ls https://github.com/helm/helm/releases \
+      | grep -o 'href="/helm/helm/releases/tag/v[^"]*"' \
+      | sed 's|href="/helm/helm/releases/tag/||; s/"$//' \
+      | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' \
+      | sort -Vr \
+      | head -1)
     tar_name="helm-${version}-linux-${ARCH}.tar.gz"
     helm_download_url="https://get.helm.sh/${tar_name}"
   fi
@@ -76,6 +87,7 @@ function install_helm {
   tar -zxvf "${tar_name}"
   mv "linux-${ARCH}/helm" /usr/local/bin/helm
   rm -rf "${tar_name}" "linux-${ARCH}"
+  echo -e "\\033[32m---> crun runtime install completed!\\033[0m"
 }
 
 function configure_os {
@@ -140,11 +152,11 @@ function install_kata_runtime {
   fi
 
   kata_version=$(curl -Ls ${kata_base_url}/kata-containers/releases|grep /kata-containers/kata-containers/releases/tag/ | sed -E 's/.*\/kata-containers\/kata-containers\/releases\/tag\/([0-9\.]{1,}(-rc.[0-9]{1,})?)".*/\1/g' | head -1)
-  kata_package=kata-static-${kata_version}-${ARCH}.tar.xz
+  kata_package=kata-static-${kata_version}-${ARCH}.tar.zst
   kata_download_url=${kata_base_url}/kata-containers/releases/download/${kata_version}/${kata_package}
 
-  curl -sfL "${kata_download_url}" -o ${kata_package}
-  tar xvf ${kata_package} -C /
+  curl -fL "${kata_download_url}" -o ${kata_package}
+  tar -I zstd -xf ${kata_package} -C /
   ln -s /opt/kata/bin/containerd-shim-kata-v2 /usr/local/bin/containerd-shim-kata-v2
   ln -s /opt/kata/bin/kata-collect-data.sh /usr/local/bin/kata-collect-data.sh
   ln -s /opt/kata/bin/kata-runtime /usr/local/bin/kata-runtime
@@ -234,18 +246,10 @@ function configure_k3s_mirrors {
   if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then
     INSTALL_K3S_MIRROR="${INSTALL_DRYCC_MIRROR}"
     k3s_install_url="https://github.com/get-k3s/"
-    K3S_RELEASE_URL=https://github.com/k3s-io/k3s/releases
     export INSTALL_K3S_MIRROR
   else
     k3s_install_url="https://get.k3s.io"
-    K3S_RELEASE_URL=github.com/k3s-io/k3s/releases
-  fi
-  if [ -z "${INSTALL_K3S_VERSION}" ]; then
-    INSTALL_K3S_VERSION=$(curl -Ls "$K3S_RELEASE_URL" | grep /k3s-io/k3s/releases/tag/ | sed -E 's/.*\/k3s-io\/k3s\/releases\/tag\/(v[0-9\.]{1,}[rc0-9\-]{0,}%2Bk3s[0-9])".*/\1/g' | head -1)
-  else
-    INSTALL_K3S_VERSION=$(urlencode "$INSTALL_K3S_VERSION")
   fi
-  export INSTALL_K3S_VERSION
   echo -e "\\033[32m---> Configuring k3s mirrors finish\\033[0m"
 }
 

From 44837f67317e8b0543a55bcb653b76c643165458 Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Tue, 14 Oct 2025 15:37:30 +0800
Subject: [PATCH 26/37] fix(install): gateway crds metadata.annotations too
 long

---
 install.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/install.sh b/install.sh
index e738f26f..c06c8218 100755
--- a/install.sh
+++ b/install.sh
@@ -435,7 +435,7 @@ function install_gateway() {
 
   helm repo add istio https://github.com/istio-charts
   helm repo update
-  kubectl apply -f $gateway_api_url/releases/download/${version}/experimental-install.yaml
+  kubectl apply --server-side -f $gateway_api_url/releases/download/${version}/experimental-install.yaml
   helm upgrade --install istio-base istio/base -n istio-system --set defaultRevision=default --create-namespace --wait $options
   helm upgrade --install istio-istiod istio/istiod -n istio-system \
     --set pilot.env.PILOT_ENABLE_ALPHA_GATEWAY_API=true \

From e98e566898ddb569b1762bc51b1ce4873af9f535 Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Thu, 16 Oct 2025 08:36:14 +0800
Subject: [PATCH 27/37] chore(install): change aws-mountpoint-s3-csi-driver
 image

---
 install.sh | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/install.sh b/install.sh
index c06c8218..493f2a2c 100755
--- a/install.sh
+++ b/install.sh
@@ -319,18 +319,22 @@ function install_mountpoint {
   helm repo update
 
   if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then
-    mountpoint_api_url=https://github.com/drycc-addons/mountpoint-s3-csi-driver
+    mountpoint_api_url=https://github.com/drycc/mountpoint-s3-csi-driver
   else
-    mountpoint_api_url=https://github.com/drycc-addons/mountpoint-s3-csi-driver
+    mountpoint_api_url=https://github.com/drycc/mountpoint-s3-csi-driver
   fi
-  version=$(curl -Ls $mountpoint_api_url/releases|grep /drycc-addons/mountpoint-s3-csi-driver/releases/tag/ | sed -E 's/.*\/drycc-addons\/mountpoint-s3-csi-driver\/releases\/tag\/v([0-9\.]{1,}(-rc.[0-9]{1,})?)".*/\1/g' | head -1)
-
+  version=$(curl -Ls $mountpoint_api_url/releases|grep /drycc/mountpoint-s3-csi-driver/releases/tag/\
+    | grep -o 'href="/drycc/mountpoint-s3-csi-driver/releases/tag/[^"]*"' \
+    | sed 's|href="/drycc/mountpoint-s3-csi-driver/releases/tag/||; s/"$//' \
+    | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' \
+    | sort -Vr \
+    | head -1)
   helm upgrade --install aws-mountpoint-s3-csi-driver aws-mountpoint-s3-csi-driver/aws-mountpoint-s3-csi-driver \
-    --set experimental.podMounter=true \
-    --set image.repository=registry.drycc.cc/drycc-addons/mountpoint-s3-csi-driver \
-    --set image.tag=${version} \
+    --set supportLegacySystemDMounts=false \
+    --set image.repository=registry.drycc.cc/drycc/mountpoint-s3-csi-driver \
+    --set image.tag=${version#v} \
     --namespace kube-system $options --wait
-  echo -e "\\033[32m---> Longhorn install completed!\\033[0m"
+  echo -e "\\033[32m---> Mountpoint install completed!\\033[0m"
 }
 
 function check_metallb {

From 05eab6f3b22e24d8f8be4e55b918f81d8ab14e78 Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Fri, 7 Nov 2025 11:57:58 +0800
Subject: [PATCH 28/37] fix(mountpoint-s3-csi-driver): version error

---
 install.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/install.sh b/install.sh
index 493f2a2c..3f419e8f 100755
--- a/install.sh
+++ b/install.sh
@@ -326,7 +326,7 @@ function install_mountpoint {
   version=$(curl -Ls $mountpoint_api_url/releases|grep /drycc/mountpoint-s3-csi-driver/releases/tag/\
     | grep -o 'href="/drycc/mountpoint-s3-csi-driver/releases/tag/[^"]*"' \
     | sed 's|href="/drycc/mountpoint-s3-csi-driver/releases/tag/||; s/"$//' \
-    | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' \
+    | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' \
     | sort -Vr \
     | head -1)
   helm upgrade --install aws-mountpoint-s3-csi-driver aws-mountpoint-s3-csi-driver/aws-mountpoint-s3-csi-driver \

From 5ce51881886ab052d7de64fc612f45ff7ca695b1 Mon Sep 17 00:00:00 2001
From: lijianguo <lijianguo1991@outlook.com>
Date: Tue, 17 Mar 2026 13:33:55 +0800
Subject: [PATCH 29/37] chore(install): cilium add ipam clusterPoolIPv4MaskSize
 config (#65)

---
 install.sh | 1 +
 1 file changed, 1 insertion(+)

diff --git a/install.sh b/install.sh
index 3f419e8f..0a6824bd 100755
--- a/install.sh
+++ b/install.sh
@@ -373,6 +373,7 @@ function install_network() {
     --set prometheus.enabled=true \
     --set operator.prometheus.enabled=true \
     --set envoy.enabled=false \
+    --set ipam.operator.clusterPoolIPv4MaskSize=${CLUSTER_POOL_IPV4_MASK_SIZE:-24} \
     --namespace kube-system $options --wait
   echo -e "\\033[32m---> Network install completed!\\033[0m"
 }

From 6eb779869bd617a61d71546289d7681717b9a781 Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Sun, 29 Mar 2026 01:07:05 +0800
Subject: [PATCH 30/37] fix(install): incus error

---
 install.sh | 30 ++++++++++++++----------------
 1 file changed, 14 insertions(+), 16 deletions(-)

diff --git a/install.sh b/install.sh
index 0a6824bd..dbf81824 100755
--- a/install.sh
+++ b/install.sh
@@ -93,37 +93,35 @@ function install_helm {
 function configure_os {
   echo -e "\\033[32m---> Start configuring kernel parameters\\033[0m"
   if [[ "$(command -v iptables)" != "" ]] ; then
-    iptables -F
-    iptables -X
-    iptables -F -t nat
-    iptables -X -t nat
-    iptables -P FORWARD ACCEPT
+    iptables -F || echo -e "\\033[33m---> Warning: iptables -F failed, skipping (container environment?)\\033[0m"
+    iptables -X || echo -e "\\033[33m---> Warning: iptables -X failed, skipping\\033[0m"
+    iptables -F -t nat || echo -e "\\033[33m---> Warning: iptables -F -t nat failed, skipping\\033[0m"
+    iptables -X -t nat || echo -e "\\033[33m---> Warning: iptables -X -t nat failed, skipping\\033[0m"
+    iptables -P FORWARD ACCEPT || echo -e "\\033[33m---> Warning: iptables -P FORWARD ACCEPT failed, skipping\\033[0m"
   else
-    # Kube hostport depends on iptables
-    echo -e "\\033[33m---> The iptables does not exist...\\033[0m"
-    exit 1
+    echo -e "\\033[33m---> Warning: iptables does not exist, skipping iptables configuration...\\033[0m"
   fi
-  swapoff -a
-  sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
-  mount bpffs -t bpf /sys/fs/bpf
+  swapoff -a 2>/dev/null || true
+  sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab 2>/dev/null || true
+  mount bpffs -t bpf /sys/fs/bpf 2>/dev/null || echo -e "\\033[33m---> Warning: mount bpffs failed, skipping (container environment?)\\033[0m"
   rmem_max=$(sysctl -ne net.core.rmem_max)
   if [ ! -n "$rmem_max" ] || [ 2500000 -gt $rmem_max ] ;then
-    echo 'net.core.rmem_max = 2500000' >> /etc/sysctl.conf
+    echo 'net.core.rmem_max = 2500000' >> /etc/sysctl.conf 2>/dev/null || true
   fi
   nr_hugepages=$(sysctl -ne vm.nr_hugepages)
   if [ ! -n "$nr_hugepages" ] || [ 1024 -gt $nr_hugepages ] ;then
-    echo 'vm.nr_hugepages = 1024' >> /etc/sysctl.conf
+    echo 'vm.nr_hugepages = 1024' >> /etc/sysctl.conf 2>/dev/null || true
   fi
   max_user_instances=$(sysctl -ne fs.inotify.max_user_instances)
   if [ ! -n "$max_user_instances" ] || [ 65535 -gt $max_user_instances ] ;then
-    echo 'fs.inotify.max_user_instances = 65535' >> /etc/sysctl.conf
+    echo 'fs.inotify.max_user_instances = 65535' >> /etc/sysctl.conf 2>/dev/null || true
   fi
-  sysctl -p
+  sysctl -p 2>/dev/null || echo -e "\\033[33m---> Warning: sysctl -p failed, skipping (container environment?)\\033[0m"
 
   cpufreq=$(ls /sys/devices/system/cpu/cpu*/cpufreq >/dev/null 2>&1 || echo "false")
   if [[ $cpufreq != "false" ]]; then
     for cpu in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do
-      echo performance > $cpu
+      echo performance > $cpu 2>/dev/null || true
     done
   fi
   echo -e "\\033[32m---> Configuring kernel parameters finish\\033[0m"

From 76e07e116e80e487be080b0ef4999966cc64c83d Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Sun, 5 Apr 2026 22:42:56 +0800
Subject: [PATCH 31/37] chore(kubectl): add server-side apply

---
 install.sh | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/install.sh b/install.sh
index dbf81824..04bfae4f 100755
--- a/install.sh
+++ b/install.sh
@@ -239,6 +239,23 @@ EOF
   fi
 }
 
+function configure_kubectl {
+  echo -e "\\033[32m---> Start configuring kubectl defaults\\033[0m"
+  mkdir -p "$HOME/.kube"
+  cat << EOF > "$HOME/.kube/kuberc"
+apiVersion: kubectl.config.k8s.io/v1beta1
+kind: Preference
+defaults:
+  # Default to server-side apply
+  - command: apply
+    options:
+      - name: server-side
+        default: "true"
+EOF
+  chmod 600 "$HOME/.kube/kuberc"
+  echo -e "\\033[32m---> Kubectl defaults configured (server-side apply enabled)\\033[0m"
+}
+
 function configure_k3s_mirrors {
   echo -e "\\033[32m---> Start configuring k3s mirrors\\033[0m"
   if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then
@@ -254,6 +271,7 @@ function configure_k3s_mirrors {
 function install_k3s_server {
   configure_os
   install_runtime
+  configure_kubectl
   configure_registry
   configure_k3s_mirrors
   INSTALL_K3S_EXEC="server ${INSTALL_K3S_EXEC} --embedded-registry --flannel-backend=none  --disable-network-policy --disable=traefik --disable=servicelb --disable-kube-proxy --cluster-cidr=${CLUSTER_CIDR} --service-cidr=${SERVICE_CIDR}"
@@ -281,6 +299,7 @@ EOF
 function install_k3s_agent {
   configure_os
   install_runtime
+  configure_kubectl
   configure_registry
   configure_k3s_mirrors
   if [[ -n "${K3S_DATA_DIR}" ]] ; then
@@ -438,7 +457,7 @@ function install_gateway() {
 
   helm repo add istio https://github.com/istio-charts
   helm repo update
-  kubectl apply --server-side -f $gateway_api_url/releases/download/${version}/experimental-install.yaml
+  kubectl apply -f $gateway_api_url/releases/download/${version}/experimental-install.yaml
   helm upgrade --install istio-base istio/base -n istio-system --set defaultRevision=default --create-namespace --wait $options
   helm upgrade --install istio-istiod istio/istiod -n istio-system \
     --set pilot.env.PILOT_ENABLE_ALPHA_GATEWAY_API=true \

From 30778bb3a8919512e2e354758614fe7bff6956ec Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Wed, 8 Apr 2026 09:06:48 +0800
Subject: [PATCH 32/37] chore(sysctl): add fs.inotify.max_user_watches

---
 install.sh | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/install.sh b/install.sh
index 04bfae4f..2af43fee 100755
--- a/install.sh
+++ b/install.sh
@@ -116,6 +116,10 @@ function configure_os {
   if [ ! -n "$max_user_instances" ] || [ 65535 -gt $max_user_instances ] ;then
     echo 'fs.inotify.max_user_instances = 65535' >> /etc/sysctl.conf 2>/dev/null || true
   fi
+  max_user_watches=$(sysctl -ne fs.inotify.max_user_watches)
+  if [ ! -n "$max_user_watches" ] || [ 65535 -gt $max_user_watches ] ;then
+    echo 'fs.inotify.max_user_watches = 65535' >> /etc/sysctl.conf 2>/dev/null || true
+  fi
   sysctl -p 2>/dev/null || echo -e "\\033[33m---> Warning: sysctl -p failed, skipping (container environment?)\\033[0m"
 
   cpufreq=$(ls /sys/devices/system/cpu/cpu*/cpufreq >/dev/null 2>&1 || echo "false")

From 3e84f1e7c80107ad0aef3b11f6e5668e48021ca1 Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Wed, 8 Apr 2026 09:29:37 +0800
Subject: [PATCH 33/37] chore(sysctl): add 99-zzz-override-drycc.conf

---
 install.sh | 26 +++++++++-----------------
 1 file changed, 9 insertions(+), 17 deletions(-)

diff --git a/install.sh b/install.sh
index 2af43fee..36dc2364 100755
--- a/install.sh
+++ b/install.sh
@@ -104,23 +104,15 @@ function configure_os {
   swapoff -a 2>/dev/null || true
   sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab 2>/dev/null || true
   mount bpffs -t bpf /sys/fs/bpf 2>/dev/null || echo -e "\\033[33m---> Warning: mount bpffs failed, skipping (container environment?)\\033[0m"
-  rmem_max=$(sysctl -ne net.core.rmem_max)
-  if [ ! -n "$rmem_max" ] || [ 2500000 -gt $rmem_max ] ;then
-    echo 'net.core.rmem_max = 2500000' >> /etc/sysctl.conf 2>/dev/null || true
-  fi
-  nr_hugepages=$(sysctl -ne vm.nr_hugepages)
-  if [ ! -n "$nr_hugepages" ] || [ 1024 -gt $nr_hugepages ] ;then
-    echo 'vm.nr_hugepages = 1024' >> /etc/sysctl.conf 2>/dev/null || true
-  fi
-  max_user_instances=$(sysctl -ne fs.inotify.max_user_instances)
-  if [ ! -n "$max_user_instances" ] || [ 65535 -gt $max_user_instances ] ;then
-    echo 'fs.inotify.max_user_instances = 65535' >> /etc/sysctl.conf 2>/dev/null || true
-  fi
-  max_user_watches=$(sysctl -ne fs.inotify.max_user_watches)
-  if [ ! -n "$max_user_watches" ] || [ 65535 -gt $max_user_watches ] ;then
-    echo 'fs.inotify.max_user_watches = 65535' >> /etc/sysctl.conf 2>/dev/null || true
-  fi
-  sysctl -p 2>/dev/null || echo -e "\\033[33m---> Warning: sysctl -p failed, skipping (container environment?)\\033[0m"
+  mkdir -p /etc/sysctl.d
+  cat << EOF > /etc/sysctl.d/99-zzz-override-drycc.conf
+fs.file-max = 2097152
+fs.inotify.max_user_instances = 65535
+fs.inotify.max_user_watches = 1048576
+net.core.rmem_max = 2500000
+vm.nr_hugepages = 1024
+EOF
+  sysctl --system 2>/dev/null || echo -e "\\033[33m---> Warning: sysctl --system failed, skipping (container environment?)\\033[0m"
 
   cpufreq=$(ls /sys/devices/system/cpu/cpu*/cpufreq >/dev/null 2>&1 || echo "false")
   if [[ $cpufreq != "false" ]]; then

From 4fbc47a16c3bc12c43ee08047adac99723fddf35 Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Wed, 8 Apr 2026 12:55:56 +0800
Subject: [PATCH 34/37] fix(metallb): IP conflict

---
 install.sh | 14 --------------
 1 file changed, 14 deletions(-)

diff --git a/install.sh b/install.sh
index 36dc2364..7becaaee 100755
--- a/install.sh
+++ b/install.sh
@@ -405,19 +405,6 @@ function install_metallb() {
     kubectl apply -n metallb -f - <<EOF
 apiVersion: metallb.io/v1beta1
 kind: IPAddressPool
-metadata:
-  name: public
-spec:
-  addresses:
-  - $(ip -o route get to 8.8.8.8 | sed -n 's/.*src \([0-9.]\+\).*/\1/p')/32
-  serviceAllocation:
-    priority: 50
-    namespaces:
-    - drycc
-
----
-apiVersion: metallb.io/v1beta1
-kind: IPAddressPool
 metadata:
   name: default
 spec:
@@ -432,7 +419,6 @@ metadata:
   namespace: metallb
 spec:
   ipAddressPools:
-  - public
   - default
 EOF
   else

From 22f733946e6dd42bf03d5e72c10cac24d9670a91 Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Wed, 8 Apr 2026 13:11:11 +0800
Subject: [PATCH 35/37] chore(istio): change gateway service type

---
 install.sh | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/install.sh b/install.sh
index 7becaaee..8c370061 100755
--- a/install.sh
+++ b/install.sh
@@ -445,7 +445,9 @@ function install_gateway() {
     --set pilot.env.PILOT_ENABLE_ALPHA_GATEWAY_API=true \
     --set pilot.env.PILOT_ENABLE_QUIC_LISTENERS=true \
     --wait $options
-  helm upgrade --install istio-gateway istio/gateway -n istio-gateway --create-namespace --wait $options
+  helm upgrade --install istio-gateway istio/gateway -n istio-gateway \
+    --set service.type=ClusterIP \
+    --create-namespace --wait $options
   echo -e "\\033[32m---> Gateway install completed!\\033[0m"
 }
 

From cc7fd11a5a1104b427da4af33839e0315cdc8ac0 Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Wed, 8 Apr 2026 16:11:27 +0800
Subject: [PATCH 36/37] fix(installer): make helm installs resilient and
 helmbroker idempotent

---
 install.sh | 63 ++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 45 insertions(+), 18 deletions(-)

diff --git a/install.sh b/install.sh
index 8c370061..c73c12f6 100755
--- a/install.sh
+++ b/install.sh
@@ -90,6 +90,33 @@ function install_helm {
   echo -e "\\033[32m---> crun runtime install completed!\\033[0m"
 }
 
+function helm_upgrade {
+  local max_retries=${HELM_MAX_RETRIES:-3}
+  local retry_interval=${HELM_RETRY_INTERVAL:-10}
+  local has_timeout=false
+  for arg in "$@"; do
+    if [[ "$arg" == "--timeout" ]]; then
+      has_timeout=true
+      break
+    fi
+  done
+  local timeout_args=()
+  if [[ "$has_timeout" == "false" ]]; then
+    timeout_args=(--timeout 10m0s)
+  fi
+  for (( attempt=1; attempt<=max_retries; attempt++ )); do
+    if helm upgrade --install "$@" "${timeout_args[@]}"; then
+      return 0
+    fi
+    if [[ $attempt -lt $max_retries ]]; then
+      echo -e "\\033[33m---> Warning: helm upgrade --install failed (attempt $attempt/$max_retries), retrying in ${retry_interval}s...\\033[0m"
+      sleep "$retry_interval"
+    fi
+  done
+  echo -e "\\033[31m---> Error: helm upgrade --install failed after $max_retries attempts\\033[0m"
+  return 1
+}
+
 function configure_os {
   echo -e "\\033[32m---> Start configuring kernel parameters\\033[0m"
   if [[ "$(command -v iptables)" != "" ]] ; then
@@ -151,9 +178,9 @@ function install_kata_runtime {
 
   curl -fL "${kata_download_url}" -o ${kata_package}
   tar -I zstd -xf ${kata_package} -C /
-  ln -s /opt/kata/bin/containerd-shim-kata-v2 /usr/local/bin/containerd-shim-kata-v2
-  ln -s /opt/kata/bin/kata-collect-data.sh /usr/local/bin/kata-collect-data.sh
-  ln -s /opt/kata/bin/kata-runtime /usr/local/bin/kata-runtime
+  ln -sf /opt/kata/bin/containerd-shim-kata-v2 /usr/local/bin/containerd-shim-kata-v2
+  ln -sf /opt/kata/bin/kata-collect-data.sh /usr/local/bin/kata-collect-data.sh
+  ln -sf /opt/kata/bin/kata-runtime /usr/local/bin/kata-runtime
   rm -rf ${kata_package}
   echo -e "\\033[32m---> Kata runtime install completed!\\033[0m"
 }
@@ -209,7 +236,7 @@ EOF
 
 function configure_registry {
   if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]]; then
-    cat << EOF >> "${REGISTRY_CONFIG_FILE}"
+    cat << EOF > "${REGISTRY_CONFIG_FILE}"
 mirrors:
   docker.io:
     endpoint:
@@ -310,7 +337,7 @@ function install_longhorn {
   helm repo update
   if [[ -z "${LONGHORN_CONFIG_FILE}" ]] ; then
     echo -e "\\033[32m---> Longhorn using the default configuration.\\033[0m"
-    helm upgrade --install longhorn longhorn/longhorn \
+    helm_upgrade longhorn longhorn/longhorn \
       --set csi.attacherReplicaCount=1 \
       --set csi.provisionerReplicaCount=1 \
       --set csi.resizerReplicaCount=1 \
@@ -321,7 +348,7 @@ function install_longhorn {
       --namespace longhorn-system \
       --create-namespace $options --wait
   else
-    helm upgrade --install longhorn longhorn/longhorn -f "${LONGHORN_CONFIG_FILE}" --wait
+    helm_upgrade longhorn longhorn/longhorn -f "${LONGHORN_CONFIG_FILE}" --wait
   fi
   echo -e "\\033[32m---> Longhorn install completed!\\033[0m"
 }
@@ -342,7 +369,7 @@ function install_mountpoint {
     | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' \
     | sort -Vr \
     | head -1)
-  helm upgrade --install aws-mountpoint-s3-csi-driver aws-mountpoint-s3-csi-driver/aws-mountpoint-s3-csi-driver \
+  helm_upgrade aws-mountpoint-s3-csi-driver aws-mountpoint-s3-csi-driver/aws-mountpoint-s3-csi-driver \
     --set supportLegacySystemDMounts=false \
     --set image.repository=registry.drycc.cc/drycc/mountpoint-s3-csi-driver \
     --set image.tag=${version#v} \
@@ -370,7 +397,7 @@ function install_network() {
   options=${1:-""}
   echo -e "\\033[32m---> Start install network...\\033[0m"
   kubernetes_service_host=(`ip -o route get to 8.8.8.8 | sed -n 's/.*src \([0-9.]\+\).*/\1/p'`)
-  helm upgrade --install cilium $CHARTS_URL/cilium \
+  helm_upgrade cilium $CHARTS_URL/cilium \
     --set endpointHealthChecking.enabled=false \
     --set healthChecking=false \
     --set operator.replicas=1 \
@@ -395,7 +422,7 @@ function install_metallb() {
   check_metallb
   options=${1:-""}
   echo -e "\\033[32m---> Start install metallb...\\033[0m"
-  helm upgrade --install metallb $CHARTS_URL/metallb \
+  helm_upgrade metallb $CHARTS_URL/metallb \
     --set speaker.frr.enabled=true \
     --namespace metallb \
     --create-namespace $options --wait
@@ -440,12 +467,12 @@ function install_gateway() {
   helm repo add istio https://github.com/istio-charts
   helm repo update
   kubectl apply -f $gateway_api_url/releases/download/${version}/experimental-install.yaml
-  helm upgrade --install istio-base istio/base -n istio-system --set defaultRevision=default --create-namespace --wait $options
-  helm upgrade --install istio-istiod istio/istiod -n istio-system \
+  helm_upgrade istio-base istio/base -n istio-system --set defaultRevision=default --create-namespace --wait $options
+  helm_upgrade istio-istiod istio/istiod -n istio-system \
     --set pilot.env.PILOT_ENABLE_ALPHA_GATEWAY_API=true \
     --set pilot.env.PILOT_ENABLE_QUIC_LISTENERS=true \
     --wait $options
-  helm upgrade --install istio-gateway istio/gateway -n istio-gateway \
+  helm_upgrade istio-gateway istio/gateway -n istio-gateway \
     --set service.type=ClusterIP \
     --create-namespace --wait $options
   echo -e "\\033[32m---> Gateway install completed!\\033[0m"
@@ -454,7 +481,7 @@ function install_gateway() {
 function install_cert_manager() {
   options=${1:-""}
   echo -e "\\033[32m---> Start install cert-manager...\\033[0m"
-  helm upgrade --install cert-manager $CHARTS_URL/cert-manager \
+  helm_upgrade cert-manager $CHARTS_URL/cert-manager \
     --namespace cert-manager \
     --create-namespace \
     --set clusterResourceNamespace=drycc \
@@ -476,7 +503,7 @@ function install_catalog() {
 
   options=${1:-""}
   echo -e "\\033[32m---> Start install catalog...\\033[0m"
-  helm upgrade --install catalog $CHARTS_URL/catalog \
+  helm_upgrade catalog $CHARTS_URL/catalog \
     --set asyncBindingOperationsEnabled=true \
     --set image=registry.drycc.cc/drycc-addons/service-catalog:${service_catalog_version#v} \
     --namespace catalog \
@@ -667,7 +694,7 @@ EOF
     export VICTORIAMETRICS_CONFIG_FILE
   fi
 
-  helm upgrade --install drycc $CHARTS_URL/workflow \
+  helm_upgrade drycc $CHARTS_URL/workflow \
     --namespace drycc \
     --values /tmp/drycc-values.yaml \
     --values /tmp/drycc-mirror-values.yaml \
@@ -694,12 +721,12 @@ function install_helmbroker {
 
   options=${1:-""}
   local VALKEY_PASSWORD=$(kubectl get secrets -n drycc valkey-creds -o jsonpath="{.data.password}"| base64 -d)
-  local HELMBROKER_USERNAME=${HELMBROKER_USERNAME:-$(cat /proc/sys/kernel/random/uuid)}
-  local HELMBROKER_PASSWORD=${HELMBROKER_PASSWORD:-$(cat /proc/sys/kernel/random/uuid)}
+  local HELMBROKER_USERNAME=${HELMBROKER_USERNAME:-$(kubectl get secrets -n drycc-helmbroker helmbroker-creds -o jsonpath="{.data.username}" 2>/dev/null | base64 -d || cat /proc/sys/kernel/random/uuid)}
+  local HELMBROKER_PASSWORD=${HELMBROKER_PASSWORD:-$(kubectl get secrets -n drycc-helmbroker helmbroker-creds -o jsonpath="{.data.password}" 2>/dev/null | base64 -d || cat /proc/sys/kernel/random/uuid)}
 
   echo -e "\\033[32m---> Start install helmbroker...\\033[0m"
 
-  helm upgrade --install helmbroker $CHARTS_URL/helmbroker \
+  helm_upgrade helmbroker $CHARTS_URL/helmbroker \
     --set valkey.enabled=false \
     --set gateway.gatewayClass=${GATEWAY_CLASS} \
     --set global.platformDomain=${PLATFORM_DOMAIN} \

From 444e1f99421d31d890af02b85905764b9ad5fbdf Mon Sep 17 00:00:00 2001
From: duanhongyi <duanhongyi@doopai.com>
Date: Thu, 9 Apr 2026 18:09:20 +0800
Subject: [PATCH 37/37] fix(github): get latest github release error

---
 install.sh | 134 +++++++++++++++++++++++++++++++++++------------------
 1 file changed, 89 insertions(+), 45 deletions(-)

diff --git a/install.sh b/install.sh
index c73c12f6..6c5ab750 100755
--- a/install.sh
+++ b/install.sh
@@ -62,25 +62,38 @@ urlencode() {
   LC_COLLATE=$old_lc_collate
 }
 
+# get_latest_github_release fetches the latest GitHub release tag matching a regex pattern.
+# Usage: get_latest_github_release <org/repo> <pattern>
+#   org/repo  - GitHub organization and repository (e.g. "helm/helm")
+#   pattern   - extended regex that the tag must match (e.g. "^v[0-9]+\.[0-9]+\.[0-9]+$")
+# The function automatically selects the mirror URL based on INSTALL_DRYCC_MIRROR.
+function get_latest_github_release {
+  local repo="$1"
+  local pattern="$2"
+  local base_url
+
+  if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]]; then
+    base_url="https://github.com/${repo}"
+  else
+    base_url="https://github.com/${repo}"
+  fi
+
+  curl -Ls "${base_url}/releases" \
+    | grep -o "href=\"/${repo}/releases/tag/[^\"]*\"" \
+    | sed "s|href=\"/${repo}/releases/tag/||; s|\"$||" \
+    | grep -E "${pattern}" \
+    | sort -Vr \
+    | head -1
+}
+
+# install_helm downloads and installs the Helm CLI tool from the latest GitHub release.
 function install_helm {
   echo -e "\\033[32m---> Start install helm\\033[0m"
+  version=$(get_latest_github_release "helm/helm" "^v[0-9]+\.[0-9]+\.[0-9]+$")
+  tar_name="helm-${version}-linux-${ARCH}.tar.gz"
   if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then
-    version=$(curl -Ls https://github.com/helm/helm/releases \
-      | grep -o 'href="/helm/helm/releases/tag/v[^"]*"' \
-      | sed 's|href="/helm/helm/releases/tag/||; s/"$//' \
-      | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' \
-      | sort -Vr \
-      | head -1)
-    tar_name="helm-${version}-linux-${ARCH}.tar.gz"
     helm_download_url="https://github.com/helm/${tar_name}"
   else
-    version=$(curl -Ls https://github.com/helm/helm/releases \
-      | grep -o 'href="/helm/helm/releases/tag/v[^"]*"' \
-      | sed 's|href="/helm/helm/releases/tag/||; s/"$//' \
-      | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' \
-      | sort -Vr \
-      | head -1)
-    tar_name="helm-${version}-linux-${ARCH}.tar.gz"
     helm_download_url="https://get.helm.sh/${tar_name}"
   fi
   curl -fsSL -o "${tar_name}" "${helm_download_url}"
@@ -90,6 +103,11 @@ function install_helm {
   echo -e "\\033[32m---> crun runtime install completed!\\033[0m"
 }
 
+# helm_upgrade wraps "helm upgrade --install" with retry logic and a default timeout.
+# Usage: helm_upgrade <release> <chart> [helm-options...]
+#   HELM_MAX_RETRIES    - max number of retry attempts (default: 3)
+#   HELM_RETRY_INTERVAL - seconds between retries (default: 10)
+# A default timeout of 10m0s is applied unless --timeout is explicitly passed.
 function helm_upgrade {
   local max_retries=${HELM_MAX_RETRIES:-3}
   local retry_interval=${HELM_RETRY_INTERVAL:-10}
@@ -117,6 +135,8 @@ function helm_upgrade {
   return 1
 }
 
+# configure_os tunes kernel parameters and OS settings for Kubernetes workloads.
+# Includes: iptables cleanup, swap disable, BPF mount, sysctl overrides, CPU governor.
 function configure_os {
   echo -e "\\033[32m---> Start configuring kernel parameters\\033[0m"
   if [[ "$(command -v iptables)" != "" ]] ; then
@@ -150,6 +170,7 @@ EOF
   echo -e "\\033[32m---> Configuring kernel parameters finish\\033[0m"
 }
 
+# install_crun_runtime downloads and installs the crun OCI runtime binary.
 function install_crun_runtime {
   echo -e "\\033[32m---> Start install crun runtime\\033[0m"
   if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then
@@ -157,13 +178,14 @@ function install_crun_runtime {
   else
     crun_base_url="https://github.com/containers"
   fi
-  crun_version=$(curl -Ls ${crun_base_url}/crun/releases|grep /containers/crun/releases/tag/ | sed -E 's/.*\/containers\/crun\/releases\/tag\/([0-9\.]{1,}(-rc.[0-9]{1,})?)".*/\1/g' | head -1)
+  crun_version=$(get_latest_github_release "containers/crun" "^[0-9]+\.[0-9]+(\.[0-9]+)?(-rc[0-9]+)?$")
   crun_download_url=${crun_base_url}/crun/releases/download/${crun_version}/crun-${crun_version}-linux-${ARCH}
   curl -sfL "${crun_download_url}" -o /usr/local/bin/crun
   chmod a+rx /usr/local/bin/crun
   echo -e "\\033[32m---> crun runtime install completed!\\033[0m"
 }
 
+# install_kata_runtime downloads and installs the Kata Containers runtime for VM-based isolation.
 function install_kata_runtime {
   echo -e "\\033[32m---> Start install kata runtime\\033[0m"
   if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then
@@ -172,7 +194,7 @@ function install_kata_runtime {
     kata_base_url="https://github.com/kata-containers"
   fi
 
-  kata_version=$(curl -Ls ${kata_base_url}/kata-containers/releases|grep /kata-containers/kata-containers/releases/tag/ | sed -E 's/.*\/kata-containers\/kata-containers\/releases\/tag\/([0-9\.]{1,}(-rc.[0-9]{1,})?)".*/\1/g' | head -1)
+  kata_version=$(get_latest_github_release "kata-containers/kata-containers" "^[0-9]+\.[0-9]+\.[0-9]+(-rc[0-9]+)?$")
   kata_package=kata-static-${kata_version}-${ARCH}.tar.zst
   kata_download_url=${kata_base_url}/kata-containers/releases/download/${kata_version}/${kata_package}
 
@@ -185,6 +207,9 @@ function install_kata_runtime {
   echo -e "\\033[32m---> Kata runtime install completed!\\033[0m"
 }
 
+# install_runtime configures containerd runtimes based on CONTAINERD_RUNTIMES.
+# Supported values: "runc" (default), "crun", "kata". Multiple values can be comma-separated.
+# Generates the containerd config template and installs the selected runtimes.
 function install_runtime {
   readarray -d , -t containerd_runtimes <<<"$CONTAINERD_RUNTIMES"
   if [[ "$CONTAINERD_RUNTIMES" =~ "crun" ]]; then
@@ -234,6 +259,8 @@ EOF
   done
 }
 
+# configure_registry writes container registry mirror configuration for k3s/containerd.
+# Only applies when INSTALL_DRYCC_MIRROR is set to "cn".
 function configure_registry {
   if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]]; then
     cat << EOF > "${REGISTRY_CONFIG_FILE}"
@@ -262,6 +289,7 @@ EOF
   fi
 }
 
+# configure_kubectl sets up kubectl defaults, enabling server-side apply by default.
 function configure_kubectl {
   echo -e "\\033[32m---> Start configuring kubectl defaults\\033[0m"
   mkdir -p "$HOME/.kube"
@@ -279,6 +307,7 @@ EOF
   echo -e "\\033[32m---> Kubectl defaults configured (server-side apply enabled)\\033[0m"
 }
 
+# configure_k3s_mirrors selects the k3s install URL based on INSTALL_DRYCC_MIRROR.
 function configure_k3s_mirrors {
   echo -e "\\033[32m---> Start configuring k3s mirrors\\033[0m"
   if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then
@@ -291,6 +320,9 @@ function configure_k3s_mirrors {
   echo -e "\\033[32m---> Configuring k3s mirrors finish\\033[0m"
 }
 
+# install_k3s_server installs and bootstraps a k3s server (control plane) node.
+# Configures OS, runtimes, kubectl, registry mirrors, then installs k3s with
+# embedded registry, Cilium CNI, and registers RuntimeClass resources.
 function install_k3s_server {
   configure_os
   install_runtime
@@ -319,6 +351,7 @@ EOF
   done
 }
 
+# install_k3s_agent installs and joins a k3s agent (worker) node to an existing cluster.
 function install_k3s_agent {
   configure_os
   install_runtime
@@ -331,6 +364,9 @@ function install_k3s_agent {
   curl -sfL "${k3s_install_url}" |INSTALL_K3S_EXEC="$INSTALL_K3S_EXEC" sh -s -
 }
 
+# install_longhorn deploys Longhorn distributed block storage via Helm.
+# Usage: install_longhorn [helm-options...]
+#   LONGHORN_CONFIG_FILE - path to a custom Helm values file; uses defaults if unset.
 function install_longhorn {
   options=${1:-""}
   helm repo add longhorn https://github.com/longhorn-charts
@@ -353,22 +389,13 @@ function install_longhorn {
   echo -e "\\033[32m---> Longhorn install completed!\\033[0m"
 }
 
+# install_mountpoint deploys the AWS Mountpoint S3 CSI driver via Helm.
 function install_mountpoint {
   options=${1:-""}
   helm repo add aws-mountpoint-s3-csi-driver https://github.com/mountpoint-charts
   helm repo update
 
-  if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then
-    mountpoint_api_url=https://github.com/drycc/mountpoint-s3-csi-driver
-  else
-    mountpoint_api_url=https://github.com/drycc/mountpoint-s3-csi-driver
-  fi
-  version=$(curl -Ls $mountpoint_api_url/releases|grep /drycc/mountpoint-s3-csi-driver/releases/tag/\
-    | grep -o 'href="/drycc/mountpoint-s3-csi-driver/releases/tag/[^"]*"' \
-    | sed 's|href="/drycc/mountpoint-s3-csi-driver/releases/tag/||; s/"$//' \
-    | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' \
-    | sort -Vr \
-    | head -1)
+  version=$(get_latest_github_release "drycc/mountpoint-s3-csi-driver" "^v[0-9]+\.[0-9]+\.[0-9]+$")
   helm_upgrade aws-mountpoint-s3-csi-driver aws-mountpoint-s3-csi-driver/aws-mountpoint-s3-csi-driver \
     --set supportLegacySystemDMounts=false \
     --set image.repository=registry.drycc.cc/drycc/mountpoint-s3-csi-driver \
@@ -377,6 +404,7 @@ function install_mountpoint {
   echo -e "\\033[32m---> Mountpoint install completed!\\033[0m"
 }
 
+# check_metallb validates that METALLB_CONFIG_FILE exists if it is set.
 function check_metallb {
   if [[ "${METALLB_CONFIG_FILE}" && ! -f "${METALLB_CONFIG_FILE}" ]] ; then
     echo -e "\\033[33m---> The path ${METALLB_CONFIG_FILE} does not exist...\\033[0m"
@@ -384,8 +412,10 @@ function check_metallb {
   fi
 }
 
-# Best practices
+# install_network deploys Cilium as the CNI with kube-proxy replacement and BPF masquerade.
+# Usage: install_network [helm-options...]
 #
+# Best practices for production optimization:
 # 1. Jumbo frames, change MTU(9000).
 # 2. Big tcp, enableIPv6BIGTCP/enableIPv4BIGTCP.
 # 3. Set `routingMode=native` and `ipv4NativeRoutingCIDR`.
@@ -418,6 +448,10 @@ function install_network() {
   echo -e "\\033[32m---> Network install completed!\\033[0m"
 }
 
+# install_metallb deploys MetalLB for LoadBalancer service support with L2 advertisement.
+# Usage: install_metallb [helm-options...]
+#   METALLB_CONFIG_FILE - path to a custom IPAddressPool/L2Advertisement manifest;
+#                         uses a default 192.168.254.0/24 pool if unset.
 function install_metallb() {
   check_metallb
   options=${1:-""}
@@ -454,6 +488,9 @@ EOF
   echo -e "\\033[32m---> Metallb install completed!\\033[0m"
 }
 
+# install_gateway deploys the Istio Gateway API and Istio ingress gateway.
+# Installs: Gateway API CRDs, istio-base, istiod, and istio-gateway.
+# Usage: install_gateway [helm-options...]
 function install_gateway() {
   options=${1:-""}
   echo -e "\\033[32m---> Start install gateway...\\033[0m"
@@ -462,7 +499,7 @@ function install_gateway() {
   else
     gateway_api_url=https://github.com/kubernetes-sigs/gateway-api
   fi
-  version=$(curl -Ls $gateway_api_url/releases|grep /kubernetes-sigs/gateway-api/releases/tag/ | sed -E 's/.*\/kubernetes-sigs\/gateway-api\/releases\/tag\/(v[0-9\.]{1,}(-rc.[0-9]{1,})?)".*/\1/g' | head -1)
+  version=$(get_latest_github_release "kubernetes-sigs/gateway-api" "^v[0-9]+\.[0-9]+\.[0-9]+(-rc[0-9]+)?$")
 
   helm repo add istio https://github.com/istio-charts
   helm repo update
@@ -478,6 +515,8 @@ function install_gateway() {
   echo -e "\\033[32m---> Gateway install completed!\\033[0m"
 }
 
+# install_cert_manager deploys cert-manager with Gateway API support enabled.
+# Usage: install_cert_manager [helm-options...]
 function install_cert_manager() {
   options=${1:-""}
   echo -e "\\033[32m---> Start install cert-manager...\\033[0m"
@@ -490,15 +529,13 @@ function install_cert_manager() {
   echo -e "\\033[32m---> Cert-manager install completed!\\033[0m"
 }
 
+# install_catalog deploys the Kubernetes Service Catalog via Helm.
+# Uses the "canary" image by default; fetches the latest stable version when CHANNEL is "stable".
+# Usage: install_catalog [helm-options...]
 function install_catalog() {
   service_catalog_version="canary"
   if [[ "$CHANNEL" == "stable" ]]; then
-    if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then
-      service_catalog_url=https://github.com/drycc-addons/service-catalog
-    else
-      service_catalog_url=https://github.com/drycc-addons/service-catalog
-    fi
-    service_catalog_version=$(curl -Ls $service_catalog_url/releases|grep /drycc-addons/service-catalog/releases/tag/ | sed -E 's/.*\/drycc-addons\/service-catalog\/releases\/tag\/(v[0-9\.]{1,}(-rc.[0-9]{1,})?)".*/\1/g' | head -1)
+    service_catalog_version=$(get_latest_github_release "drycc-addons/service-catalog" "^v[0-9]+\.[0-9]+\.[0-9]+(-rc[0-9]+)?$")
   fi
 
   options=${1:-""}
@@ -511,6 +548,8 @@ function install_catalog() {
   echo -e "\\033[32m---> Catalog install completed!\\033[0m"
 }
 
+# install_components installs all infrastructure components in order:
+# network (Cilium), metallb, gateway (Istio), cert-manager, catalog.
 function install_components {
   install_network
   install_metallb
@@ -519,6 +558,8 @@ function install_components {
   install_catalog
 }
 
+# check_drycc validates that required environment variables are set before installing workflow.
+# Requires: PLATFORM_DOMAIN, DRYCC_ADMIN_USERNAME, DRYCC_ADMIN_PASSWORD.
 function check_drycc {
   if [[ -z "${PLATFORM_DOMAIN}" ]] ; then
     echo -e "\\033[33m---> Please set the PLATFORM_DOMAIN variable.\\033[0m"
@@ -541,16 +582,16 @@ function check_drycc {
   fi
 }
 
+# install_drycc deploys the Drycc Workflow platform via Helm.
+# Usage: install_drycc [helm-options...]
+# Requires: PLATFORM_DOMAIN, DRYCC_ADMIN_USERNAME, DRYCC_ADMIN_PASSWORD.
+# Optional: VICTORIAMETRICS_CONFIG_FILE - path to custom VictoriaMetrics values file.
 function install_drycc {
   check_drycc
   options=${1:-""}
   echo -e "\\033[32m---> Start install workflow...\\033[0m"
   if [[ "$CHANNEL" == "stable" ]]; then
-    if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then
-      FILER_VERSION=$(curl -Ls https://github.com/drycc/filer/releases|grep /drycc/filer/releases/tag/ | sed -E 's/.*\/drycc\/filer\/releases\/tag\/(v[0-9\.]{1,}(-rc.[0-9]{1,})?)".*/\1/g' | head -1)
-    else
-      FILER_VERSION=$(curl -Ls https://github.com/drycc/filer/releases|grep /drycc/filer/releases/tag/ | sed -E 's/.*\/drycc\/filer\/releases\/tag\/(v[0-9\.]{1,}(-rc.[0-9]{1,})?)".*/\1/g' | head -1)
-    fi
+    FILER_VERSION=$(get_latest_github_release "drycc/filer" "^v[0-9]+\.[0-9]+\.[0-9]+(-rc[0-9]+)?$")
     FILER_IMAGE=${DRYCC_REGISTRY}/drycc/filer:$(sed 's#v##' <<< $FILER_VERSION)
     FILER_IMAGE_PULL_POLICY="IfNotPresent"
   else
@@ -703,6 +744,10 @@ EOF
   echo -e "\\033[32m---> Workflow install completed!\\033[0m"
 }
 
+# install_helmbroker deploys the Helm Broker and registers it as a ClusterServiceBroker.
+# Usage: install_helmbroker [helm-options...]
+#   HELMBROKER_USERNAME - override the auto-generated broker username
+#   HELMBROKER_PASSWORD - override the auto-generated broker password
 function install_helmbroker {
   if [[ "${INSTALL_DRYCC_MIRROR}" == "cn" ]] ; then
     addons_base_url="https://github.com/drycc-addons/addons"
@@ -711,11 +756,8 @@ function install_helmbroker {
   fi
   version="latest"
   if [[ "$CHANNEL" == "stable" ]]; then
-    for version in $(curl -Ls "${addons_base_url}"/releases|grep /drycc-addons/addons/releases/tag/ | sed -E 's/.*\/drycc-addons\/addons\/releases\/tag\/(v[0-9]{1,})".*/\1/g'); do
-      if [[ "$version" != "latest" ]]; then
-        break
-      fi
-    done
+    version=$(get_latest_github_release "drycc-addons/addons" "^v[0-9]+$")
+    version=${version:-latest}
   fi
   addons_url="${addons_base_url}/releases/download/${version}/index.yaml"
 
@@ -767,6 +809,8 @@ EOF
   echo -e "\\033[32m---> Helmbroker install completed!\\033[0m"
 }
 
+# upgrade upgrades all installed components using --reset-then-reuse-values to preserve
+# previous Helm values while applying new chart defaults.
 function upgrade {
   install_network --reset-then-reuse-values
   install_metallb --reset-then-reuse-values
