You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@submarine.apache.org by pi...@apache.org on 2022/08/23 04:21:03 UTC
[submarine] branch master updated: SUBMARINE-1286. Install grafana
This is an automated email from the ASF dual-hosted git repository.
pingsutw 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 3fc12adc SUBMARINE-1286. Install grafana
3fc12adc is described below
commit 3fc12adc9da1768c60e8c273a41d08210f8c82a7
Author: jeff-901 <b0...@ntu.edu.tw>
AuthorDate: Mon Jul 4 22:32:12 2022 +0800
SUBMARINE-1286. Install grafana
### What is this PR for?
Install grafana by using grafana original image
### What type of PR is it?
Feature
### Todos
### What is the Jira issue?
https://issues.apache.org/jira/browse/SUBMARINE-1286
### How should this be tested?
go to http://{istio ingress ip}/grafana
### Screenshots (if appropriate)
![image](https://user-images.githubusercontent.com/54139205/174744181-7b38c5b1-7309-4be9-a61a-15286dc3a927.png)
### Questions:
* Do the license files need updating? No
* Are there breaking changes for older versions? No
* Does this need new documentation? No
Author: jeff-901 <b0...@ntu.edu.tw>
Signed-off-by: Kevin <pi...@apache.org>
Closes #970 from jeff-901/SUBMARINE-1286 and squashes the following commits:
a7d4661c [jeff-901] set database
c99c29f4 [jeff-901] reset file permission
41b60684 [jeff-901] install grafana
fed79026 [jeff-901] grafana ingress
122abe3c [jeff-901] install grafana
---
dev-support/docker-images/database/startup.sh | 3 +
.../artifacts/submarine/submarine-grafana.yaml | 118 +++++++++++++
.../artifacts/submarine/submarine-ingress.yaml | 8 +
submarine-cloud-v2/main.go | 1 +
submarine-cloud-v2/pkg/controller/controller.go | 11 ++
.../pkg/controller/controller_builder.go | 2 +
.../pkg/controller/controller_builder_config.go | 8 +
.../pkg/controller/controller_event_handlers.go | 17 ++
submarine-cloud-v2/pkg/controller/parser.go | 11 ++
.../pkg/controller/submarine_grafana.go | 182 +++++++++++++++++++++
10 files changed, 361 insertions(+)
diff --git a/dev-support/docker-images/database/startup.sh b/dev-support/docker-images/database/startup.sh
index c52fc936..af917c98 100755
--- a/dev-support/docker-images/database/startup.sh
+++ b/dev-support/docker-images/database/startup.sh
@@ -36,4 +36,7 @@ use metastore; source /tmp/database/metastore.sql;
CREATE DATABASE mlflowdb;
CREATE USER 'mlflow'@'%' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON * . * TO 'mlflow'@'%';
+CREATE DATABASE grafana;
+CREATE USER 'grafana'@'%' IDENTIFIED BY 'password';
+GRANT ALL PRIVILEGES ON * . * TO 'grafana'@'%';
EOF
diff --git a/submarine-cloud-v2/artifacts/submarine/submarine-grafana.yaml b/submarine-cloud-v2/artifacts/submarine/submarine-grafana.yaml
new file mode 100644
index 00000000..3a42735c
--- /dev/null
+++ b/submarine-cloud-v2/artifacts/submarine/submarine-grafana.yaml
@@ -0,0 +1,118 @@
+---
+# Source: submarine/templates/submarine-mlflow.yaml
+#
+# 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: submarine-grafana-config
+data:
+ grafana.ini: |
+ [server]
+ root_url = http://submarine-grafana-service/grafana/
+ serve_from_sub_path = true
+ [database]
+ type = mysql
+ name = grafana
+ host = submarine-database:3306
+ user = grafana
+ password = password
+ url = mysql://grafana:password@submarine-database:3306/grafana
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: submarine-grafana-pvc
+spec:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 1Gi
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ labels:
+ app: submarine-grafana
+ name: submarine-grafana
+spec:
+ selector:
+ matchLabels:
+ app: submarine-grafana
+ template:
+ metadata:
+ labels:
+ app: submarine-grafana
+ spec:
+ securityContext:
+ fsGroup: 472
+ supplementalGroups:
+ - 0
+ containers:
+ - name: submarine-grafana
+ image: grafana/grafana:8.3.1
+ imagePullPolicy: IfNotPresent
+ ports:
+ - containerPort: 3000
+ name: http-grafana
+ protocol: TCP
+ readinessProbe:
+ failureThreshold: 3
+ httpGet:
+ path: /robots.txt
+ port: 3000
+ scheme: HTTP
+ initialDelaySeconds: 10
+ periodSeconds: 30
+ successThreshold: 1
+ timeoutSeconds: 2
+ livenessProbe:
+ failureThreshold: 3
+ initialDelaySeconds: 30
+ periodSeconds: 10
+ successThreshold: 1
+ tcpSocket:
+ port: 3000
+ timeoutSeconds: 1
+ volumeMounts:
+ - mountPath: /var/lib/grafana
+ name: submarine-grafana-pv
+ - mountPath: /etc/grafana
+ name: submarine-grafana-config
+ volumes:
+ - name: submarine-grafana-pv
+ persistentVolumeClaim:
+ claimName: submarine-grafana-pvc
+ - name: submarine-grafana-config
+ configMap:
+ name: submarine-grafana-config
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: submarine-grafana-service
+ labels:
+ app: submarine-grafana
+spec:
+ ports:
+ - port: 3000
+ targetPort: 3000
+ protocol: TCP
+ targetPort: http-grafana
+ selector:
+ app: submarine-grafana
diff --git a/submarine-cloud-v2/artifacts/submarine/submarine-ingress.yaml b/submarine-cloud-v2/artifacts/submarine/submarine-ingress.yaml
index 73f4c842..f60f7989 100644
--- a/submarine-cloud-v2/artifacts/submarine/submarine-ingress.yaml
+++ b/submarine-cloud-v2/artifacts/submarine/submarine-ingress.yaml
@@ -49,6 +49,14 @@ spec:
host: submarine-minio-service
port:
number: 9000
+ - match:
+ - uri:
+ prefix: /grafana
+ route:
+ - destination:
+ host: submarine-grafana-service
+ port:
+ number: 3000
- route:
- destination:
host: submarine-server
diff --git a/submarine-cloud-v2/main.go b/submarine-cloud-v2/main.go
index f977ae93..48a90357 100644
--- a/submarine-cloud-v2/main.go
+++ b/submarine-cloud-v2/main.go
@@ -155,6 +155,7 @@ func NewSubmarineController(
WithServiceInformer(kubeInformerFactory.Core().V1().Services()).
WithServiceAccountInformer(kubeInformerFactory.Core().V1().ServiceAccounts()).
WithPersistentVolumeClaimInformer(kubeInformerFactory.Core().V1().PersistentVolumeClaims()).
+ WithConfigMapClaimInformer(kubeInformerFactory.Core().V1().ConfigMaps()).
WithIngressInformer(kubeInformerFactory.Extensions().V1beta1().Ingresses()).
// WithIngressRouteInformer(traefikInformerFactory.Traefik().V1alpha1().IngressRoutes()).
WithVirtualServiceInformer(istioInformerFactory.Networking().V1alpha3().VirtualServices()).
diff --git a/submarine-cloud-v2/pkg/controller/controller.go b/submarine-cloud-v2/pkg/controller/controller.go
index 10117c99..0e31156b 100644
--- a/submarine-cloud-v2/pkg/controller/controller.go
+++ b/submarine-cloud-v2/pkg/controller/controller.go
@@ -79,10 +79,15 @@ const (
minioPvcName = minioName + "-pvc"
minioServiceName = minioName + "-service"
minioIngressRouteName = minioName + "-ingressroute"
+ grafanaName = "submarine-grafana"
+ grafanaPvcName = grafanaName + "-pvc"
+ grafanaServiceName = grafanaName + "-service"
+ grafanaConfigMapName = grafanaName + "-config"
artifactPath = "./artifacts/submarine/"
databaseYamlPath = artifactPath + "submarine-database.yaml"
ingressYamlPath = artifactPath + "submarine-ingress.yaml"
minioYamlPath = artifactPath + "submarine-minio.yaml"
+ grafanaYamlPath = artifactPath + "submarine-grafana.yaml"
mlflowYamlPath = artifactPath + "submarine-mlflow.yaml"
serverYamlPath = artifactPath + "submarine-server.yaml"
tensorboardYamlPath = artifactPath + "submarine-tensorboard.yaml"
@@ -142,6 +147,7 @@ type Controller struct {
serviceaccountLister corelisters.ServiceAccountLister
serviceLister corelisters.ServiceLister
persistentvolumeclaimLister corelisters.PersistentVolumeClaimLister
+ configMapLister corelisters.ConfigMapLister
ingressLister extlisters.IngressLister
// ingressrouteLister traefiklisters.IngressRouteLister
virtualServiceLister istioListers.VirtualServiceLister
@@ -512,6 +518,11 @@ func (c *Controller) createSubmarine(submarine *v1alpha1.Submarine) error {
return err
}
+ err = c.createSubmarineGrafana(submarine)
+ if err != nil && !errors.IsAlreadyExists(err) {
+ return err
+ }
+
return nil
}
diff --git a/submarine-cloud-v2/pkg/controller/controller_builder.go b/submarine-cloud-v2/pkg/controller/controller_builder.go
index 192fea4e..6c34f8b9 100644
--- a/submarine-cloud-v2/pkg/controller/controller_builder.go
+++ b/submarine-cloud-v2/pkg/controller/controller_builder.go
@@ -90,6 +90,7 @@ func (cb *ControllerBuilder) addListers() *ControllerBuilder {
cb.controller.serviceLister = cb.config.serviceInformer.Lister()
cb.controller.serviceaccountLister = cb.config.serviceaccountInformer.Lister()
cb.controller.persistentvolumeclaimLister = cb.config.persistentvolumeclaimInformer.Lister()
+ cb.controller.configMapLister = cb.config.configMapInformer.Lister()
cb.controller.ingressLister = cb.config.ingressInformer.Lister()
// cb.controller.ingressrouteLister = cb.config.ingressrouteInformer.Lister()
cb.controller.virtualServiceLister = cb.config.virtualServiceInformer.Lister()
@@ -111,6 +112,7 @@ func (cb *ControllerBuilder) addEventHandlers() *ControllerBuilder {
cb.addServiceEventHandlers()
cb.addServiceAccountEventHandlers()
cb.addPersistentVolumeClaimEventHandlers()
+ cb.addConfigMapEventHandlers()
cb.addIngressEventHandlers()
// cb.addIngressRouteEventHandlers()
cb.addRoleEventHandlers()
diff --git a/submarine-cloud-v2/pkg/controller/controller_builder_config.go b/submarine-cloud-v2/pkg/controller/controller_builder_config.go
index b8a2dcc9..91b8100b 100644
--- a/submarine-cloud-v2/pkg/controller/controller_builder_config.go
+++ b/submarine-cloud-v2/pkg/controller/controller_builder_config.go
@@ -46,6 +46,7 @@ type BuilderConfig struct {
serviceInformer coreinformers.ServiceInformer
serviceaccountInformer coreinformers.ServiceAccountInformer
persistentvolumeclaimInformer coreinformers.PersistentVolumeClaimInformer
+ configMapInformer coreinformers.ConfigMapInformer
ingressInformer extinformers.IngressInformer
// ingressrouteInformer traefikinformers.IngressRouteInformer
virtualServiceInformer istioInformers.VirtualServiceInformer
@@ -158,6 +159,13 @@ func (bc *BuilderConfig) WithPersistentVolumeClaimInformer(
return bc
}
+func (bc *BuilderConfig) WithConfigMapClaimInformer(
+ configMapInformer coreinformers.ConfigMapInformer,
+) *BuilderConfig {
+ bc.configMapInformer = configMapInformer
+ return bc
+}
+
func (bc *BuilderConfig) WithIngressInformer(
ingressInformer extinformers.IngressInformer,
) *BuilderConfig {
diff --git a/submarine-cloud-v2/pkg/controller/controller_event_handlers.go b/submarine-cloud-v2/pkg/controller/controller_event_handlers.go
index 1e0036c5..20efdd81 100644
--- a/submarine-cloud-v2/pkg/controller/controller_event_handlers.go
+++ b/submarine-cloud-v2/pkg/controller/controller_event_handlers.go
@@ -122,6 +122,23 @@ func (cb *ControllerBuilder) addPersistentVolumeClaimEventHandlers() *Controller
return cb
}
+func (cb *ControllerBuilder) addConfigMapEventHandlers() *ControllerBuilder {
+ cb.config.configMapInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
+ AddFunc: cb.controller.handleObject,
+ UpdateFunc: func(old, new interface{}) {
+ newConfigMap := new.(*corev1.ConfigMap)
+ oldConfigMap := old.(*corev1.ConfigMap)
+ if newConfigMap.ResourceVersion == oldConfigMap.ResourceVersion {
+ return
+ }
+ cb.controller.handleObject(new)
+ },
+ DeleteFunc: cb.controller.handleObject,
+ })
+
+ return cb
+}
+
func (cb *ControllerBuilder) addIngressEventHandlers() *ControllerBuilder {
cb.config.ingressInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: cb.controller.handleObject,
diff --git a/submarine-cloud-v2/pkg/controller/parser.go b/submarine-cloud-v2/pkg/controller/parser.go
index e844f3e8..040e64eb 100644
--- a/submarine-cloud-v2/pkg/controller/parser.go
+++ b/submarine-cloud-v2/pkg/controller/parser.go
@@ -169,6 +169,17 @@ func ParsePersistentVolumeClaimYaml(relativePath string) (*v1.PersistentVolumeCl
return &pvc, nil
}
+// ParseConfigMap parse ConfigMap from yaml file.
+func ParseConfigMapYaml(relativePath string) (*v1.ConfigMap, error) {
+ var configMap v1.ConfigMap
+ marshaled, err := parseYaml(relativePath, "ConfigMap")
+ if err != nil {
+ return nil, err
+ }
+ json.Unmarshal(marshaled, &configMap)
+ return &configMap, nil
+}
+
// ParseIngressRouteYaml parse IngressRoute from yaml file.
func ParseIngressRouteYaml(relativePath string) (*traefikv1alpha1.IngressRoute, error) {
var ingressRoute traefikv1alpha1.IngressRoute
diff --git a/submarine-cloud-v2/pkg/controller/submarine_grafana.go b/submarine-cloud-v2/pkg/controller/submarine_grafana.go
new file mode 100644
index 00000000..90c8f2b2
--- /dev/null
+++ b/submarine-cloud-v2/pkg/controller/submarine_grafana.go
@@ -0,0 +1,182 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package controller
+
+import (
+ "context"
+ "fmt"
+
+ v1alpha1 "github.com/apache/submarine/submarine-cloud-v2/pkg/apis/submarine/v1alpha1"
+
+ appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/api/errors"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/klog/v2"
+)
+
+func newSubmarineGrafanaConfigMap(submarine *v1alpha1.Submarine) *corev1.ConfigMap {
+ configMap, err := ParseConfigMapYaml(grafanaYamlPath)
+ if err != nil {
+ klog.Info("[Error] ParseConfigMap", err)
+ }
+ configMap.ObjectMeta.OwnerReferences = []metav1.OwnerReference{
+ *metav1.NewControllerRef(submarine, v1alpha1.SchemeGroupVersion.WithKind("Submarine")),
+ }
+
+ return configMap
+}
+
+func newSubmarineGrafanaPersistentVolumeClaim(submarine *v1alpha1.Submarine) *corev1.PersistentVolumeClaim {
+ pvc, err := ParsePersistentVolumeClaimYaml(grafanaYamlPath)
+ if err != nil {
+ klog.Info("[Error] ParsePersistentVolumeClaim", err)
+ }
+ pvc.ObjectMeta.OwnerReferences = []metav1.OwnerReference{
+ *metav1.NewControllerRef(submarine, v1alpha1.SchemeGroupVersion.WithKind("Submarine")),
+ }
+
+ return pvc
+}
+
+func newSubmarineGrafanaDeployment(submarine *v1alpha1.Submarine) *appsv1.Deployment {
+ deployment, err := ParseDeploymentYaml(grafanaYamlPath)
+ if err != nil {
+ klog.Info("[Error] ParseDeploymentYaml", err)
+ }
+ deployment.ObjectMeta.OwnerReferences = []metav1.OwnerReference{
+ *metav1.NewControllerRef(submarine, v1alpha1.SchemeGroupVersion.WithKind("Submarine")),
+ }
+
+ return deployment
+}
+
+func newSubmarineGrafanaService(submarine *v1alpha1.Submarine) *corev1.Service {
+ service, err := ParseServiceYaml(grafanaYamlPath)
+ if err != nil {
+ klog.Info("[Error] ParseServiceYaml", err)
+ }
+ service.ObjectMeta.OwnerReferences = []metav1.OwnerReference{
+ *metav1.NewControllerRef(submarine, v1alpha1.SchemeGroupVersion.WithKind("Submarine")),
+ }
+ return service
+}
+
+// createSubmarineGrafana is a function to create submarine-grafana
+func (c *Controller) createSubmarineGrafana(submarine *v1alpha1.Submarine) error {
+ klog.Info("[createSubmarineGrafana]")
+
+ // Step 1: Create ConfigMap
+ configMap, err := c.configMapLister.ConfigMaps(submarine.Namespace).Get(grafanaConfigMapName)
+ klog.Info(" Create ConfigMap: ", configMap)
+ // If the resource doesn't exist, we'll create it
+ if errors.IsNotFound(err) {
+ klog.Info("Into not found")
+ configMap, err = c.kubeclientset.CoreV1().ConfigMaps(submarine.Namespace).Create(context.TODO(),
+ newSubmarineGrafanaConfigMap(submarine),
+ metav1.CreateOptions{})
+ if err != nil {
+ klog.Info(err)
+ }
+ klog.Info(" Create ConfigMap: ", configMap.Name)
+ }
+ // If an error occurs during Get/Create, we'll requeue the item so we can
+ // attempt processing again later. This could have been caused by a
+ // temporary network failure, or any other transient reason.
+ if err != nil {
+ return err
+ }
+
+ if !metav1.IsControlledBy(configMap, submarine) {
+ msg := fmt.Sprintf(MessageResourceExists, configMap.Name)
+ c.recorder.Event(submarine, corev1.EventTypeWarning, ErrResourceExists, msg)
+ return fmt.Errorf(msg)
+ }
+
+ // Step 2: Create PersistentVolumeClaim
+ pvc, err := c.persistentvolumeclaimLister.PersistentVolumeClaims(submarine.Namespace).Get(grafanaPvcName)
+ // If the resource doesn't exist, we'll create it
+ if errors.IsNotFound(err) {
+ pvc, err = c.kubeclientset.CoreV1().PersistentVolumeClaims(submarine.Namespace).Create(context.TODO(),
+ newSubmarineGrafanaPersistentVolumeClaim(submarine),
+ metav1.CreateOptions{})
+ if err != nil {
+ klog.Info(err)
+ }
+ klog.Info(" Create PersistentVolumeClaim: ", pvc.Name)
+ }
+ // If an error occurs during Get/Create, we'll requeue the item so we can
+ // attempt processing again later. This could have been caused by a
+ // temporary network failure, or any other transient reason.
+ if err != nil {
+ return err
+ }
+
+ if !metav1.IsControlledBy(pvc, submarine) {
+ msg := fmt.Sprintf(MessageResourceExists, pvc.Name)
+ c.recorder.Event(submarine, corev1.EventTypeWarning, ErrResourceExists, msg)
+ return fmt.Errorf(msg)
+ }
+
+ // Step 3: Create Deployment
+ deployment, err := c.deploymentLister.Deployments(submarine.Namespace).Get(grafanaName)
+ if errors.IsNotFound(err) {
+ deployment, err = c.kubeclientset.AppsV1().Deployments(submarine.Namespace).Create(context.TODO(), newSubmarineGrafanaDeployment(submarine), metav1.CreateOptions{})
+ if err != nil {
+ klog.Info(err)
+ }
+ klog.Info(" Create Deployment: ", deployment.Name)
+ }
+ // If an error occurs during Get/Create, we'll requeue the item so we can
+ // attempt processing again later. This could have been caused by a
+ // temporary network failure, or any other transient reason.
+ if err != nil {
+ return err
+ }
+
+ if !metav1.IsControlledBy(deployment, submarine) {
+ msg := fmt.Sprintf(MessageResourceExists, deployment.Name)
+ c.recorder.Event(submarine, corev1.EventTypeWarning, ErrResourceExists, msg)
+ return fmt.Errorf(msg)
+ }
+
+ // Step 4: Create Service
+ service, err := c.serviceLister.Services(submarine.Namespace).Get(grafanaServiceName)
+ // If the resource doesn't exist, we'll create it
+ if errors.IsNotFound(err) {
+ service, err = c.kubeclientset.CoreV1().Services(submarine.Namespace).Create(context.TODO(), newSubmarineGrafanaService(submarine), metav1.CreateOptions{})
+ if err != nil {
+ klog.Info(err)
+ }
+ klog.Info(" Create Service: ", service.Name)
+ }
+ // If an error occurs during Get/Create, we'll requeue the item so we can
+ // attempt processing again later. This could have been caused by a
+ // temporary network failure, or any other transient reason.
+ if err != nil {
+ return err
+ }
+
+ if !metav1.IsControlledBy(service, submarine) {
+ msg := fmt.Sprintf(MessageResourceExists, service.Name)
+ c.recorder.Event(submarine, corev1.EventTypeWarning, ErrResourceExists, msg)
+ return fmt.Errorf(msg)
+ }
+
+ return nil
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@submarine.apache.org
For additional commands, e-mail: dev-help@submarine.apache.org