使用Nginx InfluxDB模块监控Kubernetes Nginx Ingress
作者:Lorenzo Fontana / 产品,用例,开发者
2018年2月26日
导航至
在我们将一些容器工作负载迁移到Kubernetes的过程中,我们部署了ingress-nginx项目,以拥有一个能够对暴露服务的传入流量进行仪表化的Ingress控制器。
该项目本身制作得相当精良,并满足了我们在Kubernetes环境下对项目的所有期望。总体来说,我们喜欢它有一个控制守护进程(控制器)通过管理、配置和扩展Nginx来控制nginx的想法。
然而,在使用了几个星期之后,我们发现整个系统缺少了一个最重要的可观察性功能:实时跟踪所有传入请求,无论是本地请求还是代理请求。
事实上,由于Prometheus端点(Prometheus endpoint)和Telegraf插件(Telegraf plugin)的使用混合,我们很容易拉取控制器状态的聚合指标。另一方面,在特定情况下,我们发现对我们来说非常有用,能够跟踪每个请求,并在它发生时立即将其推送到InfluxDB。
我们想要这样做的三个主要原因
- 尽快发现任何代理后端错误或意外状态码;
- 了解客户端如何连接到我们的服务、HTTP方法、连接类型和请求的端点;
- 对原始数据流采取行动(使用Kapacitor)。在这种情况下,由于数据本身的性质,这更为有效。例如,如果请求没有处理并返回给发起请求的客户,我想要一个警报,然后,在警报之后,我想要对这个特定请求采取行动。
当发生恶意请求时,进行此类查询是理想的情况
SELECT * FROM FROM nginx_requests.threedays WHERE "status" = '502'
1518524349994255769 173 0 text/html 152 GET 35 myserver 502 /bad
1518524349994714916 173 0 text/html 152 GET 35 myserver 502 /bad
在互联网上搜索了一些之后,我们编写了一个模块(nginx-influxdb-module),它作为每个请求上的过滤器以非阻塞方式工作,并使用UDP和行协议将处理后的数据发送到InfluxDB后端。
Kubernetes Ingress和Telegraf作为Sidecar
编写了Nginx模块来满足我们的需求后,我们需要将其连接到Kubernetes Ingress控制器。为此,我们实际上分叉了ingress项目,在nginx中编译该模块。
为什么分叉?我们需要分叉有几个原因
- 制作一个深度集成的完整pull request(包括configmaps等)与控制器是一项需要分叉的努力;
- Nginx支持动态模块,但它有严格的运行时要求,不允许在某个环境中编译的模块共享对象直接放入;
要在Kubernetes Nginx Ingress控制器中使用该模块,您有两个选项
- 直接UDP连接的普通使用
- 使用Telegraf作为旁路代理进行连接
直接UDP连接的简单用法
直接UDP连接的简单用法
您可以通过将with-rbac.yml
或without-rbac.yml
中的控制器镜像替换为我们的分支控制器,来遵循官方步骤。
注意:我们的分支正在镜像官方ingress控制器的实际标签。从nginx-0.10.2
开始的每个标签,您都可以在这里找到对应的标签。
目前我们没有一组深度集成的特定参数,但我们依赖于nginx.ingress.kubernetes.io/configuration-snippet注解
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/configuration-snippet: |
influxdb server_name=yourappname host=your-influxdb port=8089 measurement=nginx enabled=true;
使用注解配置InfluxDB模块的完整示例如下
---
apiVersion: v1
kind: Namespace
metadata:
name: caturday
---
apiVersion: v1
kind: Service
metadata:
name: caturday
namespace: caturday
labels:
app: caturday
spec:
selector:
app: caturday
ports:
- name: caturday
port: 8080
protocol: TCP
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/configuration-snippet: |
influxdb server_name=acceptance-ingress host=127.0.0.1 port=8094 measurement=nginx enabled=true;
name: caturday
namespace: caturday
spec:
rules:
- host: kittens.local
http:
paths:
- backend:
serviceName: caturday
servicePort: 8080
path: /
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: caturday
namespace: caturday
labels:
app: catrday
spec:
replicas: 3
selector:
matchLabels:
app: caturday
template:
metadata:
labels:
app: caturday
spec:
containers:
- name: caturday
image: docker.io/fntlnz/caturday:latest
resources:
limits:
cpu: 0.1
memory: 100M
使用Telegraf作为旁路代理进行连接
此配置与官方配置略有不同,因为它涉及到在每个Nginx控制器pod中部署一个Telegraf容器作为旁路代理。为此,我们需要不同的控制器定义,一个configmap来配置Telegraf的环境变量,以及一个secret来配置InfluxDB的URL、用户名、密码和数据库名。
控制器
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-ingress-controller
namespace: ingress-nginx
spec:
replicas: 1
selector:
matchLabels:
app: ingress-nginx
template:
metadata:
labels:
app: ingress-nginx
annotations:
prometheus.io/port: '10254'
prometheus.io/scrape: 'true'
spec:
serviceAccountName: nginx-ingress-serviceaccount
initContainers:
- command:
- sh
- -c
- sysctl -w net.core.somaxconn=32768; sysctl -w net.ipv4.ip_local_port_range="1024 65535"
image: docker.io/alpine:3.6
imagePullPolicy: IfNotPresent
name: sysctl
securityContext:
privileged: true
containers:
- name: nginx-ingress-controller
image: quay.io/fntlnz/nginx-ingress-controller:kubernetes-controller-8b30ff6
args:
- /nginx-ingress-controller
- --default-backend-service=$(POD_NAMESPACE)/default-http-backend
- --configmap=$(POD_NAMESPACE)/nginx-configuration
- --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
- --udp-services-configmap=$(POD_NAMESPACE)/udp-services
- --annotations-prefix=nginx.ingress.kubernetes.io
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
livenessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
- name: nginx-telegraf-collector
image: docker.io/telegraf:1.5.2
ports:
- name: udp
containerPort: 8094
env:
- name: HOSTNAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: ENV
valueFrom:
secretKeyRef:
name: telegraf
key: env
- name: MONITOR_RETENTION_POLICY
valueFrom:
secretKeyRef:
name: telegraf
key: monitor_retention_policy
- name: MONITOR_USERNAME
valueFrom:
secretKeyRef:
name: telegraf
key: monitor_username
- name: MONITOR_PASSWORD
valueFrom:
secretKeyRef:
name: telegraf
key: monitor_password
- name: MONITOR_HOST
valueFrom:
secretKeyRef:
name: telegraf
key: monitor_host
- name: MONITOR_DATABASE
valueFrom:
secretKeyRef:
name: telegraf
key: monitor_database
volumeMounts:
- name: config
mountPath: /etc/telegraf
volumes:
- name: config
configMap:
name: telegraf
Telegraf的ConfigMap
---
apiVersion: v1
kind: ConfigMap
metadata:
name: telegraf
namespace: ingress-nginx
labels:
k8s-app: telegraf
data:
telegraf.conf: |+
[global_tags]
env = "$ENV"
[agent]
interval = "10s"
round_interval = true
metric_batch_size = 1000
metric_buffer_limit = 10000
collection_jitter = "0s"
flush_interval = "10s"
flush_jitter = "0s"
precision = ""
debug = false
quiet = false
logfile = ""
hostname = "$HOSTNAME"
omit_hostname = false
[[outputs.influxdb]]
urls = ["$MONITOR_HOST"]
database = "$MONITOR_DATABASE"
retention_policy = "$MONITOR_RETENTION_POLICY"
write_consistency = "any"
timeout = "5s"
username = "$MONITOR_USERNAME"
password = "$MONITOR_PASSWORD"
[[inputs.socket_listener]]
service_address = "udp://:8094"
需要配置configmap以允许Telegraf连接到InfluxDB后端。为此
kubectl create secret -n ingress-nginx generic telegraf \
--from-literal=env=acc \
--from-literal=monitor_retention_policy="threedays" \
--from-literal=monitor_username="" \
--from-literal=monitor_password="" \
--from-literal=monitor_host=http://your-influxdb:8086 \
--from-literal=monitor_database=nginx_ingress
在上面的示例中,我们使用了“threedays”作为保留策略。您可以将保留策略留空,但如果您想保留三天,就像示例中那样,您可以简单地这样做查询
CREATE RETENTION POLICY threedays ON nginx_ingress DURATION 3d REPLICATION 1
下一步
总体计划是稳定模块的API并发布1.0版本。在这个过程中,我们将完成与Kubernetes Ingress的集成,并向上游项目提交PR,以允许人们在他们自己的Ingress控制器中可选地启用该模块。
这适合用于生产吗?
我们正在生产中使用所有这些,然而,我们不建议您在这个阶段这样做。如果您有一个预演/验收环境,您可以对其进行测试,并为模块做出贡献,以帮助我们推进1.0版本,并帮助我们为kubernetes/ingress-nginx项目做出贡献。
结论
尽管编写这种模块是一种简单的方法,但它仍然需要努力。幸运的是,由于nginx/nginx-tests仓库允许我们识别出错误和边缘行为,因此旅行之路已经变得更容易。此外,对可高度自定义并公开nginx.ingress.kubernetes.io/configuration-snippet
的Ingress控制器表示敬意,这在这一阶段非常有用。