클라우드/DevOps

[90DaysOfDevOps] Day 77~78 - Service Mesh

dayeonsheep 2024. 4. 16. 13:13

Day 77

<Service Mesh 개념>

 

1. 서비스 메시가 나온 배경... 


최신 분산 환경에서 애플리케이션은 컨테이너 내부에서 실행되는 작은 코드 덩어리로 나뉩니다. 

이러한 컨테이너는 서로 통신할 수 있어야 하며, 일반적으로 가능하지만

Kubernetes 환경에서는 더 높은 수준의 제어, 가시성 및 보안이 필요합니다. 

 

이러한 각 컨테이너 또는 서비스는 다른 서비스와 상호 작용하지만, 암호화되고 승인된 방식으로 상호 작용해야 합니다. 

서비스 간 통신을 조정하는 데에는 다른 과제(challenges)도 있습니다. 

 

응답을 제공하기 위해 특정 서비스를 사용할 수 없으면 어떻게 되나요? 

이 문제를 어떻게 해결하고 다시는 이런 일이 발생하지 않도록 수정하시겠습니까? 

적절한 시간 내에 응답하도록 애플리케이션을 어떻게 조정할 수 있습니까?
=> 이러한 문제는 네트워크에서 애플리케이션이나 마이크로서비스를 실행하고 관리할 때 발생하는 문제의 일부(작은 하위 집합)입니다. 

 

네트워크의 예측 불가능성은, 우리가 네트워크의 존재에 너무 많이 의존해서는 안 된다는 것을 의미합니다. 

또한 변화하는 네트워크 조건에 적응하기 위해 코드를 계속 변경할 수 없습니다. 그렇다면 어떻게 해야 할까요?

해서 나온 게 서비스 메시

= 세분화된 트래픽 제어, AuthN, AuthZ 및 관찰 가능성(Observability)을 위한 계층을 제공하여 서비스 간 통신을 처리하는 애플리케이션 네트워크 계층

 


2. 서비스 메시가 해결하려는 과제는?

  • 마이크로서비스가 확장되는 동안 적응해야 하는 복잡하고 불안정하고 변화하는 네트워크
  • RBAC, AuthZ 및 AuthN이 중요한 환경과 같은 제로 트러스트를 거의 보장
  • 암호화 및 트래픽 필터링 기술을 사용하여 데이터 손실 방지 접근 방식 보장
  • 애플리케이션 상태와 애플리케이션이 요청을 처리하는 방식의 특성을 확인하고 시각화
  • 서비스의 가용성과 안정성을 보장


3. 서비스 메시의 주요 기능

  • 서비스의 로드 밸런싱
  • 여러 환경에서 서비스 검색
  • HTTP 및 gRPC 요청의 세분화된 트래픽 제어 및 라우팅
  • 요청 자동 재시도
  • 탄력성을 위한 결함 주입(Fault injection for resiliency)
  • 로깅, 모니터링 및 측정항목(metrics)
  • peer 인증 및 권한 부여
  • mTLS를 사용한 서비스 간 암호화

 

+ peer authentication & mTLS

더보기

서비스 메시(service mesh)는 마이크로서비스 아키텍처에서 통신과 보안, 관리를 위해 설계된 소프트웨어 인프라스트럭처입니다.  'Peer authentication and authorization'과 'Service-to-service encryption with mTLS'는 서비스 메시에서 중요한 보안 기능들입니다.

1. **Peer Authentication and Authorization**
   - **Peer Authentication (피어 인증)**: 이는 서비스 간에 요청을 보낼 때 각 서비스의 신원을 확인하는 과정입니다. 각 서비스가 누구인지 확실히 인증하는 것이죠. 예를 들어, 서비스 A가 서비스 B에 데이터를 요청할 때, 서비스 B는 서비스 A의 신원을 인증받아 그 요청이 유효한 서비스로부터 왔는지를 검증합니다.
   - **Authorization (권한 부여)**: 인증 후, 해당 서비스가 요청한 작업을 수행할 권한이 있는지를 결정하는 과정입니다. 예를 들어, 서비스 A가 특정 데이터를 읽을 권한이 있는지 확인하는 것입니다.

2. **Service-to-service Encryption with mTLS**
   - **mTLS (Mutual TLS, 상호 TLS)**: TLS (Transport Layer Security)의 확장된 형태로, 두 서비스가 서로의 신원을 상호 인증하는 방식입니다. 일반적인 TLS가 클라이언트와 서버 간의 단방향 인증인 반면, mTLS는 양방향입니다. 이를 통해 서비스 간의 데이터 전송이 암호화되어, 중간에 데이터가 도청되거나 변조되는 것을 방지합니다.
   - 이 기능은 데이터가 네트워크를 통해 전송될 때 높은 보안 수준을 유지하도록 합니다.

서비스 메시는 이러한 보안 기능들을 구현함으로써, 마이크로서비스 간의 안전한 통신을 보장하고, 복잡한 마이크로서비스 환경에서 보안 관리를 간소화할 수 있도록 돕습니다. 

보통 이러한 기능들은 서비스 메시의 사이드카(proxy) 패턴을 통해 각 서비스 인스턴스와 함께 배포되어 자동으로 처리됩니다.

 

 

++ mTLS 

더보기

mTLS (Mutual TLS)는 양방향 TLS를 말합니다. 이는 TLS의 표준 보안 기능을 확장하여, 클라이언트와 서버가 서로의 신원을 동시에 인증하는 방식입니다. 일반적인 TLS가 주로 서버의 신원만을 인증하는 데 반해, mTLS는 클라이언트도 서버처럼 인증을 수행합니다. 이로 인해 양쪽 모두가 신뢰할 수 있는지 확인하는 더욱 강력한 보안 연결이 가능해집니다.

### mTLS의 구조 및 작동 방식:
1. **핸드셰이크(Handshake) 과정**
   - **클라이언트와 서버 인증**: mTLS 세션은 표준 TLS 핸드셰이크로 시작합니다. 서버는 먼저 자신의 공개 키가 포함된 디지털 인증서를 클라이언트에게 제공합니다. 클라이언트는 이 인증서를 검증하고, 서버의 신원을 인증합니다. 그 다음, mTLS에서는 클라이언트도 자신의 인증서를 서버에 제공하여 신원을 인증하게 됩니다.
   
2. **암호화 키 교환**
   - 클라이언트와 서버는 안전한 통신을 위해 공유되는 세션 키를 협상합니다. 이 키는 세션 동안 전송되는 모든 데이터를 암호화하는 데 사용됩니다.

3. **데이터 전송 및 암호화**
   - 핸드셰이크가 성공적으로 완료되면, 클라이언트와 서버는 상호 합의된 암호화 방식을 사용하여 데이터를 안전하게 주고받을 수 있습니다.

### mTLS의 사용:
mTLS는 특히 서비스 간의 통신이나, 기업 내부 네트워크 같이 높은 보안이 요구되는 환경에서 중요합니다. 예를 들어, 클라우드 서비스 간의 데이터 전송, API 호출에서 인증과 암호화를 강화하는 데 사용됩니다.

### 장점:
- **양방향 인증**: 서버와 클라이언트 모두를 인증함으로써 보안을 강화합니다.
- **데이터 보호**: 데이터가 암호화되므로 중간자 공격에 대한 보호가 가능합니다.
- **신뢰성 있는 통신**: 인증된 서비스나 디바이스 간에만 통신이 가능하므로, 신뢰성 있는 네트워크 환경을 조성할 수 있습니다.

mTLS는 구성과 관리가 복잡할 수 있지만, 보안 수준을 크게 향상시키므로 많은 조직에서 중요하게 사용하고 있습니다.

 

 

4. 구성 요소

 

  • 구성을 배포할 control plane
  • 사이드카와 게이트웨이 모두에(both) 구현된 data plane
  • 상주하는(resides on) Kubernetes 클러스터

 

서비스 메시의 작동 방식을 설명하기 위해 

operator는 트래픽 라우팅 또는 보안 정책을 적용하고,

서비스 메시 control plane은 모든 구성이나 정책을 게이트웨이 또는 사이드카 프록시에 push합니다. 

게이트웨이와 사이드카는 모든 트래픽 규칙을 시행합니다. 

위 다이어그램에서 ingress 게이트웨이는 외부 인바운드 요청을 가장 먼저 수신합니다. 

요청 경로의 첫 번째 서비스인 서비스 A로 이를 전달합니다.

서비스 A에는 이 요청을 처리하고 모든 원격 측정 데이터를 control plane으로 다시 보내는 사이드카가 있습니다. 

 

(요청 -> ingress g.w. -> service A에 요청 전달 -> 이 요청을 service A의 sidecar가 control plane으로 전송)


5. 쿠버네티스와의 관계
Kubernetes는 다중 클러스터 및 클러스터 간 통신, ID 관리와 같은 작업을 처리하는 방법에 대해 몇 가지 과제를 안고 있습니다. 

Service mesh는 다음과 같은 책임을 맡고 있음:

  • 인증서 순환 및 관리
  • 서비스 간 암호화
  • Ingress와 서비스 간 라우팅을 통한 세분화된 트래픽 라우팅
  • 애플리케이션 상태에 대한 가시성 및 지표

 

6. 다른 서비스메시 서비스

Istio, AWS AppMesh, Consul, Linkerd, Cilium, etc.

 

 

Day 78

<install 해보자~>

 

나와있는 install 단계들 명령어는 잘 시행이 되는데, 얘네가 무슨 뜻인지 알고 따라해야 될 것 같아서 

다 한 다음 다시 되돌아보깃

 

1) Istio 설치

#클러스터가 작동 중인지 확인하고 오류가 없는지 확인하기
#노드와 해당 IP, OS 정보, 모든 namespace에서 실행 중인 pod를 각각 출력

kubectl get nodes -o wide
kubectl get pods -A

 

 

istio download

observability까지 한 뒤에 구성 요소를 받아서 다른 것들도 포함되어 있다 ㅎ;;

 

2) 사이드카 주입(Injection) 및 Bookinfo 배포

 

+ injection한다는 게 무슨 뜻?

더보기

"사이드카 프록시를 주입한다(injection)"는 컨테이너화된 애플리케이션의 파드에 추가적인 컨테이너를 자동으로 삽입하는 과정을 의미합니다.

이 추가 컨테이너는 특히 Istio와 같은 서비스 메시에서는 네트워크 트래픽을 관리하고 보안, 관찰성, 그리고 기타 중앙 집중화된 정책을 적용하는 역할을 수행하는 사이드카 프록시로 구성됩니다. 

이 사이드카 프록시는 애플리케이션 컨테이너와 동일한 네트워크와 스토리지 리소스를 공유하며 파드 내에서 함께 동작합니다.

사이드카 주입의 기술적 과정:

1. **사이드카 인젝터**:
   Istio는 자동 사이드카 인젝션을 담당하는 컴포넌트인 사이드카 인젝터를 사용합니다. 이 인젝터는 파드 생성 요청이 API 서버로 전송될 때 중간에서 이를 가로채고, 사이드카 컨테이너의 정의를 포함하도록 파드의 구성을 수정합니다.

2. **Admission Controller**:
   Kubernetes에는 Admission Controller라는 메커니즘이 있습니다. 이는 API 서버에 도달한 요청을 실제로 처리하기 전에 수정하거나 거부할 수 있게 해주는 플러그인의 집합입니다. Istio의 사이드카 인젝터는 Mutating Admission Webhook의 일종으로 작동하여, 파드 생성 요청에 자동으로 사이드카 컨테이너를 추가합니다.

3. **주입 과정**:
   사이드카 인젝터는 파드의 원래 정의에 Istio 프록시(예: Envoy)와 관련 설정을 포함한 컨테이너 및 필요한 환경 변수를 추가합니다. 이 과정은 사용자가 파드를 생성할 때 수동으로 각 파드에 사이드카를 추가하는 수고를 덜어주며, 일관된 방식으로 사이드카를 적용할 수 있게 해줍니다.

4. **파드 시작**:
   수정된 파드 정의는 이제 사이드카 컨테이너를 포함하고 있으며, 이 파드가 스케줄링되고 실행될 때, 사이드카 프록시도 함께 시작됩니다. 사이드카는 네트워크 트래픽을 자동으로 가로채고 관리하며, 모든 트래픽은 사이드카 프록시를 통해 들어오고 나가게 됩니다.

#istio-injection=enabled 레이블을 사용하여 기본 네임스페이스에 레이블을 지정
#Istiod에게 네임스페이스에 배포된 새로운 마이크로서비스에 사이드카를 푸시하도록 지시함

kubectl label namespace default istio-injection=enabled

 

이 명령어는 Kubernetes 환경에서 특정 네임스페이스(여기서는 'default' 네임스페이스)에 라벨을 추가하는 작업을 수행합니다. 

이 명령어의 목적은 'default' 네임스페이스 내에 새로 생성되는 모든 파드(Pod)에 자동으로 Istio의 사이드카 프록시를 주입하도록 설정하는 것입니다.

명령어 분석:
- `kubectl`: Kubernetes 클러스터를 관리하기 위한 커맨드 라인 인터페이스 도구입니다.
- `label`: Kubernetes 리소스에 라벨을 추가하거나 수정하는 데 사용됩니다.
- `namespace`: 이 경우에는 네임스페이스 리소스를 지정하고 있습니다. 네임스페이스는 Kubernetes에서 리소스를 그룹화하고 격리하는 데 사용되는 방법입니다.
- `default`: 'default'는 기본적으로 생성되어 있는 네임스페이스 이름입니다. Kubernetes에서 리소스가 특정 네임스페이스를 명시하지 않고 생성될 때 이 네임스페이스에 할당됩니다.
- `istio-injection=enabled`: 여기서 `istio-injection`은 라벨의 키이며, `enabled`는 그 값입니다. 이 설정은 Istio 측에서 이 네임스페이스에 포함된 파드에 자동으로 Istio 사이드카 프록시를 주입할 것인지 여부를 결정합니다. `enabled`로 설정하면 Istio는 이 네임스페이스에 새로 생성되는 모든 파드에 사이드카 프록시를 자동으로 삽입합니다.

사용 목적:
📍Istio 사이드카 프록시의 자동 주입은 서비스 메시 내의 모든 트래픽을 관리하고, 서비스 간의 보안 통신, 로드 밸런싱, 서비스 간 추적 및 모니터링 등 다양한 네트워크 기능을 투명하게 제공합니다. 

이렇게 함으로써 개발자는 애플리케이션 로직에 더 집중할 수 있고, 네트워크 및 보안 관련 사항은 Istio가 처리하도록 할 수 있습니다.

 

 

🤔 enabled말고 다른 옵션은 뭐가 있을까?

 

- istio-injection라벨을 사용하여 Kubernetes 네임스페이스에 설정할 수 있는 옵션은 주로 두 가지입니다: 

`enabled` 와 `disabled`.

1. enabled: 이 옵션을 설정하면 Istio의 사이드카 인젝터(Sidecar Injector)가 해당 네임스페이스에 속한 새로운 파드(Pod)에 자동으로 Istio의 사이드카 프록시를 주입합니다. 이 사이드카는 각 파드의 네트워크 트래픽을 가로채어 Istio 서비스 메시의 다양한 기능을 제공할 수 있게 해줍니다.

2. disabled: `disabled`로 설정되면 해당 네임스페이스에서 파드를 생성할 때 자동으로 사이드카 프록시가 주입되지 않습니다. 이는 해당 네임스페이스에 파드가 Istio의 관리 없이 독립적으로 실행되길 원할 때 사용할 수 있습니다.

이 외에 Istio에서 제공하는 세밀한 제어를 위해 파드 단위로도 사이드카 주입을 관리할 수 있습니다. 파드의 메타데이터에 주석(annotation)을 추가하여 개별 파드에 대한 사이드카 주입 여부를 설정할 수 있습니다. 

예를 들어, 특정 파드에 대해 사이드카 주입을 비활성화하고 싶다면 다음과 같은 주석을 파드 정의에 추가할 수 있습니다:

 

metadata:
  annotations:
    sidecar.istio.io/inject: "false"


이렇게 하면, 네임스페이스 레벨에서 `istio-injection=enabled`가 설정되어 있더라도 특정 파드에는 사이드카가 주입되지 않습니다.
Istio의 이러한 설정들은 네트워크 보안과 성능 최적화를 위해 매우 유용하며, 서비스 간의 통신을 효율적으로 관리하고 모니터링할 수 있게 해줍니다.

 

>> 설정하면 labels가 이렇게 바뀐다

 

3) Bookinfo 앱 배포

 

#pwd ~/istio-1.21.1에서 적용하기

kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml

여기서 바뀐 점!!!

pod에 2/2개의 컨테이너가 준비되어 있음 => 사이드카가 이제 존재한다! 

(사이드카는 pod에 2개의 컨테이너를 띄우는 거니까)

 

혹시 위에서 enabled해줘서 적용된건지, yaml파일에 sidecar 설정해주는 부분이 있어서 생긴건지 궁금해서 봣더니

yaml파일에는 설정하는 부분이 없음

고로 

만약 yaml 파일에 sidecar.istio.io/inject: "true"와 같은 주석이 포함되어 있다면, 해당 파드에는 사이드카가 주입됩니다, 

하지만 이는 주로 개별 파드 수준에서 세밀한 제어를 필요로 할 때 사용됨

대부분의 경우, 네임스페이스 레벨의 사이드카 인젝션 설정이 자동 사이드카 주입을 결정하는 주된 요소가 됩니다. 

따라서, istio-injection=enabled 설정이 이미 적용된 네임스페이스에 Bookinfo 애플리케이션을 배포하면,

사이드카 인젝터가 자동으로 모든 파드에 Istio 사이드카 프록시를 주입합니다. 

이로 인해 각 파드에는 원래의 애플리케이션 컨테이너 외에 추가적인 Istio 사이드카 컨테이너가 생성되는 것

 

 

4) 테스트

 

팟 중에 하나를 연결해서 응답을 받을 수 있는지 확인, sleep pod을 배포해보자

 

kubectl exec sleep-75bbc86479-xw5lw -c sleep -- curl -sS productpage:9080

#kubectl exec: 특정 파드 내부의 컨테이너에서 명령어를 실행하는 데 사용되는 명령어
#sleep-75bbc86479-xw5lw: 실행할 파드의 이름
#-c sleep: sleep 파드 내의 sleep 컨테이너에서 명령을 실행하라는 의미
#curl -sS productpage:9080: sleep 파드 내부에서 productpage 서비스의 9080 포트로 HTTP 요청을 보내는 명령어
#-sS 옵션은 curl 실행 결과를 표시하지 않고, 오류 메시지만 표시하도록 설정

 

 

5) 앱을 외부로 exposing 해보자

 

Istio 수신 게이트웨이 구성과 가상 서비스 구성을 배포해 보겠습니다. Ingress 게이트웨이 구성은 Istio-ingress-gateway에 대한 추상화이며 단순히 요청을 수신하는 호스트와 포트를 알려줍니다. 가상 서비스 구성은 요청을 라우팅하는 방법(또는 요청을 라우팅할 대상)을 게이트웨이에 알려줍니다. 원래 폴더에서 벗어나지 않은 경우 다음 명령을 실행합니다.

 

 

 

음 근데 80이 아니라 8080으로 당연하게 해줬어야 하는걸까? 내가 무지한 걸까? 내가 멍청한 걸까??

kubectl get svc -n istio-system 명령어의 결과를 확인해보면 
istio-ingressgateway 서비스가 LoadBalancer 타입으로 설정되어 있으며, 
EXTERNAL-IP는 127.0.0.1로 표시되어 있습니다.

이는 Istio Ingress Gateway가 로컬 머신에서만 접근 가능하도록 설정되어 있다는 것을 의미합니다.
이로 인해 외부에서 127.0.0.1의 80 포트에 직접 접근할 수 없습니다.

으흠... 그렇다고 한다.

 

아무튼 안돼서

 

Port Forwarding을 사용하여 접근:
로컬 머신에서 Istio Ingress Gateway의 80 포트로 포트 포워딩을 설정하면 된다길래

 

(근데 그게 뭔디)

더보기

포트 포워딩(port forwarding)은 네트워크 트래픽을 한 포트에서 다른 포트로 전달하는 방법을 말합니다. 

Kubernetes 환경에서 `kubectl port-forward` 명령어를 사용하면,

로컬 머신과 클러스터 내의 파드 또는 서비스 간에 네트워크 트래픽을 안전하게 전달할 수 있습니다.

`kubectl port-forward`의 작동 원리:

1. **로컬 포트 설정**: 
   - `kubectl port-forward` 명령어를 사용하여 로컬 머신의 특정 포트를 클러스터 내의 포트로 포워딩합니다.
   - 예: `kubectl port-forward svc/istio-ingressgateway -n istio-system 8080:80` 
     - 이 경우, 로컬 머신의 `8080` 포트가 클러스터 내의 `istio-ingressgateway` 서비스의 `80` 포트로 포워딩됩니다.

2. **트래픽 전달**:
   - 이제 로컬 머신의 `8080` 포트로 요청이 들어오면, `kubectl port-forward` 명령어에 의해 설정된 포트 포워딩 규칙에 따라 해당 요청이 클러스터 내의 `istio-ingressgateway` 서비스의 `80` 포트로 전달됩니다.

3. **결과 확인**:
   - `curl` 같은 명령어를 사용하여 로컬 머신의 포트(`8080`)로 요청을 보내면, 클러스터 내의 서비스(`istio-ingressgateway`)에서 해당 포트(`80`)로 전달됩니다.
   - 이렇게 하면 외부에서도 Istio Ingress Gateway를 로컬 머신을 통해 접근할 수 있게 됩니다.

예시:
# 8080 포트로 로컬 포트를 열고, 이를 80 포트로 전달
kubectl port-forward svc/istio-ingressgateway -n istio-system 8080:80

이렇게 설정하면, 로컬 머신에서 `curl 127.0.0.1:8080` 명령어를 사용하여 Istio Ingress Gateway에 접근할 수 있습니다.

 

kubectl port-forward svc/istio-ingressgateway -n istio-system 8080:80

이렇게 수정하고

 

재접속

성공 우하하

 

근데 외부에서 접속하려면 

>> EXTERNAL-IP 설정 변경 해주면 된다고 함
만약 외부에서 접근하려면 istio-ingressgateway의 EXTERNAL-IP를 변경해야 합니다. 

클라우드 환경에서는 로드 밸런서나 외부 IP를 할당할 수 있습니다.

 

 


 

k8s 클러스터 옵션이 여러가지가 있었는데 모르는 게 있어서 ↓

 

1. KinD (Kubernetes in Docker)

KinD는 로컬 개발 환경에서 Kubernetes 클러스터를 구축하고 실행하기 위한 도구입니다.

KinD는 Docker 컨테이너 내에서 동작하는 Kubernetes 클러스터를 쉽게 생성할 수 있게 해줍니다. 로컬 머신에서 빠르게 테스트와 개발을 진행할 수 있다.

 

2. Civo K8s

Civo K8s는 개발자와 기업들이 클릭 몇 번으로 빠르게 Kubernetes 클러스터를 생성하고 관리할 수 있는 클라우드 서비스입니다.

Civo는 Kubernetes를 위한 관리되는 서비스를 제공하며, 사용자 친화적인 인터페이스를 통해 쉽게 클러스터를 생성하고 관리할 수 있습니다.

 

3. MetalLB

MetalLB는 Kubernetes 클러스터 내에서 로드 밸런서(LoadBalancer) 기능을 제공하기 위한 메타스 로드밸런서입니다.

일반적으로 로컬 또는 개인 데이터 센터 환경에서 Kubernetes 클러스터를 운영할 때, 클라우드 제공자의 로드 밸런서 서비스가 없을 경우 MetalLB를 사용하여 내부 또는 외부 네트워크에서 서비스에 접근할 수 있게 해줍니다.

 

4. Cloud Load-balancer

Cloud Load-balancer는 클라우드 서비스 제공자가 제공하는 로드 밸런서 서비스입니다.

AWS의 ELB (Elastic Load Balancer), GCP의 Load Balancer, Azure의 Load Balancer 등이 이에 해당됩니다.

이 서비스들은 클라우드 환경에서 애플리케이션 트래픽을 분산시키기 위해 사용됩니다.

 

5. Inlets

Inlets는 네트워크 터널링 솔루션으로, 로컬 머신 또는 개인 서버와 원격 클러스터 사이에 안전한 네트워크 연결을 생성하는 데 사용됩니다. Inlets를 사용하면 로컬 머신에서 생성한 서비스를 외부에서 접근할 수 있게 하거나, 로컬 머신과 클러스터 사이의 네트워크 트래픽을 안전하게 전달할 수 있습니다.

 


https://blog.container-solutions.com/wtf-is-a-service-mesh