【SkyWalking从入门到精通】第24篇:SkyWalking Kubernetes部署实战——让监控与云原生共舞
·
上一篇【第23篇】SkyWalking与单体应用——老系统也能焕发新活力
下一篇【第25篇】SkyWalking的内存消息队列DataCarrier——高性能数据中转站
1. 引言:从"单机部署"到"集群编排"
上一篇文章我们聊了SkyWalking在单体应用中的价值。但是,当你的系统从一台服务器变成几十个Pod在Kubernetes集群中飘来飘去的时候,问题来了:
- Agent怎么装到每个Pod里?总不能让人手动SSH进容器吧?
- Pod的IP是动态变化的,OAP Server怎么找到Agent?
- Pod重启后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 Server | StatefulSet | 有状态服务,需要稳定的网络标识和存储 |
| UI | Deployment | 无状态Web服务,可水平扩展 |
| Elasticsearch | StatefulSet | 持久化存储Trace、指标数据 |
| Agent | InitContainer/Sidecar | 与应用容器共享卷,注入探针 |
3. Helm Chart一键部署
3.1 添加Helm仓库
# 添加SkyWalking官方Helm仓库
helm repo add skywalking https://apache.jfrog.io/artifactory/skywalking-helm
helm repo update
# 查看可用版本
helm search repo skywalking -l
3.2 自定义values.yaml
# skywalking-values.yaml
oap:
image:
tag: 9.7.0
replicas: 2
resources:
requests:
cpu: 2
memory: 4Gi
limits:
cpu: 4
memory: 8Gi
# 使用Elasticsearch作为存储
storageType: elasticsearch
env:
SW_STORAGE_ES_CLUSTER_NODES: "elasticsearch-master:9200"
SW_STORAGE_ES_USER: "elastic"
SW_STORAGE_ES_PASSWORD: "changeme"
# 暴露gRPC和HTTP端口
ports:
grpc: 11800
http: 12800
ui:
image:
tag: 9.7.0
service:
type: ClusterIP
port: 80
# 如果需要外部访问,可以改为NodePort或LoadBalancer
elasticsearch:
enabled: true
replicas: 3
minimumMasterNodes: 2
volumeClaimTemplate:
resources:
requests:
storage: 100Gi
3.3 安装部署
# 创建命名空间
kubectl create namespace skywalking
# 安装(将命名改为skywalking)
helm install skywalking skywalking/skywalking \
-n skywalking \
-f skywalking-values.yaml
# 查看部署状态
kubectl get pods -n skywalking
# 输出示例:
# 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
# 端口转发访问UI
kubectl port-forward svc/skywalking-ui 8080:80 -n skywalking
4. InitContainer方式挂载Agent
4.1 为什么要用InitContainer
在K8s中给应用注入Agent有三种主流方式:
+------------------------------------------------------------------+
| Agent注入方式对比 |
+------------------------------------------------------------------+
| |
| 方式 | 原理 | 优点 | 缺点 |
+------------------------------------------------------------------+
| InitContainer | 先用init容器拷贝 | 镜像无侵入 | 启动稍慢 |
| (推荐) | Agent到共享卷 | 易于维护 | |
+------------------------------------------------------------------+
| 基础镜像预装 | Dockerfile中 | 启动快 | 镜像耦合 |
| | 直接COPY Agent | | Agent升级 |
| | | | 需重构建 |
+------------------------------------------------------------------+
| Sidecar容器 | 同Pod的另一个 | 完全解耦 | 资源开销 |
| | 容器运行Agent | | 大 |
+------------------------------------------------------------------+
4.2 InitContainer配置示例
# app-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: order-service
template:
metadata:
labels:
app: order-service
spec:
# ① InitContainer:拷贝Agent到共享卷
initContainers:
- name: skywalking-agent-init
image: apache/skywalking-java-agent:9.3.0
imagePullPolicy: IfNotPresent
command:
- sh
- -c
- |
set -ex
# 拷贝Agent到共享挂载卷
cp -r /skywalking/agent/* /skywalking-agent/
echo "SkyWalking Agent copied successfully"
volumeMounts:
- name: skywalking-agent
mountPath: /skywalking-agent
# ② 应用容器
containers:
- name: order-service
image: myregistry/order-service:v1.2.3
ports:
- containerPort: 8080
env:
# ③ 环境变量传递配置
- name: SW_AGENT_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: SW_AGENT_COLLECTOR_BACKEND_SERVICES
value: "skywalking-oap.skywalking.svc.cluster.local:11800"
- name: SW_AGENT_INSTANCE_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: JAVA_TOOL_OPTIONS
value: "-javaagent:/skywalking-agent/skywalking-agent.jar"
volumeMounts:
- name: skywalking-agent
mountPath: /skywalking-agent
# ④ 共享卷
volumes:
- name: skywalking-agent
emptyDir: {}
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_NAME=order-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_name |
SW_AGENT_NAME |
服务名称 |
collector.backend_service |
SW_AGENT_COLLECTOR_BACKEND_SERVICES |
OAP地址 |
agent.instance_name |
SW_AGENT_INSTANCE_NAME |
实例名称 |
agent.sample_n_per_3_secs |
SW_AGENT_SAMPLE_N_PER_3_SECS |
采样率 |
logging.level |
SW_LOGGING_LEVEL |
日志级别 |
plugin.peer_max_length |
SW_PLUGIN_PEER_MAX_LENGTH |
对端地址最大长度 |
5.2 K8s环境变量注入最佳实践
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
template:
spec:
containers:
- name: order-service
env:
# 基础配置
- name: SW_AGENT_NAME
value: "order-service"
# OAP服务发现(使用K8s Service DNS)
- name: SW_AGENT_COLLECTOR_BACKEND_SERVICES
value: "skywalking-oap.skywalking:11800"
# 实例名使用Pod名(方便定位)
- name: SW_AGENT_INSTANCE_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
# 日志级别(生产环境用WARN)
- name: SW_LOGGING_LEVEL
value: "WARN"
# 采样率控制
- name: SW_AGENT_SAMPLE_N_PER_3_SECS
value: "1"
# 忽略健康检查端点
- name: SW_TRACE_IGNORE_PATH
value: "/actuator/**,/health,/metrics/**"
5.3 ConfigMap统一管理配置
# skywalking-agent-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: skywalking-agent-config
namespace: production
data:
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_params=true
plugin.springmvc.collect_http_params=true
# K8s下关闭服务端服务发现(使用Agent端配置)
plugin.kubernetes.enabled=false
6. 与K8s服务发现结合
6.1 OAP Serivce的Headless Service设计
# oap-service.yaml
apiVersion: v1
kind: Service
metadata:
name: skywalking-oap
namespace: skywalking
spec:
type: ClusterIP
clusterIP: None # Headless Service
ports:
- name: grpc
port: 11800
targetPort: 11800
- name: http
port: 12800
targetPort: 12800
selector:
app: skywalking-oap
6.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 API
env:
# 注入Pod所在节点信息
- name: SW_AGENT_INSTANCE_PROPERTIES
value: |
node_name=$(NODE_NAME)
namespace=$(POD_NAMESPACE)
pod_ip=$(POD_IP)
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
7. 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/v1
kind: Deployment
metadata:
name: order-service
spec:
template:
spec:
terminationGracePeriodSeconds: 60 # 给够60秒用于flush
containers:
- name: order-service
lifecycle:
preStop:
exec:
command:
- sh
- -c
- |
# 1. 等待Agent flush数据
sleep 10
# 2. 应用正常关闭
curl -X POST http://localhost:8080/actuator/shutdown
sleep 5
7.3 滚动更新时的追踪连续性
apiVersion: apps/v1
kind: Deployment
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 最多多启动1个Pod
maxUnavailable: 0 # 滚动期间不允许不可用Pod
# 配合readinessProbe确保新旧Pod追踪连续
template:
spec:
containers:
- name: order-service
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
failureThreshold: 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 Service,Agent自动发现OAP节点
- 优雅关闭:PreStop Hook确保Agent数据不丢失
Kubernetes不是监控的"敌人",而是最佳拍档——它提供了统一的部署、服务发现、滚动更新机制,搭配SkyWalking的自动探针注入,真正做到了"零配置接入"。
下一篇文章,我们将深入SkyWalking的内部机制,解析它的内存消息队列——DataCarrier,看看它是如何在Agent端实现高性能数据上报的。
上一篇【第23篇】SkyWalking与单体应用——老系统也能焕发新活力
下一篇【第25篇】SkyWalking的内存消息队列DataCarrier——高性能数据中转站
更多推荐


所有评论(0)