常用服务
pg, mysql, redis 等服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| docker run -d \ --name=postgres \ -e POSTGRES_PASSWORD=password \ -e POSTGRES_USER=postgres \ -e POSTGRES_DB=postgres \ -v ./postgres/data:/var/lib/postgresql/data \ -p 5432:5432 \ postgres
docker run -d \ --name=mysql \ -e MYSQL_ROOT_PASSWORD=yourrootpassword \ -e MYSQL_DATABASE=yourdatabase \ -e MYSQL_USER=yourusername \ -e MYSQL_PASSWORD=yourpassword \ -v ./mysql/data:/var/lib/mysql \ -p 3306:3306 \ mysql
docker run -d \ --name=redis \ -v ./redis/data:/data \ -p 6379:6379 \ redis
|
prometheus, grafana, nodeexport 等服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| docker run -d \ --name=prometheus \ -v ./prometheus/config/prometheus.yml:/etc/prometheus/prometheus.yml \ -v ./prometheus/data:/prometheus \ -p 9090:9090 \ prom/prometheus
docker run -p 3000:3000 --name grafana \ -v /opt/prometheus/grafana/data:/var/lib/grafana \ -e "GF_SECURITY_ADMIN_PASSWORD=grafana123" \ -itd grafana/grafana
# -v ./prometheus/grafana/grafana.ini:/etc/grafana/grafana.ini # 按需设置
docker run -d --name node-exporter --restart=always -p 9100:9100 -v "/proc:/host/proc:ro" -v "/sys:/host/sys:ro" -v "/:/rootfs:ro" prom/node-exporter
|
Pyroscope
Pyroscope 是一个开源的性能剖析工具,可以帮助开发者对应用程序进行性能分析、热点诊断,并提供对性能问题的可视化支持。它支持多种语言和运行时环境(如 Go、Python、Ruby、Java 等),可以在生产环境中对应用程序进行低开销的性能剖析
安装
1
| docker run -it --net=host -e "PYROSCOPE_SERVER_HTTP_ADDRESS=0.0.0.0:4040" grafana/pyroscope
|
使用 pyroscope-test.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| # pip install pyroscope-io import pyroscope import time import random
# 配置 Pyroscope pyroscope.configure( application_name="my2.python.app", server_address="http://localhost:4040", # 可选:设置更多参数 # sample_rate=100, # 每秒采样次数 # detect_subprocesses=True, # 检测子进程 # gil_only=False # 是否只分析持有 GIL 的线程 )
def cpu_intensive_task(): """模拟 CPU 密集型任务""" result = 0 for _ in range(10000): result += random.randint(1, 100) ** 2 return result
def main(): try: while True: cpu_intensive_task() time.sleep(0.1) # 控制执行频率 except KeyboardInterrupt: print("性能分析结束")
if __name__ == "__main__": main()
|
验证

集成到 grafana
grafana 里运行
grafana-cli plugins install pyroscope-datasource


使用 alloy 搭配
alloy 配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| logging { level = "info" format = "logfmt" }
pyroscope.scrape "local" { targets = array.concat([ {"__address__" = "pyroscope:4040", "service_name"="pyroscope"}, {"__address__" = "localhost:12345", "service_name"="alloy"}, ])
forward_to = [pyroscope.write.local.receiver] }
pyroscope.write "local" { endpoint { url = "http://pyroscope:4040" } }
|
alloy 安装 (k8s helm)
1 2 3
| helm repo add grafana https://grafana.github.io/helm-charts helm repo update helm install --namespace pyroscope alloy2 grafana/alloy
|
默认生成的配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| # Source: alloy/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: alloy2 labels: helm.sh/chart: alloy-0.10.0 app.kubernetes.io/name: alloy app.kubernetes.io/instance: alloy2
app.kubernetes.io/version: "v1.5.0" app.kubernetes.io/managed-by: Helm app.kubernetes.io/part-of: alloy app.kubernetes.io/component: config data: config.alloy: |-
logging { level = "info" format = "logfmt" }
profiling { enabled = true endpoint = "http://pyroscope:4040" application_name = "alloy" }
discovery.kubernetes "pods" { role = "pod" }
discovery.kubernetes "nodes" { role = "node" }
discovery.kubernetes "services" { role = "service" }
discovery.kubernetes "endpoints" { role = "endpoints" }
discovery.kubernetes "endpointslices" { role = "endpointslice" }
discovery.kubernetes "ingresses" { role = "ingress" }
|
使用 values.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| alloy: configMap: create: true content: | discovery.kubernetes "all_pods" { role = "pod" selectors { field = "spec.nodeName=" + env("HOSTNAME") role = "pod" } }
discovery.relabel "local_pods" { targets = discovery.kubernetes.all_pods.targets rule { action = "drop" regex = "Succeeded|Failed" source_labels = ["__meta_kubernetes_pod_phase"] } rule { action = "replace" regex = "(.*)@(.*)" replacement = "ebpf/${1}/${2}" separator = "@" source_labels = ["__meta_kubernetes_namespace", "__meta_kubernetes_pod_container_name"] target_label = "service_name" } rule { action = "labelmap" regex = "__meta_kubernetes_pod_label_(.+)" } rule { action = "replace" source_labels = ["__meta_kubernetes_namespace"] target_label = "namespace" } rule { action = "replace" source_labels = ["__meta_kubernetes_pod_name"] target_label = "pod" } rule { action = "replace" source_labels = ["__meta_kubernetes_node_name"] target_label = "node" } rule { action = "replace" source_labels = ["__meta_kubernetes_pod_container_name"] target_label = "container" } } pyroscope.ebpf "local_pods" { forward_to = [ pyroscope.write.endpoint.receiver ] targets = discovery.relabel.local_pods.output }
pyroscope.write "endpoint" { endpoint { url = "http://pyroscope:4040" } } securityContext: privileged: true runAsGroup: 0 runAsUser: 0
controller: hostPID: true
|
生成的配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| apiVersion: v1 kind: ConfigMap metadata: name: alloy2 namespace: common-infra-prod data: config.alloy: |- discovery.kubernetes "all_pods" { role = "pod" selectors { field = "spec.nodeName=" + env("HOSTNAME") role = "pod" } }
discovery.relabel "local_pods" { targets = discovery.kubernetes.all_pods.targets rule { action = "drop" regex = "Succeeded|Failed" source_labels = ["__meta_kubernetes_pod_phase"] } rule { action = "replace" regex = "(.*)@(.*)" replacement = "ebpf/${1}/${2}" separator = "@" source_labels = ["__meta_kubernetes_namespace", "__meta_kubernetes_pod_container_name"] target_label = "service_name" } rule { action = "labelmap" regex = "__meta_kubernetes_pod_label_(.+)" } rule { action = "replace" source_labels = ["__meta_kubernetes_namespace"] target_label = "namespace" } rule { action = "replace" source_labels = ["__meta_kubernetes_pod_name"] target_label = "pod" } rule { action = "replace" source_labels = ["__meta_kubernetes_node_name"] target_label = "node" } rule { action = "replace" source_labels = ["__meta_kubernetes_pod_container_name"] target_label = "container" } } pyroscope.ebpf "local_pods" { forward_to = [ pyroscope.write.endpoint.receiver ] targets = discovery.relabel.local_pods.output }
pyroscope.write "endpoint" { endpoint { url = "http://pyroscope:4040" } }
|