O eBPF abre possibilidades de desenvolver ferramentas de observabilidade rodando no Kubernetes.
Pode-se começar com BCC libbpf-tools desenvolvido em C, por exemplo, iniciar o programa tcpconnlat e processar seu stdout com outro programa para detectar casos em que demorou muito para estabelecer uma conexão TCP.
Na prática, o comando curl <https://andrebassi.com.br> levou 47,80 milissegundos para estabelecer uma conexão, o qual seu IP de origem seria 10.0.2.15 e o IP de destino seria 76.76.21.21.
PID COMM IP SADDR DADDR DPORT LAT(ms)
21168 curl 4 10.0.2.15 76.76.21.21 443 47.80
FROM ubuntu:groovy as build
RUN apt-get update && \
apt-get install -y git flex bison llvm cmake clang libclang-dev libelf-dev libcap-dev python3-setuptools && \
apt-get autoremove -y && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
WORKDIR /opt/
RUN git clone <https://github.com/iovisor/bcc.git> && \
mkdir ./bcc/build/ && \
cd ./bcc/build/ && \
cmake -DPYTHON_CMD=python3 .. && \
make && \
cd ../libbpf-tools && \
make
FROM ubuntu:groovy
RUN apt-get update && \
apt-get install -y libelf-dev && \
apt-get autoremove -y && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
WORKDIR /opt/
COPY --from=build \
/opt/bcc/libbpf-tools/ext4dist \
/opt/bcc/libbpf-tools/runqlen \
/opt/bcc/libbpf-tools/cpudist \
/opt/bcc/libbpf-tools/softirqs \
/opt/bcc/libbpf-tools/filelife \
/opt/bcc/libbpf-tools/readahead \
/opt/bcc/libbpf-tools/funclatency \
/opt/bcc/libbpf-tools/biolatency \
/opt/bcc/libbpf-tools/biosnoop \
/opt/bcc/libbpf-tools/llcstat \
/opt/bcc/libbpf-tools/biopattern \
/opt/bcc/libbpf-tools/runqslower \
/opt/bcc/libbpf-tools/xfsslower \
/opt/bcc/libbpf-tools/numamove \
/opt/bcc/libbpf-tools/hardirqs \
/opt/bcc/libbpf-tools/bitesize \
/opt/bcc/libbpf-tools/opensnoop \
/opt/bcc/libbpf-tools/runqlat \
/opt/bcc/libbpf-tools/tcpconnect \
/opt/bcc/libbpf-tools/cpufreq \
/opt/bcc/libbpf-tools/drsnoop \
/opt/bcc/libbpf-tools/vfsstat \
/opt/bcc/libbpf-tools/biostacks \
/opt/bcc/libbpf-tools/cachestat \
/opt/bcc/libbpf-tools/tcpconnlat \
/opt/bcc/libbpf-tools/syscount \
/opt/bcc/libbpf-tools/execsnoop \
./
Crie a imagem docker:
docker build -t ttl.sh/ebpf-golang:2h .
E seu devido push:
docker push ttl.sh/ebpf-golang:2h
Um Pod com recurso de observabilidade deve ser executada em cada node, e assim através de DaemonSet garante que todos executem o tcpconnlat.
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: tcpconnlat-daemon
spec:
selector:
matchLabels:
app: tcpconnlat
template:
metadata:
labels:
app: tcpconnlat
spec:
containers:
- name: libbpf-tools
image: ttl.sh/ebpf-golang:2h
command:
- /opt/libbpf-tools/tcpconnlat
Infelizmente, os pods deram o status como Error, pois os containers não possuem modo privilegiado.
[1:31:15] andrebassi:~ $ kubectl get pods
NAME READY STATUS RESTARTS AGE
tcpconnlat-daemon-np6w8 0/1 Error 3 (36s ago) 64s
[1:32:17] andrebassi:~ $ kubectl logs -f tcpconnlat-daemon-np6w8
2023/01/04 04:32:11 failed to set temporary RLIMIT_MEMLOCK: operation not permitted
Por padrão, um container não tem permissão para acessar nenhum dispositivo no host, mas um container "privilegiado" tem acesso a todos os dispositivos no host.
Isso permite que o container tenha todo o mesmo acesso que os processos em execução no host.
**https://kubernetes.io/docs/concepts/security/pod-security-policy/#privileged**
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: tcpconnlat-daemon
spec:
selector:
matchLabels:
app: tcpconnlat
template:
metadata:
labels:
app: tcpconnlat
spec:
containers:
- name: libbpf-tools
image: ttl.sh/ebpf-golang:2h
command:
- /opt/libbpf-tools/tcpconnlat
securityContext:
privileged: true
Ao aplicar o manifesto acima com securityContext com privileged ativo com true, teremos sucesso ao rodar o que precisamos para esse contexto.