Metricbeat kubernetes module can’t connect to kubelet - kubernetes

We have a setup, where Metricbeat is deployed as a DaemonSet on a Kubernetes cluster (specifically -- AWS EKS).
All seems to be functioning properly, but the kubelet connection.
To clarify, the following module:
- module: kubernetes
enabled: true
metricsets:
- state_pod
period: 10s
hosts: ["kube-state-metrics.system:8080"]
works properly (the events flow into logstash/elastic).
This module configuration, however, doesn't work in any variants of hosts value (localhost/kubernetes.default/whatever):
- module: kubernetes
period: 10s
metricsets:
- pod
hosts: ["localhost:10255"]
enabled: true
add_metadata: true
in_cluster: true
NOTE: using cluster IP instead of localhost (so that it goes to
control plane) also works (although doesn't retrieve the needed
information, of course).
The configuration above was taken directly from the Metricbeat
documentation and immediately struck me as odd -- how does localhost
get translated (from within Metricbeat docker) to corresponding
kubelet?
The error is, as one would expect, in light of the above:
error making http request: Get http://localhost:10255/stats/summary:
dial tcp [::1]:10255: connect: cannot assign requested address
which indicates some sort of connectivity issue.
However, when SSH-ing to any node Metricbeat is deployed on, http://localhost:10255/stats/summary provides the correct output:
{
"node": {
"nodeName": "...",
"systemContainers": [
{
"name": "pods",
"startTime": "2018-12-06T11:22:07Z",
"cpu": {
"time": "2018-12-23T06:54:06Z",
...
},
"memory": {
"time": "2018-12-23T06:54:06Z",
"availableBytes": 17882275840,
....
I must be missing something very obvious. Any suggestion would do.
NOTE: I cross-posted (and got no response for a couple of days) the same on Elasticsearch Forums

Inject the Pod's Node's IP via the valueFrom provider in the env: list:
env:
- name: HOST_IP
valueFrom:
fieldRef: status.hostIP
and then update the metricbeat config file to use the host's IP:
hosts: ["${HOST_IP}:10255"]
which metricbeat will resolve via its environment variable config injection

Related

Connect Consul client on VM to Consul Server in Kubernetes

I'm having trouble setting up this scenario. I have a server that's running 4 VMs:
k8s master
k8s worker 1
k8s worker 2
vm1
I've deployed a Consul cluster with Helm chart into k8s cluster, resulting in 1 server on each worker node, 1 client on each worker node. Here's current config (I'm trying all sorts of things so some might be commented/disabled)
global:
name: consul
enabled: true
datacenter: dc1
gossipEncryption:
autoGenerate: true
tls:
enabled: true
enableAutoEncrypt: true
verify: true
acls:
manageSystemACLs: true
# client:
# exposeGossipPorts: true
server:
replicas: 2
# exposeGossipAndRPCPorts: true
# ports:
# serflan:
# port: 9301
extraConfig: |
{ "log_level": "debug" }
exposeService:
enabled: true
type: NodePort
nodePort:
http: 31500 # 8500 + 23k
https: 31501 # 8501 + 23k
grpc: 31503 # 8503 + 23k
serf: 32301 # 9301 + 23k
rpc: 31300 # 8300 + 23k
securityContext:
runAsNonRoot: false
runAsUser: 0
storageClass: nfs-synology-test
connectInject:
enabled: true
controller:
enabled: true
syncCatalog:
enabled: true
dns:
enabled: true
This works mostly fine in the cluster itself (I can run a Job that does a dig to a Consul service name and I do get a response). Now I wanted to install another Consul client, this time on the vm1 VM and join it into my Consul in K8s cluster.
As you can see in the comments, I've tried exposing gossip and RPC ports as host ports, now instead exposing the server service as NodePort service on given ports.
From the VM I can verify with nmap that those ports are indeed open on TCP, but for the love of all that's holy I can't figure out what to configure in the vm1 client. Here's my current config:
{
"server": false,
"domain": "consul",
"datacenter": "dc1",
"data_dir": "/etc/consul/data",
"tls": {
"defaults": {
"ca_file": "/etc/consul/tls/ca/tls.crt",
"verify_incoming": false,
"verify_outgoing": true
},
"internal_rpc": {
"verify_server_hostname": true
}
},
"auto_encrypt": { "tls": true },
"encrypt": "redacted",
"log_level": "DEBUG",
"enable_syslog": true,
"leave_on_terminate": true,
"retry_join": [
"192.168.1.207:32301",
"192.168.1.208:32301",
"10.233.94.138:8300",
"10.233.119.94:8300"
],
"advertise_addr": "192.168.1.230",
"bind_addr": "0.0.0.0",
"ports": { "server": 31300 },
"acl": {
"tokens": {
"agent": "redacted",
"default": "redacted"
}
}
}
I've taken the value of encrypt from the secret in k8s, same as the tls.crt. I've tried to generate a token with the GUI assigned to client-policy, defined as:
node_prefix "" {
policy = "write"
}
service_prefix "" {
policy = "read"
}
But all to no avail. The client generally fails UDP connections, tries to connect to internal k8s cluster IPs (even without me adding them to retry_join, again just trying), overall geting timeouts and rpc error: lead thread didn't get connection.
I'm out of ideas and I'm at the stage of just trying random ports and configs until I hit jackpots. Can anyone help?
I somewhat figured out my answer so posting if anyone is stuck on the same thing. While I like exposing a service on node ports, it didn't quite work out. The servers were accessible from the 32301 port (so VM client was able to join), but the server themselves were advertising themselves on the pod IP which was inaccessible from outside.
The solution in my case was:
actually use the commented out client.exposeGossipPorts: true, server.exposeGossipAndRPCPorts: true and server.ports.serflan.port: 9301
retry_join in the config should use the node IP + 9301 port
the way I set up the TLS cert, tokens and encrypt was probably right
as far as RPC and failing UDP, the problem was in the fact that Kube cluster failed to deploy the servers and clients correctly (Serflan-UDP ports weren't exposed via UDP). When I kubectl patched it, it started to work (eventually we fixed the cluster itself instead)

cetic-nifi Invalid host header issue

Helm version: v3.5.2
Kubernetes version: v1.20.4
nifi chart version:latest : 1.0.2 rel
Issue: [cetic/nifi]-issue
I'm trying to connect to nifi UI deployed in kubernetes.
I have set following properties in values yaml
properties:
# use externalSecure for when inbound SSL is provided by nginx-ingress or other external mechanism
sensitiveKey: changeMechangeMe # Must to have minimal 12 length key
algorithm: NIFI_PBKDF2_AES_GCM_256
externalSecure: false
isNode: false
httpsPort: 8443
webProxyHost: 10.0.39.39:30666
clusterPort: 6007
# ui service
service:
type: NodePort
httpsPort: 8443
nodePort: 30666
annotations: {}
# loadBalancerIP:
## Load Balancer sources
## https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service
##
# loadBalancerSourceRanges:
# - 10.10.10.0/24
## OIDC authentication requires "sticky" session on the LoadBalancer for JWT to work properly...but AWS doesn't like it on creation
# sessionAffinity: ClientIP
# sessionAffinityConfig:
# clientIP:
# timeoutSeconds: 10800
10.0.39.39 - is the kubernetes masternode internal ip.
When nifi get started i get follwoing
WARNING: Kubernetes configuration file is group-readable. This is insecure. Location: /home/k8sadmin/.kube/config
WARNING: Kubernetes configuration file is world-readable. This is insecure. Location: /home/k8sadmin/.kube/config
NAME: nifi
LAST DEPLOYED: Thu Nov 25 12:38:00 2021
NAMESPACE: jeed-cluster
STATUS: deployed
REVISION: 1
NOTES:
Cluster endpoint IP address will be available at:
kubectl get svc nifi -n jeed-cluster -o jsonpath='{.status.loadBalancer.ingress[*].ip}'
Cluster endpoint domain name is: 10.0.39.39:30666 - please update your DNS or /etc/hosts accordingly!
Once you are done, your NiFi instance will be available at:
https://10.0.39.39:30666/nifi
and when i do a curl
curl https://10.0.39.39:30666 put sample.txt -k
<h1>System Error</h1>
<h2>The request contained an invalid host header [<code>10.0.39.39:30666</
the request [<code>/</code>]. Check for request manipulation or third-part
t.</h2>
<h3>Valid host headers are [<code>empty
<ul><li>127.0.0.1</li>
<li>127.0.0.1:8443</li>
<li>localhost</li>
<li>localhost:8443</li>
<li>[::1]</li>
<li>[::1]:8443</li>
<li>nifi-0.nifi-headless.jeed-cluste
<li>nifi-0.nifi-headless.jeed-cluste
<li>10.42.0.8</li>
<li>10.42.0.8:8443</li>
<li>0.0.0.0</li>
<li>0.0.0.0:8443</li>
</ul>
Tried lot of things but still cannot whitelist master node ip in
proxy hosts
Ingress is not used
edit: it looks like properties set in values.yaml is not set in nifi.properties in side the pod. Is there any reason for this?
Appreciate help!
As NodePort service you can also assign port number from 30000-32767.
You can apply values when you install your chart with:
properties:
webProxyHost: localhost
httpsPort:
This should let nifi whitelist your https://localhost:

strimzi operator 0.20 kafka 'useServiceDnsDomain' has no effect

PROBLEM:
For some reason client pod can only resolve fully qualified fully-qualified DNS names including the cluster service suffix.
That problem is stated in this quesion:
AKS, WIndows Node, dns does not resolve service until fully qualified name is used
To workaround this issue, I'm using useServiceDnsDomain flag. The documentation (https://strimzi.io/docs/operators/master/using.html#type-GenericKafkaListenerConfiguration-schema-reference ) explains it as
Configures whether the Kubernetes service DNS domain should be used or
not. If set to true, the generated addresses with contain the service
DNS domain suffix (by default .cluster.local, can be configured using
environment variable KUBERNETES_SERVICE_DNS_DOMAIN). Defaults to
false.This field can be used only with internal type listener.
Part of my yaml is as follows
apiVersion: kafka.strimzi.io/v1beta1
kind: Kafka
metadata:
name: tt-kafka
namespace: shared
spec:
kafka:
version: 2.5.0
replicas: 3
listeners:
- name: local
port: 9092
type: internal
tls: false
useServiceDnsDomain: true
This didn't do anything, so I also tried adding KUBERNETES_SERVICE_DNS_DOMAIN like below
template:
kafkaContainer:
env:
- name: KUBERNETES_SERVICE_DNS_DOMAIN
value: .cluster.local
strimzi/operator:0.20.0 image is being used.
In my client (.net Confluent.Kafka 1.4.4), I used tt-kafka-kafka-bootstrap.shared.svc.cluster.local as BootstrapServers.
It gives me error as
Error: GroupCoordinator: Failed to resolve
'tt-kafka-kafka-2.tt-kafka-kafka-brokers.shared.svc:9092': No such
host is known.
I'm expecting the broker service to provide full names to the client but from the error it seems useServiceDnsDomain has no effect.
Any help is appreciated. Thanks.
As exmaplained in https://github.com/strimzi/strimzi-kafka-operator/issues/3898, there is a typo in the docs. The right YAML is:
listeners:
- name: plain
port: 9092
type: internal
tls: false
configuration:
useServiceDnsDomain: true
If your domain is different from .cluster.local, you can use the KUBERNETES_SERVICE_DNS_DOMAIN env var to override it. But you have to configure it on the Strimzi Cluster Operator pod. Not on the Kafka pods: https://strimzi.io/docs/operators/latest/full/using.html#ref-operator-cluster-str

Connecting to Google Cloud SQL from Container Engine: can't resolve cloud sql proxy

I'm trying to connect to Google Cloud SQL from a node app, which is running in a Google Container Engine pod managed by Kubernetes. I've followed the instructions here to create a Cloud SQL proxy.
When I run the app, I receive:
{
"code": "ENOTFOUND",
"errno": "ENOTFOUND",
"syscall": "getaddrinfo",
"hostname": "127.0.0.1:3306",
"host": "127.0.0.1:3306",
"port": 3306,
"fatal": true
}
So it looks as though the proxy can't be resolved.
I've run kubectl describe pods <pod_name> and the proxy appears to be healthy:
cloudsql-proxy:
Container ID: docker://47dfb6d22d5e0924f0bb4e1df85220270b4f21e971228d03148fef6b3aad6c6c
Image: b.gcr.io/cloudsql-docker/gce-proxy:1.05
Image ID: docker://sha256:338793fcb60d519482682df9d6f88da99888ba69bc6da96b18a636e1a233e5ec
Port:
Command:
/cloud_sql_proxy
--dir=/cloudsql
-instances=touch-farm:asia-east1:api-staging=tcp:3306
-credential_file=/secrets/cloudsql/credentials.json
Requests:
cpu: 100m
State: Running
Started: Sat, 01 Oct 2016 20:38:40 +1000
Ready: True
Restart Count: 0
Environment Variables: <none>
The only thing that seems unusual to me is that the Port field is blank, however there was no instruction in the guide referenced above to expose a port in the deployment config file. I've also tried specifying the 3306 port in the configuration file, but although the port then shows in the kubectl describe pods output, node still can't find the proxy.
What am I missing here? Why can't I resolve the proxy?
Edit (more info)
Logs from the cloudsql-proxy container:
2016-10-01T11:44:40.108529344Z 2016/10/01 11:44:40 Listening on 127.0.0.1:3306 for touch-farm:asia-east1:api-staging
2016-10-01T11:44:40.108561194Z 2016/10/01 11:44:40 Ready for new connections
It looks like you are specifying the host as 127.0.0.1:3306 instead of 127.0.0.1.

Is there a way to add arbitrary records to kube-dns?

I will use a very specific way to explain my problem, but I think this is better to be specific than explain in an abstract way...
Say, there is a MongoDB replica set outside of a Kubernetes cluster but in a network. The ip addresses of all members of the replica set were resolved by /etc/hosts in app servers and db servers.
In an experiment/transition phase, I need to access those mongo db servers from kubernetes pods.
However, kubernetes doesn't seem to allow adding custom entries to /etc/hosts in pods/containers.
The MongoDB replica sets are already working with large data set, creating a new replica set in the cluster is not an option.
Because I use GKE, changing any of resources in kube-dns namespace should be avoided I suppose. Configuring or replace kube-dns to be suitable for my need are last thing to try.
Is there a way to resolve ip address of custom hostnames in a Kubernetes cluster?
It is just an idea, but if kube2sky can read some entries of configmap and use them as dns records, it colud be great.
e.g. repl1.mongo.local: 192.168.10.100.
EDIT: I referenced this question from https://github.com/kubernetes/kubernetes/issues/12337
There are 2 possible solutions for this problem now:
Pod-wise (Adding the changes to every pod needed to resolve these domains)
cluster-wise (Adding the changes to a central place which all pods have access to, Which is in our case is the DNS)
Let's begin with the pod-wise solution:
As of Kunbernetes 1.7, It's possible now to add entries to a Pod's /etc/hosts directly using .spec.hostAliases
For example: to resolve foo.local, bar.local to 127.0.0.1 and foo.remote,
bar.remote to 10.1.2.3, you can configure HostAliases for a Pod under
.spec.hostAliases:
apiVersion: v1
kind: Pod
metadata:
name: hostaliases-pod
spec:
restartPolicy: Never
hostAliases:
- ip: "127.0.0.1"
hostnames:
- "foo.local"
- "bar.local"
- ip: "10.1.2.3"
hostnames:
- "foo.remote"
- "bar.remote"
containers:
- name: cat-hosts
image: busybox
command:
- cat
args:
- "/etc/hosts"
The Cluster-wise solution:
As of Kubernetes v1.12, CoreDNS is the recommended DNS Server, replacing kube-dns. If your cluster originally used kube-dns, you may still have kube-dns deployed rather than CoreDNS. I'm going to assume that you're using CoreDNS as your K8S DNS.
In CoreDNS it's possible to Add an arbitrary entries inside the cluster domain and that way all pods will resolve this entries directly from the DNS without the need to change each and every /etc/hosts file in every pod.
First:
Let's change the coreos ConfigMap and add required changes:
kubectl edit cm coredns -n kube-system
apiVersion: v1
kind: ConfigMap
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
hosts /etc/coredns/customdomains.db example.org {
fallthrough
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
forward . "/etc/resolv.conf"
cache 30
loop
reload
loadbalance
}
customdomains.db: |
10.10.1.1 mongo-en-1.example.org
10.10.1.2 mongo-en-2.example.org
10.10.1.3 mongo-en-3.example.org
10.10.1.4 mongo-en-4.example.org
Basically we added two things:
The hosts plugin before the kubernetes plugin and used the fallthrough option of the hosts plugin to satisfy our case.
To shed some more lights on the fallthrough option. Any given backend is usually the final word for its zone - it either returns a result, or it returns NXDOMAIN for the
query. However, occasionally this is not the desired behavior, so some of the plugin support a fallthrough option.
When fallthrough is enabled, instead of returning NXDOMAIN when a record is not found, the plugin will pass the
request down the chain. A backend further down the chain then has the opportunity to handle the request and that backend in our case is kubernetes.
We added a new file to the ConfigMap (customdomains.db) and added our custom domains (mongo-en-*.example.org) in there.
Last thing is to Remember to add the customdomains.db file to the config-volume for the CoreDNS pod template:
kubectl edit -n kube-system deployment coredns
volumes:
- name: config-volume
configMap:
name: coredns
items:
- key: Corefile
path: Corefile
- key: customdomains.db
path: customdomains.db
and finally to make kubernetes reload CoreDNS (each pod running):
$ kubectl rollout restart -n kube-system deployment/coredns
#OxMH answer is fantastic, and can be simplified for brevity. CoreDNS allows you to specify hosts directly in the hosts plugin (https://coredns.io/plugins/hosts/#examples).
The ConfigMap can therefore be edited like so:
$ kubectl edit cm coredns -n kube-system
apiVersion: v1
kind: ConfigMap
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
hosts {
10.10.1.1 mongo-en-1.example.org
10.10.1.2 mongo-en-2.example.org
10.10.1.3 mongo-en-3.example.org
10.10.1.4 mongo-en-4.example.org
fallthrough
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
forward . "/etc/resolv.conf"
cache 30
loop
reload
loadbalance
}
You will still need to restart coredns so it rereads the config:
$ kubectl rollout restart -n kube-system deployment/coredns
Inlining the contents of the hostsfile removes the need to map the hostsfile from the configmap. Both approaches achieve the same outcome, it is up to personal preference as to where you want to define the hosts.
A type of External Name is required to access hosts or ips outside of the kubernetes.
The following worked for me.
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "tiny-server-5",
"namespace": "default"
},
"spec": {
"type": "ExternalName",
"externalName": "192.168.1.15",
"ports": [{ "port": 80 }]
}
}
For the record, an alternate solution for those not checking the referenced github issue.
You can define an "external" Service in Kubernetes, by not specifying any selector or ClusterIP. You have to also define a corresponding Endpoint pointing to your external IP.
From the Kubernetes documentation:
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "my-service"
},
"spec": {
"ports": [
{
"protocol": "TCP",
"port": 80,
"targetPort": 9376
}
]
}
}
{
"kind": "Endpoints",
"apiVersion": "v1",
"metadata": {
"name": "my-service"
},
"subsets": [
{
"addresses": [
{ "ip": "1.2.3.4" }
],
"ports": [
{ "port": 9376 }
]
}
]
}
With this, you can point your app inside the containers to my-service:9376 and the traffic should be forwarded to 1.2.3.4:9376
Limitations:
The DNS name used needs to be only letters, numbers or dashes. You can't use multi-level names (something.like.this). This means you probably have to modify your app to point just to your-service, and not yourservice.domain.tld.
You can only point to a specific IP, not a DNS name. For that, you can define a kind of a DNS alias with an ExternalName type Service.
UPDATE: 2017-07-03 Kunbernetes 1.7 now support Adding entries to Pod /etc/hosts with HostAliases.
The solution is not about kube-dns, but /etc/hosts.
Anyway, following trick seems to work so far...
EDIT: Changing /etc/hosts may has race condition with kubernetes system. Let it retry.
1) create a configMap
apiVersion: v1
kind: ConfigMap
metadata:
name: db-hosts
data:
hosts: |
10.0.0.1 db1
10.0.0.2 db2
2) Add a script named ensure_hosts.sh.
#!/bin/sh
while true
do
grep db1 /etc/hosts > /dev/null || cat /mnt/hosts.append/hosts >> /etc/hosts
sleep 5
done
Don't forget chmod a+x ensure_hosts.sh.
3) Add a wrapper script start.sh your image
#!/bin/sh
$(dirname "$(realpath "$0")")/ensure_hosts.sh &
exec your-app args...
Don't forget chmod a+x start.sh
4) Use the configmap as a volume and run start.sh
apiVersion: extensions/v1beta1
kind: Deployment
...
spec:
template:
...
spec:
volumes:
- name: hosts-volume
configMap:
name: db-hosts
...
containers:
command:
- ./start.sh
...
volumeMounts:
- name: hosts-volume
mountPath: /mnt/hosts.append
...
Use configMap seems better way to set DNS, but it's a little bit heavy when just add a few record (in my opinion). So I add records to /etc/hosts by shell script executed by docker CMD.
for example:
Dockerfile
...(ignore)
COPY run.sh /tmp/run.sh
CMD bash /tmp/run.sh
run.sh
#!/bin/bash
echo repl1.mongo.local 192.168.10.100 >> /etc/hosts
# some else command...
Notice, if your run MORE THAN ONE container in a pod, you have to add script in each container, because kubernetes start container randomly, /etc/hosts may be override by another container (which start later).