From d110960d567f203c7928522a4f45b4c5306ae4af Mon Sep 17 00:00:00 2001 From: Yash Tibrewal Date: Wed, 5 Jun 2024 10:58:37 -0700 Subject: [PATCH] [CSM O11y] Add example without Stateful Session Affinity (#36806) Fork the existing CSM example and just keep the observability parts. Closes #36806 PiperOrigin-RevId: 640580476 --- examples/cpp/csm/observability/BUILD | 50 ++++++++++++ .../cpp/csm/observability/Dockerfile.client | 39 +++++++++ .../cpp/csm/observability/Dockerfile.server | 39 +++++++++ examples/cpp/csm/observability/README.md | 35 ++++++++ .../csm/observability/csm_greeter_client.cc | 79 +++++++++++++++++++ .../csm/observability/csm_greeter_server.cc | 67 ++++++++++++++++ examples/cpp/otel/BUILD | 2 +- 7 files changed, 310 insertions(+), 1 deletion(-) create mode 100644 examples/cpp/csm/observability/BUILD create mode 100644 examples/cpp/csm/observability/Dockerfile.client create mode 100644 examples/cpp/csm/observability/Dockerfile.server create mode 100644 examples/cpp/csm/observability/README.md create mode 100644 examples/cpp/csm/observability/csm_greeter_client.cc create mode 100644 examples/cpp/csm/observability/csm_greeter_server.cc diff --git a/examples/cpp/csm/observability/BUILD b/examples/cpp/csm/observability/BUILD new file mode 100644 index 00000000000..d6d8bb0eb33 --- /dev/null +++ b/examples/cpp/csm/observability/BUILD @@ -0,0 +1,50 @@ +# Copyright 2023 the gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +licenses(["notice"]) + +cc_binary( + name = "csm_greeter_client", + srcs = ["csm_greeter_client.cc"], + defines = ["BAZEL_BUILD"], + deps = [ + "//:grpc++", + "//:grpcpp_csm_observability", + "//examples/cpp/otel:util", + "//examples/protos:helloworld_cc_grpc", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/flags:parse", + "@io_opentelemetry_cpp//exporters/prometheus:prometheus_exporter", + "@io_opentelemetry_cpp//sdk/src/metrics", + ], +) + +cc_binary( + name = "csm_greeter_server", + srcs = ["csm_greeter_server.cc"], + defines = ["BAZEL_BUILD"], + deps = [ + "//:grpc++", + "//:grpc++_reflection", + "//:grpcpp_admin", + "//:grpcpp_csm_observability", + "//examples/cpp/otel:util", + "//examples/protos:helloworld_cc_grpc", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/flags:parse", + "@com_google_absl//absl/log", + "@io_opentelemetry_cpp//exporters/prometheus:prometheus_exporter", + "@io_opentelemetry_cpp//sdk/src/metrics", + ], +) diff --git a/examples/cpp/csm/observability/Dockerfile.client b/examples/cpp/csm/observability/Dockerfile.client new file mode 100644 index 00000000000..b3590593e33 --- /dev/null +++ b/examples/cpp/csm/observability/Dockerfile.client @@ -0,0 +1,39 @@ +# Copyright 2023 The gRPC Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM python:3.9-slim-bookworm + +RUN apt-get update -y && apt-get upgrade -y && apt-get install -y build-essential clang curl + +WORKDIR /workdir + +RUN ln -s /usr/bin/python3 /usr/bin/python +RUN mkdir /artifacts + +COPY . . +RUN tools/bazel build //examples/cpp/csm/observability:csm_greeter_client +RUN cp -rL /workdir/bazel-bin/examples/cpp/csm/observability/csm_greeter_client /artifacts/ + +FROM python:3.9-slim-bookworm + +RUN apt-get update \ + && apt-get -y upgrade \ + && apt-get -y autoremove \ + && apt-get install -y curl + +COPY --from=0 /artifacts ./ + +ENV GRPC_EXPERIMENTAL_XDS_ENABLE_OVERRIDE_HOST=true + +ENTRYPOINT ["/csm_greeter_client"] diff --git a/examples/cpp/csm/observability/Dockerfile.server b/examples/cpp/csm/observability/Dockerfile.server new file mode 100644 index 00000000000..c532b03b91c --- /dev/null +++ b/examples/cpp/csm/observability/Dockerfile.server @@ -0,0 +1,39 @@ +# Copyright 2023 The gRPC Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM python:3.9-slim-bookworm + +RUN apt-get update -y && apt-get upgrade -y && apt-get install -y build-essential clang curl + +WORKDIR /workdir + +RUN ln -s /usr/bin/python3 /usr/bin/python +RUN mkdir /artifacts + +COPY . . +RUN OVERRIDE_BAZEL_VERSION=5.4.0 tools/bazel build //examples/cpp/csm/observability:csm_greeter_server +RUN cp -rL /workdir/bazel-bin/examples/cpp/csm/observability/csm_greeter_server /artifacts/ + +FROM python:3.9-slim-bookworm + +RUN apt-get update \ + && apt-get -y upgrade \ + && apt-get -y autoremove \ + && apt-get install -y curl + +COPY --from=0 /artifacts ./ + +ENV GRPC_EXPERIMENTAL_XDS_ENABLE_OVERRIDE_HOST=true + +ENTRYPOINT ["/csm_greeter_server"] diff --git a/examples/cpp/csm/observability/README.md b/examples/cpp/csm/observability/README.md new file mode 100644 index 00000000000..264be09b3d8 --- /dev/null +++ b/examples/cpp/csm/observability/README.md @@ -0,0 +1,35 @@ +# gRPC C++ CSM Hello World Example + +This CSM example builds on the [Hello World Example](https://github.com/grpc/grpc/tree/master/examples/cpp/helloworld) and changes the gRPC client and server to accept configuration from an xDS control plane and test CSM observability. + +## Configuration + +The client takes the following command-line arguments - +* target - By default, the client tries to connect to the xDS "xds:///helloworld:50051" and gRPC would use xDS to resolve this target and connect to the server backend. This can be overridden to change the target. +* prometheus_endpoint - Endpoint used for prometheus. Default value is localhost:9464 + + +The server takes the following command-line arguments - +* port - Port on which the Hello World service is run. Defaults to 50051. +* prometheus_endpoint - Endpoint used for prometheus. Default value is localhost:9464 + +## Building + +From the gRPC workspace folder: + +Client: +``` +docker build -f examples/cpp/csm/observability/Dockerfile.client +``` +Server: +``` +docker build -f examples/cpp/csm/observability/Dockerfile.server +``` + +To push to a registry, add a tag to the image either by adding a `-t` flag to `docker build` command above or run: + +``` +docker image tag ${sha from build command above} ${tag} +``` + +And then push the tagged image using `docker push` \ No newline at end of file diff --git a/examples/cpp/csm/observability/csm_greeter_client.cc b/examples/cpp/csm/observability/csm_greeter_client.cc new file mode 100644 index 00000000000..7040bc13f90 --- /dev/null +++ b/examples/cpp/csm/observability/csm_greeter_client.cc @@ -0,0 +1,79 @@ +/* + * + * Copyright 2023 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include + +#include +#include +#include +#include +#include + +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "absl/types/optional.h" +#include "examples/cpp/otel/util.h" +#include "opentelemetry/exporters/prometheus/exporter_factory.h" +#include "opentelemetry/exporters/prometheus/exporter_options.h" +#include "opentelemetry/sdk/metrics/meter_provider.h" + +#include +#include +#include + +ABSL_FLAG(std::string, target, "xds:///helloworld:50051", "Target string"); +ABSL_FLAG(std::string, prometheus_endpoint, "localhost:9464", + "Prometheus exporter endpoint"); + +namespace { + +absl::StatusOr InitializeObservability() { + opentelemetry::exporter::metrics::PrometheusExporterOptions opts; + // default was "localhost:9464" which causes connection issue across GKE pods + opts.url = "0.0.0.0:9464"; + auto prometheus_exporter = + opentelemetry::exporter::metrics::PrometheusExporterFactory::Create(opts); + auto meter_provider = + std::make_shared(); + // The default histogram boundaries are not granular enough for RPCs. Override + // the "grpc.client.attempt.duration" view as recommended by + // https://github.com/grpc/proposal/blob/master/A66-otel-stats.md. + AddLatencyView(meter_provider.get(), "grpc.client.attempt.duration", "s"); + meter_provider->AddMetricReader(std::move(prometheus_exporter)); + return grpc::CsmObservabilityBuilder() + .SetMeterProvider(std::move(meter_provider)) + .BuildAndRegister(); +} + +} // namespace + +int main(int argc, char** argv) { + absl::ParseCommandLine(argc, argv); + // Setup CSM observability + auto observability = InitializeObservability(); + if (!observability.ok()) { + std::cerr << "CsmObservability::Init() failed: " + << observability.status().ToString() << std::endl; + return static_cast(observability.status().code()); + } + + // Continuously send RPCs every second. + RunClient(absl::GetFlag(FLAGS_target)); + + return 0; +} diff --git a/examples/cpp/csm/observability/csm_greeter_server.cc b/examples/cpp/csm/observability/csm_greeter_server.cc new file mode 100644 index 00000000000..12cdef49ca4 --- /dev/null +++ b/examples/cpp/csm/observability/csm_greeter_server.cc @@ -0,0 +1,67 @@ +/* + * + * Copyright 2023 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include + +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "absl/log/log.h" +#include "absl/strings/str_cat.h" +#include "examples/cpp/otel/util.h" +#include "opentelemetry/exporters/prometheus/exporter_factory.h" +#include "opentelemetry/exporters/prometheus/exporter_options.h" +#include "opentelemetry/sdk/metrics/meter_provider.h" + +#include +#include +#include +#include +#include +#include + +ABSL_FLAG(int32_t, port, 50051, "Server port for service."); +ABSL_FLAG(std::string, prometheus_endpoint, "localhost:9464", + "Prometheus exporter endpoint"); + +int main(int argc, char** argv) { + absl::ParseCommandLine(argc, argv); + opentelemetry::exporter::metrics::PrometheusExporterOptions opts; + // default was "localhost:9464" which causes connection issue across GKE pods + opts.url = "0.0.0.0:9464"; + auto prometheus_exporter = + opentelemetry::exporter::metrics::PrometheusExporterFactory::Create(opts); + auto meter_provider = + std::make_shared(); + // The default histogram boundaries are not granular enough for RPCs. Override + // the "grpc.server.call.duration" view as recommended by + // https://github.com/grpc/proposal/blob/master/A66-otel-stats.md. + AddLatencyView(meter_provider.get(), "grpc.server.call.duration", "s"); + meter_provider->AddMetricReader(std::move(prometheus_exporter)); + auto observability = grpc::CsmObservabilityBuilder() + .SetMeterProvider(std::move(meter_provider)) + .BuildAndRegister(); + if (!observability.ok()) { + std::cerr << "CsmObservability::Init() failed: " + << observability.status().ToString() << std::endl; + return static_cast(observability.status().code()); + } + RunServer(absl::GetFlag(FLAGS_port)); + return 0; +} diff --git a/examples/cpp/otel/BUILD b/examples/cpp/otel/BUILD index ff1ec187a19..c763c5fc3d0 100644 --- a/examples/cpp/otel/BUILD +++ b/examples/cpp/otel/BUILD @@ -15,7 +15,7 @@ licenses(["notice"]) package( - default_visibility = ["//examples/cpp/otel:__subpackages__"], + default_visibility = ["//examples/cpp:__subpackages__"], ) cc_library(