kubesphere / kubeeye

KubeEye aims to find various problems on Kubernetes, such as application misconfiguration, unhealthy cluster components and node problems.
https://kubesphere.io
Apache License 2.0
810 stars 126 forks source link

Support Web Interface #146

Open zheng1 opened 2 years ago

zheng1 commented 2 years ago

What would you like to be added:

Provide a web interface that allows users to view results directly through a browser

Why is this needed:

The pure CLI view of the inspect results is not easy to visualize, it is easier to understand the visual results through the web page, and it can be increased for the inspection and solution of the results.

zheng1 commented 2 years ago

Proposal

How to build a web server

Sample code: https://github.com/zheng1/kubeeye/tree/dev-web/web

First we build a static file server for the front-end

//go:embed dist/*
var assets embed.FS

func RunWebService(ctx context.Context) error {
    subFS, _ := fs.Sub(assets, "dist")
    assetsFs := http.FileServer(http.FS(subFS))
    mux := http.NewServeMux()
    mux.Handle("/", assetsFs)
    return http.ListenAndServe(":8000", mux)
}

Then we forward the API to the kube-apiserver

type errorResponder struct{}

func (e *errorResponder) Error(w http.ResponseWriter, req *http.Request, err error) {
    klog.Error(err)
    responsewriters.InternalError(w, req, err)
}

func loadConfig() (*rest.Config, error) {
    config, err := rest.InClusterConfig()
    if err == nil {
        return config, nil
    }
    return clientcmd.BuildConfigFromFlags("", os.Getenv("HOME")+"/.kube/config")

}

func RunWebService(ctx context.Context) error {
    config, err := loadConfig()
    if err != nil {
        return err
    }

    kubernetes, _ := url.Parse(config.Host)
    defaultTransport, err := rest.TransportFor(config)
    if err != nil {
        return err
    }

    var handleKubeAPIfunc = func(w http.ResponseWriter, req *http.Request) {
        klog.Info(req.URL)
        s := *req.URL
        s.Host = kubernetes.Host
        s.Scheme = kubernetes.Scheme

        // make sure we don't override kubernetes's authorization
        req.Header.Del("Authorization")
        httpProxy := proxy.NewUpgradeAwareHandler(&s, defaultTransport, true, false, &errorResponder{})
        httpProxy.UpgradeTransport = proxy.NewUpgradeRequestRoundTripper(defaultTransport, defaultTransport)
        httpProxy.ServeHTTP(w, req)
        return
    }

    mux := http.NewServeMux()
    mux.HandleFunc("/apis/", handleKubeAPIfunc)
    mux.HandleFunc("/api/", handleKubeAPIfunc)

    return http.ListenAndServe(":8000", mux)
}

In this way we only need to put the relative index.html and js and css files in the dist folder.

https://parceljs.org/ is a blazing fast javascript packer!

https://github.com/kubesphere/kubeeye/blob/ce7ddab57442f9f9313426bc5c6a98d1a701c0fb/web/package.json#L7-L8

Development

Run yarn dev and another terminal run go run ./cmd/web/ you can start a dev environment, and open http://localhost:1234 to see result

WechatIMG70

Here is just an example, we have listed all the namespaces in the cluster in the code.

https://github.com/kubesphere/kubeeye/blob/ce7ddab57442f9f9313426bc5c6a98d1a701c0fb/web/src/App.js#L6-L33

https://github.com/kubesphere/kubeeye/blob/ce7ddab57442f9f9313426bc5c6a98d1a701c0fb/web/src/services/namespace.js#L3-L8

In the following configuration, port 1234 will proxy k8s request to port 8000

https://github.com/kubesphere/kubeeye/blob/ce7ddab57442f9f9313426bc5c6a98d1a701c0fb/web/.proxyrc#L2-L7

Production

Run yarn build and go run ./cmd/web/, and open http://localhost:8000, you can see the same result in pure go without other process.

zheng1 commented 2 years ago

https://www.figma.com/file/aDij53tnzKPr7dofRE54mX/