admin: Add optional /debug/pprof/profile endpoint (#2516)

This change introduces a new, optional /debug/pprof/profile.pb.gz
endpoint to the proxy's admin server. This endpoint is feature-gated
and, initially, it will not be included in release builds. It replicates
Go's /debug/pprof/profile, but it always returns gzipped protobuf (i.e.
as can be read by pprof pprofutils).

When the feature is enabled, profiling requests are only permitted over
the loopback interface.

The development Dockerfile is updated to prevent stripping debug
symbols when pprof is enabled so that the pprof data has useful names.

Co-authored-by: Eliza Weisman <eliza@buoyant.io>
This commit is contained in:
Oliver Gould 2023-11-16 13:09:43 -08:00 committed by GitHub
parent bf5cb67b0a
commit 9f7e7ac2f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 518 additions and 64 deletions

View File

@ -28,3 +28,4 @@ jobs:
- run: git config --global --add safe.directory "$PWD" # actions/runner#2033 - run: git config --global --add safe.directory "$PWD" # actions/runner#2033
- run: just fetch - run: just fetch
- run: just check --exclude=linkerd-meshtls-boring - run: just check --exclude=linkerd-meshtls-boring
- run: just check --exclude=linkerd-meshtls-boring --features=pprof

View File

@ -1,4 +1,6 @@
{ {
"rust-analyzer.cargo.features": [], "rust-analyzer.cargo.features": [
"pprof"
],
"files.insertFinalNewline": true "files.insertFinalNewline": true
} }

View File

@ -2,6 +2,15 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "addr2line"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
dependencies = [
"gimli",
]
[[package]] [[package]]
name = "adler" name = "adler"
version = "1.0.2" version = "1.0.2"
@ -29,9 +38,9 @@ dependencies = [
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "0.7.20" version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@ -81,7 +90,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.12", "syn 2.0.39",
] ]
[[package]] [[package]]
@ -135,6 +144,21 @@ dependencies = [
"tower-service", "tower-service",
] ]
[[package]]
name = "backtrace"
version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
dependencies = [
"addr2line",
"cc",
"cfg-if",
"libc",
"miniz_oxide 0.7.1",
"object",
"rustc-demangle",
]
[[package]] [[package]]
name = "base64" name = "base64"
version = "0.13.1" version = "0.13.1"
@ -164,7 +188,7 @@ dependencies = [
"regex", "regex",
"rustc-hash", "rustc-hash",
"shlex", "shlex",
"syn 2.0.12", "syn 2.0.39",
] ]
[[package]] [[package]]
@ -179,6 +203,15 @@ version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]] [[package]]
name = "boring" name = "boring"
version = "3.0.4" version = "3.0.4"
@ -266,6 +299,24 @@ dependencies = [
"cc", "cc",
] ]
[[package]]
name = "cpp_demangle"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e8227005286ec39567949b33df9896bcadfa6051bccca2488129f108ca23119"
dependencies = [
"cfg-if",
]
[[package]]
name = "cpufeatures"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "crc32fast" name = "crc32fast"
version = "1.3.2" version = "1.3.2"
@ -275,12 +326,31 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]] [[package]]
name = "data-encoding" name = "data-encoding"
version = "2.3.3" version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb"
[[package]]
name = "debugid"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d"
dependencies = [
"uuid",
]
[[package]] [[package]]
name = "deflate" name = "deflate"
version = "1.0.0" version = "1.0.0"
@ -311,6 +381,16 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]] [[package]]
name = "drain" name = "drain"
version = "0.1.1" version = "0.1.1"
@ -369,6 +449,18 @@ dependencies = [
"instant", "instant",
] ]
[[package]]
name = "findshlibs"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64"
dependencies = [
"cc",
"lazy_static",
"libc",
"winapi",
]
[[package]] [[package]]
name = "fixedbitset" name = "fixedbitset"
version = "0.4.2" version = "0.4.2"
@ -382,7 +474,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
dependencies = [ dependencies = [
"crc32fast", "crc32fast",
"miniz_oxide", "miniz_oxide 0.6.2",
] ]
[[package]] [[package]]
@ -499,7 +591,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.12", "syn 2.0.39",
] ]
[[package]] [[package]]
@ -532,6 +624,16 @@ dependencies = [
"slab", "slab",
] ]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.8" version = "0.2.8"
@ -543,6 +645,12 @@ dependencies = [
"wasi", "wasi",
] ]
[[package]]
name = "gimli"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
[[package]] [[package]]
name = "glob" name = "glob"
version = "0.3.1" version = "0.3.1"
@ -846,9 +954,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.140" version = "0.2.150"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]] [[package]]
name = "libfuzzer-sys" name = "libfuzzer-sys"
@ -913,12 +1021,14 @@ dependencies = [
name = "linkerd-app-admin" name = "linkerd-app-admin"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"deflate",
"futures", "futures",
"http", "http",
"hyper", "hyper",
"linkerd-app-core", "linkerd-app-core",
"linkerd-app-inbound", "linkerd-app-inbound",
"linkerd-tracing", "linkerd-tracing",
"pprof",
"serde", "serde",
"serde_json", "serde_json",
"thiserror", "thiserror",
@ -1493,7 +1603,7 @@ dependencies = [
"linkerd-tls", "linkerd-tls",
"linkerd2-proxy-api", "linkerd2-proxy-api",
"pin-project", "pin-project",
"prost", "prost 0.11.8",
"tonic", "tonic",
"tower", "tower",
"tracing", "tracing",
@ -1535,7 +1645,7 @@ dependencies = [
"linkerd2-proxy-api", "linkerd2-proxy-api",
"maplit", "maplit",
"once_cell", "once_cell",
"prost-types", "prost-types 0.11.8",
"quickcheck", "quickcheck",
"thiserror", "thiserror",
"tonic", "tonic",
@ -1642,7 +1752,7 @@ dependencies = [
"linkerd-http-route", "linkerd-http-route",
"linkerd2-proxy-api", "linkerd2-proxy-api",
"maplit", "maplit",
"prost-types", "prost-types 0.11.8",
"quickcheck", "quickcheck",
"thiserror", "thiserror",
] ]
@ -1665,7 +1775,7 @@ dependencies = [
"linkerd2-proxy-api", "linkerd2-proxy-api",
"parking_lot", "parking_lot",
"pin-project", "pin-project",
"prost-types", "prost-types 0.11.8",
"quickcheck", "quickcheck",
"rand", "rand",
"thiserror", "thiserror",
@ -1764,7 +1874,7 @@ dependencies = [
"linkerd-tonic-watch", "linkerd-tonic-watch",
"linkerd2-proxy-api", "linkerd2-proxy-api",
"once_cell", "once_cell",
"prost-types", "prost-types 0.11.8",
"quickcheck", "quickcheck",
"regex", "regex",
"thiserror", "thiserror",
@ -1916,8 +2026,8 @@ dependencies = [
"linkerd-error", "linkerd-error",
"linkerd-io", "linkerd-io",
"linkerd-stack", "linkerd-stack",
"prost", "prost 0.11.8",
"prost-build", "prost-build 0.11.8",
"tokio", "tokio",
"tokio-test", "tokio-test",
"tracing", "tracing",
@ -1961,8 +2071,8 @@ dependencies = [
"h2", "h2",
"http", "http",
"ipnet", "ipnet",
"prost", "prost 0.11.8",
"prost-types", "prost-types 0.11.8",
"quickcheck", "quickcheck",
"thiserror", "thiserror",
"tonic", "tonic",
@ -2026,7 +2136,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
dependencies = [ dependencies = [
"regex-automata", "regex-automata 0.1.10",
] ]
[[package]] [[package]]
@ -2047,6 +2157,15 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "memmap2"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a5a03cefb0d953ec0be133036f14e109412fa594edc2f77227249db66cc3ed"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "mime" name = "mime"
version = "0.3.16" version = "0.3.16"
@ -2068,6 +2187,15 @@ dependencies = [
"adler", "adler",
] ]
[[package]]
name = "miniz_oxide"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
dependencies = [
"adler",
]
[[package]] [[package]]
name = "mio" name = "mio"
version = "0.8.6" version = "0.8.6"
@ -2086,6 +2214,17 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
[[package]]
name = "nix"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b"
dependencies = [
"bitflags 1.3.2",
"cfg-if",
"libc",
]
[[package]] [[package]]
name = "nom" name = "nom"
version = "7.1.0" version = "7.1.0"
@ -2126,6 +2265,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "object"
version = "0.32.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.17.1" version = "1.17.1"
@ -2137,8 +2285,8 @@ name = "opencensus-proto"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bytes", "bytes",
"prost", "prost 0.11.8",
"prost-types", "prost-types 0.11.8",
"tonic", "tonic",
"tonic-build", "tonic-build",
] ]
@ -2242,6 +2390,30 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "pprof"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef5c97c51bd34c7e742402e216abdeb44d415fbe6ae41d56b114723e953711cb"
dependencies = [
"backtrace",
"cfg-if",
"findshlibs",
"libc",
"log",
"nix",
"once_cell",
"parking_lot",
"prost 0.12.1",
"prost-build 0.12.1",
"prost-derive 0.12.1",
"sha2",
"smallvec",
"symbolic-demangle",
"tempfile",
"thiserror",
]
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.17" version = "0.2.17"
@ -2258,6 +2430,16 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "prettyplease"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d"
dependencies = [
"proc-macro2",
"syn 2.0.39",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.69" version = "1.0.69"
@ -2287,7 +2469,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e48e50df39172a3e7eb17e14642445da64996989bc212b583015435d39a58537" checksum = "e48e50df39172a3e7eb17e14642445da64996989bc212b583015435d39a58537"
dependencies = [ dependencies = [
"bytes", "bytes",
"prost-derive", "prost-derive 0.11.8",
]
[[package]]
name = "prost"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4fdd22f3b9c31b53c060df4a0613a1c7f062d4115a2b984dd15b1858f7e340d"
dependencies = [
"bytes",
"prost-derive 0.12.1",
] ]
[[package]] [[package]]
@ -2303,15 +2495,37 @@ dependencies = [
"log", "log",
"multimap", "multimap",
"petgraph", "petgraph",
"prettyplease", "prettyplease 0.1.25",
"prost", "prost 0.11.8",
"prost-types", "prost-types 0.11.8",
"regex", "regex",
"syn 1.0.109", "syn 1.0.109",
"tempfile", "tempfile",
"which", "which",
] ]
[[package]]
name = "prost-build"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8bdf592881d821b83d471f8af290226c8d51402259e9bb5be7f9f8bdebbb11ac"
dependencies = [
"bytes",
"heck",
"itertools",
"log",
"multimap",
"once_cell",
"petgraph",
"prettyplease 0.2.15",
"prost 0.12.1",
"prost-types 0.12.1",
"regex",
"syn 2.0.39",
"tempfile",
"which",
]
[[package]] [[package]]
name = "prost-derive" name = "prost-derive"
version = "0.11.8" version = "0.11.8"
@ -2325,13 +2539,35 @@ dependencies = [
"syn 1.0.109", "syn 1.0.109",
] ]
[[package]]
name = "prost-derive"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "265baba7fabd416cf5078179f7d2cbeca4ce7a9041111900675ea7c4cb8a4c32"
dependencies = [
"anyhow",
"itertools",
"proc-macro2",
"quote",
"syn 2.0.39",
]
[[package]] [[package]]
name = "prost-types" name = "prost-types"
version = "0.11.8" version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "379119666929a1afd7a043aa6cf96fa67a6dce9af60c88095a4686dbce4c9c88" checksum = "379119666929a1afd7a043aa6cf96fa67a6dce9af60c88095a4686dbce4c9c88"
dependencies = [ dependencies = [
"prost", "prost 0.11.8",
]
[[package]]
name = "prost-types"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e081b29f63d83a4bc75cfc9f3fe424f9156cf92d8a4f0c9407cce9a1b67327cf"
dependencies = [
"prost 0.12.1",
] ]
[[package]] [[package]]
@ -2351,9 +2587,9 @@ dependencies = [
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.26" version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@ -2426,13 +2662,14 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.7.3" version = "1.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
"regex-syntax", "regex-automata 0.3.7",
"regex-syntax 0.7.5",
] ]
[[package]] [[package]]
@ -2441,7 +2678,18 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
dependencies = [ dependencies = [
"regex-syntax", "regex-syntax 0.6.29",
]
[[package]]
name = "regex-automata"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax 0.7.5",
] ]
[[package]] [[package]]
@ -2450,6 +2698,12 @@ version = "0.6.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]]
name = "regex-syntax"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
[[package]] [[package]]
name = "resolv-conf" name = "resolv-conf"
version = "0.7.0" version = "0.7.0"
@ -2475,6 +2729,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "rustc-demangle"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]] [[package]]
name = "rustc-hash" name = "rustc-hash"
version = "1.1.0" version = "1.1.0"
@ -2591,6 +2851,17 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "sha2"
version = "0.10.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]] [[package]]
name = "sharded-slab" name = "sharded-slab"
version = "0.1.4" version = "0.1.4"
@ -2646,6 +2917,35 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "symbolic-common"
version = "12.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "405af7bd5edd866cef462e22ef73f11cf9bf506c9d62824fef8364eb69d4d4ad"
dependencies = [
"debugid",
"memmap2",
"stable_deref_trait",
"uuid",
]
[[package]]
name = "symbolic-demangle"
version = "12.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bcd041ccfb77d9c70639efcd5b804b508ac7a273e9224d227379e225625daf9"
dependencies = [
"cpp_demangle",
"rustc-demangle",
"symbolic-common",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.109" version = "1.0.109"
@ -2659,9 +2959,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.12" version = "2.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79d9531f94112cfc3e4c8f5f02cb2b58f72c97b7efd85f70203cc6d8efda5927" checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2881,8 +3181,8 @@ dependencies = [
"hyper-timeout", "hyper-timeout",
"percent-encoding", "percent-encoding",
"pin-project", "pin-project",
"prost", "prost 0.11.8",
"prost-derive", "prost-derive 0.11.8",
"tokio", "tokio",
"tokio-stream", "tokio-stream",
"tokio-util", "tokio-util",
@ -2899,9 +3199,9 @@ version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bf5e9b9c0f7e0a7c027dcfaba7b2c60816c7049171f679d99ee2ff65d0de8c4" checksum = "5bf5e9b9c0f7e0a7c027dcfaba7b2c60816c7049171f679d99ee2ff65d0de8c4"
dependencies = [ dependencies = [
"prettyplease", "prettyplease 0.1.25",
"proc-macro2", "proc-macro2",
"prost-build", "prost-build 0.11.8",
"quote", "quote",
"syn 1.0.109", "syn 1.0.109",
] ]
@ -3005,12 +3305,12 @@ dependencies = [
[[package]] [[package]]
name = "tracing-log" name = "tracing-log"
version = "0.1.3" version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
dependencies = [ dependencies = [
"lazy_static",
"log", "log",
"once_cell",
"tracing-core", "tracing-core",
] ]
@ -3026,9 +3326,9 @@ dependencies = [
[[package]] [[package]]
name = "tracing-subscriber" name = "tracing-subscriber"
version = "0.3.16" version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
dependencies = [ dependencies = [
"matchers", "matchers",
"nu-ansi-term", "nu-ansi-term",
@ -3097,6 +3397,12 @@ version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]] [[package]]
name = "unicode-bidi" name = "unicode-bidi"
version = "0.3.11" version = "0.3.11"
@ -3135,6 +3441,12 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "uuid"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc"
[[package]] [[package]]
name = "valuable" name = "valuable"
version = "0.1.0" version = "0.1.0"
@ -3448,5 +3760,5 @@ checksum = "9731702e2f0617ad526794ae28fbc6f6ca8849b5ba729666c2a5bc4b6ddee2cd"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.12", "syn 2.0.39",
] ]

View File

@ -7,11 +7,11 @@ ARG RUST_IMAGE=ghcr.io/linkerd/dev:v42-rust
# Use an arbitrary ~recent edge release image to get the proxy # Use an arbitrary ~recent edge release image to get the proxy
# identity-initializing and linkerd-await wrappers. # identity-initializing and linkerd-await wrappers.
# Currently pinned to a build off of edge-23.11.1 + dev:v42 ARG LINKERD2_IMAGE=ghcr.io/linkerd/proxy:edge-23.11.2
ARG LINKERD2_IMAGE=ghcr.io/olix0r/l2-proxy:git-04283611
# Build the proxy. FROM $LINKERD2_IMAGE as linkerd2
FROM --platform=$BUILDPLATFORM $RUST_IMAGE as build
FROM --platform=$BUILDPLATFORM $RUST_IMAGE as fetch
ARG PROXY_FEATURES="" ARG PROXY_FEATURES=""
RUN apt-get update && \ RUN apt-get update && \
@ -28,24 +28,27 @@ WORKDIR /src
COPY . . COPY . .
RUN --mount=type=cache,id=cargo,target=/usr/local/cargo/registry \ RUN --mount=type=cache,id=cargo,target=/usr/local/cargo/registry \
just fetch just fetch
# Build the proxy.
FROM fetch as build
ENV CARGO_INCREMENTAL=0 ENV CARGO_INCREMENTAL=0
ENV RUSTFLAGS="-D warnings -A deprecated" ENV RUSTFLAGS="-D warnings -A deprecated"
ARG TARGETARCH="amd64" ARG TARGETARCH="amd64"
ARG PROFILE="release" ARG PROFILE="release"
ARG LINKERD2_PROXY_VERSION="" ARG LINKERD2_PROXY_VERSION=""
ARG LINKERD2_PROXY_VENDOR="" ARG LINKERD2_PROXY_VENDOR=""
SHELL ["/bin/bash", "-c"]
RUN --mount=type=cache,id=cargo,target=/usr/local/cargo/registry \ RUN --mount=type=cache,id=cargo,target=/usr/local/cargo/registry \
/usr/bin/time -v just arch="$TARGETARCH" features="$PROXY_FEATURES" profile="$PROFILE" build && \ if [[ "$PROXY_FEATURES" =~ .*pprof.* ]] ; then cmd=build-debug ; else cmd=build ; fi ; \
bin=$(just --evaluate profile="$PROFILE" _target_bin) ; \ /usr/bin/time -v just arch="$TARGETARCH" features="$PROXY_FEATURES" profile="$PROFILE" "$cmd" && \
du -sh "$bin" "$bin".dbg && \ ( mkdir -p /out ; \
mkdir -p /out && mv "$bin" /out/linkerd2-proxy mv $(just --evaluate profile="$PROFILE" _target_bin) /out/ ; \
du -sh /out/* )
FROM $LINKERD2_IMAGE as linkerd2 # Install the proxy binary into a base image that we can at least get a shell
# for debugging.
# Install the proxy binary into a base image that we can at least get a shell to
# debug on.
FROM docker.io/library/debian:bookworm-slim as runtime FROM docker.io/library/debian:bookworm-slim as runtime
WORKDIR /linkerd WORKDIR /linkerd
COPY --from=linkerd2 /usr/lib/linkerd/* /usr/lib/linkerd/ COPY --from=linkerd2 /usr/lib/linkerd/* /usr/lib/linkerd/
COPY --from=build /out/linkerd2-proxy /usr/lib/linkerd/linkerd2-proxy COPY --from=build /out/* /usr/lib/linkerd/
ENTRYPOINT ["/usr/lib/linkerd/linkerd2-proxy-identity"] ENTRYPOINT ["/usr/lib/linkerd/linkerd2-proxy-identity"]

View File

@ -76,6 +76,15 @@ skip = [
# `linkerd-trace-context`, `rustls-pemfile` and `tonic` depend on `base64` # `linkerd-trace-context`, `rustls-pemfile` and `tonic` depend on `base64`
# v0.13.1 while `rcgen` depends on v0.21.5 # v0.13.1 while `rcgen` depends on v0.21.5
{ name = "base64" }, { name = "base64" },
# https://github.com/hawkw/matchers/pull/4
{ name = "regex-automata", version = "0.1" },
{ name = "regex-syntax", version = "0.6" },
# linkerd2-proxy-api needs to upgrade tonic to upgrade prost...
{ name = "prost", version = "0.11" },
{ name = "prost-build", version = "0.11" },
{ name = "prost-derive", version = "0.11" },
{ name = "prost-types", version = "0.11" },
{ name = "prettyplease", version = "0.1" },
] ]
skip-tree = [ skip-tree = [
# right now we have a mix of versions of this crate in the ecosystem # right now we have a mix of versions of this crate in the ecosystem

View File

@ -116,7 +116,12 @@ test-dir dir *flags:
cd {{ dir }} && {{ _cargo }} test --frozen {{ _features }} {{ flags }} cd {{ dir }} && {{ _cargo }} test --frozen {{ _features }} {{ flags }}
# Build the proxy # Build the proxy
build: && checksec _strip build: _build checksec _strip
# Build the proxy without stripping debug symbols
build-debug: _build
_build:
@rm -f {{ _target_bin }} {{ _target_bin }}.dbg @rm -f {{ _target_bin }} {{ _target_bin }}.dbg
@{{ _cargo }} build --frozen --package=linkerd2-proxy {{ _features }} @{{ _cargo }} build --frozen --package=linkerd2-proxy {{ _features }}

View File

@ -14,6 +14,7 @@ This is used by tests and the executable.
[features] [features]
allow-loopback = ["linkerd-app-outbound/allow-loopback"] allow-loopback = ["linkerd-app-outbound/allow-loopback"]
log-streaming = ["linkerd-app-admin/log-streaming"] log-streaming = ["linkerd-app-admin/log-streaming"]
pprof = ["linkerd-app-admin/pprof"]
[dependencies] [dependencies]
futures = { version = "0.3", default-features = false } futures = { version = "0.3", default-features = false }

View File

@ -10,15 +10,19 @@ The linkerd proxy's admin server.
""" """
[features] [features]
default = []
pprof = ["deflate", "dep:pprof"]
log-streaming = ["linkerd-tracing/stream"] log-streaming = ["linkerd-tracing/stream"]
[dependencies] [dependencies]
deflate = { version = "1", optional = true, features = ["gzip"] }
http = "0.2" http = "0.2"
hyper = { version = "0.14", features = ["http1", "http2"] } hyper = { version = "0.14", features = ["http1", "http2"] }
futures = { version = "0.3", default-features = false } futures = { version = "0.3", default-features = false }
linkerd-app-core = { path = "../core" } linkerd-app-core = { path = "../core" }
linkerd-app-inbound = { path = "../inbound" } linkerd-app-inbound = { path = "../inbound" }
linkerd-tracing = { path = "../../tracing" } linkerd-tracing = { path = "../../tracing" }
pprof = { version = "0.13", optional = true, features = ["prost-codec"] }
serde = "1" serde = "1"
serde_json = "1" serde_json = "1"
thiserror = "1" thiserror = "1"

View File

@ -1,6 +1,8 @@
#![deny(rust_2018_idioms, clippy::disallowed_methods, clippy::disallowed_types)] #![deny(rust_2018_idioms, clippy::disallowed_methods, clippy::disallowed_types)]
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
#[cfg(feature = "pprof")]
mod pprof;
mod server; mod server;
mod stack; mod stack;

View File

@ -0,0 +1,62 @@
use linkerd_app_core::Result;
#[derive(Copy, Clone, Debug)]
pub(crate) struct Pprof;
impl Pprof {
pub async fn profile<B>(self, req: http::Request<B>) -> Result<http::Response<hyper::Body>> {
use pprof::protos::Message;
fn query_param<'r, B>(req: &'r http::Request<B>, name: &'static str) -> Option<&'r str> {
let params = req.uri().path_and_query()?.query()?.split('&');
params
.filter_map(|p| p.strip_prefix(name)?.strip_prefix('='))
.next()
}
// TODO(ver) Pretty-up error handling if we ever expose this outside of
// development.
let duration = std::time::Duration::from_secs_f64(
query_param(&req, "seconds")
.map(|s| s.parse::<f64>())
.transpose()?
.unwrap_or(30.0),
);
let frequency = query_param(&req, "frequency")
.map(|s| s.parse::<i32>())
.transpose()?
// Go's default.
.unwrap_or(100);
tracing::info!(?duration, frequency, "Collecting");
let report = {
let guard = pprof::ProfilerGuard::new(frequency)?;
tokio::time::sleep(duration).await;
guard.report().build()?
};
tracing::info!(
?duration,
frequency,
frames = report.data.len(),
"Collected"
);
let pb_gz = {
let mut gz = deflate::write::GzEncoder::new(
Vec::<u8>::new(),
deflate::CompressionOptions::fast(),
);
std::io::Write::write_all(&mut gz, &{
let mut buf = Vec::new();
report.pprof()?.encode(&mut buf)?;
buf
})?;
gz.finish()?
};
Ok(http::Response::builder()
.header(http::header::CONTENT_TYPE, "application/octet-stream")
.body(hyper::Body::from(pb_gz))
.expect("response must be valid"))
}
}

View File

@ -19,7 +19,7 @@ use hyper::{
use linkerd_app_core::{ use linkerd_app_core::{
metrics::{self as metrics, FmtMetrics}, metrics::{self as metrics, FmtMetrics},
proxy::http::ClientHandle, proxy::http::ClientHandle,
trace, Error, trace, Error, Result,
}; };
use std::{ use std::{
future::Future, future::Future,
@ -40,10 +40,11 @@ pub struct Admin<M> {
tracing: trace::Handle, tracing: trace::Handle,
ready: Readiness, ready: Readiness,
shutdown_tx: mpsc::UnboundedSender<()>, shutdown_tx: mpsc::UnboundedSender<()>,
#[cfg(feature = "pprof")]
pprof: Option<crate::pprof::Pprof>,
} }
pub type ResponseFuture = pub type ResponseFuture = Pin<Box<dyn Future<Output = Result<Response<Body>>> + Send + 'static>>;
Pin<Box<dyn Future<Output = Result<Response<Body>, Error>> + Send + 'static>>;
impl<M> Admin<M> { impl<M> Admin<M> {
pub fn new( pub fn new(
@ -57,9 +58,18 @@ impl<M> Admin<M> {
ready, ready,
shutdown_tx, shutdown_tx,
tracing, tracing,
#[cfg(feature = "pprof")]
pprof: None,
} }
} }
#[cfg(feature = "pprof")]
pub fn with_profiling(mut self, enabled: bool) -> Self {
self.pprof = enabled.then_some(crate::pprof::Pprof);
self
}
fn ready_rsp(&self) -> Response<Body> { fn ready_rsp(&self) -> Response<Body> {
if self.ready.is_ready() { if self.ready.is_ready() {
Response::builder() Response::builder()
@ -254,6 +264,26 @@ where
} }
} }
#[cfg(feature = "pprof")]
"/debug/pprof/profile.pb.gz" if self.pprof.is_some() => {
let pprof = self.pprof.expect("unreachable");
if !Self::client_is_localhost(&req) {
return Box::pin(future::ok(Self::forbidden_not_localhost()));
}
if req.method() != http::Method::GET {
return Box::pin(future::ok(Self::method_not_allowed()));
}
Box::pin(async move {
Ok(pprof
.profile(req)
.await
.unwrap_or_else(Self::internal_error_rsp))
})
}
_ => Box::pin(future::ok(Self::not_found())), _ => Box::pin(future::ok(Self::not_found())),
} }
} }

View File

@ -22,6 +22,8 @@ use tracing::debug;
pub struct Config { pub struct Config {
pub server: ServerConfig, pub server: ServerConfig,
pub metrics_retain_idle: Duration, pub metrics_retain_idle: Duration,
#[cfg(feature = "pprof")]
pub enable_profiling: bool,
} }
pub struct Task { pub struct Task {
@ -96,7 +98,13 @@ impl Config {
let policy = policy.get_policy(OrigDstAddr(listen_addr.into())); let policy = policy.get_policy(OrigDstAddr(listen_addr.into()));
let (ready, latch) = crate::server::Readiness::new(); let (ready, latch) = crate::server::Readiness::new();
#[cfg_attr(not(feature = "pprof"), allow(unused_mut))]
let admin = crate::server::Admin::new(report, ready, shutdown, trace); let admin = crate::server::Admin::new(report, ready, shutdown, trace);
#[cfg(feature = "pprof")]
let admin = admin.with_profiling(self.enable_profiling);
let http = svc::stack(move |_| admin.clone()) let http = svc::stack(move |_| admin.clone())
.push( .push(
metrics metrics

View File

@ -717,6 +717,12 @@ pub fn parse_config<S: Strings>(strings: &S) -> Result<super::Config, EnvError>
keepalive: inbound.proxy.server.keepalive, keepalive: inbound.proxy.server.keepalive,
h2_settings, h2_settings,
}, },
// TODO(ver) Currently we always enable profiling when the pprof feature
// is enabled. In the future, this should be driven by runtime
// configuration.
#[cfg(feature = "pprof")]
enable_profiling: true,
}; };
let dns = dns::Config { let dns = dns::Config {

View File

@ -17,9 +17,17 @@ slab = { version = "0.4", optional = true }
thingbuf = { version = "0.1.2", features = ["std"], optional = true } thingbuf = { version = "0.1.2", features = ["std"], optional = true }
tokio = { version = "1", features = ["time"] } tokio = { version = "1", features = ["time"] }
tracing = "0.1" tracing = "0.1"
tracing-log = "0.1" tracing-log = "0.2"
[dependencies.tracing-subscriber] [dependencies.tracing-subscriber]
version = "0.3.16" version = "0.3.16"
default-features = false default-features = false
features = ["env-filter", "fmt", "smallvec", "tracing-log", "json", "parking_lot", "registry"] features = [
"env-filter",
"fmt",
"smallvec",
"tracing-log",
"json",
"parking_lot",
"registry",
]

View File

@ -14,6 +14,7 @@ meshtls-boring = ["linkerd-meshtls/boring"]
meshtls-boring-fips = ["linkerd-meshtls/boring-fips"] meshtls-boring-fips = ["linkerd-meshtls/boring-fips"]
meshtls-rustls = ["linkerd-meshtls/rustls"] meshtls-rustls = ["linkerd-meshtls/rustls"]
log-streaming = ["linkerd-app/log-streaming"] log-streaming = ["linkerd-app/log-streaming"]
pprof = ["linkerd-app/pprof"]
[dependencies] [dependencies]
futures = { version = "0.3", default-features = false } futures = { version = "0.3", default-features = false }