Merge pull request #2586 from dyusupov/master

support for EdgeFS UI
This commit is contained in:
Alexander Trost authored and GitHub committed 2019-01-29 11:39:31 +01:00
commit 1cfa41cf4e
7 files changed
+180 -16

No files matched your search

+2 -2
View File
@@ -1,10 +1,10 @@
---
title: Monitoring
title: EdgeFS Monitoring
weight: 48
indent: true
---
# Monitoring
# EdgeFS Monitoring
Each Rook EdgeFS cluster has some built in metrics collectors/exporters for monitoring with [Prometheus](https://prometheus.io/).
If you do not have Prometheus running, follow the steps below to enable monitoring of Rook. If your cluster already
+47
View File
@@ -0,0 +1,47 @@
---
title: EdgeFS User Interface
weight: 49
indent: true
---
# EdgeFS Dashboard and User Interface
EdgeFS comes with built-in local cluster Dashboard and User Interface.
The dashboard is a very helpful tool to give you an overview of the status of your cluster, including overall health,
status of the corosync quorum, status of the VDEVs, and other EdgeFS services.
![EdgeFS UI Dashboard](media/edgefs-ui-dashboard.png)
Rook EdgeFS Operator enables the dashboard by default.
A K8s service will be created to expose HTTP/S ports inside the cluster.
This example shows what ports was configured for EdgeFS right after successful cluster deployment:
```bash
# kubectl get svc -n rook-edgefs
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
rook-edgefs-restapi NodePort 10.105.177.93 <none> 8881:32135/TCP,8080:31363/TCP,4443:31485/TCP 3h14m
rook-edgefs-ui NodePort 10.97.70.209 <none> 3000:32048/TCP,3443:30273/TCP 3h14m
rook-edgefs-mgr NodePort 10.108.199.1 <none> 6789:31370/TCP 3h14m
```
The `rook-edgefs-restapi` service is used for the [Prometheus metrics](edgefs-monitoring.md) scrape and REST API endpoints.
REST API endpoint is used by Console and Graphical UIs. It exposing ClusterIPs with HTTP ports 8080 and 4443(SSL). NodePort(s) for external access automatically pre-created.
The `rook-edgefs-ui` service is used to expose browser based User Interface ports.
Using NodePort you will be able to connect to the dashboard by direct node IP and provided port number, in this example at `http://NODEIP:32048`.
The `rook-edgefs-mgr` service is for gRPC communication between the [EdgeFS CSI Provisioner](edgefs-si.md), REST API and services. It exposes cluster internal port 6789.
## Dynamic EdgeFS Service CRD editing
One of the very useful features of EdgeFS Dashboard is Dynamic Service CRD editing UI. Ability to edit CRDs via intuitive graphical inteface can simplify on-going EdgeFS cluster management drastically. For instance, below picture demostrantes how NFS CRD service can be dynamically edited, exports can be added or removed:
![EdgeFS UI NFS Editing](media/edgefs-ui-nfs-edit.png)
EdgeFS UI renders user requests and sends them to the REST API where service CRD is constructed, validated and executed. Certain parameters can only be updated within a cluster service definition itself, and as such this UI blends the two, thus providing simplified management functionality.
### Credentials
After you connect to the dashboard you will need to login for secure access. Rook EdgeFS operator creates a default user named
`admin` and password `edgefs`. It can be changed later via `neadm system passwd` command executed within `mgr` pod.
Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

@@ -18,6 +18,9 @@ rules:
- apiGroups: [""]
resources: ["configmaps", "endpoints"]
verbs: [ "get", "list", "watch", "create", "update", "delete" ]
- apiGroups: ["edgefs.rook.io"]
resources: ["*"]
verbs: ["*"]
- apiGroups: [""]
resources: ["pods"]
verbs: [ "get", "list" ]
+127 -13
View File
@@ -38,11 +38,15 @@ var logger = capnslog.NewPackageLogger("github.com/rook/rook", "edgefs-op-mgr")
const (
appName = "rook-edgefs-mgr"
restapiSvcName = "rook-edgefs-restapi"
uiSvcName = "rook-edgefs-ui"
defaultServiceAccountName = "rook-edgefs-cluster"
defaultGrpcPort = 6789
defaultRestPort = 8080
defaultRestSPort = 4443
defaultMetricsPort = 8881
defaultUiPort = 3000
defaultUiSPort = 3443
/* Volumes definitions */
dataVolumeName = "edgefs-datadir"
@@ -121,14 +125,36 @@ func (c *Cluster) Start(rookImage string) error {
}
// create the mgr service
service := c.makeMgrService(appName)
if _, err := c.context.Clientset.CoreV1().Services(c.Namespace).Create(service); err != nil {
mgrService := c.makeMgrService(appName)
if _, err := c.context.Clientset.CoreV1().Services(c.Namespace).Create(mgrService); err != nil {
if !errors.IsAlreadyExists(err) {
return fmt.Errorf("failed to create mgr service. %+v", err)
}
logger.Infof("mgr mgr service already exists")
logger.Infof("mgr service already exists")
} else {
logger.Infof("mgr mgr service started")
logger.Infof("mgr service started")
}
// create the restapi service
restapiService := c.makeRestapiService(restapiSvcName)
if _, err := c.context.Clientset.CoreV1().Services(c.Namespace).Create(restapiService); err != nil {
if !errors.IsAlreadyExists(err) {
return fmt.Errorf("failed to create restapi service. %+v", err)
}
logger.Infof("restapi service already exists")
} else {
logger.Infof("restapi service started")
}
// create the ui/dashboard service
uiService := c.makeUiService(uiSvcName)
if _, err := c.context.Clientset.CoreV1().Services(c.Namespace).Create(uiService); err != nil {
if !errors.IsAlreadyExists(err) {
return fmt.Errorf("failed to create ui service. %+v", err)
}
logger.Infof("ui service already exists")
} else {
logger.Infof("ui service started")
}
return nil
@@ -144,25 +170,45 @@ func (c *Cluster) makeMgrService(name string) *v1.Service {
},
Spec: v1.ServiceSpec{
Selector: labels,
Type: v1.ServiceTypeClusterIP,
Type: v1.ServiceTypeNodePort,
Ports: []v1.ServicePort{
{
Name: "mgr",
Port: int32(defaultGrpcPort),
Protocol: v1.ProtocolTCP,
},
},
},
}
k8sutil.SetOwnerRef(c.context.Clientset, c.Namespace, &svc.ObjectMeta, &c.ownerRef)
return svc
}
func (c *Cluster) makeRestapiService(name string) *v1.Service {
labels := c.getLabels()
svc := &v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: c.Namespace,
Labels: labels,
},
Spec: v1.ServiceSpec{
Selector: labels,
Type: v1.ServiceTypeNodePort,
Ports: []v1.ServicePort{
{
Name: "http-metrics",
Port: int32(defaultMetricsPort),
Protocol: v1.ProtocolTCP,
},
{
Name: "http-mgmt",
Name: "http-restapi",
Port: int32(defaultRestPort),
Protocol: v1.ProtocolTCP,
},
{
Name: "https-mgmt",
Name: "https-restapi",
Port: int32(defaultRestSPort),
Protocol: v1.ProtocolTCP,
},
@@ -174,6 +220,36 @@ func (c *Cluster) makeMgrService(name string) *v1.Service {
return svc
}
func (c *Cluster) makeUiService(name string) *v1.Service {
labels := c.getLabels()
svc := &v1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: c.Namespace,
Labels: labels,
},
Spec: v1.ServiceSpec{
Selector: labels,
Type: v1.ServiceTypeNodePort,
Ports: []v1.ServicePort{
{
Name: "http-ui",
Port: int32(defaultUiPort),
Protocol: v1.ProtocolTCP,
},
{
Name: "https-ui",
Port: int32(defaultUiSPort),
Protocol: v1.ProtocolTCP,
},
},
},
}
k8sutil.SetOwnerRef(c.context.Clientset, c.Namespace, &svc.ObjectMeta, &c.ownerRef)
return svc
}
func (c *Cluster) makeDeployment(name, clusterName, rookImage string, replicas int32) *extensions.Deployment {
volumes := []v1.Volume{}
@@ -215,12 +291,13 @@ func (c *Cluster) makeDeployment(name, clusterName, rookImage string, replicas i
},
Spec: v1.PodSpec{
ServiceAccountName: c.serviceAccount,
Containers: []v1.Container{c.mgmtContainer(name, "edgefs/edgefs-restapi:"+rookImageVer), c.mgrContainer("grpc", rookImage)},
RestartPolicy: v1.RestartPolicyAlways,
Volumes: volumes,
HostIPC: true,
HostNetwork: isHostNetworkDefined(c.HostNetworkSpec),
NodeSelector: map[string]string{c.Namespace: "cluster"},
Containers: []v1.Container{c.mgmtContainer(name, "edgefs/edgefs-restapi:"+rookImageVer),
c.mgrContainer("grpc", rookImage), c.uiContainer("ui", "edgefs/edgefs-ui:"+rookImageVer)},
RestartPolicy: v1.RestartPolicyAlways,
Volumes: volumes,
HostIPC: true,
HostNetwork: isHostNetworkDefined(c.HostNetworkSpec),
NodeSelector: map[string]string{c.Namespace: "cluster"},
},
}
if isHostNetworkDefined(c.HostNetworkSpec) {
@@ -239,6 +316,43 @@ func (c *Cluster) makeDeployment(name, clusterName, rookImage string, replicas i
return d
}
func (c *Cluster) uiContainer(name string, containerImage string) v1.Container {
runAsUser := int64(0)
readOnlyRootFilesystem := false
securityContext := &v1.SecurityContext{
RunAsUser: &runAsUser,
ReadOnlyRootFilesystem: &readOnlyRootFilesystem,
}
return v1.Container{
Name: name,
Image: containerImage,
ImagePullPolicy: v1.PullAlways,
Args: []string{},
Env: []v1.EnvVar{
{
Name: "API_ENDPOINT",
Value: "http://0.0.0.0:8080",
},
},
SecurityContext: securityContext,
Resources: c.resources,
Ports: []v1.ContainerPort{
{
Name: "http-ui",
ContainerPort: int32(defaultUiPort),
Protocol: v1.ProtocolTCP,
},
{
Name: "https-ui",
ContainerPort: int32(defaultUiSPort),
Protocol: v1.ProtocolTCP,
},
},
}
}
func (c *Cluster) mgmtContainer(name string, containerImage string) v1.Container {
runAsUser := int64(0)
+1 -1
View File
@@ -117,7 +117,7 @@ func TestServiceSpec(t *testing.T) {
s := c.makeMgrService("rook-edgefs-mgr")
assert.NotNil(t, s)
assert.Equal(t, "rook-edgefs-mgr", s.Name)
assert.Equal(t, 4, len(s.Spec.Ports))
assert.Equal(t, 1, len(s.Spec.Ports))
}
func TestHostNetwork(t *testing.T) {