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

jshao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/main by this push:
     new 1e79831382 [#6594] feat(deploy): Provide gravitino chart for deploying 
different storage backend on K8S (#6599)
1e79831382 is described below

commit 1e79831382377272781c842ed9d75ad32383583b
Author: Danhua Wang <[email protected]>
AuthorDate: Wed Apr 16 15:04:16 2025 +0800

    [#6594] feat(deploy): Provide gravitino chart for deploying different 
storage backend on K8S (#6599)
    
    ### What changes were proposed in this pull request?
    
    1. Provide gravitino chart for deploying on K8S
    2. Provide CI to check and test chart
    
    ### Why are the changes needed?
    
    Fix: #6594
    
    ### Does this PR introduce _any_ user-facing change?
    
    N/A
    
    ### How was this patch tested?
    
    Add CI
---
 .github/workflows/chart-test.yaml                  |  85 +++++
 LICENSE                                            |   4 +
 dev/charts/gravitino/.helmignore                   |  40 ++
 dev/charts/gravitino/Chart.yaml                    |  38 ++
 .../gravitino/resources/config/gravitino.conf      |  91 +++++
 dev/charts/gravitino/resources/config/init.sh      |  44 +++
 .../gravitino/resources/config/log4j2.properties   |  56 +++
 dev/charts/gravitino/resources/files/mysql         |   1 +
 .../gravitino/resources/scenarios/ci-values.yaml   |  84 +++++
 dev/charts/gravitino/templates/NOTES.txt           |  25 ++
 dev/charts/gravitino/templates/_helpers.tpl        |  67 ++++
 .../gravitino/templates/configmap-mysql-init.yaml  |  46 +++
 dev/charts/gravitino/templates/configmap.yaml      |  33 ++
 dev/charts/gravitino/templates/deployment.yaml     | 136 +++++++
 dev/charts/gravitino/templates/ingress.yaml        |  80 ++++
 dev/charts/gravitino/templates/service.yaml        |  67 ++++
 .../gravitino/templates/tests/test-connection.yaml |  64 ++++
 dev/charts/gravitino/values.yaml                   | 417 +++++++++++++++++++++
 dev/ci/chart_schema.yaml                           |  55 +++
 dev/ci/lintconf.yaml                               |  60 +++
 docs/chart.md                                      | 135 +++++++
 21 files changed, 1628 insertions(+)

diff --git a/.github/workflows/chart-test.yaml 
b/.github/workflows/chart-test.yaml
new file mode 100644
index 0000000000..38b09c8588
--- /dev/null
+++ b/.github/workflows/chart-test.yaml
@@ -0,0 +1,85 @@
+name: Test Charts
+
+# Controls when the workflow will run
+on:
+  pull_request:
+    branches: [ "main", "branch-*" ]
+
+concurrency:
+  group: ${{ github.workflow }}-${{ github.event.pull_request.number || 
github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  changes:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - uses: dorny/[email protected]
+        id: filter
+        with:
+          filters: |
+            source_changes:
+              - .github/workflows/**
+              - dev/charts/**
+    outputs:
+      source_changes: ${{ steps.filter.outputs.source_changes }}
+
+  lint-test:
+    needs: changes
+    if: needs.changes.outputs.source_changes == 'true'
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+        with:
+          fetch-depth: 0
+
+      - name: Set up Helm
+        uses: azure/[email protected]
+
+      - uses: actions/[email protected]
+        with:
+          python-version: '3.x'
+          check-latest: true
+
+      - name: Install yamale
+        run: pip install yamale
+
+      - name: Install chart-testing
+        run: |
+          curl -LO 
https://github.com/helm/chart-testing/releases/download/v3.12.0/chart-testing_3.12.0_linux_amd64.tar.gz
+          tar -xzf chart-testing_3.12.0_linux_amd64.tar.gz
+          sudo mv ct /usr/local/bin/
+          ct version
+
+      - name: List changed
+        id: list-changed
+        run: |
+          changed=$(ct list-changed --chart-dirs=dev/charts --target-branch 
${{ github.event.repository.default_branch }})
+          if [[ -n "$changed" ]]; then
+            echo "changed=true" >> "$GITHUB_OUTPUT"
+          fi
+
+      - name: Lint
+        if: steps.list-changed.outputs.changed == 'true'
+        run: |
+          helm repo add bitnami https://charts.bitnami.com/bitnami
+          ct lint --chart-dirs=dev/charts 
--chart-yaml-schema=dev/ci/chart_schema.yaml --lint-conf=dev/ci/lintconf.yaml 
--target-branch ${{ github.event.repository.default_branch }} 
+
+      - name: Set up kind cluster
+        if: steps.list-changed.outputs.changed == 'true'
+        uses: container-tools/kind-action@v2
+        with:
+          version: v0.27.0
+          cluster_name: helm-test-cluster
+
+      - name: Set up kubectl
+        uses: azure/setup-kubectl@v4
+
+      - name: Run chart-testing (install default)
+        if: steps.list-changed.outputs.changed == 'true'
+        run: ct install --chart-dirs=dev/charts --target-branch ${{ 
github.event.repository.default_branch }}
+
+      - name: Run chart-testing (install mysql enable)
+        if: steps.list-changed.outputs.changed == 'true'
+        run: ct install --chart-dirs=dev/charts --helm-extra-set-args 
"--values dev/charts/gravitino/resources/scenarios/ci-values.yaml" 
--target-branch ${{ github.event.repository.default_branch }}
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
index 07e9f070cd..75fa0e5003 100644
--- a/LICENSE
+++ b/LICENSE
@@ -305,6 +305,10 @@
    
./authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/reference/VXUser.java
    
./authorizations/authorization-ranger/src/main/java/org/apache/gravitino/authorization/ranger/reference/VXUserList.java
 
+   Helm chart-testing
+   ./dev/ci/chart_schema.yaml
+   ./dev/ci/lintconf.yaml
+
    This product bundles a third-party component under the
    MIT License.
 
diff --git a/dev/charts/gravitino/.helmignore b/dev/charts/gravitino/.helmignore
new file mode 100644
index 0000000000..504c781888
--- /dev/null
+++ b/dev/charts/gravitino/.helmignore
@@ -0,0 +1,40 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/
\ No newline at end of file
diff --git a/dev/charts/gravitino/Chart.yaml b/dev/charts/gravitino/Chart.yaml
new file mode 100644
index 0000000000..811083a62d
--- /dev/null
+++ b/dev/charts/gravitino/Chart.yaml
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+apiVersion: v2
+appVersion: 0.9.0-incubating-SNAPSHOT
+description: Apache Gravitino is a high-performance, geo-distributed, and 
federated metadata lake. It manages the metadata directly in different sources, 
types, and regions. It also provides users with unified metadata access for 
data and AI assets.
+home: https://gravitino.apache.org
+annotations:
+  licenses: Apache-2.0
+dependencies:
+  - condition: mysql.enabled
+    name: mysql
+    repository: https://charts.bitnami.com/bitnami
+    version: 10.2.1
+kubeVersion: '>=1.29.0-0'
+maintainers:
+  - name: Gravitino
+    email: [email protected]
+    url: https://gravitino.apache.org
+name: gravitino
+sources:
+  - https://github.com/apache/gravitino
+version: 0.9.0
diff --git a/dev/charts/gravitino/resources/config/gravitino.conf 
b/dev/charts/gravitino/resources/config/gravitino.conf
new file mode 100644
index 0000000000..0ff20caff1
--- /dev/null
+++ b/dev/charts/gravitino/resources/config/gravitino.conf
@@ -0,0 +1,91 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# THE CONFIGURATION FOR Gravitino SERVER
+gravitino.server.shutdown.timeout = {{ .Values.server.shutdownTimeout | 
default 3000 }}
+
+# THE CONFIGURATION FOR Gravitino WEB SERVER
+gravitino.server.webserver.host = {{ .Values.webserver.host | default 
"0.0.0.0" }}
+gravitino.server.webserver.httpPort = {{ .Values.webserver.httpPort | default 
8090 }}
+gravitino.server.webserver.minThreads = {{ .Values.webserver.minThreads | 
default 24 }}
+gravitino.server.webserver.maxThreads = {{ .Values.webserver.maxThreads | 
default 200 }}
+gravitino.server.webserver.stopTimeout = {{ .Values.webserver.stopTimeout | 
default 30000 }}
+gravitino.server.webserver.idleTimeout = {{ .Values.webserver.idleTimeout | 
default 30000 }}
+gravitino.server.webserver.threadPoolWorkQueueSize = {{ 
.Values.webserver.threadPoolWorkQueueSize | default 100 }}
+gravitino.server.webserver.requestHeaderSize = {{ 
.Values.webserver.requestHeaderSize | default 131072 }}
+gravitino.server.webserver.responseHeaderSize = {{ 
.Values.webserver.responseHeaderSize | default 131072 }}
+
+# Comma-separated list of filter class names to apply to the API.
+gravitino.server.webserver.customFilters = {{ .Values.webserver.customFilters 
}}
+
+# Comma-separated list of REST API packages to expand
+gravitino.server.rest.extensionPackages = {{ 
.Values.server.rest.extensionPackages }}
+
+# THE CONFIGURATION FOR Gravitino ENTITY STORE
+gravitino.entity.store = {{ .Values.entity.store | default "relational" }}
+gravitino.entity.store.maxTransactionSkewTimeMs = {{ 
.Values.entity.maxTransactionSkewTimeMs }}
+gravitino.entity.store.deleteAfterTimeMs = {{ 
(.Values.entity.deleteAfterTimeMs | default 604800000) | int }}
+gravitino.entity.store.versionRetentionCount = {{ 
.Values.entity.versionRetentionCount }}
+gravitino.entity.store.relational = {{ .Values.entity.relationalBackend | 
default "JDBCBackend" }}
+gravitino.entity.store.relational.jdbcUrl = {{ if .Values.mysql.enabled 
}}jdbc:mysql://{{ .Release.Name }}-mysql:3306/{{ .Values.mysql.auth.database 
}}{{ else }}{{ .Values.entity.jdbcUrl }}{{ end }}
+gravitino.entity.store.relational.jdbcDriver = {{ if .Values.mysql.enabled 
}}com.mysql.cj.jdbc.Driver{{ else }}{{ .Values.entity.jdbcDriver }}{{ end }}
+gravitino.entity.store.relational.jdbcUser = {{ if .Values.mysql.enabled }}{{ 
.Values.mysql.auth.username }}{{ else }}{{ .Values.entity.jdbcUser }}{{ end }}
+gravitino.entity.store.relational.jdbcPassword = {{ if .Values.mysql.enabled 
}}{{ .Values.mysql.auth.password }}{{ else }}{{ .Values.entity.jdbcPassword 
}}{{ end }}
+gravitino.entity.store.relational.storagePath = {{ .Values.entity.storagePath 
}}
+
+# THE CONFIGURATION FOR Gravitino CATALOG
+gravitino.catalog.cache.evictionIntervalMs = {{ if 
.Values.catalog.evictionIntervalMs }}{{ .Values.catalog.evictionIntervalMs }}{{ 
else }}3600000{{ end }}
+
+# THE CONFIGURATION FOR authorization
+gravitino.authorization.enable = {{ .Values.authorization.enable }}
+gravitino.authorization.serviceAdmins = {{ .Values.authorization.serviceAdmins 
}}
+gravitino.authenticators = {{ .Values.authenticators }}
+gravitino.authenticator.oauth.serviceAudience = {{ 
.Values.authenticator.oauth.serviceAudience }}
+gravitino.authenticator.oauth.defaultSignKey = {{ 
.Values.authenticator.oauth.defaultSignKey }}
+gravitino.authenticator.oauth.serverUri = {{ 
.Values.authenticator.oauth.serverUri }}
+gravitino.authenticator.oauth.tokenPath = {{ 
.Values.authenticator.oauth.tokenPath }}
+
+# THE CONFIGURATION FOR AUXILIARY SERVICE
+gravitino.auxService.names = {{ .Values.auxService.names | default 
"iceberg-rest" }}
+gravitino.iceberg-rest.classpath = {{ .Values.icebergRest.classpath | default 
"iceberg-rest-server/libs, iceberg-rest-server/conf"  }}
+gravitino.iceberg-rest.host = {{ .Values.icebergRest.host | default "0.0.0.0" 
}}
+gravitino.iceberg-rest.httpPort = {{ .Values.icebergRest.httpPort | default 
9001 }}
+gravitino.iceberg-rest.catalog-backend = {{ .Values.icebergRest.catalogBackend 
| default "memory" }}
+gravitino.iceberg-rest.warehouse = {{ .Values.icebergRest.warehouse | default 
"/tmp/" }}
+
+# Audit log configuration
+gravitino.audit.enabled = {{ .Values.audit.enabled }}
+gravitino.audit.writer.className = {{ if (and .Values.audit 
.Values.audit.writer .Values.audit.writer.className) }}{{ 
.Values.audit.writer.className }}{{ else 
}}org.apache.gravitino.audit.FileAuditWriter{{- end }}
+gravitino.audit.formatter.className = {{ if (and .Values.audit 
.Values.audit.formatter .Values.audit.formatter.className) }}{{ 
.Values.audit.formatter.className }}{{ else 
}}org.apache.gravitino.audit.SimpleFormatter{{- end }}
+gravitino.audit.writer.file.fileName = {{ .Values.audit.writer.file.fileName }}
+gravitino.audit.writer.file.flushIntervalSecs = {{ 
.Values.audit.writer.file.flushIntervalSecs }}
+gravitino.audit.writer.file.append = {{ .Values.audit.writer.file.append }}
+
+# Metrics configuration
+gravitino.metrics.timeSlidingWindowSecs        = {{ 
.Values.metrics.timeSlidingWindowSecs }}
+
+{{- if .Values.visibleConfigs }}
+gravitino.server.visibleConfigs = {{ .Values.visibleConfigs }}
+{{- range $key, $val := .Values.visibleConfigsItems }}
+{{ $key }} = {{ tpl $val $ }}
+{{- end }}
+{{- end }}
+{{- range $key, $val := .Values.additionalConfigItems }}
+{{ $key }} = {{ tpl $val $ }}
+{{- end }}
\ No newline at end of file
diff --git a/dev/charts/gravitino/resources/config/init.sh 
b/dev/charts/gravitino/resources/config/init.sh
new file mode 100644
index 0000000000..905fcb968a
--- /dev/null
+++ b/dev/charts/gravitino/resources/config/init.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+echo "Start to download the jar package of JDBC"
+wget 
https://repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.27/mysql-connector-java-8.0.27.jar
 -O ${GRAVITINO_HOME}/catalogs/jdbc-mysql/libs/mysql-connector-java-8.0.27.jar
+wget https://jdbc.postgresql.org/download/postgresql-42.7.0.jar -O 
${GRAVITINO_HOME}/catalogs/jdbc-postgresql/libs/postgresql-42.7.0.jar
+
+cp ${GRAVITINO_HOME}/catalogs/jdbc-postgresql/libs/postgresql-42.7.0.jar 
${GRAVITINO_HOME}/catalogs/lakehouse-iceberg/libs
+cp ${GRAVITINO_HOME}/catalogs/jdbc-mysql/libs/mysql-connector-java-8.0.27.jar 
${GRAVITINO_HOME}/catalogs/lakehouse-iceberg/libs
+
+cp ${GRAVITINO_HOME}/catalogs/jdbc-postgresql/libs/postgresql-42.7.0.jar 
${GRAVITINO_HOME}/iceberg-rest-server/libs
+cp ${GRAVITINO_HOME}/catalogs/jdbc-mysql/libs/mysql-connector-java-8.0.27.jar 
${GRAVITINO_HOME}/iceberg-rest-server/libs
+
+cp ${GRAVITINO_HOME}/catalogs/jdbc-mysql/libs/mysql-connector-java-8.0.27.jar 
${GRAVITINO_HOME}/libs
+echo "Finish downloading"
+
+cp /tmp/conf/* ${GRAVITINO_HOME}/conf
+cp /tmp/conf/log4j2.properties ${GRAVITINO_HOME}/conf
+
+{{- if .Values.log.containerStdout }}
+# Redirect log files to container stdout and stderr
+ln -sf /dev/stdout ${GRAVITINO_HOME}/logs/gravitino_audit.log
+ln -sf /dev/stdout ${GRAVITINO_HOME}/logs/gravitino-server.log
+ln -sf /dev/stderr ${GRAVITINO_HOME}/logs/gravitino-server.out
+{{- end }}
+echo "Start the Gravitino Server"
+/bin/bash ${GRAVITINO_HOME}/bin/gravitino.sh start
diff --git a/dev/charts/gravitino/resources/config/log4j2.properties 
b/dev/charts/gravitino/resources/config/log4j2.properties
new file mode 100644
index 0000000000..20575d9333
--- /dev/null
+++ b/dev/charts/gravitino/resources/config/log4j2.properties
@@ -0,0 +1,56 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+status = {{ .Values.log4j2Properties.status | default "warn" }}
+
+# Log files location
+property.basePath = {{ .Values.log4j2Properties.basePath | default 
"${sys:gravitino.log.path}" }}
+property.serverName = {{ .Values.log4j2Properties.serverName | default 
"${sys:gravitino.server.name}" }}
+
+# RollingFileAppender name, pattern, path and rollover policy
+appender.rolling.type = {{ .Values.log4j2Properties.rollingAppenderType | 
default "RollingFile" }}
+appender.rolling.name = {{ .Values.log4j2Properties.rollingAppenderName | 
default "fileLogger" }}
+appender.rolling.fileName = {{ 
.Values.log4j2Properties.rollingAppenderFileName | default 
"${basePath}/${serverName}.log" }}
+appender.rolling.filePattern = {{ 
.Values.log4j2Properties.rollingAppenderFilePattern | default 
"${basePath}/${serverName}_%d{yyyyMMdd}.log.gz" }}
+appender.rolling.layout.type = {{ 
.Values.log4j2Properties.rollingAppenderLayoutType | default "PatternLayout" }}
+appender.rolling.layout.pattern = {{ 
.Values.log4j2Properties.rollingAppenderLayoutPattern | default "%d{yyyy-MM-dd 
HH:mm:ss.SSS} %level [%t] [%l] - %msg%n" }}
+appender.rolling.policies.type = {{ 
.Values.log4j2Properties.rollingAppenderPoliciesType | default "Policies" }}
+
+# RollingFileAppender rotation policy
+appender.rolling.policies.size.type = {{ 
.Values.log4j2Properties.rollingAppenderPoliciesSizeType | default 
"SizeBasedTriggeringPolicy" }}
+appender.rolling.policies.size.size = {{ 
.Values.log4j2Properties.rollingAppenderPoliciesSizeSize | default "10MB" }}
+appender.rolling.policies.time.type = {{ 
.Values.log4j2Properties.rollingAppenderPoliciesTimeType | default 
"TimeBasedTriggeringPolicy" }}
+appender.rolling.policies.time.interval = {{ 
.Values.log4j2Properties.rollingAppenderPoliciesTimeInterval | default 1 }}
+appender.rolling.policies.time.modulate = {{ 
.Values.log4j2Properties.rollingAppenderPoliciesTimeModulate | default true }}
+appender.rolling.strategy.type = {{ 
.Values.log4j2Properties.rollingAppenderStrategyType | default 
"DefaultRolloverStrategy" }}
+appender.rolling.strategy.delete.type = {{ 
.Values.log4j2Properties.rollingAppenderStrategyDeleteType | default "Delete" }}
+appender.rolling.strategy.delete.basePath = {{ 
.Values.log4j2Properties.rollingAppenderStrategyDeleteBasePath | default 
"${basePath}" }}
+appender.rolling.strategy.delete.maxDepth = {{ 
.Values.log4j2Properties.rollingAppenderStrategyDeleteMaxDepth | default 10 }}
+appender.rolling.strategy.delete.ifLastModified.type = {{ 
.Values.log4j2Properties.rollingAppenderStrategyDeleteIfLastModifiedType | 
default "IfLastModified" }}
+
+# Delete all files older than 30 days
+appender.rolling.strategy.delete.ifLastModified.age = {{ 
.Values.log4j2Properties.rollingAppenderStrategyDeleteIfLastModifiedAge | 
default "30d" }}
+
+# Configure root logger
+rootLogger.level = {{ .Values.log4j2Properties.rootLoggerLevel | default 
"info" }}
+rootLogger.appenderRef.rolling.ref = {{ 
.Values.log4j2Properties.rootLoggerAppenderRefRollingRef | default "fileLogger" 
}}
+
+{{- range $key, $val := .Values.additionalLog4j2Properties }}
+{{ $key }} = {{ tpl $val $ }}
+{{- end }}
\ No newline at end of file
diff --git a/dev/charts/gravitino/resources/files/mysql 
b/dev/charts/gravitino/resources/files/mysql
new file mode 120000
index 0000000000..1fadad5214
--- /dev/null
+++ b/dev/charts/gravitino/resources/files/mysql
@@ -0,0 +1 @@
+../../../../../scripts/mysql
\ No newline at end of file
diff --git a/dev/charts/gravitino/resources/scenarios/ci-values.yaml 
b/dev/charts/gravitino/resources/scenarios/ci-values.yaml
new file mode 100644
index 0000000000..9a0ecd4046
--- /dev/null
+++ b/dev/charts/gravitino/resources/scenarios/ci-values.yaml
@@ -0,0 +1,84 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+mysql:
+  enabled: true
+
+visibleConfigs: 
"gravitino.datastrato.custom.authorization.ranger.admin.url,gravitino.datastrato.custom.authorization.ranger.username,gravitino.datastrato.custom.authorization.ranger.password,gravitino.datastrato.custom.authorization.ranger.auth.type"
+
+visibleConfigsItems:
+  gravitino.datastrato.custom.authorization.ranger.admin.url: 
"http://ranger:6080";
+  gravitino.datastrato.custom.authorization.ranger.username: admin
+  gravitino.datastrato.custom.authorization.ranger.password: "rangerR0cks!"
+  gravitino.datastrato.custom.authorization.ranger.auth.type: simple
+
+additionalConfigItems:
+  gravitino.testAdditionalConfigItems.names: audit,sync
+  gravitino.testAdditionalConfigItems.names.test: test
+
+extraVolumeMounts:
+  - name: gravitino-log
+    mountPath: /root/gravitino/logs
+  - name: extra-volume
+    mountPath: /extra-volume-path
+  - name: another-extra-volume
+    mountPath: /another-extra-volume-path
+
+extraVolumes:
+  - name: gravitino-log
+    emptyDir: {}
+  - name: extra-volume
+    emptyDir: {}
+  - name: another-extra-volume
+    emptyDir: {}
+
+replicas: 2
+
+env:
+  - name: GRAVITINO_HOME
+    value: /root/gravitino
+  - name: HADOOP_USER_NAME
+    value: hdfs
+
+audit:
+  enabled: true
+
+log:
+  containerStdout: true
+
+log4j2Properties:
+  rootLoggerLevel: warn
+  rollingAppenderStrategyDeleteIfLastModifiedAge: 2d
+
+additionalLog4j2Properties:
+  appender.console.type: Console
+  appender.console.name: console
+  appender.console.layout.type: PatternLayout
+  appender.console.layout.pattern: "%d{HH:mm:ss.SSS} %level %msg%n"
+  rootLogger.appenderRef.console.ref: console
+
+resources:
+  limits:
+    cpu: 500m
+    memory: 512Mi
+  requests:
+    cpu: 500m
+    memory: 512Mi
+
+ingress:
+  enabled: true
\ No newline at end of file
diff --git a/dev/charts/gravitino/templates/NOTES.txt 
b/dev/charts/gravitino/templates/NOTES.txt
new file mode 100644
index 0000000000..f7ccb337b0
--- /dev/null
+++ b/dev/charts/gravitino/templates/NOTES.txt
@@ -0,0 +1,25 @@
+{{- /*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+  */}}
+{{ $.Chart.Name }} has been installed. Check its status by running:
+
+  kubectl get pods --namespace {{ include "gravitino.namespace" . }}
+
+Check the "gravitino.conf" by running:
+
+  kubectl get cm {{ include "gravitino.fullname" . }} -n {{ include 
"gravitino.namespace" . }} -o json | jq -r '.data["gravitino.conf"]'
diff --git a/dev/charts/gravitino/templates/_helpers.tpl 
b/dev/charts/gravitino/templates/_helpers.tpl
new file mode 100644
index 0000000000..edf00f207e
--- /dev/null
+++ b/dev/charts/gravitino/templates/_helpers.tpl
@@ -0,0 +1,67 @@
+{{/*
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+*/}}
+
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "gravitino.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to 
this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "gravitino.fullname" -}}
+{{- if .Values.fullnameOverride -}}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- $name := default .Chart.Name .Values.nameOverride -}}
+{{- if contains $name .Release.Name -}}
+{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "gravitino.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | 
trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Common labels
+*/}}
+{{- define "gravitino.labels" -}}
+app: {{ template "gravitino.name" . }}
+chart: {{ template "gravitino.chart" . }}
+release: {{ .Release.Name }}
+{{- end }}
+
+{{/*
+Define the gravitino.namespace
+*/}}
+{{- define "gravitino.namespace" -}}
+    {{- .Release.Namespace -}}
+{{- end -}}
diff --git a/dev/charts/gravitino/templates/configmap-mysql-init.yaml 
b/dev/charts/gravitino/templates/configmap-mysql-init.yaml
new file mode 100644
index 0000000000..089c47ca00
--- /dev/null
+++ b/dev/charts/gravitino/templates/configmap-mysql-init.yaml
@@ -0,0 +1,46 @@
+{{- /*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+  */}}
+
+{{- if .Values.mysql.enabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: gravitino-mysql-init
+  namespace: {{ include "gravitino.namespace" . }}
+  labels:
+    {{- include "gravitino.labels" . | nindent 4 }}
+data:
+  {{- $sqlFiles := .Files.Glob "resources/files/mysql/schema-*-mysql.sql" }}
+  {{- $maxVersionFile := "" }}
+  {{- $maxVersion := "0.0.0" }}
+  {{- range $path, $content := $sqlFiles }}
+    {{- $fileName := base $path }}
+    {{- $version := regexFind "schema-(\\d+\\.\\d+\\.\\d+)-mysql\\.sql" 
$fileName | replace "schema-" "" | replace "-mysql.sql" "" }}
+    {{- if (semverCompare ">= 0.0.0" $version) }}
+        {{- if (semverCompare (printf "> %s" $maxVersion) $version) }}
+          {{- $maxVersion = $version }}
+          {{- $maxVersionFile = $path }}
+        {{- end }}
+    {{- end }}
+  {{- end }}
+  {{- if $maxVersionFile }}
+  {{ base $maxVersionFile }}: |-
+    {{- tpl (.Files.Get $maxVersionFile | toString) $ | nindent 4 }}
+  {{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/dev/charts/gravitino/templates/configmap.yaml 
b/dev/charts/gravitino/templates/configmap.yaml
new file mode 100644
index 0000000000..a76f65fb35
--- /dev/null
+++ b/dev/charts/gravitino/templates/configmap.yaml
@@ -0,0 +1,33 @@
+{{- /*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+  */}}
+
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ include "gravitino.fullname" . }}
+  namespace: {{ include "gravitino.namespace" . }}
+  labels:
+    {{- include "gravitino.labels" . | nindent 4 }}
+data:
+  init.sh: |-
+    {{- tpl (.Files.Get "resources/config/init.sh") . | nindent 4 }}
+  gravitino.conf: |
+    {{- tpl (.Files.Get "resources/config/gravitino.conf") . | nindent 4 }}
+  log4j2.properties: |-
+    {{- tpl (.Files.Get "resources/config/log4j2.properties") . | nindent 4 }}
\ No newline at end of file
diff --git a/dev/charts/gravitino/templates/deployment.yaml 
b/dev/charts/gravitino/templates/deployment.yaml
new file mode 100644
index 0000000000..a509cef23e
--- /dev/null
+++ b/dev/charts/gravitino/templates/deployment.yaml
@@ -0,0 +1,136 @@
+{{- /*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+  */}}
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ include "gravitino.fullname" . }}
+  namespace: {{ include "gravitino.namespace" . }}
+  labels:
+    {{- include "gravitino.labels" . | nindent 4 }}
+  annotations:
+    {{- toYaml .Values.annotations | nindent 4 }}
+spec:
+  replicas: {{ .Values.replicas }}
+  selector:
+    matchLabels:
+      app: {{ include "gravitino.name" . }}
+      release: {{ .Release.Name }}
+  template:
+    metadata:
+      labels:
+        app: {{ include "gravitino.name" . }}
+        name: {{ include "gravitino.fullname" . }}
+        release: {{ .Release.Name }}
+        {{- with .Values.podLabels }}
+        {{- toYaml . | nindent 8 }}
+        {{- end }}
+      annotations:
+        {{- with .Values.podAnnotations }}
+          {{- toYaml . | nindent 8 }}
+          {{- end }}
+    spec:
+      {{- with .Values.image.pullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      containers:
+        - name: {{ include "gravitino.name" . }}
+          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
+          imagePullPolicy: {{ .Values.image.pullPolicy | quote }}
+          command:
+            - "/bin/bash"
+            - "/tmp/conf/init.sh"
+          livenessProbe:
+            {{- toYaml .Values.livenessProbe | nindent 12 }}
+          readinessProbe:
+            {{- toYaml .Values.readinessProbe | nindent 12 }}
+          resources:
+            {{- toYaml .Values.resources | nindent 12 }}
+          securityContext:
+            {{- toYaml .Values.containerSecurityContext | nindent 12 }}
+        {{- if or .Values.env .Values.envWithTpl }}
+          env:
+          {{- with .Values.env }}
+            {{- toYaml . | nindent 12 }}
+          {{- end }}
+          {{- range $item := .Values.envWithTpl }}
+            - name: {{ $item.name }}
+              value: {{ tpl $item.value $ | quote }}
+          {{- end }}
+        {{- end }}
+        {{- if .Values.envFrom }}
+          envFrom:
+            {{- toYaml .Values.envFrom | nindent 12 }}
+        {{- end }}            
+          ports:
+            - name: {{ .Values.service.portName }}
+              containerPort: {{ .Values.service.targetPort }}
+              protocol: TCP
+            {{- if .Values.extraExposePorts }}
+            {{- range $item := .Values.extraExposePorts }}
+            - name: {{ $item.name }}
+              containerPort: {{ $item.targetPort }}
+              protocol: {{ $item.protocol }}
+            {{- end }}
+            {{- end }}              
+          volumeMounts:
+            - name: gravitino-conf
+              mountPath: /tmp/conf
+            - name: storage
+              mountPath: {{ .Values.entity.storagePath }}
+        {{- if .Values.extraVolumeMounts }}
+              {{- toYaml .Values.extraVolumeMounts | nindent 12 }}
+            {{- end }}  
+      nodeSelector:
+        {{- toYaml .Values.nodeSelector | nindent 8 }}
+      affinity:
+        {{- toYaml .Values.affinity | nindent 8 }}
+      tolerations:
+        {{- toYaml .Values.tolerations | nindent 8 }}
+      volumes:
+        - name: gravitino-conf
+          configMap:
+            name: {{ include "gravitino.fullname" . }}
+        {{- if not .Values.persistence.enabled }}
+        - name: storage
+          emptyDir: {}
+        {{- else if .Values.persistence.existingClaim }}
+        - name: storage
+          persistentVolumeClaim:
+            claimName: {{ .Values.persistence.existingClaim }}
+        {{- else }}
+        volumeClaimTemplates:
+          - metadata:
+              name: storage
+              labels:
+                {{- toYaml .Values.persistence.labels | nindent 8 }}
+              annotations:
+                {{- toYaml .Values.persistence.annotations | nindent 8 }}
+            spec:
+              accessModes:
+                {{- toYaml .Values.persistence.accessModes | nindent 8 }}
+              resources:
+                requests:
+                  storage: {{ .Values.persistence.size | quote }}
+              storageClassName: {{ .Values.persistence.storageClassName }}
+        {{- end }}
+        {{- if .Values.extraVolumes }}
+          {{- toYaml .Values.extraVolumes | nindent 8 }}
+        {{- end }}
\ No newline at end of file
diff --git a/dev/charts/gravitino/templates/ingress.yaml 
b/dev/charts/gravitino/templates/ingress.yaml
new file mode 100644
index 0000000000..64252ee814
--- /dev/null
+++ b/dev/charts/gravitino/templates/ingress.yaml
@@ -0,0 +1,80 @@
+{{- /*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+  */}}
+
+  {{- if .Values.ingress.enabled -}}
+{{- $fullName := include "gravitino.fullname" . -}}
+{{- $svcPort := .Values.service.port -}}
+{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" 
.Capabilities.KubeVersion.GitVersion)) }}
+  {{- if not (hasKey .Values.ingress.annotations 
"kubernetes.io/ingress.class") }}
+  {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" 
.Values.ingress.className}}
+  {{- end }}
+{{- end }}
+{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
+apiVersion: networking.k8s.io/v1
+{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
+apiVersion: networking.k8s.io/v1beta1
+{{- else -}}
+apiVersion: extensions/v1beta1
+{{- end }}
+kind: Ingress
+metadata:
+  name: {{ $fullName }}
+  labels:
+    {{- include "gravitino.labels" . | nindent 4 }}
+  {{- with .Values.ingress.annotations }}
+  annotations:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
+spec:
+  {{- if and .Values.ingress.className (semverCompare ">=1.18-0" 
.Capabilities.KubeVersion.GitVersion) }}
+  ingressClassName: {{ .Values.ingress.className }}
+  {{- end }}
+  {{- if .Values.ingress.tls }}
+  tls:
+    {{- range .Values.ingress.tls }}
+    - hosts:
+        {{- range .hosts }}
+        - {{ . | quote }}
+        {{- end }}
+      secretName: {{ .secretName }}
+    {{- end }}
+  {{- end }}
+  rules:
+    {{- range .Values.ingress.hosts }}
+    - host: {{ .host | quote }}
+      http:
+        paths:
+          {{- range .paths }}
+          - path: {{ .path }}
+            {{- if and .pathType (semverCompare ">=1.18-0" 
$.Capabilities.KubeVersion.GitVersion) }}
+            pathType: {{ .pathType }}
+            {{- end }}
+            backend:
+              {{- if semverCompare ">=1.19-0" 
$.Capabilities.KubeVersion.GitVersion }}
+              service:
+                name: {{ $fullName }}
+                port:
+                  number: {{ $svcPort }}
+              {{- else }}
+              serviceName: {{ $fullName }}
+              servicePort: {{ $svcPort }}
+              {{- end }}
+          {{- end }}
+    {{- end }}
+{{- end }}
diff --git a/dev/charts/gravitino/templates/service.yaml 
b/dev/charts/gravitino/templates/service.yaml
new file mode 100644
index 0000000000..3ccc7eaa6c
--- /dev/null
+++ b/dev/charts/gravitino/templates/service.yaml
@@ -0,0 +1,67 @@
+{{- /*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+  */}}
+
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ .Values.service.name }}
+  namespace: {{ include "gravitino.namespace" . }}
+  labels:
+    {{- include "gravitino.labels" . | nindent 4 }}
+      {{- with .Values.service.labels }}
+      {{- toYaml . | nindent 4 }}
+      {{- end }}
+  annotations:
+    {{- toYaml .Values.service.annotations | nindent 4 }}
+spec:
+  {{- if (or (eq .Values.service.type "ClusterIP") (empty 
.Values.service.type)) }}
+  type: ClusterIP
+    {{- if .Values.service.clusterIP }}
+  clusterIP: {{ .Values.service.clusterIP }}
+    {{- end }}
+  {{- else if eq .Values.service.type "LoadBalancer" }}
+  type: {{ .Values.service.type }}
+    {{- if .Values.service.loadBalancerIP }}
+  loadBalancerIP: {{ .Values.service.loadBalancerIP }}
+    {{- end }}
+    {{- if .Values.service.loadBalancerSourceRanges }}
+  loadBalancerSourceRanges:
+    {{- toYaml .Values.service.loadBalancerSourceRanges | nindent 4 }}
+      {{- end }}
+  {{- else }}
+  type: {{ .Values.service.type }}
+  {{- end }}
+  {{- if .Values.service.externalIPs }}
+  externalIPs:
+    {{- toYaml .Values.service.externalIPs | nindent 4 }}
+  {{- end }}
+  ports:
+    - name: {{ .Values.service.portName }}
+      port: {{ .Values.service.port }}
+      protocol: TCP
+      targetPort: {{ .Values.service.targetPort }}
+      {{- if (and (eq .Values.service.type "NodePort") (not (empty 
.Values.service.nodePort))) }}
+      nodePort: {{ .Values.service.nodePort }}
+      {{- end }}
+    {{- if .Values.extraExposePorts }}
+    {{- tpl (toYaml .Values.extraExposePorts) . | nindent 4 }}
+    {{- end }}
+  selector:
+    app: {{ include "gravitino.name" . }}
+    release: {{ .Release.Name }}
\ No newline at end of file
diff --git a/dev/charts/gravitino/templates/tests/test-connection.yaml 
b/dev/charts/gravitino/templates/tests/test-connection.yaml
new file mode 100644
index 0000000000..88c51b8dbc
--- /dev/null
+++ b/dev/charts/gravitino/templates/tests/test-connection.yaml
@@ -0,0 +1,64 @@
+{{- /*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+  */}}
+
+apiVersion: v1
+kind: Pod
+metadata:
+  name: {{ include "gravitino.fullname" . }}-test-connection
+  namespace: {{ include "gravitino.namespace" . }}
+  annotations:
+    helm.sh/hook: test
+    helm.sh/hook-delete-policy: hook-succeeded
+spec:
+  containers:
+    - name: test-connection
+      image: curlimages/curl:latest
+      command:
+        - /bin/sh
+        - -c
+        - |
+          max_attempts=10
+          attempt=0
+          success=false
+
+          while [ $attempt -lt $max_attempts ]; do
+            response=$(curl -X GET -H "Content-Type: application/json" 
http://${SERVICE_NAME}:${SERVICE_PORT}/api/version)
+
+            if echo "$response" | grep -q "\"code\":0"; then
+              success=true
+              break
+            else
+              echo "Attempt $((attempt + 1)) failed..."
+              sleep 1
+            fi
+
+            ((attempt++))
+          done
+
+          if [ "$success" = true ]; then
+            exit 0
+          else
+            exit 1
+          fi
+      env:
+        - name: SERVICE_NAME
+          value: "{{ .Values.service.name }}"
+        - name: SERVICE_PORT
+          value: "{{ .Values.service.port }}"
+  restartPolicy: Never
diff --git a/dev/charts/gravitino/values.yaml b/dev/charts/gravitino/values.yaml
new file mode 100644
index 0000000000..daa5bc08a9
--- /dev/null
+++ b/dev/charts/gravitino/values.yaml
@@ -0,0 +1,417 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+image:
+  repository: apache/gravitino
+  tag: 0.9.0-incubating-SNAPSHOT
+  pullPolicy: IfNotPresent
+  ## Optionally specify an array of pullSecrets (secrets must be manually 
created in the namespace)
+  ## ref: 
https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
+  ## Example:
+  ## pullSecrets:
+  ##   - myRegistryKeySecretName
+  ##
+  pullSecrets: []
+
+## MySQL chart configuration
+## ref: https://github.com/bitnami/charts/blob/main/bitnami/mysql/values.yaml
+##
+mysql:
+  ## @param mysql.enabled Deploy MySQL container(s)
+  ##
+  enabled: false
+  ## Bitnami MySQL image version
+  ## ref: https://hub.docker.com/r/bitnami/mysql/tags/
+  ## @param image.registry MySQL image registry
+  ## @param image.repository MySQL image repository
+  ## @param image.tag MySQL image tag
+  ##
+  image:
+    tag: 8.0.36-debian-12-r12
+  ## @param initdbScriptsConfigMap ConfigMap with the initdb scripts
+  ##
+  initdbScriptsConfigMap: gravitino-mysql-init
+  ## MySQL Authentication parameters
+  ##
+  auth:
+    ## @param auth.rootPassword Password for the `root` user.
+    ##
+    rootPassword: admin
+    ## @param auth.createDatabase Whether to create the .Values.auth.database 
or not
+    ##
+    createDatabase: true
+    ## @param auth.database Name for a custom database to create
+    ##
+    database: gravitino
+    ## @param auth.username Name for a custom user to create
+    ##
+    username: gravitino
+    ## @param auth.password Password for the new user.
+    ##
+    password: gravitino
+
+## THE CONFIGURATION FOR Gravitino ENTITY STORE
+##
+entity:
+  ## The entity store to use, we only supports relational
+  ##
+  store: relational
+  maxTransactionSkewTimeMs: 2000
+  deleteAfterTimeMs: 604800000
+  versionRetentionCount: 1
+  ## The backend for the entity store, we only supports JDBC
+  ##
+  relationalBackend: JDBCBackend
+  ## The JDBC URL for the entity store
+  ##
+  jdbcUrl: jdbc:h2
+  ## The JDBC driver class name
+  ##
+  jdbcDriver: org.h2.Driver
+  ## The JDBC user name
+  ##
+  jdbcUser: gravitino
+  ## The JDBC password
+  ##
+  jdbcPassword: gravitino
+  storagePath: /root/gravitino/data/jdbc
+
+## THE CONFIGURATION FOR Gravitino SERVER
+##
+server:
+  shutdownTimeout: 3000
+  rest:
+    extensionPackages: ""
+## THE CONFIGURATION FOR Gravitino WEB SERVER
+##
+webserver:
+  ## The host name of the built-in web server
+  ##
+  host: 0.0.0.0
+  ## The http port number of the built-in web server
+  ##
+  httpPort: 8090
+  ## The min thread size of the built-in web server
+  ##
+  minThreads: 24
+  ## The max thread size of the built-in web server
+  ##
+  maxThreads: 200
+  ## The stop timeout of the built-in web server
+  ##
+  stopTimeout: 30000
+  ## The timeout of idle connections
+  ##
+  idleTimeout: 30000
+  ## The executor thread pool work queue size of the built-in web server
+  ##
+  threadPoolWorkQueueSize: 100
+  ## The request header size of the built-in web server
+  ##
+  requestHeaderSize: 131072
+  ## The response header size of the built-in web server
+  ##
+  responseHeaderSize: 131072
+  customFilters: ""
+
+## THE CONFIGURATION FOR Gravitino CATALOG
+##
+catalog:
+  ## The interval in milliseconds to evict the catalog cache
+  ##
+  cacheEvictionIntervalMs: 3600000
+
+## THE CONFIGURATION FOR authorization
+##
+authorization:
+  ## Whether Gravitino enable authorization or not
+  ##
+  enable: false
+  ## The admins of Gravitino service, multiple admins are spitted by comma.
+  ##
+  serviceAdmins: anonymous
+
+## THE CONFIGURATION FOR AUXILIARY SERVICE
+##
+auxService:
+  ## Auxiliary service names, separate by ','
+  ##
+  names: iceberg-rest
+
+icebergRest:
+  ## Iceberg REST service classpath
+  ##
+  classpath: "iceberg-rest-server/libs, iceberg-rest-server/conf"
+  ## Iceberg REST service host
+  ##
+  host: 0.0.0.0
+  ## Iceberg REST service http port
+  ##
+  httpPort: 9001
+  ## The backend Iceberg catalog for Iceberg REST service, it's recommended to 
change to hive or jdbc
+  ##
+  catalogBackend: memory
+  ## The warehouse directory of Iceberg catalog for Iceberg REST service
+  ##
+  warehouse: /tmp/
+
+## Authentication mechanisms configuration. Support simple, OAuth and Kerberos.
+##
+authenticators: simple
+
+## OAuth mode configuration
+##
+authenticator:
+  oauth:
+    serviceAudience: test
+    defaultSignKey: ""
+    serverUri: ""
+    tokenPath: /realms/myrealm/protocol/openid-connect/token
+
+## Audit log configuration
+##
+audit:
+  enabled: false
+  writer:
+    file:
+      fileName: gravitino_audit.log
+      flushIntervalSecs: 10
+      append: true
+
+## Metrics configuration
+##
+metrics:
+  timeSlidingWindowSecs: 60
+
+## Custom Gravitino configuration items
+##
+visibleConfigs: ""
+# visibleConfigs: 
"gravitino.datastrato.custom.authorization.ranger.admin.url,gravitino.datastrato.custom.authorization.ranger.username,gravitino.datastrato.custom.authorization.ranger.password,gravitino.datastrato.custom.authorization.ranger.auth.type"
+
+visibleConfigsItems: {}
+  # gravitino.datastrato.custom.authorization.ranger.admin.url: 
"http://ranger:6080";
+  # gravitino.datastrato.custom.authorization.ranger.username: admin
+  # gravitino.datastrato.custom.authorization.ranger.password: "rangerR0cks!"
+  # gravitino.datastrato.custom.authorization.ranger.auth.type: simple
+
+## Additional Gravitino configuration items in gravitino.conf can be added
+##
+additionalConfigItems: {}
+#  gravitino.eventListener.names: "audit,sync"
+
+## Additional volumes
+##
+extraVolumes:
+  - name: gravitino-log
+    emptyDir: {}
+
+## Additional volume mounts
+##
+extraVolumeMounts:
+  - name: gravitino-log
+    mountPath: /root/gravitino/logs
+
+## ref: https://kubernetes.io/docs/concepts/storage/persistent-volumes/
+## If you set enabled as "True", you need :
+## - create a pv which above 10Gi
+## - keep storageClassName same with below setting
+##
+persistence:
+  enabled: false
+  accessModes:
+    - ReadWriteOnce
+  size: 10Gi
+  labels: {}
+  annotations: {}
+  # existingClaim:
+  # storageClassName:
+
+## Whether redirect the log files to the container stdout and stderr
+##
+log:
+  containerStdout: false
+
+## Gravitino log4j2 configuration items in log4j2.properties can be customized
+##
+log4j2Properties: {}
+  # status: warn
+
+  ## Log files location
+  # basePath: "${sys:gravitino.log.path}"
+  # serverName: "${sys:gravitino.server.name}"
+
+  ## RollingFileAppender name, pattern, path and rollover policy
+  # rollingAppenderType: RollingFile
+  # rollingAppenderName: fileLogger
+  # rollingAppenderFileName: "${basePath}/${serverName}.log"
+  # rollingAppenderFilePattern: "${basePath}/${serverName}_%d{yyyyMMdd}.log.gz"
+  # rollingAppenderLayoutType: PatternLayout
+  # rollingAppenderLayoutPattern: "%d{yyyy-MM-dd HH:mm:ss.SSS} %level [%t] 
[%l] - %msg%n"
+  # rollingAppenderPoliciesType: Policies
+
+  ## RollingFileAppender rotation policy
+  # rollingAppenderPoliciesSizeType: SizeBasedTriggeringPolicy
+  # rollingAppenderPoliciesSizeSize: 10MB
+  # rollingAppenderPoliciesTimeType: TimeBasedTriggeringPolicy
+  # rollingAppenderPoliciesTimeInterval: 1
+  # rollingAppenderPoliciesTimeModulate: true
+  # rollingAppenderStrategyType: DefaultRolloverStrategy
+  # rollingAppenderStrategyDeleteType: Delete
+  # rollingAppenderStrategyDeleteBasePath: "${basePath}"
+  # rollingAppenderStrategyDeleteMaxDepth: 10
+  # rollingAppenderStrategyDeleteIfLastModifiedType: IfLastModified
+
+  ## Delete all files older than 30 days
+  # rollingAppenderStrategyDeleteIfLastModifiedAge: 30d
+
+  ## Configure root logger
+  # rootLoggerLevel: info
+  # rootLoggerAppenderRefRollingRef: fileLogger
+
+## Additional log4j2 configuration items in log4j2.properties can be added
+##
+additionalLog4j2Properties: {}
+  # appender.console.type: Console
+  # appender.console.name: console
+  # appender.console.layout.type: PatternLayout
+  # appender.console.layout.pattern: "%d{HH:mm:ss.SSS} %level %msg%n"
+  # rootLogger.appenderRef.console.ref: console
+
+## Expose the gravitino service to be accessed from outside the cluster 
(LoadBalancer service).
+## or access it from within the cluster (ClusterIP service). Set the service 
type and the port to serve it.
+## ref: http://kubernetes.io/docs/user-guide/services/
+##
+service:
+  name: gravitino
+  type: ClusterIP
+  port: 8090
+  targetPort: 8090
+  annotations: {}
+  labels: {}
+  portName: http
+  nodePort: ""
+
+## Additional ports to the gravitino services. Useful to expose extra 
container ports.
+##
+extraExposePorts:
+  - port: 9001
+    protocol: TCP
+    name: http1
+    targetPort: 9001
+
+ingress:
+  enabled: false
+  className: "nginx"
+  annotations: {}
+  # kubernetes.io/tls-acme: "true"
+  hosts:
+    - host: chart-gravitino.local
+      paths:
+        - path: /
+          pathType: ImplementationSpecific
+  tls: []
+  #  - secretName: chart-gravitino-tls
+  #    hosts:
+  #      - chart-gravitino.local
+
+## Deployment annotations
+##
+annotations: {}
+
+## Deployment replicas
+##
+replicas: 1
+
+## Pod Annotations
+##
+podAnnotations: {}
+
+## Pod Labels
+##
+podLabels: {}
+
+## Readiness probe for the Gravitino deployment
+##
+readinessProbe:
+  httpGet:
+    path: /
+    port: http
+  initialDelaySeconds: 20
+  timeoutSeconds: 5
+
+## Liveness probe for the Gravitino deployment
+##
+livenessProbe:
+  httpGet:
+    path: /
+    port: http
+  initialDelaySeconds: 20
+  timeoutSeconds: 5
+
+## Container-specific security context configuration
+## ref: 
https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
+##
+containerSecurityContext:
+  runAsNonRoot: false
+  runAsUser: 0
+
+## Container Environment
+##
+env:
+  - name: GRAVITINO_HOME
+    value: /root/gravitino
+  - name: GRAVITINO_MEM
+    value: "-Xms1024m -Xmx1024m -XX:MaxMetaspaceSize=512m"
+
+## The envWithTpl array below has the same usage as "env", but is using the 
tpl function to support templatable string.
+## This can be useful when you want to pass dynamic values to the Chart using 
the helm argument "--set <variable>=<value>"
+## https://helm.sh/docs/howto/charts_tips_and_tricks/#using-the-tpl-function
+##
+envWithTpl: []
+#  - name: FOO_2
+#    value: "{{ .Values.foo2 }}"
+
+# foo2: bar2
+
+envFrom: []
+
+## Resource limits & requests
+##
+resources: {}
+#   requests:
+#     cpu: 1000m
+#     memory: 2Gi
+#   limits:
+#     cpu: 2000m
+#     memory: 3Gi
+
+## Node labels for pod assignment
+## ref: https://kubernetes.io/docs/user-guide/node-selection/
+##
+nodeSelector: {}
+
+## Tolerations for pod assignment
+## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
+##
+tolerations: []
+
+## Affinity for pod assignment (evaluated as template)
+## ref: 
https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
+##
+affinity: {}
diff --git a/dev/ci/chart_schema.yaml b/dev/ci/chart_schema.yaml
new file mode 100644
index 0000000000..c209822a19
--- /dev/null
+++ b/dev/ci/chart_schema.yaml
@@ -0,0 +1,55 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+name: str()
+home: str(required=False)
+version: str()
+apiVersion: str()
+appVersion: any(str(), num(), required=False)
+description: str(required=False)
+keywords: list(str(), required=False)
+sources: list(str(), required=False)
+maintainers: list(include('maintainer'), required=False)
+dependencies: list(include('dependency'), required=False)
+icon: str(required=False)
+engine: str(required=False)
+condition: str(required=False)
+tags: str(required=False)
+deprecated: bool(required=False)
+kubeVersion: str(required=False)
+annotations: map(str(), str(), required=False)
+type: str(required=False)
+---
+maintainer:
+  name: str()
+  email: str(required=False)
+  url: str(required=False)
+---
+dependency:
+  name: str()
+  version: str()
+  repository: str(required=False)
+  condition: str(required=False)
+  tags: list(str(), required=False)
+  enabled: bool(required=False)
+  import-values: any(list(str()), list(include('import-value')), 
required=False)
+  alias: str(required=False)
+---
+import-value:
+  child: str()
+  parent: str()
\ No newline at end of file
diff --git a/dev/ci/lintconf.yaml b/dev/ci/lintconf.yaml
new file mode 100644
index 0000000000..c5c904f3e2
--- /dev/null
+++ b/dev/ci/lintconf.yaml
@@ -0,0 +1,60 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+---
+rules:
+  braces:
+    min-spaces-inside: 0
+    max-spaces-inside: 0
+    min-spaces-inside-empty: -1
+    max-spaces-inside-empty: -1
+  brackets:
+    min-spaces-inside: 0
+    max-spaces-inside: 0
+    min-spaces-inside-empty: -1
+    max-spaces-inside-empty: -1
+  colons:
+    max-spaces-before: 0
+    max-spaces-after: 1
+  commas:
+    max-spaces-before: 0
+    min-spaces-after: 1
+    max-spaces-after: 1
+  comments:
+    require-starting-space: true
+    min-spaces-from-content: 2
+  document-end: disable
+  document-start: disable           # No --- to start a file
+  empty-lines:
+    max: 2
+    max-start: 0
+    max-end: 0
+  hyphens:
+    max-spaces-after: 1
+  indentation:
+    spaces: consistent
+    indent-sequences: whatever      # - list indentation will handle both 
indentation and without
+    check-multi-line-strings: false
+  key-duplicates: enable
+  line-length: disable              # Lines can be any length
+  new-line-at-end-of-file: enable
+  new-lines:
+    type: unix
+  trailing-spaces: enable
+  truthy:
+    level: warning
\ No newline at end of file
diff --git a/docs/chart.md b/docs/chart.md
new file mode 100644
index 0000000000..d3a6d272b7
--- /dev/null
+++ b/docs/chart.md
@@ -0,0 +1,135 @@
+---
+title: "Apache Gravitino Helm Chart"
+slug: /chart
+keyword: chart
+license: "This software is licensed under the Apache License version 2."
+---
+
+# Apache Gravitino Helm Chart
+
+This Helm chart deploys Apache Gravitino on Kubernetes with customizable 
configurations.
+
+**Homepage:** <https://gravitino.apache.org/>
+
+## Prerequisites
+
+- Kubernetes 1.29+
+- Helm 3+
+
+## Maintainers
+
+| Name             | Email                    | Url                          |
+|------------------|--------------------------|------------------------------|
+| Apache Gravitino | [email protected] | https://gravitino.apache.org |
+
+## Source Code
+
+* <https://github.com/apache/gravitino>
+
+## Update Chart Dependency
+
+If the chart has not been released yet, navigate to the chart directory and 
update its dependencies:
+
+```console
+helm dependency update [CHART]
+```
+
+## View Chart values
+
+You can customize values.yaml parameters to override chart default settings. 
Additionally, Gravitino configurations in gravitino.conf can be modified 
through Helm values.yaml.
+
+To display the default values of the Gravitino chart, run:
+
+```console
+helm show values [CHART]
+```
+
+## Install Helm Chart
+
+```console
+helm install [RELEASE_NAME] [CHART] [flags]
+```
+
+### Deploy with Default Configuration
+
+Run the following command to deploy Gravitino using the default settings:
+
+```console
+helm upgrade --install gravitino ./gravitino -n gravitino --create-namespace
+```
+
+### Deploy with Custom Configuration
+
+To customize the deployment, use the --set flag to override specific values:
+
+```console
+helm upgrade --install gravitino ./gravitino -n gravitino --create-namespace \
+  --set key1=val1,key2=val2,...
+```
+
+Alternatively, you can provide a custom values.yaml file:
+
+```console
+helm upgrade --install gravitino ./gravitino -n gravitino --create-namespace 
-f /path/to/chart/resources/scenarios/ci-values.yaml
+```
+
+_Note: \
+/path/to/chart/resources/scenarios/ci-values.yaml is an example scenario to 
deploy._
+
+### Deploying Gravitino with MySQL as the Storage Backend
+
+To deploy both Gravitino and MySQL, where MySQL is used as the storage 
backend, enable the built-in MySQL instance:
+
+```console
+helm upgrade --install gravitino ./gravitino -n gravitino --create-namespace \
+  --set mysql.enabled=true
+```
+
+#### Disable Dynamic Storage Provisioning
+
+By default, the MySQL PersistentVolumeClaim(PVC) storage class is local-path. 
To disable dynamic provisioning, set the storage class to "-":
+
+```console
+helm upgrade --install gravitino ./gravitino -n gravitino --create-namespace \
+  --set mysql.enabled=true \
+  --set global.defaultStorageClass="-"
+```
+
+You must then manually create a PersistentVolume (PV).
+
+### Deploy Gravitino using an existed MySQL Database
+
+Ensure you have the following MySQL credentials ready: Username, Password, 
Database Name. When creating your database, we recommend calling it `gravitino`.
+
+Before deploying Gravitino, initialize your existing MySQL instance and create 
the necessary tables required for Gravitino to function properly.
+
+```console
+mysql -h database-1.***.***.rds.amazonaws.com -P 3306 -u <YOUR-USERNAME> -p 
<YOUR-PASSWORD> < schema-0.*.0-mysql.sql
+```
+
+Use Helm to install or upgrade Gravitino, specifying the MySQL connection 
details.
+
+```console
+helm upgrade --install gravitino ./gravitino -n gravitino --create-namespace \
+  --set 
entity.jdbcUrl="jdbc:mysql://database-1.***.***.rds.amazonaws.com:3306/gravitino"
 \
+  --set entity.jdbcDriver="com.mysql.cj.jdbc.Driver" \
+  --set entity.jdbcUser="admin" \
+  --set entity.jdbcPassword="admin123"
+```
+
+_Note: \
+Replace database-1.***.***.rds.amazonaws.com with your actual MySQL host. \
+Change admin and admin123 to your actual MySQL username and password. \
+Ensure the target MySQL database (gravitino) exists before deployment._
+
+## Uninstall Helm Chart
+
+```console
+helm uninstall [RELEASE_NAME] -n [NAMESPACE]
+```
+
+## Package Helm Chart
+
+```console
+helm package [CHART_PATH]
+```
\ No newline at end of file

Reply via email to