使用 Nginx InfluxDB 模块监控 Kubernetes Nginx Ingress
作者: Lorenzo Fontana / 产品, 用例, 开发者
2018 年 2 月 26 日
导航至
在将我们的一些容器工作负载迁移到 Kubernetes 的过程中,我们部署了 ingress-nginx 项目,以便拥有一个 Ingress 控制器,该控制器可以为传入暴露服务的流量检测 Nginx。
该项目本身制作精良,满足了我们对 Kubernetes 领域下项目的所有期望。总的来说,我们喜欢它拥有一个控制守护进程(控制器)通过管理、配置和扩展来控制 nginx 的想法。
然而,经过几周的使用,我们注意到整个系统缺少最重要的可观察性功能之一:实时跟踪所有传入请求(本地请求和代理请求)的能力。
事实上,借助 Prometheus 端点和 Telegraf 插件的混合使用,我们可以非常轻松地提取控制器状态的聚合指标。另一方面,对于某些情况,我们注意到跟踪每个请求并将请求直接推送到 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 控制器的方法。为此,我们实际上 fork 了 ingress 项目,以在其 nginx 内部编译该模块。
为什么要 fork?我们需要 fork 的原因有几个
- 制作完整的拉取请求以将模块与控制器深度集成(使用 configmap 和所有内容)需要 fork;
- Nginx 支持动态模块,但具有严格的运行时要求,不允许直接放入在其他环境中编译的模块共享对象;
要在 Kubernetes Nginx ingress 控制器中使用该模块,您有两种选择
- 使用直接 UDP 连接的简单用法
- 使用 Telegraf 作为 sidecar 代理进行连接
使用直接 UDP 连接的简单用法
使用直接 UDP 连接的简单用法
您可以通过替换 with-rbac.yml
或 without-rbac.yml
中控制器镜像为我们的 fork 的控制器,来遵循 官方步骤。
请注意: 我们的 fork 镜像了官方 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 作为 Sidecar 代理进行连接
此配置与官方配置略有不同,因为它涉及在每个 Nginx 控制器 pod 中部署 Telegraf 容器作为 sidecar 代理。为此,我们需要不同的控制器定义、用于配置 Telegraf 环境变量的 configmap 以及用于 InfluxDB url、用户名、密码和数据库的 secret。
控制器
---
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 仓库,旅程变得更加轻松,该仓库允许我们发现不良和边缘行为。此外,感谢 Ingress 控制器的高度可定制性以及公开了 nginx.ingress.kubernetes.io/configuration-snippet
,这在现阶段非常有用。