Skip to content

Commit

Permalink
feat: add kubectl plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
oilbeater committed Sep 17, 2019
1 parent 3bfaf0d commit ba3084e
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Kube-OVN integrates the OVN-based Network Virtualization with Kubernetes. It off
- **Direct External Connectivity**:Pod IP can be exposed to external network directly.
- **Traffic Mirror**: Duplicated container network traffic for monitoring and diagnosing.
- **IPv6 support**: Kube-OVN support ipv6-only mode pod network.
- **Kubectl Plugin**: Handy tools to diagnose container network.

## Planned Future Work
- Hardware Offloading and DPDK Support
Expand Down Expand Up @@ -47,6 +48,7 @@ If you want to install Kubernetes from scratch, you can try [kubespray](https://
- [Traffic Mirror](docs/mirror.md)
- [Webhook](docs/webhook.md)
- [IPv6](docs/ipv6.md)
- [Kubectl Plugin](docs/kubectl-plugin.md)

## Kube-OVN vs. Other CNI Implementation

Expand Down
3 changes: 3 additions & 0 deletions dist/images/Dockerfile.node
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ RUN mkdir -p /var/run/openvswitch && \
mkdir -p /etc/cni/net.d && \
mkdir -p /opt/cni/bin

RUN yum install -y tcpdump && \
yum clean all

COPY ovs-healthcheck.sh /root/ovs-healthcheck.sh
COPY start-ovs.sh /root/start-ovs.sh

Expand Down
148 changes: 148 additions & 0 deletions dist/images/kubectl-ko
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
#!/bin/bash
set -euo pipefail

KUBE_OVN_NS=kube-ovn
CENTRAL_POD=

showHelp(){
echo "kubectl ko {subcommand} [option...]"
echo "Available Subcommands:"
echo " nbctl [ovn-nbctl options ...] invoke ovn-nbctl"
echo " sbctl [ovn-sbctl options ...] invoke ovn-sbctl"
echo " tcpdump {namespace/podname} [tcpdump options ...] capture pod traffic"
echo " trace {namespace/podname} {target ip address} {icmp|tcp|udp} [target tcp or udp port] trace ovn microflow of specific packet"
}

tcpdump(){
namespacedPod="$1"; shift
namespace=$(echo "$namespacedPod" | cut -d "/" -f2)
if [ "$podName" = "$namespacedPod" ]; then
nodeName=$(kubectl get pod "$podName" -o jsonpath={.spec.nodeName})
mac=$(kubectl get pod "$podName" -o jsonpath={.metadata.annotations.ovn\\.kubernetes\\.io/mac_address})
hostNetwork=$(kubectl get pod "$podName" -o jsonpath={.spec.hostNetwork})
else
nodeName=$(kubectl get pod "$podName" -n "$namespace" -o jsonpath={.spec.nodeName})
mac=$(kubectl get pod "$podName" -n "$namespace" -o jsonpath={.metadata.annotations.ovn\\.kubernetes\\.io/mac_address})
hostNetwork=$(kubectl get pod "$podName" -n "$namespace" -o jsonpath={.spec.hostNetwork})
fi

if [ -z "$nodeName" ]; then
echo "Pod $namespacedPod not exists on any node"
exit 1
fi

if [ -z "$mac" ] && [ "$hostNetwork" != "true" ]; then
echo "pod mac address not ready"
exit 1
fi

ovnCni=$(kubectl get pod -n $KUBE_OVN_NS -o wide| grep kube-ovn-cni| grep "$nodeName" | awk '{print $1}')
if [ -z "$ovnCni" ]; then
echo "kube-ovn-cni not exist on node $nodeName"
exit 1
fi

if [ "$hostNetwork" = "true" ]; then
set -x
kubectl exec -it "$ovnCni" -n $KUBE_OVN_NS -- tcpdump -nn "$@"
else
nicName=$(kubectl exec -it "$ovnCni" -n $KUBE_OVN_NS -- ovs-vsctl --data=bare --no-heading --columns=name find interface mac_in_use="${mac//:/\\:}" | tr -d '\r')
if [ -z "$nicName" ]; then
echo "nic doesn't exist on node $nodeName"
exit 1
fi
set -x
kubectl exec -it "$ovnCni" -n $KUBE_OVN_NS -- tcpdump -nn -i "$nicName" "$@"
fi
}

trace(){
namespacedPod="$1"
namespace=$(echo "$1" | cut -d "/" -f1)
podName=$(echo "$1" | cut -d "/" -f2)
if [ "$podName" = "$1" ]; then
echo "namespace is required"
exit 1
fi

podIP=$(kubectl get pod "$podName" -n "$namespace" -o jsonpath={.metadata.annotations.ovn\\.kubernetes\\.io/ip_address})
mac=$(kubectl get pod "$podName" -n "$namespace" -o jsonpath={.metadata.annotations.ovn\\.kubernetes\\.io/mac_address})
ls=$(kubectl get pod "$podName" -n "$namespace" -o jsonpath={.metadata.annotations.ovn\\.kubernetes\\.io/logical_switch})
hostNetwork=$(kubectl get pod "$podName" -n "$namespace" -o jsonpath={.spec.hostNetwork})

if [ "$hostNetwork" = "true" ]; then
echo "Can not trace host network pod"
exit 1
fi

if [ -z "$ls" ]; then
echo "pod address not ready"
exit 1
fi

gwMac=$(kubectl exec -it ovn-central-8ddc7dd8-fm2c4 -n $KUBE_OVN_NS -- ovn-nbctl --data=bare --no-heading --columns=mac find logical_router_port name=ovn-cluster-"$ls" | tr -d '\r')

if [ -z "$gwMac" ]; then
echo "get gw mac failed"
exit 1
fi

dst="$2"
if [ -z "$dst" ]; then
echo "need a target ip address"
exit 1
fi

type="$3"

case $type in
icmp)
set -x
kubectl exec "$CENTRAL_POD" -n $KUBE_OVN_NS -- ovn-trace --ct=new "$ls" "inport == \"$podName.$namespace\" && ip.ttl == 64 && icmp && eth.src == $mac && ip4.src == $podIP && eth.dst == $gwMac && ip4.dst == $dst"
;;
tcp|udp)
set -x
kubectl exec "$CENTRAL_POD" -n $KUBE_OVN_NS -- ovn-trace --ct=new "$ls" "inport == \"$podName.$namespace\" && ip.ttl == 64 && eth.src == $mac && ip4.src == $podIP && eth.dst == $gwMac && ip4.dst == $dst && $type.src == 10000 && $type.dst == $4"
;;
*)
echo "type $type not supported"
echo "kubectl ko trace {namespace/podname} {target ip address} {icmp|tcp|udp} [target tcp or udp port]"
;;
esac
}

getOvnCentralPod(){
centralPod=$(kubectl get pod -n $KUBE_OVN_NS | grep ovn-central | head -n 1 | awk '{print $1}')
if [ -z "$centralPod" ]; then
echo "ovn-central not exists"
exit 1
fi
CENTRAL_POD=$centralPod
}

if [ $# -lt 1 ]; then
showHelp
exit 0
else
subcommand="$1"; shift
fi

getOvnCentralPod

case $subcommand in
nbctl)
kubectl exec "$CENTRAL_POD" -n $KUBE_OVN_NS -- ovn-nbctl "$@"
;;
sbctl)
kubectl exec "$CENTRAL_POD" -n $KUBE_OVN_NS -- ovn-sbctl "$@"
;;
tcpdump)
tcpdump "$@"
;;
trace)
trace "$@"
;;
*)
showHelp
;;
esac
41 changes: 41 additions & 0 deletions docs/kubectl-plugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
Kube-OVN provides a kubectl plugin to help better diagnose container network. You can use this plugin to tcpdump a specific pod, trace a specific packet or query ovn-nb/ovn-sb.

# Prerequisite

To enable kubectl plugin, kubectl version of 1.12 or later is recommended. You can use `kubectl version` to check the version.

# Install

1. Get the `kubectl-ko` file
```bash
wget https://github.com/alauda/kube-ovn/blob/master/dist/images/kubectl-ko
```

2. Move the file to one of $PATH directories
```bash
mv kubectl-ko /usr/local/bin/kubectl-ko
```

3. Add executable permission to `kubectl-ko`
```bash
chmod +x /usr/local/bin/kubectl-ko
```

4. Check if the plugin is ready
```bash
[root@kube-ovn01 ~]# kubectl plugin list
The following compatible plugins are available:

/usr/local/bin/kubectl-ko
```

# Usage

```bash
kubectl ko {subcommand} [option...]
Available Subcommands:
nbctl [ovn-nbctl options ...] invoke ovn-nbctl
sbctl [ovn-sbctl options ...] invoke ovn-sbctl
tcpdump {namespace/podname} [tcpdump options ...] capture pod traffic
trace {namespace/podname} {target ip address} {icmp|tcp|udp} [target tcp or udp port]
```

0 comments on commit ba3084e

Please sign in to comment.