diff --git a/docs/guide/install-zh.md b/docs/guide/install-zh.md index 4b3843eee..d511e62b6 100644 --- a/docs/guide/install-zh.md +++ b/docs/guide/install-zh.md @@ -15,4 +15,7 @@ 1. 执行卸载命令: ``` kubectl delete -f pkg/k8s/crd/install/shifu_install.yml - ``` \ No newline at end of file + ``` + +### 关于遥测 +要了解更多信息,包括如何禁用内置遥测,请在[此处](telemetry-zh.md)查看我们的指南 \ No newline at end of file diff --git a/docs/guide/install.md b/docs/guide/install.md index d0c58df9e..0346acdad 100644 --- a/docs/guide/install.md +++ b/docs/guide/install.md @@ -16,3 +16,6 @@ ``` kubectl delete -f pkg/k8s/crd/install/shifu_install.yml ``` + +### About Telemetry +To learn more including how to disable the built-in telemetry, checkout out our guide [here!](telemetry.md) \ No newline at end of file diff --git a/docs/guide/telemetry-zh.md b/docs/guide/telemetry-zh.md new file mode 100644 index 000000000..ad95abd48 --- /dev/null +++ b/docs/guide/telemetry-zh.md @@ -0,0 +1,58 @@ +# 遥测 + +安装 Shifu 时默认启用遥测,您可以在安装之前或之后禁用它。 + +## 我们收集的数据 + +- 外网IP +- 下载日期 +- Kubernetes 版本 +- Shifu 版本 +- Kubernetes 集群规模 +- Kubernetes Pod 名称 +- Kubernetes Deployment 名称 +- 操作系统的类型 + +## 设置 + +您可以通过设置 `pkg/k8s/crd/install/shifu_install.yaml` 上的 `--telemetry-interval=60` 对遥测的间隔时间进行设置。 + +或者您也可以在安装后通过 `kubectl edit deployment -n shifu-crd-system shifu-crd-controller-manager` 进行编辑 +```yaml +apiVersion: apps/v1 +kind: Deployment +spec: + replicas: 1 + selector: + matchLabels: + control-plane: controller-manager + template: + spec: + containers: + image: quay.io/brancz/kube-rbac-proxy:v0.12.0 + name: kube-rbac-proxy + - args: + - --telemetry-interval=60 ## 编辑此行 +``` +## 关闭遥测 + +如果要关闭 telemetry,请手动删除 `pkg/k8s/crd/install/shifu_install.yaml` 上的 `--enable-telemetry`。 + +或者您也可以在安装后通过 `kubectl edit deployment -n shifu-crd-system shifu-crd-controller-manager` 进行编辑 + +```yaml +apiVersion: apps/v1 +kind: Deployment +spec: + replicas: 1 + selector: + matchLabels: + control-plane: controller-manager + template: + spec: + containers: + image: quay.io/brancz/kube-rbac-proxy:v0.12.0 + name: kube-rbac-proxy + - args: + - --enable-telemetry ## 删除此行 +``` \ No newline at end of file diff --git a/docs/guide/telemetry.md b/docs/guide/telemetry.md new file mode 100644 index 000000000..276317ce9 --- /dev/null +++ b/docs/guide/telemetry.md @@ -0,0 +1,58 @@ +# Telemetry + +Telemetry is enabled by default when you install Shifu, while you also have the option to disable it either before or after the installation. + +## Data we collect + +- External network IP +- Download date +- Kubernetes version +- Shifu version +- Kubernetes cluster size +- Kubernetes Pod Name +- Kubernetes Deployment Name +- The type of the operating system + +## Setting + +You can modify telemetry interval by edit `--enable-telemetry` on `pkg/k8s/crd/install/shifu_install.yaml` manually. + +Or you can also edit via `kubectl edit deployment -n shifu-crd-system shifu-crd-controller-manager` after installation +```yaml +apiVersion: apps/v1 +kind: Deployment +spec: + replicas: 1 + selector: + matchLabels: + control-plane: controller-manager + template: + spec: + containers: + image: quay.io/brancz/kube-rbac-proxy:v0.12.0 + name: kube-rbac-proxy + - args: + - --telemetry-interval=60 ## Edit this line +``` +## To turn-off Telemetry + +If you want to turn off temeletry, please delete `--enable-telemetry` on `pkg/k8s/crd/install/shifu_install.yaml` manually. + +Or you can also edit via `kubectl edit deployment -n shifu-crd-system shifu-crd-controller-manager` after installation + +```yaml +apiVersion: apps/v1 +kind: Deployment +spec: + replicas: 1 + selector: + matchLabels: + control-plane: controller-manager + template: + spec: + containers: + image: quay.io/brancz/kube-rbac-proxy:v0.12.0 + name: kube-rbac-proxy + - args: + - --enable-telemetry ## delete on demand +``` diff --git a/pkg/k8s/crd/Dockerfile b/pkg/k8s/crd/Dockerfile index c89aee6a3..3eaa49d84 100644 --- a/pkg/k8s/crd/Dockerfile +++ b/pkg/k8s/crd/Dockerfile @@ -14,6 +14,7 @@ RUN go mod download # Copy the go source COPY pkg/k8s/crd/main.go main.go +COPY pkg/k8s/crd/telemetry pkg/k8s/crd/telemetry COPY pkg/k8s/api pkg/k8s/api COPY pkg/k8s/controllers pkg/k8s/controllers diff --git a/pkg/k8s/crd/config/default/manager_auth_proxy_patch.yaml b/pkg/k8s/crd/config/default/manager_auth_proxy_patch.yaml index b51bb1ada..08e484e28 100644 --- a/pkg/k8s/crd/config/default/manager_auth_proxy_patch.yaml +++ b/pkg/k8s/crd/config/default/manager_auth_proxy_patch.yaml @@ -24,3 +24,5 @@ spec: - "--health-probe-bind-address=:8081" - "--metrics-bind-address=127.0.0.1:8080" - "--leader-elect" + - "--enable-telemetry" + - "--telemetry-interval=60" \ No newline at end of file diff --git a/pkg/k8s/crd/config/manager/manager.yaml b/pkg/k8s/crd/config/manager/manager.yaml index 79adfe72a..4e5c86d0b 100644 --- a/pkg/k8s/crd/config/manager/manager.yaml +++ b/pkg/k8s/crd/config/manager/manager.yaml @@ -29,6 +29,8 @@ spec: - /manager args: - --leader-elect + - --enable-telemetry + - --telemetry-interval=60 image: controller:latest name: manager securityContext: diff --git a/pkg/k8s/crd/install/config_default.yaml b/pkg/k8s/crd/install/config_default.yaml index aaa46a29e..11569a62b 100644 --- a/pkg/k8s/crd/install/config_default.yaml +++ b/pkg/k8s/crd/install/config_default.yaml @@ -434,6 +434,8 @@ spec: - --health-probe-bind-address=:8081 - --metrics-bind-address=127.0.0.1:8080 - --leader-elect + - --enable-telemetry + - --telemetry-interval=60 command: - /manager image: edgehub/shifu-controller:v0.1.0 diff --git a/pkg/k8s/crd/install/shifu_install.yml b/pkg/k8s/crd/install/shifu_install.yml index 6caf12de2..fd84d25ab 100644 --- a/pkg/k8s/crd/install/shifu_install.yml +++ b/pkg/k8s/crd/install/shifu_install.yml @@ -434,6 +434,8 @@ spec: - --health-probe-bind-address=:8081 - --metrics-bind-address=127.0.0.1:8080 - --leader-elect + - --enable-telemetry + - --telemetry-interval=60 command: - /manager image: edgehub/shifu-controller:v0.1.0 diff --git a/pkg/k8s/crd/main.go b/pkg/k8s/crd/main.go index 2bc2dd953..c557075d4 100644 --- a/pkg/k8s/crd/main.go +++ b/pkg/k8s/crd/main.go @@ -18,9 +18,12 @@ package main import ( "flag" + "os" + "github.com/edgenesis/shifu/pkg/k8s/api/v1alpha1" "github.com/edgenesis/shifu/pkg/k8s/controllers" - "os" + "github.com/edgenesis/shifu/pkg/k8s/crd/telemetry" + "github.com/edgenesis/shifu/pkg/k8s/crd/telemetry/utils" // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) // to ensure that exec-entrypoint and run can make use of them. @@ -50,18 +53,25 @@ func init() { func main() { var metricsAddr string var enableLeaderElection bool + var enableTelemetry bool var probeAddr string flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") flag.BoolVar(&enableLeaderElection, "leader-elect", false, "Enable leader election for controller manager. "+ "Enabling this will ensure there is only one active controller manager.") + flag.BoolVar(&enableTelemetry, "enable-telemetry", false, "Collect telemetry") + flag.IntVar(&utils.TelemetryIntervalInSecond, "telemetry-interval", 60, "Telemetry Interval") opts := zap.Options{ Development: true, } opts.BindFlags(flag.CommandLine) flag.Parse() + if enableTelemetry { + go telemetry.StartTelemetry() + } + ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ diff --git a/pkg/k8s/crd/telemetry/telemetry.go b/pkg/k8s/crd/telemetry/telemetry.go new file mode 100644 index 000000000..c2af7c4bc --- /dev/null +++ b/pkg/k8s/crd/telemetry/telemetry.go @@ -0,0 +1,87 @@ +package telemetry + +import ( + "context" + "time" + + "github.com/edgenesis/shifu/pkg/k8s/crd/telemetry/types" + "github.com/edgenesis/shifu/pkg/k8s/crd/telemetry/utils" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + "k8s.io/klog/v2" +) + +func StartTelemetry() { + for { + publicIP, err := utils.GetPublicIPAddr(utils.URL_EXTERNAL_IP) + if err != nil { + klog.Errorf("issue getting Public IP") + publicIP = utils.URL_DEFAULT_PUBLIC_IP + } + + klog.Infof("Public IP is %v\n", publicIP) + config, err := rest.InClusterConfig() + if err != nil { + klog.Errorln("error when get cluster Config,error: ", err) + continue + } + + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + klog.Errorln("cannot get ClusterInfo,errors: ", err) + continue + } + + kVersion, err := clientset.ServerVersion() + if err != nil { + klog.Errorln("cannot get Kubernetes Server Info,errors: ", err) + continue + } + klog.Infof("%#v", kVersion) + pods, err := clientset.CoreV1().Pods("").List(context.TODO(), metav1.ListOptions{}) + if err != nil { + klog.Errorln("cannot get Pod Info,errors: ", err) + continue + } + + deploy, err := clientset.AppsV1().Deployments("").List(context.TODO(), metav1.ListOptions{}) + if err != nil { + klog.Errorln("cannot get Deployment Info,errors: ", err) + continue + } + + podList := make([]string, len(pods.Items)) + deploymentList := make([]string, len(deploy.Items)) + for index, item := range pods.Items { + podList[index] = item.Name + } + + for index, item := range deploy.Items { + deploymentList[index] = item.Name + } + + clusterInfoTelemetry := types.ClusterInfo{ + NumPods: len(podList), + NumDeployments: len(deploymentList), + Pods: podList, + Deployments: deploymentList, + KubernetesVersion: kVersion.GitVersion, + Platform: kVersion.Platform, + } + + controllerTelemetry := types.TelemetryResponse{ + IP: publicIP, + Source: utils.SOURCE_SHIFU_CONTROLLER, + Task: utils.TASK_RUN_DEMO_KIND, + ClusterInfo: clusterInfoTelemetry, + } + + if result := utils.SendTelemetry(controllerTelemetry); result == nil { + klog.Infoln("telemetry done") + } + + time.Sleep(time.Duration(utils.TelemetryIntervalInSecond) * time.Second) + } +} diff --git a/pkg/k8s/crd/telemetry/types/types.go b/pkg/k8s/crd/telemetry/types/types.go new file mode 100644 index 000000000..f817e3330 --- /dev/null +++ b/pkg/k8s/crd/telemetry/types/types.go @@ -0,0 +1,17 @@ +package types + +type TelemetryResponse struct { + IP string `json:"ip"` + Source string `json:"source"` + Task string `json:"task"` + ClusterInfo ClusterInfo `json:"cluster_info"` +} + +type ClusterInfo struct { + KubernetesVersion string `json:"kubernetesVersion"` + Platform string `json:"platform"` + NumPods int `json:"num_pods"` + NumDeployments int `json:"num_deployments"` + Pods []string `json:"pods"` + Deployments []string `json:"deployments"` +} diff --git a/pkg/k8s/crd/telemetry/utils/utils.go b/pkg/k8s/crd/telemetry/utils/utils.go new file mode 100644 index 000000000..eacfee046 --- /dev/null +++ b/pkg/k8s/crd/telemetry/utils/utils.go @@ -0,0 +1,71 @@ +package utils + +import ( + "bufio" + "bytes" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "strings" + + "github.com/edgenesis/shifu/pkg/k8s/crd/telemetry/types" + "k8s.io/klog/v2" +) + +const ( + URL_EXTERNAL_IP = "http://cip.cc" + URL_IP_LINE = "
IP"
+	URL_SHIFU_TELEMETRY     = "https://telemetry.shifu.run/shifu-telemetry/"
+	URL_DEFAULT_PUBLIC_IP   = "0.0.0.0"
+	TASK_RUN_DEMO_KIND      = "run_shifu_release"
+	SOURCE_SHIFU_CONTROLLER = "shifu_controller"
+	HTTP_CONTENT_TYPE_JSON  = "application/json"
+)
+
+var TelemetryIntervalInSecond int
+
+func GetPublicIPAddr(url string) (string, error) {
+	resp, err := http.Get(url)
+	if err != nil {
+		return "", fmt.Errorf("error getting public IP")
+	}
+
+	defer resp.Body.Close()
+	if resp.StatusCode == http.StatusOK {
+		bodyBytes, err := io.ReadAll(resp.Body)
+		if err != nil {
+			klog.Errorf("Error getting response of IP query")
+			return "", err
+		}
+
+		responseText := string(bodyBytes)
+		scanner := bufio.NewScanner(strings.NewReader(responseText))
+		for scanner.Scan() {
+			if strings.Contains(scanner.Text(), URL_IP_LINE) {
+				ipString := strings.Split(scanner.Text(), ": ")
+				return ipString[len(ipString)-1], nil
+			}
+		}
+
+	}
+	return "", errors.New("Did not find IP in return query")
+}
+
+func SendTelemetry(telemetry types.TelemetryResponse) error {
+	postBodyJson, err := json.Marshal(telemetry)
+	if err != nil {
+		klog.Errorf("Error marshaling telemetry")
+		return err
+	}
+
+	resp, err := http.Post(URL_SHIFU_TELEMETRY, HTTP_CONTENT_TYPE_JSON, bytes.NewBuffer(postBodyJson))
+	if err != nil {
+		klog.Errorln("error posting telemetry, errors: ", err)
+		return err
+	}
+
+	defer resp.Body.Close()
+	return nil
+}