Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(btfhack): add btfhack & replace initContainer image #107

Merged
merged 1 commit into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,7 @@ RUN apk add --no-cache \
COPY --from=build /go/src/github.com/alibaba/kubeskoop/bin/inspector /bin/inspector
COPY --from=build /go/src/github.com/alibaba/kubeskoop/bin/pod-collector /bin/pod-collector
COPY --from=build /go/src/github.com/alibaba/kubeskoop/bin/skoop /bin/skoop
COPY --from=build /go/src/github.com/alibaba/kubeskoop/bin/btfhack /bin/btfhack

COPY tools/scripts/* /bin/
COPY deploy/resource/kubeskoop-exporter-dashboard.json /etc/
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ GIT_COMMIT=${shell git rev-parse HEAD}
ldflags="-X $(VERSION_PKG).Version=$(TAG) -X $(VERSION_PKG).Commit=${GIT_COMMIT}"

.PHONY: all
all: build-exporter build-skoop build-collector
all: build-exporter build-skoop build-collector build-btfhack

.PHONY: fmt
fmt:
Expand All @@ -36,6 +36,10 @@ build-skoop:
build-collector:
CGO_ENABLED=0 go build -o bin/pod-collector -ldflags $(ldflags) ./cmd/collector

.PHONY: build-btfhack
build-btfhack:
CGO_ENABLED=0 go build -o bin/btfhack -ldflags $(ldflags) ./cmd/btfhack

.PHONY: image
image: ## build kubeskoop image
docker build -t $(SKOOP_REPO):$(TAG) .
Expand Down
9 changes: 9 additions & 0 deletions cmd/btfhack/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package main

import (
"github.com/alibaba/kubeskoop/pkg/exporter/btfhack"
)

func main() {
btfhack.Execute()
}
2 changes: 1 addition & 1 deletion deploy/helm/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ image:

initContainer:
enabled: true
repository: registry.cn-hangzhou.aliyuncs.com/acs/btfhack
repository: kubeskoop/kubeskoop
tag: latest
imagePullPolicy: Always

Expand Down
4 changes: 2 additions & 2 deletions deploy/skoopbundle.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ spec:
dnsPolicy: ClusterFirstWithHostNet
initContainers:
- name: inspector-prepare
image: registry.cn-hangzhou.aliyuncs.com/acs/btfhack:latest
image: "kubeskoop/kubeskoop:latest"
volumeMounts:
- name: btf-rawdata
mountPath: /etc/net-exporter/btf
- mountPath: /boot/
name: boot
command: [btfhack, discover,-p ,/etc/net-exporter/btf/]
command: [btfhack, discover, -p, /etc/net-exporter/btf/]
containers:
- image: "kubeskoop/kubeskoop:latest"
name: inspector
Expand Down
13 changes: 11 additions & 2 deletions pkg/exporter/bpfutil/btf.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ func KernelRelease() (string, error) {
return unix.ByteSliceToString(uname.Release[:]), nil
}

func KernelArch() (string, error) {
var uname unix.Utsname
if err := unix.Uname(&uname); err != nil {
return "", fmt.Errorf("uname failed: %w", err)
}

return unix.ByteSliceToString(uname.Machine[:]), nil
}

// LoadBTFSpecOrNil once error occurs in load process, return nil and use system raw spec instead
func LoadBTFSpecOrNil() *btf.Spec {
var (
Expand All @@ -60,7 +69,7 @@ func LoadBTFSpecOrNil() *btf.Spec {
btffile = kernelBTFPath
} else if os.IsNotExist(err) {
for _, btfPath := range []string{BTFPATH, bpfSharePath, userCustomBtfPath} {
btffile, err = findBTFFileWithPath(btfPath)
btffile, err = FindBTFFileWithPath(btfPath)
if err == nil {
break
}
Expand All @@ -85,7 +94,7 @@ func LoadBTFSpecOrNil() *btf.Spec {
return spec
}

func findBTFFileWithPath(path string) (string, error) {
func FindBTFFileWithPath(path string) (string, error) {
path = filepath.Clean(path)

v, err := KernelRelease()
Expand Down
70 changes: 70 additions & 0 deletions pkg/exporter/btfhack/discover.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package btfhack

import (
"fmt"
"log"
"os/exec"

"github.com/alibaba/kubeskoop/pkg/exporter/bpfutil"

"github.com/spf13/cobra"
)

const (
defaultBTFDstPath = "/etc/net-exporter/btf"
)

// cpCmd represents the cp command
var (
cpCmd = &cobra.Command{
Use: "discover",
Short: "copy or download appropriate btf file to dst path",
Run: func(cmd *cobra.Command, args []string) {
if btfSrcPath == "" {
btfSrcPath = defaultBTFPath
}
if btfDstPath == "" {
btfDstPath = defaultBTFDstPath
}

btffile, err := bpfutil.FindBTFFileWithPath(btfSrcPath)
if err == nil {
err := copyBtfFile(btffile, btfDstPath)
if err != nil {
log.Fatalf("Failed copy btf file: %s\n", err)
}
log.Printf("Copy btf file %s to %s succeed\n", btffile, btfDstPath)
return
}

btffile, err = downloadBTFOnline(btfDstPath)
if err != nil {
log.Printf("Download btf error: %s\n", err)
return
}
log.Printf("Download btf file %s succeed\n", btffile)
},
}

btfDstPath string
)

func copyBtfFile(path, dstPath string) error {
cmdToExecute := exec.Command("cp", path, dstPath)
output, err := cmdToExecute.CombinedOutput()
if err != nil {
return fmt.Errorf("load btf with:%s err:%s", output, err)
}

log.Printf("load btf %s to %s succeed", path, dstPath)
return nil
}

func init() {
rootCmd.AddCommand(cpCmd)

flags := cpCmd.PersistentFlags()

flags.StringVarP(&btfSrcPath, "src", "s", "", "btf source file")
flags.StringVarP(&btfDstPath, "dst", "p", "", "btf destination directory")
}
90 changes: 90 additions & 0 deletions pkg/exporter/btfhack/download.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package btfhack

import (
"fmt"
"io"
"log"
"net"
"net/http"
"net/url"
"os"
"path"
"time"

"github.com/alibaba/kubeskoop/pkg/exporter/bpfutil"
)

const (
EnvBTFDownloadURL = "BTF_DOWNLOAD_URL"
OpenBTFURL = "https://mirrors.openanolis.cn/coolbpf/btf/"
)

func downloadBTFOnline(btfDstPath string) (string, error) {
release, err := bpfutil.KernelRelease()
if err != nil {
return "", err
}
arch, err := bpfutil.KernelArch()
if err != nil {
return "", err
}

filename := fmt.Sprintf("vmlinux-%s", release)
dst := path.Join(btfDstPath, filename)
urlPath := fmt.Sprintf("%s/%s", arch, filename)
if envURL, ok := os.LookupEnv(EnvBTFDownloadURL); ok {
downloadURL, err := url.JoinPath(envURL, urlPath)
if err != nil {
return "", err
}
err = downloadTo(downloadURL, dst)
if err == nil {
log.Printf("Downloaded btf file from %s", downloadURL)
return dst, nil
}
log.Printf("Download btf file failed from %s: %s", downloadURL, err)
}

downloadURL, err := url.JoinPath(OpenBTFURL, urlPath)
if err != nil {
return "", err
}
err = downloadTo(downloadURL, dst)
if err != nil {
return "", fmt.Errorf("download btf file failed from %s: %w", downloadURL, err)
}
return dst, nil
}

func downloadTo(url, dst string) error {
tr := &http.Transport{
Dial: (&net.Dialer{
Timeout: 1 * time.Second,
KeepAlive: 30 * time.Second,
}).Dial,
}

client := http.Client{
Timeout: 50 * time.Second,
Transport: tr,
}

res, err := client.Get(url)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return fmt.Errorf("got status code %d", res.StatusCode)
}

f, err := os.Create(dst)
if err != nil {
return err
}
_, err = io.Copy(f, res.Body)
if err != nil {
return err
}
return nil
}
23 changes: 23 additions & 0 deletions pkg/exporter/btfhack/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package btfhack

import (
"os"

"github.com/spf13/cobra"
)

const (
defaultBTFPath = "/etc/btf"
)

var rootCmd = &cobra.Command{
Use: "btfhack",
Short: "A tool to automatically discover btf file from local path or online",
}

func Execute() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}
55 changes: 55 additions & 0 deletions pkg/exporter/btfhack/test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package btfhack

import (
"log"

"github.com/alibaba/kubeskoop/pkg/exporter/bpfutil"
"github.com/alibaba/kubeskoop/pkg/exporter/testbtf"

"github.com/cilium/ebpf/btf"
"github.com/spf13/cobra"
)

// testCmd represents the test command
var (
testCmd = &cobra.Command{
Use: "test",
Short: "test btf support locally",
Run: func(cmd *cobra.Command, args []string) {
if btfSrcPath == "" {
btfSrcPath = defaultBTFPath
}

file, err := bpfutil.FindBTFFileWithPath(btfSrcPath)
if err != nil {
log.Printf("failed with %s", err)
return
}

spec, err := bpfutil.LoadBTFFromFile(file)
if err != nil {
log.Printf("load btf spec faiild with %s", err)
return
}

if err := testBTFAvailable(spec); err != nil {
log.Printf("btf test failed: %v", err)
} else {
log.Printf("btf test ok")
}
},
}

btfSrcPath string
)

func init() {
rootCmd.AddCommand(testCmd)
flags := testCmd.PersistentFlags()

flags.StringVarP(&btfSrcPath, "src", "s", "", "btf source file")
}

func testBTFAvailable(spec *btf.Spec) error {
return testbtf.RunBTFTest(spec)
}
20 changes: 20 additions & 0 deletions pkg/exporter/btfhack/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package btfhack

import (
"github.com/alibaba/kubeskoop/version"
"github.com/spf13/cobra"
)

var (
versionCmd = &cobra.Command{
Use: "version",
Short: "show version",
Run: func(_ *cobra.Command, args []string) {
version.PrintVersion()
},
}
)

func init() {
rootCmd.AddCommand(versionCmd)
}
Loading
Loading