← Back to Index

openshift 4.14 Network Observability

openshift 4.14 introduce eBPF as agent for netoberv, we try it out, and see how it works. We focus on egress IP senario, and want to see RTT value from backend service outside of cluster.

here is the architecture of this lab:

try with loki

install loki

RTT value need loki as backend, we install loki first.

install a minio as backend

we need s3 storage, we will use minio as backend, and use local disk as storage.

deploy a minio for testing only, not for production. becuase official minio will enable https, it will bring so many trouble into app integration, we use a old version minio.


        # oc new-project llm-demo
        
        # oc label --overwrite ns llm-demo \
        
        #    pod-security.kubernetes.io/enforce=privileged
        
        oc new-project netobserv
        
        # on helper
        
        S3_NAME='netobserv'
        S3_NS='netobserv'
        S3_IMAGE='docker.io/minio/minio:RELEASE.2021-06-17T00-10-46Z.hotfix.35a0912ff'
        
        cat << EOF > ${BASE_DIR}/data/install/s3-codellama.yaml
        ---
        apiVersion: v1
        kind: Service
        metadata:
          name: minio-${S3_NAME}
        spec:
          ports:
            - name: minio-client-port
              port: 9000
              protocol: TCP
              targetPort: 9000
          selector:
            app: minio-${S3_NAME}
        
        # ---
        
        # apiVersion: route.openshift.io/v1
        
        # kind: Route
        
        # metadata:
        
        #   name: s3-${S3_NAME}
        
        # spec:
        
        #   to:
        
        #     kind: Service
        
        #     name: minio-${S3_NAME}
        
        #   port:
        
        #     targetPort: 9000
        
        ---
        apiVersion: v1
        kind: PersistentVolumeClaim
        metadata:
          name: minio-${S3_NAME}-pvc
        spec:
          accessModes:
            - ReadWriteOnce
          resources:
            requests:
              storage: 100Gi
          storageClassName: hostpath-csi
        
        ---
        apiVersion: apps/v1
        kind: Deployment
        metadata:
          name: minio-${S3_NAME}
          labels:
            app: minio-${S3_NAME}
        spec:
          replicas: 1
          selector:
            matchLabels:
              app: minio-${S3_NAME}
          template:
            metadata:
              labels:
                app: minio-${S3_NAME}
            spec:
              initContainers:
                - name: create-demo-dir
                  image: docker.io/busybox
                  command: ["mkdir", "-p", "/data1/demo"]
                  volumeMounts:
                    - name: data
                      mountPath: "/data1"
              containers:
                - args:
                    - server
                    - /data1
                  env:
                    - name: MINIO_ACCESS_KEY
                      value:  admin
                    - name: MINIO_SECRET_KEY
                      value: redhatocp
                  image: ${S3_IMAGE}
                  imagePullPolicy: IfNotPresent
                  name: minio
                  nodeSelector:
                    kubernetes.io/hostname: "worker-01-demo"
                  securityContext:
                    allowPrivilegeEscalation: false
                    capabilities:
                        drop:
                        - ALL
                    runAsNonRoot: true
                    seccompProfile:
                        type: RuntimeDefault
                  volumeMounts:
                    - mountPath: "/data1"
                      name: data
              volumes:
                - name: data 
                  persistentVolumeClaim:
                    claimName: minio-${S3_NAME}-pvc
        
        EOF
        
        oc create -n netobserv -f ${BASE_DIR}/data/install/s3-codellama.yaml
        
        # oc delete -n netobserv -f ${BASE_DIR}/data/install/s3-codellama.yaml
        
        # open in browser to check, and create bucket 'demo'
        
        # http://s3-netobserv-netobserv.apps.demo-gpu.wzhlab.top/
        

install loki operator

we have a s3 storage, and we will install loki operator.


        # oc new-project netobserv
        
        # netobserv is a resource-hungry application, it has high requirements for the underlying loki, we configure the maximum gear, and the number of replicas, etc., to adapt to our test environment.
        
        cat << EOF > ${BASE_DIR}/data/install/loki-netobserv.yaml
        ---
        apiVersion: v1
        kind: Secret
        metadata:
          name: loki-s3 
        stringData:
          access_key_id: admin
          access_key_secret: redhatocp
          bucketnames: demo
          endpoint: http://minio-netobserv.netobserv.svc.cluster.local:9000
          # region: eu-central-1
        
        ---
        apiVersion: loki.grafana.com/v1
        kind: LokiStack
        metadata:
          name: loki
        spec:
          size: 1x.medium
          replication:
            factor: 1
          storage:
            schemas:
            - version: v12
              effectiveDate: '2022-06-01'
            secret:
              name: loki-s3
              type: s3
          storageClassName: hostpath-csi
          tenants:
            mode: openshift-network
            openshift:
                adminGroups: 
                - cluster-admin
          template:
            gateway:
              replicas: 1
            ingester:
              replicas: 1
            indexGateway:
              replicas: 1
        
        EOF
        
        oc create --save-config -n netobserv -f ${BASE_DIR}/data/install/loki-netobserv.yaml
        
        # to delete
        
        # oc delete -n netobserv -f ${BASE_DIR}/data/install/loki-netobserv.yaml
        
        # oc get pvc -n netobserv | grep loki- | awk '{print $1}' | xargs oc delete -n netobserv pvc
        
        # run below, if reinstall
        
        oc adm groups new cluster-admin
        
        oc adm groups add-users cluster-admin admin
        
        oc adm policy add-cluster-role-to-group cluster-admin cluster-admin

install net observ

we will install net observ operator, the installation is simple, just follow the official document. If you use eBPF agent, there seems have bugs with the installation steps, it is better to restart nodes to make the ebpf agent function well.

RTT tracing

enable rtt tracing, following official document.

It is better to increate the memory limit, otherwise, the bpf agent pod will OOM. In my case, I increate to 2GB.

or if you want to change yaml directly

apiVersion: flows.netobserv.io/v1beta2
        kind: FlowCollector
        metadata:
          name: cluster
        spec:
          namespace: netobserv
          deploymentModel: Direct
          agent:
            type: eBPF
            ebpf:
              features:
               - FlowRTT 

try it out

RRT

we can see RRT based on each flow. At this point, we did not introduct network latency on backend service, so the RTT is very low.

deploy egress IP

next, we will deploy egress IP on worker-02, and make traffic from worker-01 to worker-02, and then backend-service, and see the RTT value.


        # label a node to host egress ip
        
        oc label nodes worker-02-demo k8s.ovn.org/egress-assignable="" 
        
        # label a namespace with env
        
        oc label ns llm-demo env=egress-demo
        
        
        # create a egress ip
        
        cat << EOF > ${BASE_DIR}/data/install/egressip.yaml
        apiVersion: k8s.ovn.org/v1
        kind: EgressIP
        metadata:
          name: egressips-prod
        spec:
          egressIPs:
          - 172.21.6.22
          namespaceSelector:
            matchLabels:
              env: egress-demo
        EOF
        
        oc create --save-config -f ${BASE_DIR}/data/install/egressip.yaml
        
        # oc delete -f ${BASE_DIR}/data/install/egressip.yaml
        
        oc get egressip -o json | jq -r '.items[] | [.status.items[].egressIP, .status.items[].node] | @tsv'
        
        # 172.21.6.22     worker-02-demo

make traffic and see result

then, we create backend http service, and introduce network latency by 1s.


        # on backend host, 172.21.6.8
        
        # create a web service
        
        python3 -m http.server 13000
        
        # ...
        
        # 172.21.6.22 - - [08/Apr/2024 12:22:39] "GET / HTTP/1.1" 200 -
        
        # 172.21.6.22 - - [08/Apr/2024 12:22:42] "GET / HTTP/1.1" 200 -
        
        # 172.21.6.22 - - [08/Apr/2024 12:22:45] "GET / HTTP/1.1" 200 -
        
        # ...
        
        # using tc to traffic control / delay 1s
        
        dnf install -y kernel-modules-extra # to install netem module
        dnf install -y /usr/sbin/tc
        
        iptables -A OUTPUT -t mangle -p tcp --sport 13000 -j MARK --set-mark 13000
        
        tc qdisc del dev ens192 root
        tc qdisc add dev ens192 root handle 1: htb
        tc class add dev ens192 parent 1: classid 1:1 htb rate 100mbit
        tc filter add dev ens192 protocol ip parent 1:0 prio 1 handle 13000 fw flowid 1:1
        tc qdisc add dev ens192 parent 1:1 handle 10: netem delay 1s
        
        tc qdisc show dev ens192
        
        # qdisc htb 1: root refcnt 3 r2q 10 default 0 direct_packets_stat 453 direct_qlen 1000
        
        # qdisc netem 10: parent 1:1 limit 1000 delay 1s

and then, we create testing pod, and curl from the pod to backend service


        # go back to helper
        
        # create a dummy pod
        
        cat << EOF > ${BASE_DIR}/data/install/demo1.yaml
        ---
        kind: Pod
        apiVersion: v1
        metadata:
          name: wzh-demo-pod
        spec:
          nodeSelector:
            kubernetes.io/hostname: 'worker-01-demo'
          restartPolicy: Always
          containers:
            - name: demo1
              image: >- 
                quay.io/wangzheng422/qimgs:rocky9-test
              env:
                - name: key
                  value: value
              command: [ "/bin/bash", "-c", "--" ]
              args: [ "tail -f /dev/null" ]
              # imagePullPolicy: Always
        EOF
        
        oc apply -n llm-demo -f ${BASE_DIR}/data/install/demo1.yaml
        
        # oc delete -n llm-demo -f ${BASE_DIR}/data/install/demo1.yaml
        
        oc exec -n llm-demo wzh-demo-pod -it -- bash
        
        # in the container terminal
        
        while true; do curl http://172.21.6.8:13000 && sleep 1; done;
        
        # while true; do curl http://192.168.77.8:13000/cache.db > /dev/null; done;

and you get the result like this, you can see the RTT become 1s.:

after setting the columnes, we can see something interesting.

as we can see 4 mac address, lets check what they are:


        VAR_POD=`oc get pod -n openshift-ovn-kubernetes -o wide | grep worker-01-demo | awk '{print $1}'`
        
        oc exec -it ${VAR_POD} -c ovn-controller -n openshift-ovn-kubernetes -- ovn-nbctl show | grep -i 0A:58:0A:85:00:01 -A 10 -B 10
        
        # router 032109ba-320f-4790-a3e6-44f305fa2397 (ovn_cluster_router)
        
        #     port rtoj-ovn_cluster_router
        
        #         mac: "0a:58:64:40:00:01"
        
        #         networks: ["100.64.0.1/16"]
        
        #     port rtos-worker-01-demo
        
        #         mac: "0a:58:0a:85:00:01"
        
        #         networks: ["10.133.0.1/23"]
        
        #         gateway chassis: [163c3827-a827-450e-931c-65eaab2d67d8]
        
        #     port rtots-worker-01-demo
        
        #         mac: "0a:58:64:58:00:03"
        
        #         networks: ["100.88.0.3/16"]
        
        
        oc exec -it ${VAR_POD} -c ovn-controller -n openshift-ovn-kubernetes -- ovn-nbctl show | grep -i 0A:58:0A:85:00:2B -A 10 -B 20
        
        # switch 2ae42bdd-9dde-43d6-9c1d-46b77298aebf (worker-01-demo)
        
        #     port llm-demo_wzh-demo-pod
        
        #         addresses: ["0a:58:0a:85:00:2b 10.133.0.43"]
        
        oc exec -it ${VAR_POD} -c ovn-controller -n openshift-ovn-kubernetes -- ovn-nbctl show | grep -i 0A:58:64:58:00:03 -A 10 -B 20
        
        # router 032109ba-320f-4790-a3e6-44f305fa2397 (ovn_cluster_router)
        
        #     port rtoj-ovn_cluster_router
        
        #         mac: "0a:58:64:40:00:01"
        
        #         networks: ["100.64.0.1/16"]
        
        #     port rtos-worker-01-demo
        
        #         mac: "0a:58:0a:85:00:01"
        
        #         networks: ["10.133.0.1/23"]
        
        #         gateway chassis: [163c3827-a827-450e-931c-65eaab2d67d8]
        
        #     port rtots-worker-01-demo
        
        #         mac: "0a:58:64:58:00:03"
        
        #         networks: ["100.88.0.3/16"]
        
        oc exec -it ${VAR_POD} -c ovn-controller -n openshift-ovn-kubernetes -- ovn-nbctl show | grep -i 0A:58:64:58:00:04 -A 10 -B 20
        
        # switch ceda4a6b-cac9-49d8-bc7c-7a419e7c51bd (transit_switch)
        
        #     port tstor-worker-01-demo
        
        #         type: router
        
        #         router-port: rtots-worker-01-demo
        
        #     port tstor-worker-02-demo
        
        #         type: remote
        
        #         addresses: ["0a:58:64:58:00:04 100.88.0.4/16"]
        
        #     port tstor-master-01-demo
        
        #         type: remote
        
        #         addresses: ["0a:58:64:58:00:02 100.88.0.2/16"]
        
        oc exec -it ${VAR_POD} -c ovn-controller -n openshift-ovn-kubernetes -- ovn-nbctl list Logical_Router_Port | grep -i 0A:58:0A:85:00:01 -A 10 -B 10
        
        # _uuid               : 53b1cec8-ff5a-4fba-896d-da3bdbea07c1
        
        # enabled             : []
        
        # external_ids        : {}
        
        # gateway_chassis     : [4b714c8d-1508-4a28-ab25-c8df85457fbb]
        
        # ha_chassis_group    : []
        
        # ipv6_prefix         : []
        
        # ipv6_ra_configs     : {}
        
        # mac                 : "0a:58:0a:85:00:01"
        
        # name                : rtos-worker-01-demo
        
        # networks            : ["10.133.0.1/23"]
        
        # options             : {}
        
        # peer                : []
        
        # status              : {hosting-chassis="163c3827-a827-450e-931c-65eaab2d67d8"}
        
        
        oc exec -it ${VAR_POD} -c ovn-controller -n openshift-ovn-kubernetes -- ovn-nbctl list Logical_Switch_Port | grep -i 0A:58:0A:85:00:2B -A 10 -B 10
        
        # _uuid               : 641b3330-2216-4a6a-abbc-ecea5c888adc
        
        # addresses           : ["0a:58:0a:85:00:2b 10.133.0.43"]
        
        # dhcpv4_options      : []
        
        # dhcpv6_options      : []
        
        # dynamic_addresses   : []
        
        # enabled             : []
        
        # external_ids        : {namespace=llm-demo, pod="true"}
        
        # ha_chassis_group    : []
        
        # mirror_rules        : []
        
        # name                : llm-demo_wzh-demo-pod
        
        # options             : {iface-id-ver="20b12566-0596-4b45-8ed6-9bd4ea68c649", requested-chassis=worker-01-demo}
        
        # parent_name         : []
        
        # port_security       : ["0a:58:0a:85:00:2b 10.133.0.43"]
        
        # tag                 : []
        
        # tag_request         : []
        
        # type                : ""
        
        # up                  : true
        
        
        oc exec -it ${VAR_POD} -c ovn-controller -n openshift-ovn-kubernetes -- ovn-nbctl list Logical_Router_Port | grep -i 0A:58:64:58:00:03 -A 10 -B 10
        
        # _uuid               : 5e750f8b-0951-4b5f-b415-a6f870dfc3a3
        
        # enabled             : []
        
        # external_ids        : {}
        
        # gateway_chassis     : []
        
        # ha_chassis_group    : []
        
        # ipv6_prefix         : []
        
        # ipv6_ra_configs     : {}
        
        # mac                 : "0a:58:64:58:00:03"
        
        # name                : rtots-worker-01-demo
        
        # networks            : ["100.88.0.3/16"]
        
        # options             : {mcast_flood="true"}
        
        # peer                : []
        
        # status              : {}
        
        oc exec -it ${VAR_POD} -c ovn-controller -n openshift-ovn-kubernetes -- ovn-nbctl list Logical_Switch_Port | grep -i 0A:58:64:58:00:04 -A 10 -B 10
        
        # _uuid               : 225dc4bd-6fe0-4a49-a61f-ab20576fb159
        
        # addresses           : ["0a:58:64:58:00:04 100.88.0.4/16"]
        
        # dhcpv4_options      : []
        
        # dhcpv6_options      : []
        
        # dynamic_addresses   : []
        
        # enabled             : []
        
        # external_ids        : {node=worker-02-demo}
        
        # ha_chassis_group    : []
        
        # mirror_rules        : []
        
        # name                : tstor-worker-02-demo
        
        # options             : {requested-tnl-key="4"}
        
        # parent_name         : []
        
        oc exec -it ${VAR_POD} -c ovn-controller -n openshift-ovn-kubernetes -- ovn-nbctl list Logical_Router | grep name
        
        # name                : GR_worker-01-demo
        
        # name                : ovn_cluster_router
        
        oc exec -it ${VAR_POD} -c ovn-controller -n openshift-ovn-kubernetes -- ovn-nbctl lr-list
        
        # f462fab4-9a08-4dec-ab6b-2576c31908e2 (GR_worker-01-demo)
        
        # 032109ba-320f-4790-a3e6-44f305fa2397 (ovn_cluster_router)
        
        oc exec -it ${VAR_POD} -c ovn-controller -n openshift-ovn-kubernetes -- ovn-nbctl lr-nat-list GR_worker-01-demo
        
        # TYPE             GATEWAY_PORT          EXTERNAL_IP        EXTERNAL_PORT    LOGICAL_IP          EXTERNAL_MAC         LOGICAL_PORT
        
        # snat                                   172.21.6.26                         10.133.0.3
        
        # snat                                   172.21.6.26                         10.133.0.6
        
        # snat                                   172.21.6.26                         10.133.0.103
        
        # snat                                   172.21.6.26                         10.133.0.5
        
        # snat                                   172.21.6.26                         10.133.0.10
        
        # snat                                   172.21.6.26                         10.133.0.20
        
        # snat                                   172.21.6.26                         10.133.0.96
        
        # snat                                   172.21.6.26                         10.133.0.7
        
        # snat                                   172.21.6.26                         10.133.0.11
        
        # snat                                   172.21.6.26                         10.133.0.89
        
        # snat                                   172.21.6.26                         10.133.0.9
        
        # snat                                   172.21.6.26                         10.133.0.91
        
        # snat                                   172.21.6.26                         10.133.0.4
        
        # snat                                   172.21.6.26                         10.133.0.87
        
        # snat                                   172.21.6.26                         10.133.0.92
        
        # snat                                   172.21.6.26                         10.133.0.95
        
        # snat                                   172.21.6.26                         10.133.0.83
        
        # snat                                   172.21.6.26                         10.133.0.12
        
        # snat                                   172.21.6.26                         10.133.0.8
        
        # snat                                   172.21.6.26                         10.133.0.118
        
        # snat                                   172.21.6.26                         10.133.0.86
        
        # snat                                   172.21.6.26                         100.64.0.3
        
        # snat                                   172.21.6.26                         10.133.0.88
        
        # snat                                   172.21.6.26                         10.133.0.13
        
        # snat                                   172.21.6.26                         10.133.0.43
        
        # snat                                   172.21.6.26                         10.133.0.90
        
        # snat                                   172.21.6.26                         10.133.0.93
        
        oc exec -it ${VAR_POD} -c ovn-controller -n openshift-ovn-kubernetes -- ovn-sbctl dump-flows | grep 172.21.6.22
        
        # no result
        
        
        # search on worker-02
        
        VAR_POD=`oc get pod -n openshift-ovn-kubernetes -o wide | grep worker-02-demo | awk '{print $1}'`
        
        
        oc exec -it ${VAR_POD} -c ovn-controller -n openshift-ovn-kubernetes -- ovn-nbctl lr-list
        
        # 373ab1b4-7948-4370-a5ab-17f9f3d4b742 (GR_worker-02-demo)
        
        # b23e792d-a79a-47b5-a4c3-c2716ffdb55b (ovn_cluster_router)
        
        
        oc exec -it ${VAR_POD} -c ovn-controller -n openshift-ovn-kubernetes -- ovn-nbctl lr-nat-list GR_worker-02-demo
        
        # TYPE             GATEWAY_PORT          EXTERNAL_IP        EXTERNAL_PORT    LOGICAL_IP          EXTERNAL_MAC         LOGICAL_PORT
        
        # snat                                   172.21.6.22                         10.133.0.43
        
        # snat                                   172.21.6.27                         10.134.0.5
        
        # snat                                   172.21.6.27                         10.134.0.12
        
        # snat                                   172.21.6.27                         100.64.0.4
        
        # snat                                   172.21.6.27                         10.134.0.4
        
        # snat                                   172.21.6.27                         10.134.0.7
        
        # snat                                   172.21.6.27                         10.134.0.3
        
        # snat                                   172.21.6.27                         10.134.0.6
        
        # snat                                   172.21.6.27                         10.134.0.8
        
        # check mac address again
        
        oc exec -it ${VAR_POD} -c ovn-controller -n openshift-ovn-kubernetes -- ovn-nbctl show | grep -i 0A:58:0A:85:00:01 -A 10 -B 10
        
        # no result
        
        oc exec -it ${VAR_POD} -c ovn-controller -n openshift-ovn-kubernetes -- ovn-nbctl show | grep -i 0A:58:0A:85:00:2B -A 10 -B 20
        
        # no result
        
        oc exec -it ${VAR_POD} -c ovn-controller -n openshift-ovn-kubernetes -- ovn-nbctl show | grep -i 0A:58:64:58:00:03 -A 10 -B 20
        
        # switch 858be777-d262-4db8-9c02-7ed86d85d8a6 (transit_switch)
        
        #     port tstor-worker-02-demo
        
        #         type: router
        
        #         router-port: rtots-worker-02-demo
        
        #     port tstor-worker-01-demo
        
        #         type: remote
        
        #         addresses: ["0a:58:64:58:00:03 100.88.0.3/16"]
        
        #     port tstor-master-01-demo
        
        #         type: remote
        
        #         addresses: ["0a:58:64:58:00:02 100.88.0.2/16"]
        
        oc exec -it ${VAR_POD} -c ovn-controller -n openshift-ovn-kubernetes -- ovn-nbctl show | grep -i 0A:58:64:58:00:04 -A 10 -B 20
        
        # router b23e792d-a79a-47b5-a4c3-c2716ffdb55b (ovn_cluster_router)
        
        #     port rtots-worker-02-demo
        
        #         mac: "0a:58:64:58:00:04"
        
        #         networks: ["100.88.0.4/16"]
        
        #     port rtos-worker-02-demo
        
        #         mac: "0a:58:0a:86:00:01"
        
        #         networks: ["10.134.0.1/23"]
        
        #         gateway chassis: [0e25df85-8df7-451a-bc4e-e59173042ccd]
        
        #     port rtoj-ovn_cluster_router
        
        #         mac: "0a:58:64:40:00:01"
        
        #         networks: ["100.64.0.1/16"]
        
        
        oc exec -it ${VAR_POD} -c ovn-controller -n openshift-ovn-kubernetes -- ovn-sbctl dump-flows | grep 172.21.6.22
          # table=3 (lr_in_ip_input     ), priority=90   , match=(arp.op == 1 && arp.tpa == 172.21.6.22), action=(eth.dst = eth.src; eth.src = xreg0[0..47]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[0..47]; arp.tpa <-> arp.spa; outport = inport; flags.loopback = 1; output;)
          # table=4 (lr_in_unsnat       ), priority=90   , match=(ip && ip4.dst == 172.21.6.22), action=(ct_snat;)
          # table=3 (lr_out_snat        ), priority=33   , match=(ip && ip4.src == 10.133.0.43 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.21.6.22);)
          # table=27(ls_in_l2_lkup      ), priority=80   , match=(flags[1] == 0 && arp.op == 1 && arp.tpa == 172.21.6.22), action=(clone {outport = "etor-GR_worker-02-demo"; output; }; outport = "_MC_flood_l2"; output;)
          # table=27(ls_in_l2_lkup      ), priority=80   , match=(flags[1] == 0 && arp.op == 1 && arp.tpa == 172.21.6.22), action=(outport = "jtor-GR_worker-02-demo"; output;)
        

Here is the ovn logical network topology:

based on our case, lets draw the network topology:

try with a java app

we will create a simple java app, it will access http request, send a dummy http request to 172.21.6.8, and return. So we can see the whole path result.

the sample java app’s source project is here:


        # go back to helper
        
        # create a dummy pod
        
        cat << EOF > ${BASE_DIR}/data/install/demo1.yaml
        ---
        apiVersion: v1
        kind: Service
        metadata:
          name: wzh-demo-service
        spec:
          ports:
            - name: service-port
              port: 80
              protocol: TCP
              targetPort: 8080
          selector:
            app: wzh-demo-pod
        
        ---
        apiVersion: route.openshift.io/v1
        kind: Route
        metadata:
          name: wzh-demo
        spec:
          to:
            kind: Service
            name: wzh-demo-service
          port:
            targetPort: service-port
        
        
        ---
        kind: Pod
        apiVersion: v1
        metadata:
          name: wzh-demo-pod
          labels:
            app: wzh-demo-pod
          # annotations:
          #   instrumentation.opentelemetry.io/inject-java: "true"
        spec:
          nodeSelector:
            kubernetes.io/hostname: 'worker-01-demo'
          restartPolicy: Always
          containers:
            - name: demo1
              image: >- 
                quay.io/wangzheng422/qimgs:simple-java-http-server-2024.04.24
              env:
                - name: WZH_URL
                  value: "http://172.21.6.8:13000/singbox.config.json"
              # command: [ "/bin/bash", "-c", "--" ]
              # args: [ "tail -f /dev/null" ]
              # imagePullPolicy: Always
        
        # ---
        
        # kind: Pod
        
        # apiVersion: v1
        
        # metadata:
        
        #   name: wzh-demo-util
        
        # spec:
        
        #   nodeSelector:
        
        #     kubernetes.io/hostname: 'worker-01-demo'
        
        #   restartPolicy: Always
        
        #   containers:
        
        #     - name: demo1
        
        #       image: >- 
        
        #         quay.io/wangzheng422/qimgs:rocky9-test
        
        #       env:
        
        #         - name: key
        
        #           value: value
        
        #       command: [ "/bin/bash", "-c", "--" ]
        
        #       args: [ "tail -f /dev/null" ]
        
        #       # imagePullPolicy: Always
        
        EOF
        
        oc apply -n llm-demo -f ${BASE_DIR}/data/install/demo1.yaml
        
        # oc delete -n llm-demo -f ${BASE_DIR}/data/install/demo1.yaml
        
        # while true; do
        
        #   curl -s http://wzh-demo-llm-demo.apps.demo-gpu.wzhlab.top/sendRequest
        
        #   sleep 1
        
        # done
        
        siege -q -c 1000 http://wzh-demo-llm-demo.apps.demo-gpu.wzhlab.top/sendRequest

lets see the result

so, for ingress traffic, it can show RTT between ingress router / haproxy to pod. What is ip address 10.132.0.2 ? It is management ovn port on master-01, master-01 runs the ingress router / haproxy in host network mode.


        # on master-01, which is 172.21.6.23
        
        ip a
        
        # ....
        
        # 4: ovn-k8s-mp0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1400 qdisc noqueue state UNKNOWN group default qlen 1000
        
        #     link/ether c2:fe:9d:b7:85:f9 brd ff:ff:ff:ff:ff:ff
        
        #     inet 10.132.0.2/23 brd 10.132.1.255 scope global ovn-k8s-mp0
        
        #        valid_lft forever preferred_lft forever
        
        #     inet6 fe80::c0fe:9dff:feb7:85f9/64 scope link
        
        #        valid_lft forever preferred_lft forever
        
        # ....
        
        # on helper
        
        oc get pod -o wide -n openshift-ingress
        
        # NAME                              READY   STATUS    RESTARTS        AGE   IP            NODE             NOMINATED NODE   READINESS GATES
        
        # router-default-8575546d67-cpzvf   1/1     Running   23 (118m ago)   13d   172.21.6.23   master-01-demo   <none>           <none>
        
        oc get node -o wide
        
        # NAME             STATUS   ROLES                         AGE   VERSION            INTERNAL-IP   EXTERNAL-IP   OS-IMAGE                                                       KERNEL-VERSION                 CONTAINER-RUNTIME
        
        # master-01-demo   Ready    control-plane,master,worker   74d   v1.27.11+d8e449a   172.21.6.23   <none>        Red Hat Enterprise Linux CoreOS 414.92.202403081134-0 (Plow)   5.14.0-284.55.1.el9_2.x86_64   cri-o://1.27.4-3.rhaos4.14.git914bcba.el9
        
        # worker-01-demo   Ready    worker                        74d   v1.27.11+d8e449a   172.21.6.26   <none>        Red Hat Enterprise Linux CoreOS 414.92.202403081134-0 (Plow)   5.14.0-284.55.1.el9_2.x86_64   cri-o://1.27.4-3.rhaos4.14.git914bcba.el9
        
        # worker-02-demo   Ready    worker                        4d    v1.27.11+d8e449a   172.21.6.27   <none>        Red Hat Enterprise Linux CoreOS 414.92.202403081134-0 (Plow)   5.14.0-284.55.1.el9_2.x86_64   cri-o://1.27.4-3.rhaos4.14.git914bcba.el9

performance issue

bpf agent will cause 80GB memory, for sample:1

And due to flow drop, you can not see traffic data correct, RTT is incorrect too.

So, for production environments, carefully plan, test, and ensure performance is acceptable.

try without loki

remove loki config

remove every loki config, because we will not use them in this case

install netobserv

configure netflow collector, disable loki, and enable RTT feature.

after a moment, you can see the result from dashboard. Because we do not use loki, so data goes to promethus only.

and you can see, only namespace level data is collected and displayed.

see the result

Principles

ebpf src

Look at the source code, these 2 sentences are to register tc bpf hooks

SEC("tc_ingress")
        int ingress_flow_parse(struct __sk_buff *skb) {
            return flow_monitor(skb, INGRESS);
        }
        
        SEC("tc_egress")
        int egress_flow_parse(struct __sk_buff *skb) {
            return flow_monitor(skb, EGRESS);
        }

limitation

  1. ebpf agent stability and performance.
  2. storage and query performance.

tips

  1. sometimes, the netobserv-epf- OOM, and console do not work. restart node to fix.

ovn short word

  JoinSwitchPrefix             = "join_"
          ExternalSwitchPrefix         = "ext_"
          GWRouterPrefix               = "GR_"
          GWRouterLocalLBPostfix       = "_local"
          RouterToSwitchPrefix         = "rtos-"
          InterPrefix                  = "inter-"
          HybridSubnetPrefix           = "hybrid-subnet-"
          SwitchToRouterPrefix         = "stor-"
          JoinSwitchToGWRouterPrefix   = "jtor-"
          GWRouterToJoinSwitchPrefix   = "rtoj-"
          DistRouterToJoinSwitchPrefix = "dtoj-"
          JoinSwitchToDistRouterPrefix = "jtod-"
          EXTSwitchToGWRouterPrefix    = "etor-"
          GWRouterToExtSwitchPrefix    = "rtoe-"
          EgressGWSwitchPrefix         = "exgw-"
        
          TransitSwitchToRouterPrefix = "tstor-"
          RouterToTransitSwitchPrefix = "rtots-"

search container on interface name


        ip a | grep ace0354dc9ca1cb -A 5
        
        # 67: ace0354dc9ca1cb@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1400 qdisc noqueue master ovs-system state UP group default qlen 1000
        
        #     link/ether 3e:3a:b4:70:28:c0 brd ff:ff:ff:ff:ff:ff link-netns 301bf28d-f04c-46a6-b34c-800b34ce4c76
        
        #     inet6 fe80::3c3a:b4ff:fe70:28c0/64 scope link
        
        #        valid_lft forever preferred_lft forever
        
        # The namespace ID we're looking for
        
        namespace_id="562f3b52-881a-4057-b8fd-f17ceaf9096b"
        
        # Get all pod IDs
        
        pod_ids=$(crictl pods -q)
        
        # Loop through each pod ID
        
        for pod_id in $pod_ids; do
            # Inspect the pod and get the network namespace
            network_ns=$(crictl inspectp $pod_id | jq -r '.info.runtimeSpec.linux.namespaces[] | select(.type=="network") | .path')
        
            # Check if the network namespace contains the namespace ID
            if [[ $network_ns == *"$namespace_id"* ]]; then
                echo "Pod $pod_id is in the namespace $namespace_id"
                crictl pods --id $pod_id
            fi
        done
        

oc debug node


        # node debug with bpftop
        
        oc debug node/worker-01-demo --image=quay.io/wangzheng422/qimgs:rocky9-test-2024.04.28

end