You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@submarine.apache.org by li...@apache.org on 2020/09/12 07:31:32 UTC

[submarine] branch master updated: SUBMARINE-616. Deploying Traefik as Ingress controller in Submarine

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

liuxun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/submarine.git


The following commit(s) were added to refs/heads/master by this push:
     new 81a9ff0  SUBMARINE-616. Deploying Traefik as Ingress controller in Submarine
81a9ff0 is described below

commit 81a9ff04dedc4dde7c07d8846a788b0a5c8ed779
Author: Ryan Lo <lo...@gmail.com>
AuthorDate: Sun Sep 6 13:09:06 2020 +0800

    SUBMARINE-616. Deploying Traefik as Ingress controller in Submarine
    
    ### What is this PR for?
    1. Declaring traefik-helm-chart as a dependency(subchart). And  it should be optional.
    2. Add an Ingress object to route to submarine-server service and using NodePort (port 32080/TCP) to expose.
    
    After installing Submarine with helm, users can directly access submarine-workbench from your browser.
    If users dont want to use Traefik as default ingress controller, they can modify the value ".Value.submarine.traefik.enabled"
    
    ### What type of PR is it?
    [Feature]
    
    ### Todos
    * [ ] - Task
    
    ### What is the Jira issue?
    [SUBMARINE-616](https://issues.apache.org/jira/projects/SUBMARINE/issues/SUBMARINE-616)
    
    ### How should this be tested?
    [Travis CI](https://travis-ci.org/github/lowc1012/submarine/builds/724193208)
    
    ### Screenshots (if appropriate)
    <img width="883" alt="image1" src="https://user-images.githubusercontent.com/52355146/92350220-e6a8a380-f10a-11ea-88d3-02cc17a8de86.png">
    
    <img width="1228" alt="image2" src="https://user-images.githubusercontent.com/52355146/92350234-f32cfc00-f10a-11ea-83e3-424fc6b90ec5.png">
    
    ### Questions:
    * Does the licenses files need update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    Author: Ryan Lo <lo...@gmail.com>
    
    Closes #393 from lowc1012/SUBMARINE-616 and squashes the following commits:
    
    7629eaa [Ryan Lo] SUBMARINE-616. Update helm.md
    876d4cc [Ryan Lo] SUBMARINE-616. Update docs/userdocs/k8s/helm.md
    79e46c5 [Ryan Lo] SUBMARINE-616. Change kind-config path and rename files
    df45f5c [Ryan Lo] SUBMARINE-616. Deploying Traefik as Ingress controller in Submarine on k8s
---
 .github/workflows/python.yml                       |  23 ++
 docs/userdocs/k8s/helm.md                          |  33 +-
 helm-charts/submarine/Chart.yaml                   |  11 +-
 .../{Chart.yaml => charts/traefik/.helmignore}     |  30 +-
 .../submarine/{ => charts/traefik}/Chart.yaml      |  18 +-
 .../traefik/crds/ingressroute-tcp.yaml}            |  19 +-
 .../traefik/crds/ingressroute-udp.yaml}            |  18 +-
 .../traefik/crds/ingressroute.yaml}                |  19 +-
 .../traefik/crds/middlewares.yaml}                 |  19 +-
 .../traefik/crds/tls-options.yaml}                 |  19 +-
 .../traefik/crds/tls-stores.yaml}                  |  18 +-
 .../traefik/crds/traefik-services.yaml}            |  19 +-
 .../charts/traefik/templates/_helpers.tpl          |  71 +++++
 .../templates/dashboard-hook-ingressroute.yaml     |  45 +++
 .../charts/traefik/templates/deployment.yaml       | 260 ++++++++++++++++
 .../traefik/templates/hpa.yaml}                    |  27 +-
 .../traefik/templates/pod-disruption-budget.yaml   |  39 +++
 .../submarine/charts/traefik/templates/pvc.yaml    |  42 +++
 .../templates/rbac/cluster-role-binding.yaml}      |  27 +-
 .../traefik/templates/rbac/cluster-role.yaml       |  66 ++++
 .../traefik/templates/rbac/role-binding.yaml}      |  27 +-
 .../charts/traefik/templates/rbac/role.yaml        |  66 ++++
 .../traefik/templates/rbac/service-account.yaml}   |  23 +-
 .../charts/traefik/templates/service.yaml          | 126 ++++++++
 helm-charts/submarine/charts/traefik/values.yaml   | 336 +++++++++++++++++++++
 .../submarine/templates/submarine-ingress.yaml     |  16 +
 helm-charts/submarine/values.yaml                  |   3 +-
 27 files changed, 1322 insertions(+), 98 deletions(-)

diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml
index 636a726..caecb1b 100644
--- a/.github/workflows/python.yml
+++ b/.github/workflows/python.yml
@@ -40,10 +40,33 @@ jobs:
     timeout-minutes: 120
     steps:
       - uses: actions/checkout@v1
+      - name: Create the kind config
+        run: |
+          cat <<EOF > ./kind-config-kind.yaml
+          kind: Cluster
+          apiVersion: kind.x-k8s.io/v1alpha4
+          nodes:
+          - role: control-plane
+            kubeadmConfigPatches:
+            - |
+              kind: InitConfiguration
+              nodeRegistration:
+                kubeletExtraArgs:
+                  node-labels: "ingress-ready=true"
+                  authorization-mode: "AlwaysAllow"
+            extraPortMappings:
+            - containerPort: 32080
+              hostPort: 80
+              protocol: TCP
+            - containerPort: 443
+              hostPort: 443
+              protocol: TCP
+          EOF
       - uses: engineerd/setup-kind@v0.4.0
         with:
           version: "v0.7.0"
           image: kindest/node:v1.15.6
+          config: ./kind-config-kind.yaml
       - name: Show K8s cluster information
         run: |
           kubectl cluster-info
diff --git a/docs/userdocs/k8s/helm.md b/docs/userdocs/k8s/helm.md
index aab95e0..acf795b 100644
--- a/docs/userdocs/k8s/helm.md
+++ b/docs/userdocs/k8s/helm.md
@@ -22,7 +22,9 @@ under the License.
 
 ## Deploy Submarine Using Helm Chart (Recommended)
 
-Submarine's Helm Chart will not only deploy Submarine Server, but also deploys TF Operator / PyTorch Operator (which will be used by Submarine Server to run TF/PyTorch jobs on K8s).
+Submarine's Helm Chart will deploy Submarine Server, TF/PyTorch Operator, Notebook controller
+and Traefik. We use the TF/PyTorch operator to run tf/pytorch job, the notebook controller to
+manage jupyter notebook and Traefik as reverse-proxy.
 
 
 ### Install Helm
@@ -72,15 +74,36 @@ notebook-controller-deployment-5db8b6cbf7-k65jm   1/1     Running   0          5
 pytorch-operator-7ff5d96d59-gx7f5                 1/1     Running   0          5s
 submarine-database-8d95d74f7-ntvqp                1/1     Running   0          5s
 submarine-server-b6cd4787b-7bvr7                  1/1     Running   0          5s
+submarine-traefik-9bb6f8577-66sx6                 1/1     Running   0          5s
 tf-job-operator-7844656dd-lfgmd                   1/1     Running   0          5s
 ```
 
-### Enable local access to Submarine Server
-Submarine server by default expose 8080 port within K8s cluster.
-To access the server from outside of the cluster, we need to expose the service.
-We can either use port-forward, or use K8s `Ingress`, here is an example of port-forward.
+### Access to Submarine Server
+Submarine server by default expose 8080 port within K8s cluster. After Submarine v0.5
+uses Traefik as reverse-proxy by default. If you don't want to
+use Traefik, you can modify below value to ***false*** in `./helm-charts/submarine/values.yaml`.
+```yaml
+# Use Traefik by default
+traefik:
+  enabled: true
+```
+
+To access the server from outside of the cluster, we use Traefik ingress controller and
+NodePort for external access.\
+Please refer to `./helm-charts/submarine/charts/traefik/values.yaml` and [Traefik docs](https://docs.traefik.io/)
+for more details if you want to customize the default value for Traefik.
+
+```
+# Use nodePort and Traefik ingress controller by default.
+# To access the submarine server, open the following URL in your browser.
+http://127.0.0.1:32080
+```
+
+Or you can use port-forward to forward a local port to a port on the
+submarine server pod.
 
 ```bash
+# Use port-forward
 kubectl port-forward svc/submarine-server 8080:8080
 
 # In another terminal. Run below command to verify it works
diff --git a/helm-charts/submarine/Chart.yaml b/helm-charts/submarine/Chart.yaml
index 40aaa43..9e40ebf 100644
--- a/helm-charts/submarine/Chart.yaml
+++ b/helm-charts/submarine/Chart.yaml
@@ -21,4 +21,13 @@ description: Submarine is Cloud Native Machine Learning Platform.
 name: submarine
 version: 0.5.0-SNAPSHOT
 icon: https://submarine.apache.org/assets/themes/submarine/img/submarine_white_logo.png
-
+dependencies:
+- name: tfjob
+  version: "0.1.0"
+- name: pytorchjob
+  version: "0.1.0"
+- name: notebook-controller
+  version: "0.1.0"
+- name: traefik
+  version: "9.1.0"
+  condition: submarine.traefik.enabled
diff --git a/helm-charts/submarine/Chart.yaml b/helm-charts/submarine/charts/traefik/.helmignore
similarity index 69%
copy from helm-charts/submarine/Chart.yaml
copy to helm-charts/submarine/charts/traefik/.helmignore
index 40aaa43..cab781a 100644
--- a/helm-charts/submarine/Chart.yaml
+++ b/helm-charts/submarine/charts/traefik/.helmignore
@@ -15,10 +15,26 @@
 # limitations under the License.
 #
 
-apiVersion: v2
-appVersion: "0.5.0-SNAPSHOT"
-description: Submarine is Cloud Native Machine Learning Platform.
-name: submarine
-version: 0.5.0-SNAPSHOT
-icon: https://submarine.apache.org/assets/themes/submarine/img/submarine_white_logo.png
-
+# 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
+*.orig
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/
diff --git a/helm-charts/submarine/Chart.yaml b/helm-charts/submarine/charts/traefik/Chart.yaml
similarity index 70%
copy from helm-charts/submarine/Chart.yaml
copy to helm-charts/submarine/charts/traefik/Chart.yaml
index 40aaa43..5ec6bc5 100644
--- a/helm-charts/submarine/Chart.yaml
+++ b/helm-charts/submarine/charts/traefik/Chart.yaml
@@ -16,9 +16,15 @@
 #
 
 apiVersion: v2
-appVersion: "0.5.0-SNAPSHOT"
-description: Submarine is Cloud Native Machine Learning Platform.
-name: submarine
-version: 0.5.0-SNAPSHOT
-icon: https://submarine.apache.org/assets/themes/submarine/img/submarine_white_logo.png
-
+name: traefik
+description: A Traefik based Kubernetes ingress controller
+type: application
+version: 9.1.0
+appVersion: 2.2.8
+keywords:
+  - traefik
+  - ingress
+home: https://traefik.io/
+sources:
+  - https://github.com/containous/traefik
+icon: https://raw.githubusercontent.com/containous/traefik/v2.2/docs/content/assets/img/traefik.logo.png
diff --git a/helm-charts/submarine/Chart.yaml b/helm-charts/submarine/charts/traefik/crds/ingressroute-tcp.yaml
similarity index 72%
copy from helm-charts/submarine/Chart.yaml
copy to helm-charts/submarine/charts/traefik/crds/ingressroute-tcp.yaml
index 40aaa43..7dbacea 100644
--- a/helm-charts/submarine/Chart.yaml
+++ b/helm-charts/submarine/charts/traefik/crds/ingressroute-tcp.yaml
@@ -15,10 +15,15 @@
 # limitations under the License.
 #
 
-apiVersion: v2
-appVersion: "0.5.0-SNAPSHOT"
-description: Submarine is Cloud Native Machine Learning Platform.
-name: submarine
-version: 0.5.0-SNAPSHOT
-icon: https://submarine.apache.org/assets/themes/submarine/img/submarine_white_logo.png
-
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: ingressroutetcps.traefik.containo.us
+spec:
+  group: traefik.containo.us
+  version: v1alpha1
+  names:
+    kind: IngressRouteTCP
+    plural: ingressroutetcps
+    singular: ingressroutetcp
+  scope: Namespaced
diff --git a/helm-charts/submarine/Chart.yaml b/helm-charts/submarine/charts/traefik/crds/ingressroute-udp.yaml
similarity index 72%
copy from helm-charts/submarine/Chart.yaml
copy to helm-charts/submarine/charts/traefik/crds/ingressroute-udp.yaml
index 40aaa43..4efa15d 100644
--- a/helm-charts/submarine/Chart.yaml
+++ b/helm-charts/submarine/charts/traefik/crds/ingressroute-udp.yaml
@@ -15,10 +15,16 @@
 # limitations under the License.
 #
 
-apiVersion: v2
-appVersion: "0.5.0-SNAPSHOT"
-description: Submarine is Cloud Native Machine Learning Platform.
-name: submarine
-version: 0.5.0-SNAPSHOT
-icon: https://submarine.apache.org/assets/themes/submarine/img/submarine_white_logo.png
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: ingressrouteudps.traefik.containo.us
 
+spec:
+  group: traefik.containo.us
+  version: v1alpha1
+  names:
+    kind: IngressRouteUDP
+    plural: ingressrouteudps
+    singular: ingressrouteudp
+  scope: Namespaced
diff --git a/helm-charts/submarine/Chart.yaml b/helm-charts/submarine/charts/traefik/crds/ingressroute.yaml
similarity index 73%
copy from helm-charts/submarine/Chart.yaml
copy to helm-charts/submarine/charts/traefik/crds/ingressroute.yaml
index 40aaa43..d42e457 100644
--- a/helm-charts/submarine/Chart.yaml
+++ b/helm-charts/submarine/charts/traefik/crds/ingressroute.yaml
@@ -15,10 +15,15 @@
 # limitations under the License.
 #
 
-apiVersion: v2
-appVersion: "0.5.0-SNAPSHOT"
-description: Submarine is Cloud Native Machine Learning Platform.
-name: submarine
-version: 0.5.0-SNAPSHOT
-icon: https://submarine.apache.org/assets/themes/submarine/img/submarine_white_logo.png
-
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: ingressroutes.traefik.containo.us
+spec:
+  group: traefik.containo.us
+  version: v1alpha1
+  names:
+    kind: IngressRoute
+    plural: ingressroutes
+    singular: ingressroute
+  scope: Namespaced
diff --git a/helm-charts/submarine/Chart.yaml b/helm-charts/submarine/charts/traefik/crds/middlewares.yaml
similarity index 73%
copy from helm-charts/submarine/Chart.yaml
copy to helm-charts/submarine/charts/traefik/crds/middlewares.yaml
index 40aaa43..8b19370 100644
--- a/helm-charts/submarine/Chart.yaml
+++ b/helm-charts/submarine/charts/traefik/crds/middlewares.yaml
@@ -15,10 +15,15 @@
 # limitations under the License.
 #
 
-apiVersion: v2
-appVersion: "0.5.0-SNAPSHOT"
-description: Submarine is Cloud Native Machine Learning Platform.
-name: submarine
-version: 0.5.0-SNAPSHOT
-icon: https://submarine.apache.org/assets/themes/submarine/img/submarine_white_logo.png
-
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: middlewares.traefik.containo.us
+spec:
+  group: traefik.containo.us
+  version: v1alpha1
+  names:
+    kind: Middleware
+    plural: middlewares
+    singular: middleware
+  scope: Namespaced
diff --git a/helm-charts/submarine/Chart.yaml b/helm-charts/submarine/charts/traefik/crds/tls-options.yaml
similarity index 74%
copy from helm-charts/submarine/Chart.yaml
copy to helm-charts/submarine/charts/traefik/crds/tls-options.yaml
index 40aaa43..4bc2697 100644
--- a/helm-charts/submarine/Chart.yaml
+++ b/helm-charts/submarine/charts/traefik/crds/tls-options.yaml
@@ -15,10 +15,15 @@
 # limitations under the License.
 #
 
-apiVersion: v2
-appVersion: "0.5.0-SNAPSHOT"
-description: Submarine is Cloud Native Machine Learning Platform.
-name: submarine
-version: 0.5.0-SNAPSHOT
-icon: https://submarine.apache.org/assets/themes/submarine/img/submarine_white_logo.png
-
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: tlsoptions.traefik.containo.us
+spec:
+  group: traefik.containo.us
+  version: v1alpha1
+  names:
+    kind: TLSOption
+    plural: tlsoptions
+    singular: tlsoption
+  scope: Namespaced
diff --git a/helm-charts/submarine/Chart.yaml b/helm-charts/submarine/charts/traefik/crds/tls-stores.yaml
similarity index 74%
copy from helm-charts/submarine/Chart.yaml
copy to helm-charts/submarine/charts/traefik/crds/tls-stores.yaml
index 40aaa43..7283454 100644
--- a/helm-charts/submarine/Chart.yaml
+++ b/helm-charts/submarine/charts/traefik/crds/tls-stores.yaml
@@ -15,10 +15,16 @@
 # limitations under the License.
 #
 
-apiVersion: v2
-appVersion: "0.5.0-SNAPSHOT"
-description: Submarine is Cloud Native Machine Learning Platform.
-name: submarine
-version: 0.5.0-SNAPSHOT
-icon: https://submarine.apache.org/assets/themes/submarine/img/submarine_white_logo.png
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: tlsstores.traefik.containo.us
 
+spec:
+  group: traefik.containo.us
+  version: v1alpha1
+  names:
+    kind: TLSStore
+    plural: tlsstores
+    singular: tlsstore
+  scope: Namespaced
diff --git a/helm-charts/submarine/Chart.yaml b/helm-charts/submarine/charts/traefik/crds/traefik-services.yaml
similarity index 72%
copy from helm-charts/submarine/Chart.yaml
copy to helm-charts/submarine/charts/traefik/crds/traefik-services.yaml
index 40aaa43..7eb8ab9 100644
--- a/helm-charts/submarine/Chart.yaml
+++ b/helm-charts/submarine/charts/traefik/crds/traefik-services.yaml
@@ -15,10 +15,15 @@
 # limitations under the License.
 #
 
-apiVersion: v2
-appVersion: "0.5.0-SNAPSHOT"
-description: Submarine is Cloud Native Machine Learning Platform.
-name: submarine
-version: 0.5.0-SNAPSHOT
-icon: https://submarine.apache.org/assets/themes/submarine/img/submarine_white_logo.png
-
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: traefikservices.traefik.containo.us
+spec:
+  group: traefik.containo.us
+  version: v1alpha1
+  names:
+    kind: TraefikService
+    plural: traefikservices
+    singular: traefikservice
+  scope: Namespaced
diff --git a/helm-charts/submarine/charts/traefik/templates/_helpers.tpl b/helm-charts/submarine/charts/traefik/templates/_helpers.tpl
new file mode 100644
index 0000000..d599823
--- /dev/null
+++ b/helm-charts/submarine/charts/traefik/templates/_helpers.tpl
@@ -0,0 +1,71 @@
+{{/*
+#
+# 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 "traefik.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "traefik.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | 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 "traefik.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 -}}
+
+{{/*
+The name of the service account to use
+*/}}
+{{- define "traefik.serviceAccountName" -}}
+{{- default (include "traefik.fullname" .) .Values.serviceAccount.name -}}
+{{- end -}}
+
+{{/*
+Construct the path for the providers.kubernetesingress.ingressendpoint.publishedservice.
+By convention this will simply use the <namespace>/<service-name> to match the name of the
+service generated.
+Users can provide an override for an explicit service they want bound via `.Values.providers.kubernetesIngress.publishedService.pathOverride`
+*/}}
+{{- define "providers.kubernetesIngress.publishedServicePath" -}}
+{{- $defServiceName := printf "%s/%s" .Release.Namespace (include "traefik.fullname" .) -}}
+{{- $servicePath := default $defServiceName .Values.providers.kubernetesIngress.publishedService.pathOverride }}
+{{- print $servicePath | trimSuffix "-" -}}
+{{- end -}}
diff --git a/helm-charts/submarine/charts/traefik/templates/dashboard-hook-ingressroute.yaml b/helm-charts/submarine/charts/traefik/templates/dashboard-hook-ingressroute.yaml
new file mode 100644
index 0000000..9565b93
--- /dev/null
+++ b/helm-charts/submarine/charts/traefik/templates/dashboard-hook-ingressroute.yaml
@@ -0,0 +1,45 @@
+#
+# 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.ingressRoute.dashboard.enabled -}}
+apiVersion: traefik.containo.us/v1alpha1
+kind: IngressRoute
+metadata:
+  name: {{ template "traefik.fullname" . }}-dashboard
+  annotations:
+    helm.sh/hook: "post-install,post-upgrade"
+    {{- with .Values.ingressRoute.dashboard.annotations }}
+    {{- toYaml . | nindent 4 }}
+    {{- end }}
+  labels:
+    app.kubernetes.io/name: {{ template "traefik.name" . }}
+    helm.sh/chart: {{ template "traefik.chart" . }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+    {{- with .Values.ingressRoute.dashboard.labels }}
+    {{- toYaml . | nindent 4 }}
+    {{- end }}
+spec:
+  entryPoints:
+    - traefik
+  routes:
+  - match: PathPrefix(`/dashboard`) || PathPrefix(`/api`)
+    kind: Rule
+    services:
+    - name: api@internal
+      kind: TraefikService
+{{- end -}}
diff --git a/helm-charts/submarine/charts/traefik/templates/deployment.yaml b/helm-charts/submarine/charts/traefik/templates/deployment.yaml
new file mode 100644
index 0000000..0c6e65d
--- /dev/null
+++ b/helm-charts/submarine/charts/traefik/templates/deployment.yaml
@@ -0,0 +1,260 @@
+#
+# 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.deployment.enabled -}}
+  {{- if gt (int .Values.deployment.replicas) 1 -}}
+    {{- with .Values.additionalArguments -}}
+      {{- range . -}}
+        {{- if contains ".acme." . -}}
+          {{- fail (printf "You can not enabled acme if you set more than one traefik replica") -}}
+        {{- end -}}
+      {{- end -}}
+    {{- end -}}
+  {{- end -}}
+
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ template "traefik.fullname" . }}
+  labels:
+    app.kubernetes.io/name: {{ template "traefik.name" . }}
+    helm.sh/chart: {{ template "traefik.chart" . }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+  annotations:
+  {{- with .Values.deployment.annotations }}
+  {{- toYaml . | nindent 4 }}
+  {{- end }}
+spec:
+  {{- if not .Values.autoscaling.enabled }}
+  replicas: {{ default 1 .Values.deployment.replicas }}
+  {{- end }}
+  selector:
+    matchLabels:
+      app.kubernetes.io/name: {{ template "traefik.name" . }}
+      app.kubernetes.io/instance: {{ .Release.Name }}
+  strategy:
+    type: RollingUpdate
+    rollingUpdate:
+      {{- with .Values.rollingUpdate }}
+        {{- toYaml . | nindent 6 }}
+      {{- end }}
+  template:
+    metadata:
+      annotations:
+      {{- with .Values.deployment.podAnnotations }}
+      {{- toYaml . | nindent 8 }}
+      {{- end }}
+      labels:
+        app.kubernetes.io/name: {{ template "traefik.name" . }}
+        helm.sh/chart: {{ template "traefik.chart" . }}
+        app.kubernetes.io/managed-by: {{ .Release.Service }}
+        app.kubernetes.io/instance: {{ .Release.Name }}
+    spec:
+      serviceAccountName: {{ include "traefik.serviceAccountName" . }}
+      terminationGracePeriodSeconds: 60
+      hostNetwork: {{ .Values.hostNetwork }}
+      {{- with .Values.deployment.dnsPolicy }}
+      dnsPolicy: {{ . }}
+      {{- end }}
+      {{- with .Values.deployment.initContainers }}
+      initContainers:
+      {{- toYaml . | nindent 6 }}
+      {{- end }}
+      containers:
+      - image: {{ .Values.image.name }}:{{ .Values.image.tag }}
+        imagePullPolicy: {{ .Values.image.pullPolicy }}
+        name: {{ template "traefik.fullname" . }}
+        resources:
+          {{- with .Values.resources }}
+          {{- toYaml . | nindent 10 }}
+          {{- end }}
+        readinessProbe:
+          httpGet:
+            path: /ping
+            port: {{ .Values.ports.traefik.port }}
+          failureThreshold: 1
+          initialDelaySeconds: 10
+          periodSeconds: 10
+          successThreshold: 1
+          timeoutSeconds: 2
+        livenessProbe:
+          httpGet:
+            path: /ping
+            port: {{ .Values.ports.traefik.port }}
+          failureThreshold: 3
+          initialDelaySeconds: 10
+          periodSeconds: 10
+          successThreshold: 1
+          timeoutSeconds: 2
+        ports:
+        {{- range $name, $config := .Values.ports }}
+        {{- if $config }}
+        - name: {{ $name | quote }}
+          containerPort: {{ $config.port }}
+          {{- if $config.hostPort }}
+          hostPort: {{ $config.hostPort }}
+          {{- end }}
+          {{- if $config.hostIP }}
+          hostIP: {{ $config.hostIP }}
+          {{- end }}
+          protocol: {{ default "TCP" $config.protocol | quote }}
+        {{- end }}
+        {{- end }}
+        {{- with .Values.securityContext }}
+        securityContext:
+          {{- toYaml . | nindent 10 }}
+        {{- end }}
+        volumeMounts:
+          - name: data
+            mountPath: {{ .Values.persistence.path }}
+            {{- if .Values.persistence.subPath }}
+            subPath: {{ .Values.persistence.subPath }}
+            {{- end }}
+          - name: tmp
+            mountPath: /tmp
+          {{- range .Values.volumes }}
+          - name: {{ .name }}
+            mountPath: {{ .mountPath }}
+            readOnly: true
+          {{- end }}
+        args:
+          {{- with .Values.globalArguments }}
+          {{- range . }}
+          - {{ . | quote }}
+          {{- end }}
+          {{- end }}
+          {{- range $name, $config := .Values.ports }}
+          {{- if $config }}
+          - "--entryPoints.{{$name}}.address=:{{ $config.port }}/{{ default "tcp" $config.protocol | lower }}"
+          {{- end }}
+          {{- end }}
+          - "--api.dashboard=true"
+          - "--ping=true"
+          {{- if .Values.providers.kubernetesCRD.enabled }}
+          - "--providers.kubernetescrd"
+          {{- end }}
+          {{- if .Values.providers.kubernetesIngress.enabled }}
+          - "--providers.kubernetesingress"
+          {{- if and .Values.service.enabled .Values.providers.kubernetesIngress.publishedService.enabled }}
+          - "--providers.kubernetesingress.ingressendpoint.publishedservice={{ template "providers.kubernetesIngress.publishedServicePath" . }}"
+          {{- end }}
+          {{- end }}
+          {{- if and .Values.rbac.enabled .Values.rbac.namespaced }}
+          - "--providers.kubernetescrd.namespaces={{ .Release.Namespace }}"
+          - "--providers.kubernetesingress.namespaces={{ .Release.Namespace }}"
+          {{- end }}
+          {{- range $entrypoint, $config := $.Values.ports }}
+          {{- if $config.redirectTo }}
+          {{- $toPort := index $.Values.ports $config.redirectTo }}
+          - "--entrypoints.{{ $entrypoint }}.http.redirections.entryPoint.to=:{{ $toPort.exposedPort }}"
+          - "--entrypoints.{{ $entrypoint }}.http.redirections.entryPoint.scheme=https"
+          {{- end }}
+          {{- end }}
+          {{- with .Values.logs }}
+          {{- if .general.format }}
+          - "--log.format={{ .general.format }}"
+          {{- end }}
+          {{- if ne .general.level "ERROR" }}
+          - "--log.level={{ .general.level | upper }}"
+          {{- end }}
+          {{- if .access.enabled }}
+          - "--accesslog=true"
+          {{- if .access.format }}
+          - "--accesslog.format={{ .access.format }}"
+          {{- end }}
+          {{- if .access.bufferingsize }}
+          - "--accesslog.bufferingsize={{ .access.bufferingsize }}"
+          {{- end }}
+          {{- if .access.filters }}
+          {{- if .access.filters.statuscodes }}
+          - "--accesslog.filters.statuscodes={{ .access.filters.statuscodes }}"
+          {{- end }}
+          {{- if .access.filters.retryattempts }}
+          - "--accesslog.filters.retryattempts"
+          {{- end }}
+          {{- if .access.filters.minduration }}
+          - "--accesslog.filters.minduration={{ .access.filters.minduration }}"
+          {{- end }}
+          {{- end }}
+          - "--accesslog.fields.defaultmode={{ .access.fields.general.defaultmode }}"
+          {{- range $fieldname, $fieldaction := .access.fields.general.names }}
+          - "--accesslog.fields.names.{{ $fieldname }}={{ $fieldaction }}"
+          {{- end }}
+          - "--accesslog.fields.headers.defaultmode={{ .access.fields.headers.defaultmode }}"
+          {{- range $fieldname, $fieldaction := .access.fields.headers.names }}
+          - "--accesslog.fields.headers.names.{{ $fieldname }}={{ $fieldaction }}"
+          {{- end }}
+          {{- end }}
+          {{- end }}
+          {{- with .Values.additionalArguments }}
+          {{- range . }}
+          - {{ . | quote }}
+          {{- end }}
+          {{- end }}
+        {{- with .Values.env }}
+        env:
+          {{- toYaml . | nindent 10 }}
+        {{- end }}
+        {{- with .Values.envFrom }}
+        envFrom:
+          {{- toYaml . | nindent 10 }}
+        {{- end }}
+      {{- if .Values.deployment.additionalContainers }}
+        {{- toYaml .Values.deployment.additionalContainers | nindent 6 }}
+      {{- end }}
+      volumes:
+        - name: data
+          {{- if .Values.persistence.enabled }}
+          persistentVolumeClaim:
+            claimName: {{ default (include "traefik.fullname" .) .Values.persistence.existingClaim }}
+          {{- else }}
+          emptyDir: {}
+          {{- end }}
+        - name: tmp
+          emptyDir: {}
+        {{- range .Values.volumes }}
+        - name: {{ .name }}
+          {{- if eq .type "secret" }}
+          secret:
+            secretName: {{ .name }}
+          {{- else if eq .type "configMap" }}
+          configMap:
+            name: {{ .name }}
+          {{- end }}
+        {{- end }}
+      {{- with .Values.affinity }}
+      affinity:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.tolerations }}
+      tolerations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.nodeSelector }}
+      nodeSelector:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- if .Values.priorityClassName }}
+      priorityClassName: {{ .Values.priorityClassName }}
+      {{- end }}
+      {{- with .Values.podSecurityContext }}
+      securityContext:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+{{- end -}}
diff --git a/helm-charts/submarine/Chart.yaml b/helm-charts/submarine/charts/traefik/templates/hpa.yaml
similarity index 53%
copy from helm-charts/submarine/Chart.yaml
copy to helm-charts/submarine/charts/traefik/templates/hpa.yaml
index 40aaa43..9ecdd16 100644
--- a/helm-charts/submarine/Chart.yaml
+++ b/helm-charts/submarine/charts/traefik/templates/hpa.yaml
@@ -15,10 +15,23 @@
 # limitations under the License.
 #
 
-apiVersion: v2
-appVersion: "0.5.0-SNAPSHOT"
-description: Submarine is Cloud Native Machine Learning Platform.
-name: submarine
-version: 0.5.0-SNAPSHOT
-icon: https://submarine.apache.org/assets/themes/submarine/img/submarine_white_logo.png
-
+{{- if .Values.autoscaling.enabled }}
+apiVersion: autoscaling/v2beta1
+kind: HorizontalPodAutoscaler
+metadata:
+  name: {{ template "traefik.fullname" . }}
+  labels:
+    app.kubernetes.io/name: {{ template "traefik.name" . }}
+    helm.sh/chart: {{ template "traefik.chart" . }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+spec:
+  scaleTargetRef:
+    apiVersion: apps/v1
+    kind: Deployment
+    name: {{ template "traefik.fullname" . }}
+  minReplicas: {{ .Values.autoscaling.minReplicas }}
+  maxReplicas: {{ .Values.autoscaling.maxReplicas }}
+  metrics:
+{{ toYaml .Values.autoscaling.metrics | indent 4 }}
+{{- end }}
diff --git a/helm-charts/submarine/charts/traefik/templates/pod-disruption-budget.yaml b/helm-charts/submarine/charts/traefik/templates/pod-disruption-budget.yaml
new file mode 100644
index 0000000..aa460e9
--- /dev/null
+++ b/helm-charts/submarine/charts/traefik/templates/pod-disruption-budget.yaml
@@ -0,0 +1,39 @@
+#
+# 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.podDisruptionBudget.enabled -}}
+apiVersion: policy/v1beta1
+kind: PodDisruptionBudget
+metadata:
+  name: {{ template "traefik.fullname" . }}
+  labels:
+    app.kubernetes.io/name: {{ template "traefik.name" . }}
+    helm.sh/chart: {{ template "traefik.chart" . }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+spec:
+  selector:
+    matchLabels:
+      app.kubernetes.io/name: {{ template "traefik.name" . }}
+      app.kubernetes.io/instance: {{ .Release.Name }}
+  {{- if .Values.podDisruptionBudget.minAvailable }}
+  minAvailable: {{ .Values.podDisruptionBudget.minAvailable | int }}
+  {{- end }}
+  {{- if .Values.podDisruptionBudget.maxUnavailable }}
+  maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable | int }}
+  {{- end }}
+{{- end -}}
diff --git a/helm-charts/submarine/charts/traefik/templates/pvc.yaml b/helm-charts/submarine/charts/traefik/templates/pvc.yaml
new file mode 100644
index 0000000..0993ea1
--- /dev/null
+++ b/helm-charts/submarine/charts/traefik/templates/pvc.yaml
@@ -0,0 +1,42 @@
+#
+# 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 and .Values.persistence.enabled (not .Values.persistence.existingClaim) -}}
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  name: {{ template "traefik.fullname" . }}
+  annotations:
+  {{- with .Values.persistence.annotations  }}
+  {{ toYaml . | indent 4 }}
+  {{- end }}
+  labels:
+    app.kubernetes.io/name: {{ template "traefik.name" . }}
+    helm.sh/chart: {{ template "traefik.chart" . }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+spec:
+  accessModes:
+    - {{ .Values.persistence.accessMode | quote }}
+  resources:
+    requests:
+      storage: {{ .Values.persistence.size | quote }}
+  {{- if .Values.persistence.storageClass }}
+  storageClassName: {{ .Values.persistence.storageClass | quote }}
+  {{- end }}
+{{- end -}}
+
diff --git a/helm-charts/submarine/Chart.yaml b/helm-charts/submarine/charts/traefik/templates/rbac/cluster-role-binding.yaml
similarity index 54%
copy from helm-charts/submarine/Chart.yaml
copy to helm-charts/submarine/charts/traefik/templates/rbac/cluster-role-binding.yaml
index 40aaa43..d1c5c95 100644
--- a/helm-charts/submarine/Chart.yaml
+++ b/helm-charts/submarine/charts/traefik/templates/rbac/cluster-role-binding.yaml
@@ -1,3 +1,4 @@
+{{- if and .Values.rbac.enabled (not .Values.rbac.namespaced) }}
 #
 # Licensed to the Apache Software Foundation (ASF) under one or more
 # contributor license agreements.  See the NOTICE file distributed with
@@ -14,11 +15,21 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-
-apiVersion: v2
-appVersion: "0.5.0-SNAPSHOT"
-description: Submarine is Cloud Native Machine Learning Platform.
-name: submarine
-version: 0.5.0-SNAPSHOT
-icon: https://submarine.apache.org/assets/themes/submarine/img/submarine_white_logo.png
-
+kind: ClusterRoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: {{ template "traefik.fullname" . }}
+  labels:
+    app.kubernetes.io/name: {{ template "traefik.name" . }}
+    helm.sh/chart: {{ template "traefik.chart" . }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: {{ template "traefik.fullname" . }}
+subjects:
+  - kind: ServiceAccount
+    name: {{ include "traefik.serviceAccountName" . }}
+    namespace: {{ .Release.Namespace }}
+{{- end -}}
diff --git a/helm-charts/submarine/charts/traefik/templates/rbac/cluster-role.yaml b/helm-charts/submarine/charts/traefik/templates/rbac/cluster-role.yaml
new file mode 100644
index 0000000..191c9ec
--- /dev/null
+++ b/helm-charts/submarine/charts/traefik/templates/rbac/cluster-role.yaml
@@ -0,0 +1,66 @@
+{{- if and .Values.rbac.enabled (not .Values.rbac.namespaced) -}}
+#
+# 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.
+#
+kind: ClusterRole
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: {{ template "traefik.fullname" . }}
+  labels:
+    app.kubernetes.io/name: {{ template "traefik.name" . }}
+    helm.sh/chart: {{ template "traefik.chart" . }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+rules:
+  - apiGroups:
+      - ""
+    resources:
+      - services
+      - endpoints
+      - secrets
+    verbs:
+      - get
+      - list
+      - watch
+  - apiGroups:
+      - extensions
+    resources:
+      - ingresses
+    verbs:
+      - get
+      - list
+      - watch
+  - apiGroups:
+      - extensions
+    resources:
+      - ingresses/status
+    verbs:
+      - update
+  - apiGroups:
+      - traefik.containo.us
+    resources:
+      - ingressroutes
+      - ingressroutetcps
+      - ingressrouteudps
+      - middlewares
+      - tlsoptions
+      - tlsstores
+      - traefikservices
+    verbs:
+      - get
+      - list
+      - watch
+{{- end -}}
diff --git a/helm-charts/submarine/Chart.yaml b/helm-charts/submarine/charts/traefik/templates/rbac/role-binding.yaml
similarity index 54%
copy from helm-charts/submarine/Chart.yaml
copy to helm-charts/submarine/charts/traefik/templates/rbac/role-binding.yaml
index 40aaa43..d3d6996 100644
--- a/helm-charts/submarine/Chart.yaml
+++ b/helm-charts/submarine/charts/traefik/templates/rbac/role-binding.yaml
@@ -1,3 +1,4 @@
+{{- if and .Values.rbac.enabled .Values.rbac.namespaced }}
 #
 # Licensed to the Apache Software Foundation (ASF) under one or more
 # contributor license agreements.  See the NOTICE file distributed with
@@ -14,11 +15,21 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-
-apiVersion: v2
-appVersion: "0.5.0-SNAPSHOT"
-description: Submarine is Cloud Native Machine Learning Platform.
-name: submarine
-version: 0.5.0-SNAPSHOT
-icon: https://submarine.apache.org/assets/themes/submarine/img/submarine_white_logo.png
-
+kind: RoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: {{ template "traefik.fullname" . }}
+  labels:
+    app.kubernetes.io/name: {{ template "traefik.name" . }}
+    helm.sh/chart: {{ template "traefik.chart" . }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: {{ template "traefik.fullname" . }}
+subjects:
+  - kind: ServiceAccount
+    name: {{ include "traefik.serviceAccountName" . }}
+    namespace: {{ .Release.Namespace }}
+{{- end -}}
diff --git a/helm-charts/submarine/charts/traefik/templates/rbac/role.yaml b/helm-charts/submarine/charts/traefik/templates/rbac/role.yaml
new file mode 100644
index 0000000..c0775f4
--- /dev/null
+++ b/helm-charts/submarine/charts/traefik/templates/rbac/role.yaml
@@ -0,0 +1,66 @@
+{{- if and .Values.rbac.enabled .Values.rbac.namespaced }}
+#
+# 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.
+#
+kind: Role
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: {{ template "traefik.fullname" . }}
+  labels:
+    app.kubernetes.io/name: {{ template "traefik.name" . }}
+    helm.sh/chart: {{ template "traefik.chart" . }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+rules:
+  - apiGroups:
+      - ""
+    resources:
+      - services
+      - endpoints
+      - secrets
+    verbs:
+      - get
+      - list
+      - watch
+  - apiGroups:
+      - extensions
+    resources:
+      - ingresses
+    verbs:
+      - get
+      - list
+      - watch
+  - apiGroups:
+      - extensions
+    resources:
+      - ingresses/status
+    verbs:
+      - update
+  - apiGroups:
+      - traefik.containo.us
+    resources:
+      - ingressroutes
+      - ingressroutetcps
+      - ingressrouteudps
+      - middlewares
+      - tlsoptions
+      - tlsstores
+      - traefikservices
+    verbs:
+      - get
+      - list
+      - watch
+{{- end -}}
diff --git a/helm-charts/submarine/Chart.yaml b/helm-charts/submarine/charts/traefik/templates/rbac/service-account.yaml
similarity index 61%
copy from helm-charts/submarine/Chart.yaml
copy to helm-charts/submarine/charts/traefik/templates/rbac/service-account.yaml
index 40aaa43..1df7115 100644
--- a/helm-charts/submarine/Chart.yaml
+++ b/helm-charts/submarine/charts/traefik/templates/rbac/service-account.yaml
@@ -1,3 +1,4 @@
+{{- if not .Values.serviceAccount.name -}}
 #
 # Licensed to the Apache Software Foundation (ASF) under one or more
 # contributor license agreements.  See the NOTICE file distributed with
@@ -14,11 +15,17 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-
-apiVersion: v2
-appVersion: "0.5.0-SNAPSHOT"
-description: Submarine is Cloud Native Machine Learning Platform.
-name: submarine
-version: 0.5.0-SNAPSHOT
-icon: https://submarine.apache.org/assets/themes/submarine/img/submarine_white_logo.png
-
+kind: ServiceAccount
+apiVersion: v1
+metadata:
+  name: {{ include "traefik.serviceAccountName" . }}
+  labels:
+    app.kubernetes.io/name: {{ template "traefik.name" . }}
+    helm.sh/chart: {{ template "traefik.chart" . }}
+    app.kubernetes.io/managed-by: {{ .Release.Service }}
+    app.kubernetes.io/instance: {{ .Release.Name }}
+  annotations:
+  {{- with .Values.serviceAccountAnnotations }}
+  {{- toYaml . | nindent 4 }}
+  {{- end }}
+{{- end -}}
diff --git a/helm-charts/submarine/charts/traefik/templates/service.yaml b/helm-charts/submarine/charts/traefik/templates/service.yaml
new file mode 100644
index 0000000..40972e4
--- /dev/null
+++ b/helm-charts/submarine/charts/traefik/templates/service.yaml
@@ -0,0 +1,126 @@
+#
+# 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.service.enabled -}}
+
+{{ $tcpPorts := dict }}
+{{ $udpPorts := dict }}
+{{- range $name, $config := .Values.ports }}
+  {{- if eq (toString $config.protocol) "UDP" }}
+    {{ $_ := set $udpPorts $name $config }}
+  {{- else }}
+    {{ $_ := set $tcpPorts $name $config }}
+  {{- end }}
+{{- end }}
+
+apiVersion: v1
+kind: List
+items:
+{{- if  $tcpPorts }}
+  - apiVersion: v1
+    kind: Service
+    metadata:
+      name: {{ template "traefik.fullname" . }}
+      labels:
+        app.kubernetes.io/name: {{ template "traefik.name" . }}
+        helm.sh/chart: {{ template "traefik.chart" . }}
+        app.kubernetes.io/managed-by: {{ .Release.Service }}
+        app.kubernetes.io/instance: {{ .Release.Name }}
+      annotations:
+      {{- with .Values.service.annotations }}
+      {{- toYaml . | nindent 8 }}
+      {{- end }}
+    spec:
+      {{- $type := default "LoadBalancer" .Values.service.type }}
+      type: {{ $type }}
+      {{- with .Values.service.spec }}
+      {{- toYaml . | nindent 6 }}
+      {{- end }}
+      selector:
+        app.kubernetes.io/name: {{ template "traefik.name" . }}
+        app.kubernetes.io/instance: {{ .Release.Name }}
+      ports:
+      {{- range $name, $config := $tcpPorts }}
+      {{- if $config.expose }}
+      - port: {{ default $config.port $config.exposedPort }}
+        name: {{ $name }}
+        targetPort: {{ $name | quote }}
+        protocol: {{ default "TCP" $config.protocol | quote }}
+        {{- if $config.nodePort }}
+        nodePort: {{ $config.nodePort }}
+        {{- end }}
+      {{- end }}
+      {{- end }}
+      {{- if eq $type "LoadBalancer" }}
+      {{- with .Values.service.loadBalancerSourceRanges }}
+      loadBalancerSourceRanges:
+      {{- toYaml . | nindent 6 }}
+      {{- end -}}
+      {{- end -}}
+      {{- with .Values.service.externalIPs }}
+      externalIPs:
+      {{- toYaml . | nindent 6 }}
+      {{- end -}}
+{{- end }}
+
+{{- if  $udpPorts }}
+  - apiVersion: v1
+    kind: Service
+    metadata:
+      name: {{ template "traefik.fullname" . }}-udp
+      labels:
+        app.kubernetes.io/name: {{ template "traefik.name" . }}
+        helm.sh/chart: {{ template "traefik.chart" . }}
+        app.kubernetes.io/managed-by: {{ .Release.Service }}
+        app.kubernetes.io/instance: {{ .Release.Name }}
+      annotations:
+      {{- with .Values.service.annotations }}
+      {{- toYaml . | nindent 8 }}
+      {{- end }}
+    spec:
+      {{- $type := default "LoadBalancer" .Values.service.type }}
+      type: {{ $type }}
+      {{- with .Values.service.spec }}
+      {{- toYaml . | nindent 6 }}
+      {{- end }}
+      selector:
+        app.kubernetes.io/name: {{ template "traefik.name" . }}
+        app.kubernetes.io/instance: {{ .Release.Name }}
+      ports:
+      {{- range $name, $config := $udpPorts }}
+      {{- if $config.expose }}
+      - port: {{ default $config.port $config.exposedPort }}
+        name: {{ $name }}
+        targetPort: {{ $name | quote }}
+        protocol: {{ default "UDP" $config.protocol | quote }}
+        {{- if $config.nodePort }}
+        nodePort: {{ $config.nodePort }}
+        {{- end }}
+      {{- end }}
+      {{- end }}
+      {{- if eq $type "LoadBalancer" }}
+      {{- with .Values.service.loadBalancerSourceRanges }}
+      loadBalancerSourceRanges:
+      {{- toYaml . | nindent 6 }}
+      {{- end -}}
+      {{- end -}}
+      {{- with .Values.service.externalIPs }}
+      externalIPs:
+      {{- toYaml . | nindent 6 }}
+      {{- end -}}
+{{- end }}
+{{- end -}}
diff --git a/helm-charts/submarine/charts/traefik/values.yaml b/helm-charts/submarine/charts/traefik/values.yaml
new file mode 100644
index 0000000..17d164b
--- /dev/null
+++ b/helm-charts/submarine/charts/traefik/values.yaml
@@ -0,0 +1,336 @@
+#
+# 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.
+#
+
+# Default values for Traefik
+image:
+  name: traefik
+  tag: 2.2.8
+  pullPolicy: IfNotPresent
+
+#
+# Configure the deployment
+#
+deployment:
+  enabled: true
+  # Number of pods of the deployment
+  replicas: 1
+  # Additional deployment annotations (e.g. for jaeger-operator sidecar injection)
+  annotations: {}
+  # Additional pod annotations (e.g. for mesh injection or prometheus scraping)
+  podAnnotations: {}
+  # Additional containers (e.g. for metric offloading sidecars)
+  additionalContainers: []
+  # Additional initContainers (e.g. for setting file permission as shown below)
+  initContainers: []
+    # The "volume-permissions" init container is required if you run into permission issues.
+    # Related issue: https://github.com/containous/traefik/issues/6972
+    # - name: volume-permissions
+    #   image: busybox:1.31.1
+    #   command: ["sh", "-c", "chmod -Rv 600 /data/*"]
+    #   volumeMounts:
+    #     - name: data
+    #       mountPath: /data
+  # Custom pod DNS policy. Apply if `hostNetwork: true`
+  # dnsPolicy: ClusterFirstWithHostNet
+
+# Pod disruption budget
+podDisruptionBudget:
+  enabled: false
+  # maxUnavailable: 1
+  # minAvailable: 0
+
+# Create an IngressRoute for the dashboard
+ingressRoute:
+  dashboard:
+    enabled: false
+    # Additional ingressRoute annotations (e.g. for kubernetes.io/ingress.class)
+    annotations: {}
+    # Additional ingressRoute labels (e.g. for filtering IngressRoute by custom labels)
+    labels: {}
+
+rollingUpdate:
+  maxUnavailable: 1
+  maxSurge: 1
+
+
+#
+# Configure providers
+#
+providers:
+  kubernetesCRD:
+    enabled: true
+  kubernetesIngress:
+    enabled: true
+    # IP used for Kubernetes Ingress endpoints
+    publishedService:
+      enabled: false
+      # Published Kubernetes Service to copy status from. Format: namespace/servicename
+      # By default this Traefik service
+      # pathOverride: ""
+
+#
+# Add volumes to the traefik pod.
+# This can be used to mount a cert pair or a configmap that holds a config.toml file.
+# After the volume has been mounted, add the configs into traefik by using the `additionalArguments` list below, eg:
+# additionalArguments:
+# - "--providers.file.filename=/config/dynamic.toml"
+volumes: []
+# - name: public-cert
+#   mountPath: "/certs"
+#   type: secret
+# - name: configs
+#   mountPath: "/config"
+#   type: configMap
+
+# Logs
+# https://docs.traefik.io/observability/logs/
+logs:
+  # Traefik logs concern everything that happens to Traefik itself (startup, configuration, events, shutdown, and so on).
+  general:
+    # By default, the logs use a text format (common), but you can
+    # also ask for the json format in the format option
+    # format: json
+    # By default, the level is set to ERROR. Alternative logging levels are DEBUG, PANIC, FATAL, ERROR, WARN, and INFO.
+    level: ERROR
+  access:
+    # To enable access logs
+    enabled: false
+    # By default, logs are written using the Common Log Format (CLF).
+    # To write logs in JSON, use json in the format option.
+    # If the given format is unsupported, the default (CLF) is used instead.
+    # format: json
+    # To write the logs in an asynchronous fashion, specify a bufferingSize option.
+    # This option represents the number of log lines Traefik will keep in memory before writing
+    # them to the selected output. In some cases, this option can greatly help performances.
+    # bufferingSize: 100
+    # Filtering https://docs.traefik.io/observability/access-logs/#filtering
+    filters: {}
+      # statuscodes: "200,300-302"
+      # retryattempts: true
+      # minduration: 10ms
+    # Fields
+    # https://docs.traefik.io/observability/access-logs/#limiting-the-fieldsincluding-headers
+    fields:
+      general:
+        defaultmode: keep
+        names: {}
+          # Examples:
+          # ClientUsername: drop
+      headers:
+        defaultmode: drop
+        names: {}
+          # Examples:
+          # User-Agent: redact
+          # Authorization: drop
+          # Content-Type: keep
+
+globalArguments:
+  - "--global.checknewversion"
+  - "--global.sendanonymoususage"
+
+#
+# Configure Traefik static configuration
+# Additional arguments to be passed at Traefik's binary
+# All available options available on https://docs.traefik.io/reference/static-configuration/cli/
+## Use curly braces to pass values: `helm install --set="additionalArguments={--providers.kubernetesingress.ingressclass=traefik-internal,--log.level=DEBUG}"`
+additionalArguments: []
+#  - "--providers.kubernetesingress.ingressclass=traefik-internal"
+#  - "--log.level=DEBUG"
+
+# Environment variables to be passed to Traefik's binary
+env: []
+# - name: SOME_VAR
+#   value: some-var-value
+# - name: SOME_VAR_FROM_CONFIG_MAP
+#   valueFrom:
+#     configMapRef:
+#       name: configmap-name
+#       key: config-key
+# - name: SOME_SECRET
+#   valueFrom:
+#     secretKeyRef:
+#       name: secret-name
+#       key: secret-key
+
+envFrom: []
+# - configMapRef:
+#     name: config-map-name
+# - secretRef:
+#     name: secret-name
+
+# Configure ports
+ports:
+  # The name of this one can't be changed as it is used for the readiness and
+  # liveness probes, but you can adjust its config to your liking
+  traefik:
+    port: 9000
+    # Use hostPort if set.
+    # hostPort: 9000
+    #
+    # Use hostIP if set. If not set, Kubernetes will default to 0.0.0.0, which
+    # means it's listening on all your interfaces and all your IPs. You may want
+    # to set this value if you need traefik to listen on specific interface
+    # only.
+    # hostIP: 192.168.100.10
+
+    # Defines whether the port is exposed if service.type is LoadBalancer or
+    # NodePort.
+    #
+    # You SHOULD NOT expose the traefik port on production deployments.
+    # If you want to access it from outside of your cluster,
+    # use `kubectl proxy` or create a secure ingress
+    expose: false
+    # The exposed port for this service
+    exposedPort: 9000
+    # The port protocol (TCP/UDP)
+    protocol: TCP
+  web:
+    port: 8000
+    # hostPort: 8000
+    expose: true
+    exposedPort: 80
+    # The port protocol (TCP/UDP)
+    protocol: TCP
+    # Use nodeport if set. This is useful if you have configured Traefik in a
+    # LoadBalancer
+    nodePort: 32080
+    # Port Redirections
+    # Added in 2.2, you can make permanent redirects via entrypoints.
+    # https://docs.traefik.io/routing/entrypoints/#redirection
+    # redirectTo: websecure
+  websecure:
+    port: 8443
+    # hostPort: 8443
+    expose: true
+    exposedPort: 443
+    # The port protocol (TCP/UDP)
+    protocol: TCP
+    # nodePort: 32443
+
+# Options for the main traefik service, where the entrypoints traffic comes
+# from.
+service:
+  enabled: true
+  type: NodePort
+  # Additional annotations (e.g. for cloud provider specific config)
+  annotations: {}
+  # Additional entries here will be added to the service spec. Cannot contains
+  # type, selector or ports entries.
+  spec: {}
+    # externalTrafficPolicy: Cluster
+    # loadBalancerIP: "1.2.3.4"
+    # clusterIP: "2.3.4.5"
+  loadBalancerSourceRanges: []
+    # - 192.168.0.1/32
+    # - 172.16.0.0/16
+  externalIPs: []
+    # - 1.2.3.4
+
+## Create HorizontalPodAutoscaler object.
+##
+autoscaling:
+  enabled: false
+#   minReplicas: 1
+#   maxReplicas: 10
+#   metrics:
+#   - type: Resource
+#     resource:
+#       name: cpu
+#       targetAverageUtilization: 60
+#   - type: Resource
+#     resource:
+#       name: memory
+#       targetAverageUtilization: 60
+
+# Enable persistence using Persistent Volume Claims
+# ref: http://kubernetes.io/docs/user-guide/persistent-volumes/
+# After the pvc has been mounted, add the configs into traefik by using the `additionalArguments` list below, eg:
+# additionalArguments:
+# - "--certificatesresolvers.le.acme.storage=/data/acme.json"
+# It will persist TLS certificates.
+persistence:
+  enabled: false
+#  existingClaim: ""
+  accessMode: ReadWriteOnce
+  size: 128Mi
+  # storageClass: ""
+  path: /data
+  annotations: {}
+  # subPath: "" # only mount a subpath of the Volume into the pod
+
+# If hostNetwork is true, runs traefik in the host network namespace
+# To prevent unschedulabel pods due to port collisions, if hostNetwork=true
+# and replicas>1, a pod anti-affinity is recommended and will be set if the
+# affinity is left as default.
+hostNetwork: false
+
+# Whether Role Based Access Control objects like roles and rolebindings should be created
+rbac:
+  enabled: true
+
+  # If set to false, installs ClusterRole and ClusterRoleBinding so Traefik can be used across namespaces.
+  # If set to true, installs namespace-specific Role and RoleBinding and requires provider configuration be set to that same namespace
+  namespaced: false
+
+# The service account the pods will use to interact with the Kubernetes API
+serviceAccount:
+  # If set, an existing service account is used
+  # If not set, a service account is created automatically using the fullname template
+  name: ""
+
+# Additional serviceAccount annotations (e.g. for oidc authentication)
+serviceAccountAnnotations: {}
+
+resources: {}
+  # requests:
+  #   cpu: "100m"
+  #   memory: "50Mi"
+  # limits:
+  #   cpu: "300m"
+  #   memory: "150Mi"
+affinity: {}
+# # This example pod anti-affinity forces the scheduler to put traefik pods
+# # on nodes where no other traefik pods are scheduled.
+# # It should be used when hostNetwork: true to prevent port conflicts
+#   podAntiAffinity:
+#     requiredDuringSchedulingIgnoredDuringExecution:
+#     - labelSelector:
+#         matchExpressions:
+#         - key: app
+#           operator: In
+#           values:
+#           - {{ template "traefik.name" . }}
+#       topologyKey: failure-domain.beta.kubernetes.io/zone
+nodeSelector: {}
+tolerations: []
+
+# Pods can have priority.
+# Priority indicates the importance of a Pod relative to other Pods.
+priorityClassName: ""
+
+# Set the container security context
+# To run the container with ports below 1024 this will need to be adjust to run as root
+securityContext:
+  capabilities:
+    drop: [ALL]
+  readOnlyRootFilesystem: true
+  runAsGroup: 65532
+  runAsNonRoot: true
+  runAsUser: 65532
+
+podSecurityContext:
+  fsGroup: 65532
diff --git a/helm-charts/submarine/templates/submarine-ingress.yaml b/helm-charts/submarine/templates/submarine-ingress.yaml
new file mode 100644
index 0000000..6bddae3
--- /dev/null
+++ b/helm-charts/submarine/templates/submarine-ingress.yaml
@@ -0,0 +1,16 @@
+{{ if .Values.submarine.traefik.enabled }}
+apiVersion: extensions/v1beta1
+kind: Ingress
+metadata:
+  name: {{ .Values.submarine.server.name}}-ingress
+  namespace: {{ .Release.namespace }}
+
+spec:
+  rules:
+    - http:
+        paths:
+          - path: /
+            backend:
+              serviceName: {{ .Values.submarine.server.name }}
+              servicePort: {{ .Values.submarine.server.servicePort }}
+{{ end }}
diff --git a/helm-charts/submarine/values.yaml b/helm-charts/submarine/values.yaml
index f67e450..fb63dd4 100644
--- a/helm-charts/submarine/values.yaml
+++ b/helm-charts/submarine/values.yaml
@@ -29,4 +29,5 @@ submarine:
     image: apache/submarine:database-0.5.0-SNAPSHOT
     servicePort: 3306
     mysqlRootPassword: password
-
+  traefik:
+    enabled: true


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@submarine.apache.org
For additional commands, e-mail: dev-help@submarine.apache.org