Linkerd를 활용한 서비스 메시 마스터하기

Ivan (이반) Porta
37 min readNov 15, 2024

기업들이 더 빠른 개발, 독립적인 확장성, 관리 용이성, 향상된 장애 허용성, 개선된 모니터링, 비용 효율성 등 마이크로서비스 아키텍처의 이점을 누리기 위해 이를 점점 더 채택하고 있습니다. 이에 따라 견고한 인프라에 대한 수요도 증가하고 있습니다. 2023년 가트너 보고서에 따르면, 응답자의 74%가 마이크로서비스를 사용하고 있으며, 23%는 이를 도입할 계획입니다.

하지만 이러한 서비스가 확장되면서, 아키텍처는 점점 더 복잡해지고, 온프레미스와 클라우드 등 여러 위치에 걸친 다중 클러스터 환경을 포함하게 됩니다. 이러한 환경에서 네트워크 관리, 모니터링, 보안 유지와 같은 작업은 점점 더 어려워지고 있습니다. 바로 이 지점에서 서비스 메시의 필요성이 대두됩니다. 이번 글에서는 서비스 메시 기술의 기본 개념을 살펴보고, 그중에서도 대표적인 솔루션인 Buoyant사의 Linkerd에 초점을 맞추어 설명하겠습니다.

시장 동향에 관심이 있으시다면, 서비스 메시 분야가 빠르게 성장하고 있다는 점을 주목할 만합니다. 이러한 성장은 마이크로서비스의 채택 증가, 증가하는 사이버 공격, 그리고 EU의 “디지털 10년으로 가는 길”과 같은 규제 지원에 힘입고 있습니다. 또한, AI에 대한 투자 증가로 인해 한국과 같은 국가들은 데이터를 인텔리전스로 전환하기 위해 서비스 메시를 적극 활용하고 있습니다. Next Move Strategy Consulting과 Global Info Research에 따르면, 서비스 메시 시장은 2022년 약 2억 4천만 달러에서 2030년에는 23억 2천만 달러에서 34억 5천만 달러 사이로 성장할 것으로 전망되며, 2023년부터 2030년까지 연평균 성장률(CAGR)은 39.7%에 이를 것으로 보입니다.

서비스 메시란 무엇인가?

서비스 메시(Service Mesh)는 서비스 간 통신을 관리하는 로직을 중앙화하고, 이를 개별 서비스가 아닌 네트워크 계층에서 처리하는 추가적인 인프라 계층입니다. 이를 통해 개발자는 통신 오류, 재시도, 라우팅과 같은 문제를 걱정하지 않고 기능 개발에 집중할 수 있습니다. 서비스 메시가 이러한 작업을 모든 서비스에서 일관되게 처리해 주기 때문입니다.

서비스 메시가 제공하는 주요 이점은 다음과 같습니다:

  • 자동 재시도 및 서킷 브레이킹(Circuit Breaking): 통신 오류를 처리하고, 서킷 브레이킹 패턴을 적용하여 연쇄적인 장애를 방지함으로써 신뢰할 수 있는 통신을 보장합니다.
  • 자동 서비스 디스커버리: 수동 설정 없이 메시 내의 서비스를 자동으로 감지합니다.
  • 향상된 보안: mTLS(상호 TLS)를 사용하여 서비스 간 통신을 암호화합니다.
  • 정교한 트래픽 제어: 애플리케이션 코드를 수정하지 않고도 블루-그린 배포, 카나리 릴리스, A/B 테스트와 같은 배포 전략을 지원하며 동적인 트래픽 라우팅을 가능하게 하며, 애플리케이션 코드를 수정할 필요가 없습니다.
  • 관찰성: 프록시에서 직접 수집된 요청 성공률, 실패, 초당 요청 수와 같은 추가적인 메트릭을 통해 모니터링을 강화합니다.

서비스 메시는 어떻게 작동하는가?

서비스 메시의 아키텍처는 컨트롤 플레인과 데이터 플레인의 두 가지 구성 요소로 이루어져 있습니다.

데이터 플레인

데이터 플레인은 각 애플리케이션 컨테이너 인스턴스와 함께 배포되는 프록시(사이드카 패턴을 따름)로 구성됩니다. 이 프록시는 서비스로의 모든 인바운드 및 아웃바운드 트래픽을 가로채며, 중개자 역할을 하여 회로 차단, 요청 재시도, 로드 밸런싱, mTLS(상호 TLS)를 통한 보안 통신 등의 기능을 구현합니다.

컨트롤 플레인

컨트롤 플레인은 데이터 플레인에 있는 프록시를 관리하고 구성하는 역할을 합니다. 직접적으로 네트워크 패킷을 처리하지는 않지만, 메시 전반에 걸쳐 정책과 구성을 조율합니다. 주요 역할은 다음과 같습니다:

  • 서비스 레지스트리를 유지하고, 서비스의 확장, 추가 또는 제거 시 동적으로 목록을 업데이트합니다.
  • 트래픽 라우팅, 보안 규칙, 속도 제한과 같은 정책을 정의하고 적용합니다.
  • 프록시로부터 수집한 메트릭, 로그, 트레이스를 집계하여 모니터링과 관찰 가능성을 강화합니다.
  • mTLS 보안을 위해 인증서를 관리하고, 서비스 간 안전한 통신을 위한 암호화된 ID를 발급합니다.

Linkerd 컨트롤 플레인은 다음 구성 요소로 구성됩니다:

  • 데스티네이션 포드(linkerd-destination): 이 포드는 다른 서비스로 트래픽을 보낼 때 프록시에게 대상 서비스의 IP와 포트를 제공합니다. 또한 연결의 다른 쪽 끝에서 예상해야 할 TLS ID를 프록시에 알립니다. 마지막으로 인증 및 트래픽 정책에 의해 허용되는 요청 유형을 포함한 정책 정보와 재시도, 경로별 메트릭, 타임아웃 등의 서비스 프로필 정보를 가져옵니다.
  • 아이덴티티 포드(linkerd-identity): 이 포드는 프록시가 초기화 중에 인증서 서명 요청(CSR)을 보낼 때 서명된 인증서를 발급하는 인증 기관 역할을 합니다.
  • 프록시 인젝터 포드(linkerd-proxy-injector): 이 Kubernetes 어드미션 컨트롤러는 포드가 생성될 때 linkerd.io/inject: enabled 주석의 존재를 확인합니다. 존재할 경우, proxy-initlinkerd-proxy 컨테이너를 포드에 주입합니다.

Linkerd의 역사

서비스 메시 시장에서 주요 플레이어로는 Red Hat의 OpenShift Service Mesh, HashiCorp의 Consul, F5의 NGINX Service Mesh, 그리고 Google에서 개발한 후 CNCF으로 이전된 Istio가 있습니다.

이 글에서는 Buoyant사의 제품인 Linkerd에 초점을 맞추고자 합니다. Linkerd는 뛰어난 성능과 최소한의 리소스 사용을 목표로 개발되어, 초기부터 가장 효율적인 서비스 메시 중 하나로 자리 잡았습니다. Linkerd는 2021년 7월 28일에 CNCF 졸업 지위를 획득하며, 안정성과 널리 사용되고 있음을 입증했습니다. 현재 Monzo, Geico, Wells Fargo, Visa와 같은 조직들이 Linkerd를 활용하고 있습니다(HGData 자료 기준).

Linkerd는 2016년에 처음 출시된 오픈소스 서비스 메시로, 확장 가능한 마이크로서비스 라이브러리인 Finagle을 기반으로 설계되었습니다. 초기 프록시는 Scala로 작성되었으며, Java와 Scala의 네트워킹 기능을 활용했습니다. 그러나 JVM(Java Virtual Machine)에 의존하고 복잡한 인터페이스를 가지고 있었으며, Scala, Netty, Finagle의 설계 선택으로 인한 제약 때문에 프로덕션 환경에서의 채택이 다소 어려웠습니다. 이에 따라 Buoyant는 2017년에 Rust로 작성된 새로운 경량 프록시를 개발했습니다. 당시 Rust는 떠오르는 신흥 언어였지만, Buoyant는 Scala, Go, C++ 대신 Rust를 선택했으며, 그 이유는 다음과 같습니다:

  • 예측 가능한 성능: Go의 가비지 컬렉터는 수집 주기 동안 지연 시간 상승을 유발할 수 있습니다. 반면, Rust는 가비지 컬렉션 없이 예측 가능한 성능을 제공합니다.
  • 보안: 버퍼 오버플로와 같은 많은 보안 취약점은 C 및 C++과 같은 언어에서의 안전하지 않은 메모리 관리로 인해 발생합니다. Rust는 컴파일 단계에서 메모리 안전성을 보장하여 이러한 취약점의 위험을 크게 줄입니다.

Linkerd는 어떻게 로드 밸런싱을 수행하는가?

Kubernetes에서 서비스를 생성하면, 서비스 사양에 정의된 셀렉터를 기반으로 관련된 엔드포인트가 자동으로 생성됩니다. 이 셀렉터는 서비스의 일부가 되어야 하는 포드를 식별합니다:

$ kubectl get svc -n vastaya application-vastaya-svc -o yaml
apiVersion: v1
kind: Service
...
spec:
...
selector:
app.kubernetes.io/instance: application
app.kubernetes.io/name: vastaya

해당 엔드포인트는 선택된 포드들의 IP 주소로 채워집니다:

$ kubectl get endpoints -n vastaya application-vastaya-svc -o yaml
apiVersion: v1
kind: Endpoints
...
subsets:
- addresses:
- ip: 10.244.1.157
nodeName: minikube
targetRef:
kind: Pod
name: application-vastaya-dplmt-647b4dbdc-9bnwj
namespace: vastaya
uid: e3219642-4428-4bbc-89ec-a892ca571639

$ kubectl get pods -n vastaya -o yaml
apiVersion: v1
items:
- apiVersion: v1
kind: Pod
...
status:
hostIP: 192.168.49.2
hostIPs:
- ip: 192.168.49.2
phase: Running
podIP: 10.244.1.157
podIPs:
- ip: 10.244.1.157

컨테이너가 서비스를 향해 요청을 보낼 때, Linkerd의 프록시는 이 요청을 가로채 Kubernetes API에서 대상 IP 주소를 조회합니다. 대상 IP가 Kubernetes 서비스에 해당할 경우, EWMA 알고리즘을 사용하여 가장 빠른 엔드포인트를 찾아 요청을 전달합니다. 또한, 서비스에 연관된 서비스 정책(Service Policy)(사용자 정의 CRD)이 서비스에 존재하면 이를 적용하여 카나리 배포 등과 같은 트래픽 관리 기능을 제공합니다.

Linkerd 프록시는 어떻게 패킷을 가로채는가?

패킷이 네트워크 인터페이스에 도착하면, iptables 규칙을 통과하며 여러 체인을 거칩니다. 규칙이 일치하면 해당 작업이 수행됩니다. Linkerd는 NAT(네트워크 주소 변환) 테이블의 PREROUTINGOUTPUT 체인을 사용하여 패킷을 프록시로 리디렉션합니다. 이 규칙들은 linkerd-init 컨테이너에 의해 업데이트됩니다. 이 컨테이너는 초기화 컨테이너(init container)로서 다른 컨테이너가 시작되기 전에 실행되며, 포드의 iptables를 수정하여 새로운 체인을 생성하고 기존 체인을 업데이트합니다. 이러한 변경 사항은 컨테이너의 로그를 확인하여 검사할 수 있습니다.

참고: iptables는 포드의 네임스페이스에 한정되며, 노드의 iptables와는 별개로 작동합니다.

$ kubectl -n vastaya logs application-vastaya-dplmt-647b4dbdc-9bnwj linkerd-init
time="2024-09-18T23:45:26Z" level=info msg="/sbin/iptables-legacy-save -t nat"
time="2024-09-18T23:45:26Z" level=info msg="# Generated by iptables-save v1.8.10 on Wed Sep 18 23:45:26 2024\n*nat\n:PREROUTING ACCEPT [0:0]\n:INPUT ACCEPT [0:0]\n:OUTPUT ACCEPT [0:0]\n:POSTROUTING ACCEPT [0:0]\nCOMMIT\n# Completed on Wed Sep 18 23:45:26 2024\n"
time="2024-09-18T23:45:26Z" level=info msg="/sbin/iptables-legacy -t nat -N PROXY_INIT_REDIRECT"
time="2024-09-18T23:45:26Z" level=info msg="/sbin/iptables-legacy -t nat -A PROXY_INIT_REDIRECT -p tcp --match multiport --dports 4190,4191,4567,4568 -j RETURN -m comment --comment proxy-init/ignore-port-4190,4191,4567,4568"
time="2024-09-18T23:45:26Z" level=info msg="/sbin/iptables-legacy -t nat -A PROXY_INIT_REDIRECT -p tcp -j REDIRECT --to-port 4143 -m comment --comment proxy-init/redirect-all-incoming-to-proxy-port"
time="2024-09-18T23:45:26Z" level=info msg="/sbin/iptables-legacy -t nat -A PREROUTING -j PROXY_INIT_REDIRECT -m comment --comment proxy-init/install-proxy-init-prerouting"
time="2024-09-18T23:45:26Z" level=info msg="/sbin/iptables-legacy -t nat -N PROXY_INIT_OUTPUT"
time="2024-09-18T23:45:26Z" level=info msg="/sbin/iptables-legacy -t nat -A PROXY_INIT_OUTPUT -m owner --uid-owner 2102 -j RETURN -m comment --comment proxy-init/ignore-proxy-user-id"
time="2024-09-18T23:45:26Z" level=info msg="/sbin/iptables-legacy -t nat -A PROXY_INIT_OUTPUT -o lo -j RETURN -m comment --comment proxy-init/ignore-loopback"
time="2024-09-18T23:45:26Z" level=info msg="/sbin/iptables-legacy -t nat -A PROXY_INIT_OUTPUT -p tcp --match multiport --dports 4567,4568 -j RETURN -m comment --comment proxy-init/ignore-port-4567,4568"
time="2024-09-18T23:45:26Z" level=info msg="/sbin/iptables-legacy -t nat -A PROXY_INIT_OUTPUT -p tcp -j REDIRECT --to-port 4140 -m comment --comment proxy-init/redirect-all-outgoing-to-proxy-port"
time="2024-09-18T23:45:26Z" level=info msg="/sbin/iptables-legacy -t nat -A OUTPUT -j PROXY_INIT_OUTPUT -m comment --comment proxy-init/install-proxy-init-output"
time="2024-09-18T23:45:26Z" level=info msg="/sbin/iptables-legacy-save -t nat"
time="2024-09-18T23:45:26Z" level=info msg="# Generated by iptables-save v1.8.10 on Wed Sep 18 23:45:26 2024\n*nat\n:PREROUTING ACCEPT [0:0]\n:INPUT ACCEPT [0:0]\n:OUTPUT ACCEPT [0:0]\n:POSTROUTING ACCEPT [0:0]\n:PROXY_INIT_OUTPUT - [0:0]\n:PROXY_INIT_REDIRECT - [0:0]\n-A PREROUTING -m comment --comment \"proxy-init/install-proxy-init-prerouting\" -j PROXY_INIT_REDIRECT\n-A OUTPUT -m comment --comment \"proxy-init/install-proxy-init-output\" -j PROXY_INIT_OUTPUT\n-A PROXY_INIT_OUTPUT -m owner --uid-owner 2102 -m comment --comment \"proxy-init/ignore-proxy-user-id\" -j RETURN\n-A PROXY_INIT_OUTPUT -o lo -m comment --comment \"proxy-init/ignore-loopback\" -j RETURN\n-A PROXY_INIT_OUTPUT -p tcp -m multiport --dports 4567,4568 -m comment --comment \"proxy-init/ignore-port-4567,4568\" -j RETURN\n-A PROXY_INIT_OUTPUT -p tcp -m comment --comment \"proxy-init/redirect-all-outgoing-to-proxy-port\" -j REDIRECT --to-ports 4140\n-A PROXY_INIT_REDIRECT -p tcp -m multiport --dports 4190,4191,4567,4568 -m comment --comment \"proxy-init/ignore-port-4190,4191,4567,4568\" -j RETURN\n-A PROXY_INIT_REDIRECT -p tcp -m comment --comment \"proxy-init/redirect-all-incoming-to-proxy-port\" -j REDIRECT --to-ports 4143\nCOMMIT\n# Completed on Wed Sep 18 23:45:26 2024\n"

iptables 규칙을 직접 확인하려면, iptables-legacysudo로 실행해야 할 수도 있습니다. 하지만 컨테이너 내에서는 네트워킹 제한으로 인해 이 작업이 어려울 수 있습니다. 대신, 노드에서 nsenter 명령어를 사용하여 포드의 네트워크 네임스페이스에 접근할 수 있습니다. 방법은 다음과 같습니다:

  • 노드에 SSH로 접속합니다(이 경우 Minikube 사용):
$ minikube ssh
  • 컨테이너 ID를 찾습니다:
$ docker ps | grep application-vastaya-dplmt-647b4dbdc-9bnwj
3f1f370f44e4 de30a4cc9fd9 "/docker-entrypoint.…" 39 minutes ago Up 39 minutes k8s_application-vastaya-cntr_application-vastaya-dplmt-647b4dbdc-9bnwj_vastaya_e3219642-4428-4bbc-89ec-a892ca571639_3
85b5f32df37e 4585864a6b91 "/usr/lib/linkerd/li…" 39 minutes ago Up 39 minutes k8s_linkerd-proxy_application-vastaya-dplmt-647b4dbdc-9bnwj_vastaya_e3219642-4428-4bbc-89ec-a892ca571639_3
e81bac0a9f9c registry.k8s.io/pause:3.9 "/pause" 39 minutes ago Up 39 minutes k8s_POD_application-vastaya-dplmt-647b4dbdc-9bnwj_vastaya_e3219642-4428-4bbc-89ec-a892ca571639_3
  • 컨테이너의 프로세스 ID를 가져옵니다:
$ docker@minikube:~$ docker inspect --format '{{.State.Pid}}' 3f1f370f44e4  
6859
  • nsenter를 사용하여 포드의 네트워크 네임스페이스에 접근합니다:
$ sudo nsenter -t 6859 -n
  • 마지막으로 iptables 규칙을 확인할 수 있습니다:
$ root@minikube:/home/docker# iptables-legacy -t nat -L
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
PROXY_INIT_REDIRECT all -- anywhere anywhere /* proxy-init/install-proxy-init-prerouting */

Chain INPUT (policy ACCEPT)
target prot opt source destination

Chain OUTPUT (policy ACCEPT)
target prot opt source destination
PROXY_INIT_OUTPUT all -- anywhere anywhere /* proxy-init/install-proxy-init-output */

Chain POSTROUTING (policy ACCEPT)
target prot opt source destination

Chain PROXY_INIT_OUTPUT (1 references)
target prot opt source destination
RETURN all -- anywhere anywhere owner UID match 2102 /* proxy-init/ignore-proxy-user-id */
RETURN all -- anywhere anywhere /* proxy-init/ignore-loopback */
RETURN tcp -- anywhere anywhere multiport dports 4567,4568 /* proxy-init/ignore-port-4567,4568 */
REDIRECT tcp -- anywhere anywhere /* proxy-init/redirect-all-outgoing-to-proxy-port */ redir ports 4140

Chain PROXY_INIT_REDIRECT (1 references)
target prot opt source destination
RETURN tcp -- anywhere anywhere multiport dports sieve,4191,4567,4568 /* proxy-init/ignore-port-4190,4191,4567,4568 */
REDIRECT tcp -- anywhere

위 작업을 통해 확인된 PROXY_INIT_REDIRECT 체인은 모든 인바운드 트래픽을 Linkerd 프록시 컨테이너가 실행 중인 포트 4143으로 리디렉션합니다.

$ kubectl get pods application-vastaya-dplmt-647b4dbdc-9bnwj -n vastaya -o yaml
apiVersion: v1
kind: Pod
metadata:
...
name: application-vastaya-dplmt-647b4dbdc-9bnwj
spec:
containers:
image: cr.l5d.io/linkerd/proxy:edge-24.9.2
name: linkerd-proxy
ports:
- containerPort: 4143
name: linkerd-proxy
protocol: TCP
...

프록시는 이 트래픽을 처리하고, SO_ORIGINAL_DST 소켓 옵션을 사용하여 원래의 대상 IP와 포트를 유지하며 OUTPUT 체인으로 전달합니다. 요청이 프록시에 의해 소유되면 패킷은 애플리케이션으로 전달됩니다.

Linkerd 설치하기

Linkerd를 서비스 메시로 설치하는 방법에는 두 가지 주요 방식이 있습니다: Helm 차트를 사용하는 방법과 Linkerd CLI를 사용하는 방법입니다.

CLI 사용하기

CLI를 통해 Linkerd를 설치하는 과정은 간단합니다:

$ curl --proto '=https' --tlsv1.2 -sSfL https://run.linkerd.io/install-edge | sh
$ export PATH=$HOME/.linkerd2/bin:$PATH

CLI가 설치되면, 설치를 위한 환경이 올바르게 설정되었는지 확인할 수 있습니다:

$ linkerd check --pre

다음 단계에서는 Helm Chart 설치 방식과 유사하게, 먼저 CRD를 설치한 뒤 컨트롤 플레인을 설치해야 합니다:

$ linkerd install --crds | kubectl apply -f -
$ linkerd install | kubectl apply -f -

CLI는 단순한 설치 도구 이상의 역할을 하며, 운영에 대한 세부적인 제어와 유용한 확장 기능을 제공합니다:

$ linkerd
linkerd manages the Linkerd service mesh.Usage:
linkerd [command]Available Commands:
authz List authorizations for a resource
check Check the Linkerd installation for potential problems
completion Output shell completion code for the specified shell (bash, zsh or fish)
diagnostics Commands used to diagnose Linkerd components
help Help about any command
identity Display the certificate(s) of one or more selected pod(s)
inject Add the Linkerd proxy to a Kubernetes config
install Output Kubernetes configs to install Linkerd
install-cni Output Kubernetes configs to install Linkerd CNI
jaeger jaeger manages the jaeger extension of Linkerd service mesh
multicluster Manages the multicluster setup for Linkerd
profile Output service profile config for Kubernetes
prune Output extraneous Kubernetes resources in the linkerd control plane
uninject Remove the Linkerd proxy from a Kubernetes config
uninstall Output Kubernetes resources to uninstall Linkerd control plane
upgrade Output Kubernetes configs to upgrade an existing Linkerd control plane
version Print the client and server version information
viz viz manages the linkerd-viz extension of Linkerd service mesh

Helm 사용하기

Linkerd CLI와 다르게, Helm을 통해 Linkerd를 설치하기 위한 전제 조건은 mTLS(상호 TLS)를 위한 인증서를 생성하는 것입니다. 이를 위해 인증서 관리에 step CLI를 사용할 것입니다.

다음 명령어를 실행하여 step CLI를 설치합니다:

$ wget <https://dl.smallstep.com/cli/docs-cli-install/latest/step-cli_amd64.deb>
$ sudo dpkg -i step-cli_amd64.deb

다음으로 필요한 인증서를 생성합니다:

$ step certificate create root.linkerd.cluster.local ca.crt ca.key --profile root-ca --no-password --insecure
$ step certificate create identity.linkerd.cluster.local issuer.crt issuer.key --profile i

인증서를 생성한 후에는 Helm 차트를 사용하여 두 단계로 Linkerd를 설치할 수 있습니다. 이 데모에서는 로컬 Minikube 인스턴스에 설치할 것입니다. Minikube는 Docker를 컨테이너 런타임으로 사용하므로, proxy-init 컨테이너는 루트 권한으로 실행되어야 합니다( — set runAsRoot=true).

먼저, Linkerd Helm 저장소를 추가하고 업데이트합니다:

$ helm repo add linkerd-edge https://helm.linkerd.io/edge
$ helm repo update

그 다음, CRD와 컨트롤 플레인을 설치합니다:

$ helm install linkerd-crds linkerd-edge/linkerd-crds -n linkerd --create-namespace
$ helm install linkerd-control-plane linkerd-edge/linkerd-control-plane -n linkerd --create-namespace --set-file identityTrustAnchorsPEM=certificates/ca.crt --set-file identity.issuer.tls.crtPEM=certificates/issuer.crt --set-file identity.issuer.tls.keyPEM=certificates/issuer.key --set runAsRoot=true

서비스에 메시 적용하기

Linkerd의 CRD와 컨트롤 플레인이 클러스터에서 실행되면, 이제 서비스를 메시화할 수 있습니다. Linkerd의 프록시 인젝터는 Kubernetes의 어드미션 웹훅으로 구현되어 있으며, 네임스페이스, 배포, 또는 포드에 적절한 주석이 있을 경우 자동으로 새로운 포드에 프록시를 추가합니다. 특히, linkerd.io/inject: enabled 주석이 프록시 주입을 활성화하는 트리거로 사용됩니다.

프록시 주입이 활성화되면, 메시화된 각 포드에 다음 두 개의 추가 컨테이너가 포함됩니다:

  • linkerd-init: iptables를 구성하여 모든 인바운드 및 아웃바운드 TCP 트래픽을 프록시를 통해 전달합니다.
  • linkerd-proxy: 트래픽, 보안, 관찰성을 관리하는 프록시 역할을 수행합니다.

참고: 기존 네임스페이스, 배포, 또는 포드에 주석을 추가한 경우, 해당 변경 사항을 적용하려면 포드를 재시작해야 합니다. Kubernetes는 리소스를 생성하거나 업데이트할 때에만 웹훅을 트리거합니다.

배포에 대해 수동으로 프록시 주입을 활성화하려면 다음 명령어를 사용합니다:

$ kubectl annotate deployment -n vastaya application-vastaya-dplmt linkerd.io/inject=enabled
$ kubectl rollout restart -n vastaya deployment/projects-vastaya-dplmt

포드를 설명하여 프록시 주입이 적용되었는지 확인할 수 있습니다:

$ kubectl describe pod -n vastaya application-vastaya-dplmt-647b4dbdc-9bnwj 
Name: application-vastaya-dplmt-647b4dbdc-9bnwj
Namespace: vastaya
...
Annotations: linkerd.io/created-by: linkerd/proxy-injector edge-24.9.2
linkerd.io/inject: enabled
linkerd.io/proxy-version: edge-24.9.2
linkerd.io/trust-root-sha256: f6f154536a867a210de469e735af865c87a3eb61c77442bd9988353b4b632663
viz.linkerd.io/tap-enabled: true
Status: Running
IP: 10.244.1.94
IPs:
IP: 10.244.1.94
Controlled By: ReplicaSet/application-vastaya-dplmt-647b4dbdc
Init Containers:
linkerd-init:
Container ID: docker://06d8fedeac3d5d84b76aa2c4bb790f05e747402795247fe0a6087a49abd52e7a
Image: cr.l5d.io/linkerd/proxy-init:v2.4.1
Image ID: docker-pullable://cr.l5d.io/linkerd/proxy-init@sha256:e4ef473f52c453ea7895e9258738909ded899d20a252744cc0b9459b36f987ca
Port: <none>
Host Port: <none>
SeccompProfile: RuntimeDefault
Args:
--ipv6=false
--incoming-proxy-port
4143
--outgoing-proxy-port
4140
--proxy-uid
2102
--inbound-ports-to-ignore
4190,4191,4567,4568
--outbound-ports-to-ignore
4567,4568
State: Terminated
Reason: Completed
Exit Code: 0
Started: Wed, 18 Sep 2024 13:57:24 +0900
Finished: Wed, 18 Sep 2024 13:57:24 +0900
Ready: True
Restart Count: 1
Environment: <none>
Mounts:
/run from linkerd-proxy-init-xtables-lock (rw)
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-kq29n (ro)
Containers:
linkerd-proxy:
Container ID: docker://d91e9cdd9ef707538efc9467bc38ee35c95ed9d655d2d8f8a1b2a2834f910af4
Image: cr.l5d.io/linkerd/proxy:edge-24.9.2
Image ID: docker-pullable://cr.l5d.io/linkerd/proxy@sha256:43d1086980a64e14d1c3a732b0017efc8a9050bc05352e2dbefa9e954d6d607d
Ports: 4143/TCP, 4191/TCP
Host Ports: 0/TCP, 0/TCP
SeccompProfile: RuntimeDefault
State: Running
Started: Wed, 18 Sep 2024 13:57:25 +0900
Last State: Terminated
Reason: Completed
Exit Code: 0
Started: Fri, 13 Sep 2024 20:02:28 +0900
Finished: Fri, 13 Sep 2024 22:32:19 +0900
Ready: True
Restart Count: 1
Liveness: http-get http://:4191/live delay=10s timeout=1s period=10s #success=1 #failure=3
Readiness: http-get http://:4191/ready delay=2s timeout=1s period=10s #success=1 #failure=3
Environment:
_pod_name: application-vastaya-dplmt-647b4dbdc-9bnwj (v1:metadata.name)
_pod_ns: vastaya (v1:metadata.namespace)
_pod_nodeName: (v1:spec.nodeName)
LINKERD2_PROXY_SHUTDOWN_ENDPOINT_ENABLED: false
LINKERD2_PROXY_LOG: warn,linkerd=info,hickory=error,[{headers}]=off,[{request}]=off
...
application-vastaya-cntr:
Container ID: docker://e078170a412c392412f8f4fe170cdfcd139f212d2bd31dd6afda5801874b9225
Image: application:latest
Image ID: docker://sha256:de30a4cc9fd90fb6e51d51881747fb9b8a088d374e897a379c3ef87c848ace11
Port: 80/TCP
...
Volumes:
linkerd-proxy-init-xtables-lock:
Type: EmptyDir (a temporary directory that shares a pod's lifetime)
Medium:
SizeLimit: <unset>
linkerd-identity-end-entity:
Type: EmptyDir (a temporary directory that shares a pod's lifetime)
Medium: Memory
SizeLimit: <unset>
linkerd-identity-token:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 86400
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SandboxChanged 92s kubelet Pod sandbox changed, it will be killed and re-created.
Normal Pulled 92s kubelet Container image "cr.l5d.io/linkerd/proxy-init:v2.4.1" already present on machine
Normal Created 92s kubelet Created container linkerd-init
Normal Started 92s kubelet Started container linkerd-init
Normal Pulled 92s kubelet Container image "cr.l5d.io/linkerd/proxy:edge-24.9.2" already present on machine
Normal Created 91s kubelet Created container linkerd-proxy
Normal Started 91s kubelet Started container linkerd-proxy
Normal Pulled 44s kubelet Container image "application:latest" already present on machine
Normal Created 44s kubelet Created container application-vastaya-cntr
Normal Started 44s kubelet Started container application-vastaya-cntr

때로는 네임스페이스의 모든 포드를 메시화하고 싶지만 특정 포드는 제외하고 싶을 수 있습니다. 이 경우, 제외하려는 포드에 `linkerd.io/inject: disabled` 주석을 추가하면 됩니다.

대안으로, Linkerd CLI를 사용하여 기존 YAML 구성 파일에 프록시를 직접 주입할 수도 있습니다. 예를 들어:

kubectl get -n vastaya deploy -o yaml | linkerd inject - | kubectl apply -f

메트릭(Metrics)

기본적으로 Kubernetes는 메모리와 CPU와 같은 리소스 사용량과 관련된 메트릭을 수집하지만, 서비스 간에 실제로 이루어지는 요청에 대한 정보는 수집하지 않습니다. Linkerd의 프록시를 사용함으로써 얻을 수 있는 주요 이점 중 하나는 추가로 수집되고 제공되는 메트릭입니다. 여기에는 프록시를 통해 흐르는 트래픽에 대한 자세한 데이터가 포함되며, 다음과 같은 내용이 포함됩니다:

  • 프록시가 수신한 요청의 수.
  • 요청당 지연 시간(밀리초 단위).
  • 서비스 간 통신의 성공 및 실패율.

이러한 메트릭은 서비스의 동작에 대해 더 깊은 인사이트를 제공하며, 모니터링, 문제 해결, 성능 최적화에 있어 매우 중요합니다.

참고 자료

--

--

Ivan (이반) Porta
Ivan (이반) Porta

Written by Ivan (이반) Porta

Senior DevOps Engineer | Terraform Associate | Certified Argo Project Associate

No responses yet