【SkyWalking从入门到精通】第24篇:SkyWalking Kubernetes部署实战——让监控与云原生共舞
上一篇【第23篇】SkyWalking与单体应用——老系统也能焕发新活力下一篇【第25篇】SkyWalking的内存消息队列DataCarrier——高性能数据中转站1. 引言从单机部署到集群编排上一篇文章我们聊了SkyWalking在单体应用中的价值。但是当你的系统从一台服务器变成几十个Pod在Kubernetes集群中飘来飘去的时候问题来了Agent怎么装到每个Pod里总不能让人手动SSH进容器吧Pod的IP是动态变化的OAP Server怎么找到AgentPod重启后IP变了Trace会不会断滚动更新时新旧Pod共存监控数据会不会乱这篇文章就是要回答这些问题。我们将完整走一遍SkyWalking在Kubernetes上的部署实战。2. K8s上的SkyWalking架构设计2.1 整体部署架构------------------------------------------------------------------ | SkyWalking on Kubernetes 部署架构 | ------------------------------------------------------------------ | | | ┌─────────────────── Kubernetes Cluster ──────────────────────┐ | | │ │ | | │ ┌──────────────────── Namespace: monitoring ───────────┐ │ | | │ │ │ │ | | │ │ ┌─────────────┐ ┌─────────────┐ │ │ | | │ │ │ OAP Pod-1 │ │ OAP Pod-2 │ StatefulSet │ │ | | │ │ │ gRPC:11800 │ │ gRPC:11800 │ │ │ | | │ │ │ HTTP:12800 │ │ HTTP:12800 │ │ │ | | │ │ └──────┬──────┘ └──────┬──────┘ │ │ | | │ │ └────────┬────────┘ │ │ | | │ │ ▼ │ │ | | │ │ ┌──────────────┐ │ │ | | │ │ │ UI Pod │ Deployment │ │ | | │ │ │ Port:8080 │ │ │ | | │ │ └──────────────┘ │ │ | | │ │ │ │ | | │ │ ┌──────────────────────────────────────────────────┐ │ │ | | │ │ │ Elasticsearch Cluster (可选) │ │ │ | | │ │ │ Storage: 指标 Trace数据 │ │ │ | | │ │ └──────────────────────────────────────────────────┘ │ │ | | │ └───────────────────────────────────────────────────────┘ │ | | │ │ | | │ ┌─────────── Namespace: production ─────────────────────┐ │ | | │ │ │ │ | | │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ | | │ │ │ App Pod-1│ │ App Pod-2│ │ App Pod-3│ │ │ | | │ │ │ ┌──────┐ │ │ ┌──────┐ │ │ ┌──────┐ │ │ │ | | │ │ │ │ Agent│ │ │ │ Agent│ │ │ │ Agent│ │ │ │ | | │ │ │ └──┬───┘ │ │ └──┬───┘ │ │ └──┬───┘ │ │ │ | | │ │ └────┼─────┘ └────┼─────┘ └────┼─────┘ │ │ | | │ │ └──────────────┼─────────────┘ │ │ | | │ │ │ gRPC 11800 │ │ | | │ └──────────────────────┼─────────────────────────────────┘ │ | | │ │ │ | | └─────────────────────────┼─────────────────────────────────────┘ | | │ | | ┌────────▼────────┐ | | │ Service: OAP │ | | │ ClusterIP:None │ | | └─────────────────┘ | ------------------------------------------------------------------2.2 核心组件说明组件K8s资源类型说明OAP ServerStatefulSet有状态服务需要稳定的网络标识和存储UIDeployment无状态Web服务可水平扩展ElasticsearchStatefulSet持久化存储Trace、指标数据AgentInitContainer/Sidecar与应用容器共享卷注入探针3. Helm Chart一键部署3.1 添加Helm仓库# 添加SkyWalking官方Helm仓库helm repoaddskywalking https://apache.jfrog.io/artifactory/skywalking-helm helm repo update# 查看可用版本helm search repo skywalking-l3.2 自定义values.yaml# skywalking-values.yamloap:image:tag:9.7.0replicas:2resources:requests:cpu:2memory:4Gilimits:cpu:4memory:8Gi# 使用Elasticsearch作为存储storageType:elasticsearchenv:SW_STORAGE_ES_CLUSTER_NODES:elasticsearch-master:9200SW_STORAGE_ES_USER:elasticSW_STORAGE_ES_PASSWORD:changeme# 暴露gRPC和HTTP端口ports:grpc:11800http:12800ui:image:tag:9.7.0service:type:ClusterIPport:80# 如果需要外部访问可以改为NodePort或LoadBalancerelasticsearch:enabled:truereplicas:3minimumMasterNodes:2volumeClaimTemplate:resources:requests:storage:100Gi3.3 安装部署# 创建命名空间kubectl create namespace skywalking# 安装将命名改为skywalkinghelminstallskywalking skywalking/skywalking\-nskywalking\-fskywalking-values.yaml# 查看部署状态kubectl get pods-nskywalking# 输出示例# NAME READY STATUS RESTARTS# skywalking-oap-0 1/1 Running 0# skywalking-oap-1 1/1 Running 0# skywalking-ui-7d8f9b5c-abc12 1/1 Running 0# skywalking-elasticsearch-master-0 1/1 Running 0# skywalking-elasticsearch-master-1 1/1 Running 0# skywalking-elasticsearch-master-2 1/1 Running 0# 端口转发访问UIkubectl port-forward svc/skywalking-ui8080:80-nskywalking4. InitContainer方式挂载Agent4.1 为什么要用InitContainer在K8s中给应用注入Agent有三种主流方式------------------------------------------------------------------ | Agent注入方式对比 | ------------------------------------------------------------------ | | | 方式 | 原理 | 优点 | 缺点 | ------------------------------------------------------------------ | InitContainer | 先用init容器拷贝 | 镜像无侵入 | 启动稍慢 | | (推荐) | Agent到共享卷 | 易于维护 | | ------------------------------------------------------------------ | 基础镜像预装 | Dockerfile中 | 启动快 | 镜像耦合 | | | 直接COPY Agent | | Agent升级 | | | | | 需重构建 | ------------------------------------------------------------------ | Sidecar容器 | 同Pod的另一个 | 完全解耦 | 资源开销 | | | 容器运行Agent | | 大 | ------------------------------------------------------------------4.2 InitContainer配置示例# app-deployment.yamlapiVersion:apps/v1kind:Deploymentmetadata:name:order-servicenamespace:productionspec:replicas:3selector:matchLabels:app:order-servicetemplate:metadata:labels:app:order-servicespec:# ① InitContainer拷贝Agent到共享卷initContainers:-name:skywalking-agent-initimage:apache/skywalking-java-agent:9.3.0imagePullPolicy:IfNotPresentcommand:-sh--c-|set -ex # 拷贝Agent到共享挂载卷 cp -r /skywalking/agent/* /skywalking-agent/ echo SkyWalking Agent copied successfullyvolumeMounts:-name:skywalking-agentmountPath:/skywalking-agent# ② 应用容器containers:-name:order-serviceimage:myregistry/order-service:v1.2.3ports:-containerPort:8080env:# ③ 环境变量传递配置-name:SW_AGENT_NAMEvalueFrom:fieldRef:fieldPath:metadata.name-name:SW_AGENT_COLLECTOR_BACKEND_SERVICESvalue:skywalking-oap.skywalking.svc.cluster.local:11800-name:SW_AGENT_INSTANCE_NAMEvalueFrom:fieldRef:fieldPath:metadata.name-name:JAVA_TOOL_OPTIONSvalue:-javaagent:/skywalking-agent/skywalking-agent.jarvolumeMounts:-name:skywalking-agentmountPath:/skywalking-agent# ④ 共享卷volumes:-name:skywalking-agentemptyDir:{}4.3 工作流程图------------------------------------------------------------------ | InitContainer Agent注入流程 | ------------------------------------------------------------------ | | | 时间线: | | ──────────────────────────────────────────────────────────────→ | | | | ① InitContainer启动 | | ┌──────────────────────────────────────────┐ | | │ apache/skywalking-java-agent:9.3.0 │ | | │ cp -r /skywalking/agent/* /agent-volume/ │ | | └───────────────────┬──────────────────────┘ | | │ 拷贝完成 | | ┌───────────▼───────────┐ | | │ 共享卷 (emptyDir) │ | | │ ┌──────────────────┐ │ | | │ │ skywalking-agent │ │ | | │ │ .jar │ │ | | │ └────────┬─────────┘ │ | | └───────────┼───────────┘ | | │ | | ② 应用容器启动 │ | | ┌───────────────────▼──────────────────────┐ | | │ JAVA_TOOL_OPTIONS │ | | │ -javaagent:/skywalking-agent/ │ | | │ skywalking-agent.jar │ | | │ │ | | │ SW_AGENT_NAMEorder-service-pod-xxx │ | | │ SW_AGENT_COLLECTOR_BACKEND_SERVICES │ | | │ skywalking-oap:11800 │ | | └──────────────────────────────────────────┘ | ------------------------------------------------------------------5. Environment Variables传递配置5.1 Agent配置环境变量对照表SkyWalking Java Agent支持通过环境变量覆盖配置SW_前缀agent.config 配置项环境变量说明agent.service_nameSW_AGENT_NAME服务名称collector.backend_serviceSW_AGENT_COLLECTOR_BACKEND_SERVICESOAP地址agent.instance_nameSW_AGENT_INSTANCE_NAME实例名称agent.sample_n_per_3_secsSW_AGENT_SAMPLE_N_PER_3_SECS采样率logging.levelSW_LOGGING_LEVEL日志级别plugin.peer_max_lengthSW_PLUGIN_PEER_MAX_LENGTH对端地址最大长度5.2 K8s环境变量注入最佳实践apiVersion:apps/v1kind:Deploymentmetadata:name:order-servicespec:template:spec:containers:-name:order-serviceenv:# 基础配置-name:SW_AGENT_NAMEvalue:order-service# OAP服务发现使用K8s Service DNS-name:SW_AGENT_COLLECTOR_BACKEND_SERVICESvalue:skywalking-oap.skywalking:11800# 实例名使用Pod名方便定位-name:SW_AGENT_INSTANCE_NAMEvalueFrom:fieldRef:fieldPath:metadata.name# 日志级别生产环境用WARN-name:SW_LOGGING_LEVELvalue:WARN# 采样率控制-name:SW_AGENT_SAMPLE_N_PER_3_SECSvalue:1# 忽略健康检查端点-name:SW_TRACE_IGNORE_PATHvalue:/actuator/**,/health,/metrics/**5.3 ConfigMap统一管理配置# skywalking-agent-configmap.yamlapiVersion:v1kind:ConfigMapmetadata:name:skywalking-agent-confignamespace:productiondata:agent.config:|# 统一Agent配置 agent.service_name${SW_AGENT_NAME:unknown} collector.backend_service${SW_AGENT_COLLECTOR_BACKEND_SERVICES:skywalking-oap:11800} agent.sample_n_per_3_secs${SW_AGENT_SAMPLE_N_PER_3_SECS:1} logging.level${SW_LOGGING_LEVEL:WARN} plugin.tomcat.collect_http_paramstrue plugin.springmvc.collect_http_paramstrue # K8s下关闭服务端服务发现使用Agent端配置 plugin.kubernetes.enabledfalse6. 与K8s服务发现结合6.1 OAP Serivce的Headless Service设计# oap-service.yamlapiVersion:v1kind:Servicemetadata:name:skywalking-oapnamespace:skywalkingspec:type:ClusterIPclusterIP:None# Headless Serviceports:-name:grpcport:11800targetPort:11800-name:httpport:12800targetPort:12800selector:app:skywalking-oap6.2 K8s环境下的服务发现流程------------------------------------------------------------------ | K8s服务发现 SkyWalking | ------------------------------------------------------------------ | | | Application Pod | | ┌──────────────────────────────────────────────┐ | | │ SW_AGENT_COLLECTOR_BACKEND_SERVICES │ | | │ skywalking-oap.skywalking:11800 │ | | └───────────────────┬──────────────────────────┘ | | │ | | │ DNS解析 | | ▼ | | ┌──────────────────────────────────────────────┐ | | │ CoreDNS │ | | │ skywalking-oap.skywalking → Headless Service │ | | │ → 返回所有OAP Pod IP │ | | │ → 192.168.1.10, 192.168.1.11 │ | | └───────────────────┬──────────────────────────┘ | | │ | | ┌───────────┼───────────┐ | | ▼ ▼ | | ┌──────────────┐ ┌──────────────┐ | | │ OAP Pod-1 │ │ OAP Pod-2 │ | | │ 192.168.1.10 │ │ 192.168.1.11 │ | | └──────────────┘ └──────────────┘ | | | | SkyWalking Agent内置的gRPC负载均衡会自动选择可用OAP | | 如果OAP Pod-1挂了Agent会自动切换到Pod-2 | ------------------------------------------------------------------6.3 使用Kubernetes Downward APIenv:# 注入Pod所在节点信息-name:SW_AGENT_INSTANCE_PROPERTIESvalue:|node_name$(NODE_NAME) namespace$(POD_NAMESPACE) pod_ip$(POD_IP)-name:NODE_NAMEvalueFrom:fieldRef:fieldPath:spec.nodeName-name:POD_NAMESPACEvalueFrom:fieldRef:fieldPath:metadata.namespace-name:POD_IPvalueFrom:fieldRef:fieldPath:status.podIP7. Pod重启与滚动更新时的追踪连续性7.1 Pod重启对Trace的影响------------------------------------------------------------------ | Pod重启场景分析 | ------------------------------------------------------------------ | | | 场景1: 优雅关闭Graceful Shutdown | | ┌────────────────────────────────────────────────┐ | | │ PreStop Hook → Drain流量 → Agent flush数据 │ | | │ → 关闭gRPC连接 → Pod终止 │ | | │ → 效果: Trace不丢失 ✅ │ | | └────────────────────────────────────────────────┘ | | | | 场景2: 强制终止SIGKILL | | ┌────────────────────────────────────────────────┐ | | │ kubelet SIGTERM → 等待gracePeriod → SIGKILL │ | | │ → 数据未flush → 少量Trace丢失 ⚠️ │ | | └────────────────────────────────────────────────┘ | | | | 场景3: OOM Kill | | ┌────────────────────────────────────────────────┐ | | │ 内存超限 → 内核直接kill → 数据100%丢失 │ | | └────────────────────────────────────────────────┘ | ------------------------------------------------------------------7.2 优雅关闭配置apiVersion:apps/v1kind:Deploymentmetadata:name:order-servicespec:template:spec:terminationGracePeriodSeconds:60# 给够60秒用于flushcontainers:-name:order-servicelifecycle:preStop:exec:command:-sh--c-|# 1. 等待Agent flush数据 sleep 10 # 2. 应用正常关闭 curl -X POST http://localhost:8080/actuator/shutdown sleep 57.3 滚动更新时的追踪连续性apiVersion:apps/v1kind:Deploymentspec:strategy:type:RollingUpdaterollingUpdate:maxSurge:1# 最多多启动1个PodmaxUnavailable:0# 滚动期间不允许不可用Pod# 配合readinessProbe确保新旧Pod追踪连续template:spec:containers:-name:order-servicereadinessProbe:httpGet:path:/actuator/health/readinessport:8080initialDelaySeconds:30periodSeconds:10failureThreshold:3滚动更新时的状态变化------------------------------------------------------------------ | 滚动更新中的Pod与Agent状态 | ------------------------------------------------------------------ | | | 时间: T0 T1 T2 T3 T4 | | ──────────────────────────────────────────────────────────────→ | | | | Pod-A1 (旧) [在线] [在线] [在线] [PreStop] [已终止] | | Agent-A1 [上报] [上报] [上报] [Flush] [断开] | | | | Pod-A2 (旧) [在线] [在线] [PreStop] [已终止] | | Agent-A2 [上报] [上报] [Flush] [断开] | | | | Pod-B1 (新) [启动] [在线] [在线] [在线] | | Agent-B1 [连接] [上报] [上报] [上报] | | | | Pod-B2 (新) [启动] [在线] [在线] | | Agent-B2 [连接] [上报] [上报] | | | | 追踪状态: 正常 正常 正常 正常 正常 | | (只要同Service的Pod至少有一个在线Trace不会中断) | ------------------------------------------------------------------8. 监控自举——SkyWalking监控SkyWalking部署好之后别忘了——OAP Server本身也值得监控# OAP自身的监控暴露oap:env:# 启用自监控SW_PROMETHEUS_FETCHER_ENABLE:true# 暴露metrics端点SW_TELEMETRY:prometheus# 暴露端口SW_PROMETHEUS_FETCHER_PORT:1234然后就可以用Prometheus Grafana监控OAP自身的CPU、内存、gRPC吞吐量等指标。9. 总结SkyWalking在Kubernetes上的部署核心是三个字“解耦适配”InitContainer注入Agent应用镜像和Agent镜像解耦Agent升级不需要重打应用镜像环境变量传递配置告别配置文件配置随Pod走K8s Service发现利用DNS和Headless ServiceAgent自动发现OAP节点优雅关闭PreStop Hook确保Agent数据不丢失Kubernetes不是监控的敌人而是最佳拍档——它提供了统一的部署、服务发现、滚动更新机制搭配SkyWalking的自动探针注入真正做到了零配置接入。下一篇文章我们将深入SkyWalking的内部机制解析它的内存消息队列——DataCarrier看看它是如何在Agent端实现高性能数据上报的。上一篇【第23篇】SkyWalking与单体应用——老系统也能焕发新活力下一篇【第25篇】SkyWalking的内存消息队列DataCarrier——高性能数据中转站