Kubernetes集群中向Logstash发送日志失败的问题求助
背景
在Kubernetes集群内运行Logstash实例,已配置Ingress规则和TCP输入。执行命令curl http://logstash-tcp.testing.com后,能成功请求端点,且云端可见curl日志。

问题描述
在Kubernetes集群外部或Logstash容器内部执行命令echo "Test message" | logger -t logstash-tcp.testing.com -P 80手动发送日志时,日志无法送达Logstash。
环境配置
- Elastic Cloud已配置并连接
- minikube版本:v1.28.0
- kubectl版本:
Client Version: version.Info{Major:"1", Minor:"26", GitVersion:"v1.26.0", GitCommit:"b46a3f887ca979b1a5d14fd39cb1af43e7e5d12d", GitTreeState:"clean", BuildDate:"2022-12-08T19:58:30Z", GoVersion:"go1.19.4", Compiler:"gc", Platform:"linux/amd64"} Kustomize Version: v4.5.7 Server Version: version.Info{Major:"1", Minor:"25", GitVersion:"v1.25.3", GitCommit:"434bfd82814af038ad94d62ebe59b133fcb50506", GitTreeState:"clean", BuildDate:"2022-10-12T10:49:09Z", GoVersion:"go1.19.2", Compiler:"gc", Platform:"linux/amd64"}
- helm版本:v3.10.3
- Ubuntu版本:20.04
- Logstash Helm包来自Artifact Hub
自定义values配置
persistence: enabled: false logstashConfig: logstash.yml: | http.host: 0.0.0.0 xpack.monitoring.enabled: true logstashPipeline: uptime.conf: | input { exec { command => "uptime" interval => 30 } gelf { port => 5959 } tcp { port => 5960 codec => json } } filter { mutate { add_field => { "environment" => "dev" } } } output { elasticsearch { index => "logstash-dev-%{+YYYY-MM-dd}" } } ingress: enabled: true hosts: - host: logstash-gelf.testing.com paths: - path: / servicePort: 5959 - host: logstash-tcp.testing.com paths: - path: / servicePort: 5960 service: # annotations: {} type: ClusterIP # loadBalancerIP: "" ports: - name: gelf-port port: 5959 protocol: UDP targetPort: 5959 - name: tcp-port port: 5960 protocol: TCP targetPort: 5960 extraPorts: - name: gelf-port containerPort: 5959 - name: tcp-port containerPort: 5960
Ingress描述结果
执行kubectl describe ingress输出:
Name: logstash-elastic-logstash Labels: app=logstash-elastic-logstash app.kubernetes.io/managed-by=Helm chart=logstash heritage=Helm release=logstash-elastic Namespace: default Address: 192.168.39.184 Ingress Class: nginx Default backend: <default> Rules: Host Path Backends ---- ---- -------- logstash-gelf.testing.com / logstash-elastic-logstash:5959 (172.17.0.3:5959) logstash-tcp.testing.com / logstash-elastic-logstash:5960 (172.17.0.3:5960) Annotations: meta.helm.sh/release-name: logstash-elastic meta.helm.sh/release-namespace: default Events: <none>
问题排查与解决建议
1. 核心问题:标准HTTP Ingress不支持原始TCP转发
你当前配置的是标准HTTP Ingress,仅能处理HTTP/HTTPS流量。curl能成功是因为它发送的是HTTP请求,而logger发送的是原始TCP数据,Ingress Controller不会将这类流量路由到Logstash的TCP端口。
2. 解决方法:配置Nginx Ingress的TCP路由
Nginx Ingress Controller支持TCP/UDP服务暴露,需通过以下步骤配置:
- 创建/修改Nginx Ingress的ConfigMap(通常位于
kube-system命名空间,名称为nginx-ingress-controller),添加TCP端口映射:
apiVersion: v1 kind: ConfigMap metadata: name: nginx-ingress-controller namespace: kube-system data: 80: "default/logstash-elastic-logstash:5960"
这里80是外部访问端口,default/logstash-elastic-logstash:5960对应你的Logstash服务的命名空间、服务名和TCP端口。
- 更新Nginx Ingress Controller的Deployment:
在Deployment的args中添加参数:
同时在--tcp-services-configmap=$(POD_NAMESPACE)/nginx-ingress-controllervolumes和volumeMounts中添加该ConfigMap的挂载配置。
3. 修正logger命令的参数错误
你使用的logger命令中,-t是设置日志标签,而非目标主机。正确的测试命令应直接发送JSON格式数据到目标主机(Logstash TCP输入配置了codec => json,需发送JSON格式内容):
echo '{"message": "Test message"}' | nc logstash-tcp.testing.com 80
4. 容器内部的直接测试方式
在Logstash容器内部,绕过Ingress和Service,直接连接本地端口验证:
echo '{"message": "Test container message"}' | nc localhost 5960
若此方式能成功接收日志,说明Logstash本身的TCP输入配置正常,问题出在外部路由。
5. 临时端口转发验证Service可用性
通过kubectl port-forward临时转发端口,测试Service是否能正常转发流量:
kubectl port-forward service/logstash-elastic-logstash 5960:5960
然后在本地执行nc localhost 5960发送JSON数据,若能到达Logstash,说明Service配置正常,问题在Ingress层。
内容的提问来源于stack exchange,提问作者sflee

