K8S 모니터링 관측 가능성의 실제 운영을 개선하기 위한 클라우드 네이티브의 심층 분석

  • 클라우드 네이티브 관찰 가능성과 관련하여 아마도 모든 사람들이 OpenTelemetry(OTEL)를 언급할 것입니다. 왜냐하면 커뮤니티는 모든 클러스터 구성 요소 개발을 동일한 방향으로 가리키는 표준에 의존하기 때문입니다. OpenTelemetry는 로그, 메트릭, 추적 및 기타 컨텍스트 정보를 하나의 리소스로 결합할 수 있습니다. 클러스터 관리자 또는 소프트웨어 엔지니어는 이 리소스를 사용하여 정의된 기간 동안 클러스터에서 일어나는 일을 볼 수 있지만 Kubernetes 자체는 이 기술 스택을 어떻게 활용합니까?
  • Kubernetes는 여러 구성 요소로 구성되며 그 중 일부는 독립적이고 다른 구성 요소는 함께 쌓여 있습니다. 컨테이너 런타임의 관점에서 아키텍처를 살펴본 다음 위에서 아래로:
    • kube-apiserver: API 개체의 데이터를 확인하고 구성합니다.
    • kubelet: 각 노드에서 실행되는 에이전트
    • CRI 런타임: CRI-O 또는 containerd와 같은 CRI(Container Runtime Interface) 호환 컨테이너 런타임
    • OCI 런타임: runc 또는 crun과 같은 하위 수준 OCI(Open Container Initiative) 런타임
    • Linux 커널 또는 Microsoft Windows: 기본 운영 체제.
  • 즉, Kubernetes에서 컨테이너를 실행하는 데 문제가 있으면 구성 요소 중 하나를 살펴보기 시작합니다. 오늘날 클러스터 아키텍처의 복잡성이 증가함에 따라 문제의 근본 원인을 찾는 것은 우리가 직면한 가장 시간이 많이 걸리는 작업 중 하나입니다. 문제를 일으킬 수 있는 구성 요소를 알고 있더라도 여전히 다른 구성 요소를 고려해야 합니다. 이것을 어떻게 합니까?
  • 대부분의 사람들은 아마도 로그를 수집하고 필터링하고 구성 요소 경계에서 함께 조립하는 데 집착할 것입니다. 메트릭도 있지만 메트릭 값을 일반 로그와 연결하면 진행 상황을 추적하기가 더 어려워지고 일부 메트릭은 디버깅을 위해 공식화되지도 않았습니다. 목적.
  • traces~그 결과는 추적, metrics~메트릭 및 logs~로그와 같은 신호를 결합하여 클러스터 상태에 대한 통합 보기를 유지하는 것을 목표로 하는 프로젝트인 OpenTelemetry입니다 .
  • Kubernetes에서 OpenTelemetry 추적의 현재 상태는 무엇입니까? API 서버 관점에서 우리는 Kubernetes v1.22부터 추적에 대한 알파 지원을 제공하며 이는 향후 릴리스 중 하나에서 베타로 승격될 것입니다. 안타깝게도 베타 졸업생은 Kubernetes v1.26을 놓쳤으며 디자인 제안은 이에 대한 자세한 정보를 제공하는 API 서버 추적 KEP(Kubernetes Enhancement Proposal)에서 찾을 수 있습니다.
  • kubelet 추적 부분은 Kubernetes v1.25에서 알파 상태로 구현된 다른 KEP에서 추적됩니다. 작성 당시 계획된 베타 졸업은 없지만 v1.27 릴리스 주기에 더 있을 수 있습니다. 두 KEP 외에 다른 노력이 있습니다. 예를 들어 klog는 로그 메시지를 기존 추적에 연결하여 관찰 가능성을 향상시키는 OTEL 지원을 고려하고 있습니다. SIG Instrumentation 및 SIG Node에서는 이제 kubelet과 CRI 컨테이너 런타임 간의 gRPC 호출에 초점을 맞추고 있으므로 kubelet 추적을 함께 연결하는 방법에 대한 논의가 있을 것입니다.
  • CRI-O는 v1.23.0부터 OpenTelemetry 추적을 지원해 왔으며 지속적으로 개선하기 위해 노력하고 있습니다. 예를 들어 추적에 로그를 추가하거나 범위를 애플리케이션의 논리적 부분으로 확장하여 추적 사용자가 동일한 정보를 얻을 수 있도록 하지만 범위 지정이 향상되었습니다. 다른 OTEL 신호를 필터링하는 기능. CRI-O 메인테이너는 또한 conmon-rs라고 하는 conmon을 대체하는 컨테이너 모니터링을 위해 노력하고 있으며 순전히 Rust로 작성되었습니다. Rust에서 구현하는 이점 중 하나는 OpenTelemetry 지원과 같은 기능을 추가할 수 있다는 것입니다. 이러한 기능에 대한 라이브러리가 이미 존재하기 때문에 CRI-O와의 긴밀한 통합이 가능하고 소비자가 컨테이너에서 가장 낮은 수준의 추적 데이터를 볼 수 있습니다.
  • containerd는 플러그인을 사용하여 얻을 수 있는 v1.6.0부터 추적 지원을 추가했습니다. runc 또는 crun과 같은 낮은 수준의 OCI 런타임은 OTEL을 전혀 지원하지 않으며 이에 대한 계획이 없는 것 같습니다. 따라서 추적을 수집하고 데이터 싱크로 내보내는 데 따른 성능 오버헤드를 고려해야 합니다. 개인적으로 여전히 OCI 런타임에서 확장된 원격 측정 수집을 평가할 가치가 있다고 생각했는데 Rust OCI 런타임에서 미래에 비슷한 것을 고려하고 있습니까?
  • 아래 표시된 데모의 경우 여기서는 runc, conmon-rs, CRI-O 및 kubelet의 단일 로컬 노드 스택을 고수합니다. kubelet에서 추적을 활성화하려면 KubeletConfiguration에서 다음을 구성해야 합니다.
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
featureGates:
  KubeletTracing: true
tracing:
  samplingRatePerMillion: 1000000
  • Equal to samplingRatePerMillion million은 내부적으로 모든 것을 샘플링하는 것으로 변환되며 유사한 구성이 CRI-O에 적용되어야 합니다. 백만분의 샘플링 속도 1000000.
  • 100만과 같은 samplingRatePerMillion은 내부적으로 모든 것을 샘플링하는 것으로 변환되며 유사한 구성을 CRI-O에 적용해야 합니다. crio 바이너리는 --enable-tracing 및 --tracing-sampling-rate-per-million 인수로 시작할 수 있습니다. 1000000 파일을 사용하거나 다음과 같은 드롭인 구성을 사용합니다.
cat /etc/crio/crio.conf.d/99-tracing.conf
[crio.tracing]
enable_tracing = true
tracing_sampling_rate_per_million = 1000000
  • conmon-rs를 사용하도록 CRI-O를 구성하려면 최소한 최신 CRI-O v1.25.x 및 conmon-rs v0.4.0이 필요하며 다음과 같이 플러그인을 구성하여 CRI-O가 conmon-rs를 사용하도록 합니다.
cat /etc/crio/crio.conf.d/99-runtimes.conf
[crio.runtime]
default_runtime = "runc"

[crio.runtime.runtimes.runc]
runtime_type = "pod"
monitor_path = "/path/to/conmonrs" # or will be looked up in $PATH
  • 기본 구성은 OpenTelemetry 수집기 gRPC 엔드포인트인 localhost:4317을 가리키며 이 엔드포인트도 실행 중이어야 합니다. 문서에 설명된 대로 OTLP를 실행하는 방법은 여러 가지가 있지만 kubectl 프록시를 통해 Kubernetes에서 실행 중인 기존 인스턴스로 찌르는 것도 가능합니다. 모든 것이 설정되면 수집기는 들어오는 추적을 기록해야 합니다.
ScopeSpans #0
ScopeSpans SchemaURL:
InstrumentationScope go.opentelemetry.io/otel/sdk/tracer
Span #0
    Trace ID       : 71896e69f7d337730dfedb6356e74f01
    Parent ID      : a2a7714534c017e6
    ID             : 1d27dbaf38b9da8b
    Name           : github.com/cri-o/cri-o/server.(*Server).filterSandboxList
    Kind           : SPAN_KIND_INTERNAL
    Start time     : 2023-07-07 09:50:20.060325562 +0000 UTC
    End time       : 2023-07-07 09:50:20.060326291 +0000 UTC
    Status code    : STATUS_CODE_UNSET
    Status message :
Span #1
    Trace ID       : 71896e69f7d337730dfedb6356e74f01
    Parent ID      : a837a005d4389579
    ID             : a2a7714534c017e6
    Name           : github.com/cri-o/cri-o/server.(*Server).ListPodSandbox
    Kind           : SPAN_KIND_INTERNAL
    Start time     : 2023-07-07 09:50:20.060321973 +0000 UTC
    End time       : 2023-07-07 09:50:20.060330602 +0000 UTC
    Status code    : STATUS_CODE_UNSET
    Status message :
Span #2
    Trace ID       : fae6742709d51a9b6606b6cb9f381b96
    Parent ID      : 3755d12b32610516
    ID             : 0492afd26519b4b0
    Name           : github.com/cri-o/cri-o/server.(*Server).filterContainerList
    Kind           : SPAN_KIND_INTERNAL
    Start time     : 2023-07-07 09:50:20.0607746 +0000 UTC
    End time       : 2023-07-07 09:50:20.060795505 +0000 UTC
    Status code    : STATUS_CODE_UNSET
    Status message :
Events:
SpanEvent #0
     -> Name: log
     -> Timestamp: 2023-07-07 09:50:20.060778668 +0000 UTC
     -> DroppedAttributesCount: 0
     -> Attributes::
          -> id: Str(adf791e5-2eb8-4425-b092-f217923fef93)
          -> log.message: Str(No filters were applied, returning full container list)
          -> log.severity: Str(DEBUG)
          -> name: Str(/runtime.v1.RuntimeService/ListContainers)
  • 스팬에는 추적 ID가 있고 일반적으로 추가로 연결되어 있으며 로그와 같은 이벤트도 출력의 일부임을 알 수 있습니다. 위의 경우 kubelet의 팟 수명 주기 이벤트 생성기(PLEG)는 주기적으로 ListPodSandbox를 트리거하여 CRI-O의 RPC를 호출합니다. 이러한 추적은 예를 들어 Jaeger에 의해 표시될 수 있습니다. 추적 스택을 로컬로 실행할 때 Jaeger 인스턴스 주소는 기본적으로 http://localhost:16686에 노출되어야 합니다.
  • 이러한 ListPodSandbox 요청은 Jaeger UI에서 직접 볼 수 있습니다.

Jaeger UI의 ListPodSandbox RPC

  • 효과가 그다지 좋지 않으므로 워크로드는 kubectl을 통해 직접 실행됩니다.
kubectl run -it --rm --restart=Never --image=alpine alpine -- echo hi
hi
pod "alpine" deleted
  • 이제 Jaeger를 보면 conmonrs, crio 및 kubelet을 사용하여 RunPodSandbox 및 CreateContainer CRI RPC의 흔적을 볼 수 있습니다.

Jaeger UI에서 컨테이너 추적 만들기

  • kubelet과 CRI-O 스팬은 조사를 더 쉽게 하기 위해 상호 연결되어 있으며, 이제 스팬을 자세히 살펴보면 CRI-O의 로그에 해당 기능이 올바르게 포함되어 있음을 알 수 있습니다. 예를 들어 컨테이너 사용자는 다음과 같은 추적에서 추출할 수 있습니다.

Jaeger UI의 CRI-O 추적

  • 낮은 수준의 common-rs 범위도 이 추적의 일부입니다. 예를 들어 conmon-rs는 컨테이너와 최종 사용자 간의 IO를 처리하는 내부 read_loop를 유지합니다. 읽고 쓴 바이트의 로그는 스팬의 일부입니다. wait_for_exit_code 스팬에도 동일하게 적용됩니다. 코드 0:

Jaeger UI의 common-rs 추적

  • 이 모든 정보를 Jaeger의 필터링 기능과 함께 넣으면 전체 스택이 컨테이너 문제 디버깅을 위한 훌륭한 솔루션이 됩니다. "전체 스택"을 언급하면 ​​모놀리식 접근 방식의 가장 큰 단점도 드러납니다. 로그를 구문 분석하는 것보다 클러스터에서 효율성이 떨어집니다. 설정에서 사용자는 데이터를 유지하기 위해 Elasticsearch와 같은 싱크를 유지해야 하고 Jaeger UI를 노출하고 성능 문제를 염두에 둘 수 있지만 어쨌든 여전히 Kubernetes의 관찰 가능성 측면을 개선하는 가장 좋은 방법입니다.

추천

출처blog.csdn.net/Forever_wj/article/details/131845491