diff --git a/.github/workflows/build-gazer.yaml b/.github/workflows/build-gazer.yaml new file mode 100644 index 0000000..62201cd --- /dev/null +++ b/.github/workflows/build-gazer.yaml @@ -0,0 +1,44 @@ +name: gazer + +on: + push: + branches: + - main + +env: + IMAGE_NAME: ghcr.io/mrsupiri/lazy-koala/gazer + DOCKER_BUILDKIT: 1 + +jobs: + app: + runs-on: ubuntu-latest + defaults: + run: + shell: bash + working-directory: gazer + steps: + - uses: actions/checkout@v2 + - uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - run: docker build -t $IMAGE_NAME:latest . + - run: docker tag $IMAGE_NAME:latest $IMAGE_NAME:commit-${GITHUB_SHA:0:8} + - run: docker push $IMAGE_NAME --all-tags + init-headers: + runs-on: ubuntu-latest + defaults: + run: + shell: bash + working-directory: gazer/init-headers + steps: + - uses: actions/checkout@v2 + - uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - run: docker build -t $IMAGE_NAME:init . + - run: docker tag $IMAGE_NAME:init $IMAGE_NAME:init-commit-${GITHUB_SHA:0:8} + - run: docker push $IMAGE_NAME --all-tags \ No newline at end of file diff --git a/gazer/Dockerfile b/gazer/Dockerfile new file mode 100644 index 0000000..eae5c99 --- /dev/null +++ b/gazer/Dockerfile @@ -0,0 +1,11 @@ +FROM alpine:edge + +RUN apk add bcc-tools py3-pip py3-numpy py3-pandas + +RUN pip install termplotlib + +WORKDIR /gazer + +COPY . . + +CMD ["python3", "main.py"] \ No newline at end of file diff --git a/gazer/deployment.yaml b/gazer/deployment.yaml new file mode 100644 index 0000000..d83f28e --- /dev/null +++ b/gazer/deployment.yaml @@ -0,0 +1,104 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: gazer + labels: + app: gazer +spec: + selector: + matchLabels: + name: gazer + template: + metadata: + labels: + name: gazer + spec: + containers: + - name: gazer + # command: [ "sh", "-c", "sleep 60d" ] + image: ghcr.io/mrsupiri/lazy-koala/gazer:latest + imagePullPolicy: IfNotPresent + resources: + requests: + ephemeral-storage: "2Gi" + env: + - name: PYTHONUNBUFFERED + value: "1" + securityContext: + privileged: true + capabilities: + add: + - SYS_ADMIN + volumeMounts: + - name: lsb-release + mountPath: /etc/lsb-release.host + readOnly: false + - name: os-release + mountPath: /etc/os-release.host + readOnly: false + - name: modules-dir + mountPath: /lib/modules + readOnly: false + - name: modules-host + mountPath: /lib/modules.host + readOnly: false + - name: linux-headers-generated + mountPath: /usr/src/ + readOnly: false + - name: boot-host + mountPath: /boot.host + readOnly: false + - name: debug + mountPath: /sys/kernel/debug + readOnly: false + hostNetwork: true + hostPID: true + initContainers: + - name: init-headers + image: ghcr.io/mrsupiri/lazy-koala/gazer:init + imagePullPolicy: IfNotPresent + securityContext: + privileged: true + capabilities: + add: [ "SYS_ADMIN" ] + volumeMounts: + - name: lsb-release + mountPath: /etc/lsb-release.host + readOnly: false + - name: os-release + mountPath: /etc/os-release.host + readOnly: false + - name: modules-dir + mountPath: /lib/modules + readOnly: false + - name: modules-host + mountPath: /lib/modules.host + readOnly: false + - name: linux-headers-generated + mountPath: /usr/src/ + readOnly: false + - name: boot-host + mountPath: /boot.host + readOnly: false + volumes: + - name: lsb-release + hostPath: + path: /etc/lsb-release + - name: os-release + hostPath: + path: /etc/os-release + - name: modules-dir + hostPath: + path: /var/cache/linux-headers/modules_dir + - name: linux-headers-generated + hostPath: + path: /var/cache/linux-headers/generated + - name: boot-host + hostPath: + path: / + - name: modules-host + hostPath: + path: /lib/modules + - name: debug + hostPath: + path: /sys/kernel/debug \ No newline at end of file diff --git a/gazer/init-headers/Dockerfile b/gazer/init-headers/Dockerfile new file mode 100644 index 0000000..74dee51 --- /dev/null +++ b/gazer/init-headers/Dockerfile @@ -0,0 +1,18 @@ +FROM alpine:3.8 +RUN apk add --update \ + bash \ + bc \ + build-base \ + bison \ + flex \ + curl \ + elfutils-dev \ + linux-headers \ + make \ + openssl-dev + +WORKDIR / + +COPY ./fetch-linux-headers.sh / +RUN chmod +x fetch-linux-headers.sh +ENTRYPOINT [ "/fetch-linux-headers.sh" ] \ No newline at end of file diff --git a/gazer/init-headers/fetch-linux-headers.sh b/gazer/init-headers/fetch-linux-headers.sh new file mode 100644 index 0000000..2ffcc8b --- /dev/null +++ b/gazer/init-headers/fetch-linux-headers.sh @@ -0,0 +1,143 @@ +#!/bin/bash + +## Credits https://github.com/mclenhard/ebpf-summit/blob/master/init/fetch-linux-headers.sh + +set -ex + +LSB_FILE="/etc/lsb-release.host" +OS_RELEASE_FILE="/etc/os-release.host" +TARGET_DIR="/usr/src" +HOST_MODULES_DIR="/lib/modules.host" + +KERNEL_VERSION="${KERNEL_VERSION:-$(uname -r)}" + +generate_headers() +{ + echo "Generating kernel headers" + + cd "${BUILD_DIR}" + if [ -e /proc/config.gz ]; then + zcat /proc/config.gz > .config + elif [ -e "/boot.host/config-${KERNEL_VERSION}" ]; then + cp "/boot.host/config-${KERNEL_VERSION}" .config + fi + make ARCH=x86 oldconfig > /dev/null + make ARCH=x86 prepare > /dev/null + + # Clean up abundant non-header files to speed-up copying + find "${BUILD_DIR}" -regex '.*\.c\|.*\.txt\|.*Makefile\|.*Build\|.*Kconfig' -type f -delete +} + +fetch_cos_linux_sources() +{ + echo "Fetching upstream kernel sources." + mkdir -p "${BUILD_DIR}" + curl -s "https://storage.googleapis.com/cos-tools/${BUILD_ID}/kernel-src.tar.gz" \ + | tar -xzf - -C "${BUILD_DIR}" +} + +fetch_generic_linux_sources() +{ + # 4.19.76-linuxkit -> 4.19.76 + # 4.14.154-128.181.amzn2.x86_64 -> 4.14.154 + # 4.19.76+gcp-something -> 4.19.76 + kernel_version="$(echo "${KERNEL_VERSION}" | awk -vFS='[-+]' '{ print $1 }')" + major_version="$(echo "${KERNEL_VERSION}" | awk -vFS=. '{ print $1 }')" + + # Remove the '.0' as the intial kernel major release isn't published with a patch number. + if [[ $kernel_version == *.0 ]]; then + kernel_version=$(echo $kernel_version | rev | sed s/0\.// | rev) + fi + + echo "Fetching upstream kernel sources for ${kernel_version}." + mkdir -p "${BUILD_DIR}" + curl -skL "https://www.kernel.org/pub/linux/kernel/v${major_version}.x/linux-$kernel_version.tar.gz" \ + | tar --strip-components=1 -xzf - -C "${BUILD_DIR}" +} + +install_cos_linux_headers() +{ + if grep -q CHROMEOS_RELEASE_VERSION "${LSB_FILE}" >/dev/null; then + BUILD_ID=$(awk '/CHROMEOS_RELEASE_VERSION *= */ { gsub(/^CHROMEOS_RELEASE_VERSION *= */, ""); print }' "${LSB_FILE}") + BUILD_DIR="/linux-lakitu-${BUILD_ID}" + SOURCES_DIR="${TARGET_DIR}/linux-lakitu-${BUILD_ID}" + + if [[ ! -e "${SOURCES_DIR}/.installed" ]]; then + echo "Installing kernel headers for COS build ${BUILD_ID}" + time fetch_cos_linux_sources + time generate_headers + time rm -rf "${TARGET_DIR}${BUILD_DIR}" + time mv "${BUILD_DIR}" "${TARGET_DIR}" + touch "${SOURCES_DIR}/.installed" + fi + fi +} + +install_generic_linux_headers() +{ + BUILD_DIR="/linux-generic-${KERNEL_VERSION}" + SOURCES_DIR="${TARGET_DIR}/linux-generic-${KERNEL_VERSION}" + + if [[ ! -e "${SOURCES_DIR}/.installed" ]];then + echo "Installing kernel headers for generic kernel" + time fetch_generic_linux_sources + time generate_headers + time rm -rf "${TARGET_DIR}${BUILD_DIR}" + time mv "${BUILD_DIR}" "${TARGET_DIR}" + touch "${SOURCES_DIR}/.installed" + fi +} + +install_headers() +{ + distro="$(awk '/^NAME *= */ { gsub(/^NAME *= */, ""); print }' "${OS_RELEASE_FILE}")" + + case $distro in + *"Container-Optimized OS"*) + install_cos_linux_headers + HEADERS_TARGET="${SOURCES_DIR}" + ;; + *) + echo "WARNING: Cannot find distro-specific headers for ${distro}. Fetching generic headers." + install_generic_linux_headers + HEADERS_TARGET="${SOURCES_DIR}" + ;; + esac +} + +check_headers() +{ + modules_path="$1" + arch="$(uname -m)" + kdir="${modules_path}/${KERNEL_VERSION}" + + [[ "${arch}" == "x86_64" ]] && arch="x86" + + [[ ! -e "${kdir}" ]] && return 1 + [[ ! -e "${kdir}/source" ]] && [[ ! -e "${kdir}/build" ]] && return 1 + + header_dir="$([[ -e "${kdir}/source" ]] && echo "${kdir}/source" || echo "${kdir}/build")" + + [[ ! -e "${header_dir}/include/linux/kconfig.h" ]] && return 1 + [[ ! -e "${header_dir}/include/generated/uapi" ]] && return 1 + [[ ! -e "${header_dir}/arch/${arch}/include/generated/uapi" ]] && return 1 + + return 0 +} + +if [[ ! -e /lib/modules/.installed ]]; then + if check_headers "${HOST_MODULES_DIR}"; then + HEADERS_TARGET="${HOST_MODULES_DIR}/source" + else + install_headers + fi + + mkdir -p "/lib/modules/${KERNEL_VERSION}" + ln -sf "${HEADERS_TARGET}" "/lib/modules/${KERNEL_VERSION}/source" + ln -sf "${HEADERS_TARGET}" "/lib/modules/${KERNEL_VERSION}/build" + touch /lib/modules/.installed + exit 0 +else + echo "Headers already installed" + exit 0 +fi \ No newline at end of file diff --git a/gazer/service.yaml b/gazer/service.yaml deleted file mode 100644 index d9494b8..0000000 --- a/gazer/service.yaml +++ /dev/null @@ -1,29 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - name: bcc -spec: - containers: - - command: [ "sh", "-c", "sleep 60d" ] - image: zlim/bcc - imagePullPolicy: IfNotPresent - name: bcc - resources: {} - securityContext: - privileged: true - volumeMounts: - - mountPath: /lib/modules - name: host-modules - readOnly: true - - mountPath: /usr/src - name: host-usr-src - readOnly: true - volumes: - - hostPath: - path: /lib/modules - type: Directory - name: host-modules - - hostPath: - path: /usr/src - type: Directory - name: host-usr-src