diff --git a/cmd/crio/main.go b/cmd/crio/main.go index 1bc22a263d6..4ece4e19cf2 100644 --- a/cmd/crio/main.go +++ b/cmd/crio/main.go @@ -266,7 +266,7 @@ func main() { grpcL := m.MatchWithWriters(cmux.HTTP2MatchHeaderFieldSendSettings("content-type", "application/grpc")) httpL := m.Match(cmux.HTTP1Fast()) - infoMux := service.GetInfoMux() + infoMux := service.GetInfoMux(c.Bool("enable-profile-unix-socket")) httpServer := &http.Server{ Handler: infoMux, ReadTimeout: 5 * time.Second, diff --git a/completions/bash/crio b/completions/bash/crio index fdf2d3e6d84..d47c148f5d2 100755 --- a/completions/bash/crio +++ b/completions/bash/crio @@ -38,6 +38,7 @@ h --default-ulimits --drop-infra-ctr --enable-metrics +--enable-profile-unix-socket --gid-mappings --global-auth-file --grpc-max-recv-msg-size diff --git a/completions/fish/crio.fish b/completions/fish/crio.fish index 9eb0c764489..bfb46b41f6a 100644 --- a/completions/fish/crio.fish +++ b/completions/fish/crio.fish @@ -44,6 +44,7 @@ complete -c crio -n '__fish_crio_no_subcommand' -f -l default-transport -r -d 'A complete -c crio -n '__fish_crio_no_subcommand' -f -l default-ulimits -r -d 'Ulimits to apply to containers by default (name=soft:hard) (default: [])' complete -c crio -n '__fish_crio_no_subcommand' -f -l drop-infra-ctr -d 'Determines whether pods are created without an infra container (when the pod is not using a pod level PID namespace). Requires ManageNSLifecycle to be true (default: false)' complete -c crio -n '__fish_crio_no_subcommand' -f -l enable-metrics -d 'Enable metrics endpoint for the server on localhost:9090' +complete -c crio -n '__fish_crio_no_subcommand' -f -l enable-profile-unix-socket -d 'Enable pprof profiler on crio unix domain socket' complete -c crio -n '__fish_crio_no_subcommand' -f -l gid-mappings -r -d 'Specify the GID mappings to use for the user namespace (default: "")' complete -c crio -n '__fish_crio_no_subcommand' -l global-auth-file -r -d 'Path to a file like /var/lib/kubelet/config.json holding credentials necessary for pulling images from secure registries (default: "")' complete -c crio -n '__fish_crio_no_subcommand' -f -l grpc-max-recv-msg-size -r -d 'Maximum grpc receive message size in bytes' diff --git a/completions/zsh/_crio b/completions/zsh/_crio index 4e79ed47f6c..761d9b75926 100644 --- a/completions/zsh/_crio +++ b/completions/zsh/_crio @@ -7,7 +7,7 @@ it later with **--config**. Global options will modify the output.' 'version:dis _describe 'commands' cmds local -a opts - opts=('--additional-devices' '--apparmor-profile' '--big-files-temporary-dir' '--bind-mount-prefix' '--cgroup-manager' '--cni-config-dir' '--cni-default-network' '--cni-plugin-dir' '--config' '--config-dir' '--conmon' '--conmon-cgroup' '--conmon-env' '--container-attach-socket-dir' '--container-exits-dir' '--ctr-stop-timeout' '--decryption-keys-path' '--default-capabilities' '--default-env' '--default-mounts-file' '--default-runtime' '--default-sysctls' '--default-transport' '--default-ulimits' '--drop-infra-ctr' '--enable-metrics' '--gid-mappings' '--global-auth-file' '--grpc-max-recv-msg-size' '--grpc-max-send-msg-size' '--hooks-dir' '--image-volumes' '--infra-ctr-cpuset' '--insecure-registry' '--listen' '--log' '--log-dir' '--log-filter' '--log-format' '--log-journald' '--log-level' '--log-size-max' '--manage-ns-lifecycle' '--metrics-port' '--metrics-socket' '--namespaces-dir' '--no-pivot' '--pause-command' '--pause-image' '--pause-image-auth-file' '--pids-limit' '--pinns-path' '--profile' '--profile-port' '--read-only' '--registries-conf' '--registry' '--root' '--runroot' '--runtimes' '--seccomp-profile' '--seccomp-use-default-when-empty' '--selinux' '--separate-pull-cgroup' '--signature-policy' '--storage-driver' '--storage-opt' '--stream-address' '--stream-enable-tls' '--stream-port' '--stream-tls-ca' '--stream-tls-cert' '--stream-tls-key' '--uid-mappings' '--version-file' '--version-file-persist' '--help' '--version') + opts=('--additional-devices' '--apparmor-profile' '--big-files-temporary-dir' '--bind-mount-prefix' '--cgroup-manager' '--cni-config-dir' '--cni-default-network' '--cni-plugin-dir' '--config' '--config-dir' '--conmon' '--conmon-cgroup' '--conmon-env' '--container-attach-socket-dir' '--container-exits-dir' '--ctr-stop-timeout' '--decryption-keys-path' '--default-capabilities' '--default-env' '--default-mounts-file' '--default-runtime' '--default-sysctls' '--default-transport' '--default-ulimits' '--drop-infra-ctr' '--enable-metrics' '--enable-profile-unix-socket' '--gid-mappings' '--global-auth-file' '--grpc-max-recv-msg-size' '--grpc-max-send-msg-size' '--hooks-dir' '--image-volumes' '--infra-ctr-cpuset' '--insecure-registry' '--listen' '--log' '--log-dir' '--log-filter' '--log-format' '--log-journald' '--log-level' '--log-size-max' '--manage-ns-lifecycle' '--metrics-port' '--metrics-socket' '--namespaces-dir' '--no-pivot' '--pause-command' '--pause-image' '--pause-image-auth-file' '--pids-limit' '--pinns-path' '--profile' '--profile-port' '--read-only' '--registries-conf' '--registry' '--root' '--runroot' '--runtimes' '--seccomp-profile' '--seccomp-use-default-when-empty' '--selinux' '--separate-pull-cgroup' '--signature-policy' '--storage-driver' '--storage-opt' '--stream-address' '--stream-enable-tls' '--stream-port' '--stream-tls-ca' '--stream-tls-cert' '--stream-tls-key' '--uid-mappings' '--version-file' '--version-file-persist' '--help' '--version') _describe 'global options' opts return diff --git a/docs/crio.8.md b/docs/crio.8.md index 6d0e0ec8a59..d4950f7c7f3 100644 --- a/docs/crio.8.md +++ b/docs/crio.8.md @@ -37,6 +37,7 @@ crio [--default-ulimits]=[value] [--drop-infra-ctr] [--enable-metrics] +[--enable-profile-unix-socket] [--gid-mappings]=[value] [--global-auth-file]=[value] [--grpc-max-recv-msg-size]=[value] @@ -175,6 +176,8 @@ crio [GLOBAL OPTIONS] command [COMMAND OPTIONS] [ARGUMENTS...] **--enable-metrics**: Enable metrics endpoint for the server on localhost:9090 +**--enable-profile-unix-socket**: Enable pprof profiler on crio unix domain socket + **--gid-mappings**="": Specify the GID mappings to use for the user namespace (default: "") **--global-auth-file**="": Path to a file like /var/lib/kubelet/config.json holding credentials necessary for pulling images from secure registries (default: "") diff --git a/internal/criocli/criocli.go b/internal/criocli/criocli.go index 80ee8740e1d..65a83a5ea6c 100644 --- a/internal/criocli/criocli.go +++ b/internal/criocli/criocli.go @@ -643,6 +643,11 @@ func getCrioFlags(defConf *libconfig.Config) []cli.Flag { Usage: "Port for the pprof profiler", EnvVars: []string{"CONTAINER_PROFILE_PORT"}, }, + &cli.BoolFlag{ + Name: "enable-profile-unix-socket", + Usage: "Enable pprof profiler on crio unix domain socket", + EnvVars: []string{"ENABLE_PROFILE_UNIX_SOCKET"}, + }, &cli.BoolFlag{ Name: "enable-metrics", Usage: "Enable metrics endpoint for the server on localhost:9090", diff --git a/server/inspect.go b/server/inspect.go index e71b214c476..c3ebb8207cb 100644 --- a/server/inspect.go +++ b/server/inspect.go @@ -4,6 +4,7 @@ import ( "fmt" "math" "net/http" + "net/http/pprof" "github.com/containers/storage/pkg/idtools" "github.com/cri-o/cri-o/internal/lib/sandbox" @@ -100,7 +101,7 @@ const ( ) // GetInfoMux returns the mux used to serve info requests -func (s *Server) GetInfoMux() *bone.Mux { +func (s *Server) GetInfoMux(enableProfile bool) *bone.Mux { mux := bone.New() mux.Get(InspectConfigEndpoint, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { @@ -157,5 +158,14 @@ func (s *Server) GetInfoMux() *bone.Mux { } })) + // Add pprof handlers + if enableProfile { + mux.Get("/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline)) + mux.Get("/debug/pprof/profile", http.HandlerFunc(pprof.Profile)) + mux.Get("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol)) + mux.Get("/debug/pprof/trace", http.HandlerFunc(pprof.Trace)) + mux.Get("/debug/pprof/*", http.HandlerFunc(pprof.Index)) + } + return mux } diff --git a/server/inspect_ginkgo_test.go b/server/inspect_ginkgo_test.go index f3336119d73..83d6dee1cee 100644 --- a/server/inspect_ginkgo_test.go +++ b/server/inspect_ginkgo_test.go @@ -24,7 +24,7 @@ var _ = t.Describe("Inspect", func() { setupSUT() recorder = httptest.NewRecorder() - mux = sut.GetInfoMux() + mux = sut.GetInfoMux(false) Expect(mux).NotTo(BeNil()) Expect(recorder).NotTo(BeNil()) }) diff --git a/test/profile.bats b/test/profile.bats index 4b5750613a3..5134fdd441c 100644 --- a/test/profile.bats +++ b/test/profile.bats @@ -14,3 +14,8 @@ function teardown() { CONTAINER_PROFILE=true start_crio curl --silent --fail --show-error http://localhost:6060/debug/pprof/goroutine > /dev/null } + +@test "pprof over unix socket" { + ENABLE_PROFILE_UNIX_SOCKET=true start_crio + curl --silent --fail --show-error --unix-socket "$CRIO_SOCKET" http://localhost/debug/pprof/goroutine > /dev/null +}