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: just fetch
- 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
}
}

View File

@ -2,6 +2,15 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "addr2line"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
dependencies = [
"gimli",
]
[[package]]
name = "adler"
version = "1.0.2"
@ -29,9 +38,9 @@ dependencies = [
[[package]]
name = "aho-corasick"
version = "0.7.20"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
dependencies = [
"memchr",
]
@ -81,7 +90,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.12",
"syn 2.0.39",
]
[[package]]
@ -135,6 +144,21 @@ dependencies = [
"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]]
name = "base64"
version = "0.13.1"
@ -164,7 +188,7 @@ dependencies = [
"regex",
"rustc-hash",
"shlex",
"syn 2.0.12",
"syn 2.0.39",
]
[[package]]
@ -179,6 +203,15 @@ version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "boring"
version = "3.0.4"
@ -266,6 +299,24 @@ dependencies = [
"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]]
name = "crc32fast"
version = "1.3.2"
@ -275,12 +326,31 @@ dependencies = [
"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]]
name = "data-encoding"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb"
[[package]]
name = "debugid"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d"
dependencies = [
"uuid",
]
[[package]]
name = "deflate"
version = "1.0.0"
@ -311,6 +381,16 @@ dependencies = [
"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]]
name = "drain"
version = "0.1.1"
@ -369,6 +449,18 @@ dependencies = [
"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]]
name = "fixedbitset"
version = "0.4.2"
@ -382,7 +474,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
dependencies = [
"crc32fast",
"miniz_oxide",
"miniz_oxide 0.6.2",
]
[[package]]
@ -499,7 +591,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.12",
"syn 2.0.39",
]
[[package]]
@ -532,6 +624,16 @@ dependencies = [
"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]]
name = "getrandom"
version = "0.2.8"
@ -543,6 +645,12 @@ dependencies = [
"wasi",
]
[[package]]
name = "gimli"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
[[package]]
name = "glob"
version = "0.3.1"
@ -846,9 +954,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
version = "0.2.140"
version = "0.2.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]]
name = "libfuzzer-sys"
@ -913,12 +1021,14 @@ dependencies = [
name = "linkerd-app-admin"
version = "0.1.0"
dependencies = [
"deflate",
"futures",
"http",
"hyper",
"linkerd-app-core",
"linkerd-app-inbound",
"linkerd-tracing",
"pprof",
"serde",
"serde_json",
"thiserror",
@ -1493,7 +1603,7 @@ dependencies = [
"linkerd-tls",
"linkerd2-proxy-api",
"pin-project",
"prost",
"prost 0.11.8",
"tonic",
"tower",
"tracing",
@ -1535,7 +1645,7 @@ dependencies = [
"linkerd2-proxy-api",
"maplit",
"once_cell",
"prost-types",
"prost-types 0.11.8",
"quickcheck",
"thiserror",
"tonic",
@ -1642,7 +1752,7 @@ dependencies = [
"linkerd-http-route",
"linkerd2-proxy-api",
"maplit",
"prost-types",
"prost-types 0.11.8",
"quickcheck",
"thiserror",
]
@ -1665,7 +1775,7 @@ dependencies = [
"linkerd2-proxy-api",
"parking_lot",
"pin-project",
"prost-types",
"prost-types 0.11.8",
"quickcheck",
"rand",
"thiserror",
@ -1764,7 +1874,7 @@ dependencies = [
"linkerd-tonic-watch",
"linkerd2-proxy-api",
"once_cell",
"prost-types",
"prost-types 0.11.8",
"quickcheck",
"regex",
"thiserror",
@ -1916,8 +2026,8 @@ dependencies = [
"linkerd-error",
"linkerd-io",
"linkerd-stack",
"prost",
"prost-build",
"prost 0.11.8",
"prost-build 0.11.8",
"tokio",
"tokio-test",
"tracing",
@ -1961,8 +2071,8 @@ dependencies = [
"h2",
"http",
"ipnet",
"prost",
"prost-types",
"prost 0.11.8",
"prost-types 0.11.8",
"quickcheck",
"thiserror",
"tonic",
@ -2026,7 +2136,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
dependencies = [
"regex-automata",
"regex-automata 0.1.10",
]
[[package]]
@ -2047,6 +2157,15 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "memmap2"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a5a03cefb0d953ec0be133036f14e109412fa594edc2f77227249db66cc3ed"
dependencies = [
"libc",
]
[[package]]
name = "mime"
version = "0.3.16"
@ -2068,6 +2187,15 @@ dependencies = [
"adler",
]
[[package]]
name = "miniz_oxide"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
dependencies = [
"adler",
]
[[package]]
name = "mio"
version = "0.8.6"
@ -2086,6 +2214,17 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "nom"
version = "7.1.0"
@ -2126,6 +2265,15 @@ dependencies = [
"libc",
]
[[package]]
name = "object"
version = "0.32.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
version = "1.17.1"
@ -2137,8 +2285,8 @@ name = "opencensus-proto"
version = "0.1.0"
dependencies = [
"bytes",
"prost",
"prost-types",
"prost 0.11.8",
"prost-types 0.11.8",
"tonic",
"tonic-build",
]
@ -2242,6 +2390,30 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "ppv-lite86"
version = "0.2.17"
@ -2258,6 +2430,16 @@ dependencies = [
"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]]
name = "proc-macro2"
version = "1.0.69"
@ -2287,7 +2469,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e48e50df39172a3e7eb17e14642445da64996989bc212b583015435d39a58537"
dependencies = [
"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]]
@ -2303,15 +2495,37 @@ dependencies = [
"log",
"multimap",
"petgraph",
"prettyplease",
"prost",
"prost-types",
"prettyplease 0.1.25",
"prost 0.11.8",
"prost-types 0.11.8",
"regex",
"syn 1.0.109",
"tempfile",
"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]]
name = "prost-derive"
version = "0.11.8"
@ -2325,13 +2539,35 @@ dependencies = [
"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]]
name = "prost-types"
version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "379119666929a1afd7a043aa6cf96fa67a6dce9af60c88095a4686dbce4c9c88"
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]]
@ -2351,9 +2587,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.26"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
@ -2426,13 +2662,14 @@ dependencies = [
[[package]]
name = "regex"
version = "1.7.3"
version = "1.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d"
checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
"regex-automata 0.3.7",
"regex-syntax 0.7.5",
]
[[package]]
@ -2441,7 +2678,18 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
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]]
@ -2450,6 +2698,12 @@ version = "0.6.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]]
name = "regex-syntax"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
[[package]]
name = "resolv-conf"
version = "0.7.0"
@ -2475,6 +2729,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "rustc-demangle"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustc-hash"
version = "1.1.0"
@ -2591,6 +2851,17 @@ dependencies = [
"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]]
name = "sharded-slab"
version = "0.1.4"
@ -2646,6 +2917,35 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "syn"
version = "1.0.109"
@ -2659,9 +2959,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.12"
version = "2.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79d9531f94112cfc3e4c8f5f02cb2b58f72c97b7efd85f70203cc6d8efda5927"
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
dependencies = [
"proc-macro2",
"quote",
@ -2881,8 +3181,8 @@ dependencies = [
"hyper-timeout",
"percent-encoding",
"pin-project",
"prost",
"prost-derive",
"prost 0.11.8",
"prost-derive 0.11.8",
"tokio",
"tokio-stream",
"tokio-util",
@ -2899,9 +3199,9 @@ version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bf5e9b9c0f7e0a7c027dcfaba7b2c60816c7049171f679d99ee2ff65d0de8c4"
dependencies = [
"prettyplease",
"prettyplease 0.1.25",
"proc-macro2",
"prost-build",
"prost-build 0.11.8",
"quote",
"syn 1.0.109",
]
@ -3005,12 +3305,12 @@ dependencies = [
[[package]]
name = "tracing-log"
version = "0.1.3"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
dependencies = [
"lazy_static",
"log",
"once_cell",
"tracing-core",
]
@ -3026,9 +3326,9 @@ dependencies = [
[[package]]
name = "tracing-subscriber"
version = "0.3.16"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
dependencies = [
"matchers",
"nu-ansi-term",
@ -3097,6 +3397,12 @@ version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicode-bidi"
version = "0.3.11"
@ -3135,6 +3441,12 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "uuid"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc"
[[package]]
name = "valuable"
version = "0.1.0"
@ -3448,5 +3760,5 @@ checksum = "9731702e2f0617ad526794ae28fbc6f6ca8849b5ba729666c2a5bc4b6ddee2cd"
dependencies = [
"proc-macro2",
"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
# identity-initializing and linkerd-await wrappers.
# Currently pinned to a build off of edge-23.11.1 + dev:v42
ARG LINKERD2_IMAGE=ghcr.io/olix0r/l2-proxy:git-04283611
ARG LINKERD2_IMAGE=ghcr.io/linkerd/proxy:edge-23.11.2
# Build the proxy.
FROM --platform=$BUILDPLATFORM $RUST_IMAGE as build
FROM $LINKERD2_IMAGE as linkerd2
FROM --platform=$BUILDPLATFORM $RUST_IMAGE as fetch
ARG PROXY_FEATURES=""
RUN apt-get update && \
@ -28,24 +28,27 @@ WORKDIR /src
COPY . .
RUN --mount=type=cache,id=cargo,target=/usr/local/cargo/registry \
just fetch
# Build the proxy.
FROM fetch as build
ENV CARGO_INCREMENTAL=0
ENV RUSTFLAGS="-D warnings -A deprecated"
ARG TARGETARCH="amd64"
ARG PROFILE="release"
ARG LINKERD2_PROXY_VERSION=""
ARG LINKERD2_PROXY_VENDOR=""
SHELL ["/bin/bash", "-c"]
RUN --mount=type=cache,id=cargo,target=/usr/local/cargo/registry \
/usr/bin/time -v just arch="$TARGETARCH" features="$PROXY_FEATURES" profile="$PROFILE" build && \
bin=$(just --evaluate profile="$PROFILE" _target_bin) ; \
du -sh "$bin" "$bin".dbg && \
mkdir -p /out && mv "$bin" /out/linkerd2-proxy
if [[ "$PROXY_FEATURES" =~ .*pprof.* ]] ; then cmd=build-debug ; else cmd=build ; fi ; \
/usr/bin/time -v just arch="$TARGETARCH" features="$PROXY_FEATURES" profile="$PROFILE" "$cmd" && \
( mkdir -p /out ; \
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 to
# debug on.
# Install the proxy binary into a base image that we can at least get a shell
# for debugging.
FROM docker.io/library/debian:bookworm-slim as runtime
WORKDIR /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"]

View File

@ -76,6 +76,15 @@ skip = [
# `linkerd-trace-context`, `rustls-pemfile` and `tonic` depend on `base64`
# v0.13.1 while `rcgen` depends on v0.21.5
{ 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 = [
# 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 }}
# 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
@{{ _cargo }} build --frozen --package=linkerd2-proxy {{ _features }}

View File

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

View File

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

View File

@ -1,6 +1,8 @@
#![deny(rust_2018_idioms, clippy::disallowed_methods, clippy::disallowed_types)]
#![forbid(unsafe_code)]
#[cfg(feature = "pprof")]
mod pprof;
mod server;
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::{
metrics::{self as metrics, FmtMetrics},
proxy::http::ClientHandle,
trace, Error,
trace, Error, Result,
};
use std::{
future::Future,
@ -40,10 +40,11 @@ pub struct Admin<M> {
tracing: trace::Handle,
ready: Readiness,
shutdown_tx: mpsc::UnboundedSender<()>,
#[cfg(feature = "pprof")]
pprof: Option<crate::pprof::Pprof>,
}
pub type ResponseFuture =
Pin<Box<dyn Future<Output = Result<Response<Body>, Error>> + Send + 'static>>;
pub type ResponseFuture = Pin<Box<dyn Future<Output = Result<Response<Body>>> + Send + 'static>>;
impl<M> Admin<M> {
pub fn new(
@ -57,9 +58,18 @@ impl<M> Admin<M> {
ready,
shutdown_tx,
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> {
if self.ready.is_ready() {
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())),
}
}

View File

@ -22,6 +22,8 @@ use tracing::debug;
pub struct Config {
pub server: ServerConfig,
pub metrics_retain_idle: Duration,
#[cfg(feature = "pprof")]
pub enable_profiling: bool,
}
pub struct Task {
@ -96,7 +98,13 @@ impl Config {
let policy = policy.get_policy(OrigDstAddr(listen_addr.into()));
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);
#[cfg(feature = "pprof")]
let admin = admin.with_profiling(self.enable_profiling);
let http = svc::stack(move |_| admin.clone())
.push(
metrics

View File

@ -717,6 +717,12 @@ pub fn parse_config<S: Strings>(strings: &S) -> Result<super::Config, EnvError>
keepalive: inbound.proxy.server.keepalive,
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 {

View File

@ -17,9 +17,17 @@ slab = { version = "0.4", optional = true }
thingbuf = { version = "0.1.2", features = ["std"], optional = true }
tokio = { version = "1", features = ["time"] }
tracing = "0.1"
tracing-log = "0.1"
tracing-log = "0.2"
[dependencies.tracing-subscriber]
version = "0.3.16"
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-rustls = ["linkerd-meshtls/rustls"]
log-streaming = ["linkerd-app/log-streaming"]
pprof = ["linkerd-app/pprof"]
[dependencies]
futures = { version = "0.3", default-features = false }