Skip to content

Commit

Permalink
Add support to eBPF instead of Kernel Module for capturing system cal…
Browse files Browse the repository at this point in the history
…ls (#3)

This will make the capture plugin with COS

refs #2
  • Loading branch information
Néstor Salceda committed May 8, 2019
1 parent 004d527 commit 1bebf84
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 22 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,10 @@ to capture.

There are a few parameters for this plugin:

| Flag | Description |
|------------------------|---------------------------------------|
| `-ns` or `--namespace` | The namespace scope of the target Pod |
| Flag | Description |
|------------------------|----------------------------------------------------------------|
| `-ns` or `--namespace` | The namespace scope of the target Pod |
| `--ebpf` | Use eBPF probe instead of kernel module for capturing syscalls |


Aditionally, all the flags for the `sysdig` cli tool are supported. You can
Expand Down
126 changes: 109 additions & 17 deletions kubectl-capture
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ capture_duration="120"
now=$(date +%s)
capture_pod=""
sysdig_params=""
ebpf="0"

function main() {
parse_arguments "$@"
Expand All @@ -31,6 +32,9 @@ function parse_arguments() {
capture_duration=$2
shift
;;
--ebpf)
ebpf="1"
;;
-w|--write=*|-z|--compress|-pc|-pk|-pm|-print=*|-S|--summary)
# Do not allow changes on these parameters
echo $0: $1: skipping parameter for Sysdig>&2
Expand Down Expand Up @@ -59,6 +63,7 @@ function usage_and_die() {
Usage: kubectl capture POD [-ns NAMESPACE] [sysdig options]
Options:
-ns | --namespace The namespace where the target pod lives (default: default)
--ebpf Launch capture pod with eBPF probe instead of kernel module
EOF
exit $1
}
Expand All @@ -70,6 +75,32 @@ function start_capture() {
exit 1
fi

if [[ "${ebpf}" -eq "1" ]];then
build_capture_pod_for_ebpf
else
build_capture_pod
fi

kubectl apply -f capture-pod.yaml > /dev/null 2>&1
rm capture-pod.yaml

echo "Sysdig is starting to capture system calls:"
echo ""
echo "Node: ${node}"
echo "Pod: ${pod}"
echo "Duration: ${capture_duration} seconds"
echo "Parameters for Sysdig: ${sysdig_params}"
echo ""

wait_until_finished

kubectl cp ${capture_pod}:/${capture_pod}.scap.gz ${capture_pod}.scap.gz > /dev/null 2>&1
kubectl delete pod ${capture_pod} > /dev/null 2>&1
echo "The capture has been downloaded to your hard disk at:"
echo "${PWD}/${capture_pod}.scap.gz"
}

function build_capture_pod() {
cat << EOF > capture-pod.yaml
apiVersion: v1
kind: Pod
Expand Down Expand Up @@ -136,24 +167,85 @@ spec:
path: /usr
nodeName: ${node}
EOF
}

kubectl apply -f capture-pod.yaml > /dev/null 2>&1
rm capture-pod.yaml

echo "Sysdig is starting to capture system calls:"
echo ""
echo "Node: ${node}"
echo "Pod: ${pod}"
echo "Duration: ${capture_duration} seconds"
echo "Parameters for Sysdig: ${sysdig_params}"
echo ""

wait_until_finished

kubectl cp ${capture_pod}:/${capture_pod}.scap.gz ${capture_pod}.scap.gz > /dev/null 2>&1
kubectl delete pod ${capture_pod} > /dev/null 2>&1
echo "The capture has been downloaded to your hard disk at:"
echo "${PWD}/${capture_pod}.scap.gz"
function build_capture_pod_for_ebpf() {
cat << EOF > capture-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: "${capture_pod}"
spec:
hostNetwork: true
containers:
- name: capturer
image: sysdig/sysdig
args:
- /bin/bash
- "-c"
- "echo '* Capturing system calls'; sysdig ${sysdig_params}; touch /.finished; trap 'exit 0' TERM; sleep infinity & wait \$!"
imagePullPolicy: IfNotPresent
securityContext:
privileged: true
env:
- name: SYSDIG_BPF_PROBE
value:
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 100m
memory: 128Mi
volumeMounts:
- mountPath: /host/var/run/docker.sock
name: docker-socket
- mountPath: /host/dev
name: dev-fs
- mountPath: /host/proc
name: proc-fs
readOnly: true
- mountPath: /host/boot
name: boot-fs
readOnly: true
- mountPath: /host/lib/modules
name: lib-modules
readOnly: true
- mountPath: /host/usr
name: usr-fs
readOnly: true
- mountPath: /dev/shm
name: dshm
- mountPath: /host/etc
name: etc-fs
readOnly: true
volumes:
- name: dshm
emptyDir:
medium: Memory
- name: docker-socket
hostPath:
path: /var/run/docker.sock
- name: dev-fs
hostPath:
path: /dev
- name: proc-fs
hostPath:
path: /proc
- name: boot-fs
hostPath:
path: /boot
- name: lib-modules
hostPath:
path: /lib/modules
- name: usr-fs
hostPath:
path: /usr
- name: etc-fs
hostPath:
path: /etc
nodeName: ${node}
EOF
}

function wait_until_finished() {
Expand Down
17 changes: 15 additions & 2 deletions test/kubectl-capture.bats
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,25 @@
kubectl delete deployment nginx

[ "$status" -eq 0 ]
[ -f ${lines[-1]} ]
}

@test "it does a capture using ebpf" {
kubectl create deployment nginx-ebpf --image=nginx
POD=$(kubectl get pod | grep nginx-ebpf | cut -f1 -d" ")

run ./kubectl-capture $POD --ebpf -M 5

kubectl delete deployment nginx-ebpf

[ "$status" -eq 0 ]
[ -f ${lines[-1]} ]
}

@test "when pod is inside a namespace it does a capture" {
kubectl create namespace scope
kubectl -n scope create deployment nginx --image=nginx
POD=$(kubectl -n scope get pod | grep nginx | cut -f1 -d" ")
kubectl -n scope create deployment nginx-namespace --image=nginx
POD=$(kubectl -n scope get pod | grep nginx-namespace | cut -f1 -d" ")

run ./kubectl-capture $POD -M 5 -ns scope

Expand Down

0 comments on commit 1bebf84

Please # to comment.