-
[IHOS 1기] 1주차 - Istio소개, 첫걸음Kubernetes 2025. 4. 12. 21:03
- Service Mesh 소개
1.1 속도를 높이며 마주하는 문제들‣ACME 회사 K8S 도입 사례‣
- 문제 발생
- 서비스들의 요청 처리 시간이 매우 불규칙
- 배포를 자동화할 때 자동화된 테스트에서 잡히지 않은 버그가 발생
- 팀 별 다른 보안 정책 사용 : A팀(인증서, 개인 키), B팀(토큰, 서명 검증), C팀(방화벽 뒷단으로 별도 보안 없음)
- 해결 필요점 도출
- 장애가 격리 경계를 넘어 확산하는 것을 방지
- 환경 변화에 대응할 수 있는 애플리케이션/서비스 구축
- 부분적 장애 상태에서도 동작할 수 있는 시스템 구축
- 끊임없이 변화하고 발전하는 전체 시스템의 상태 파악
- 시스템의 런타임 동작을 제어할 수 없는 문제
- 공격 표면이 커짐에 따라 강력한 보안 구현하기
- 시스템 변경의 위험성 낮추기
- 시스템의 구성 요소를 누가(무엇이) /언제 사용할 수 있는지 정책 강제
1.1.1 클라우드 인프라는 신뢰할 수 없다‣- 클라우드에서는 인프라가 일시적이며 간혹 사용할 수 없다는 가정 아래 앱을 구축해야 한다. 이런 일시성은 아키텍처에서 미리 고려해야 한다.
- 예를 들어, 고객 선호도를 관리하는 추천 서비스가 고객 서비스를 호출한다고 해보자.
- 아래 그림에서 추천 서비스는 고객 서비스를 호출해 일부 고객 데이터를 업데이트 하는데, 메시지를 보낼 때 극심한 성능 저하를 경험한다.
- 이런 성능 정하는 어떤 영향을 미치는가?
- 의존하는 다운스트림이 느리면 추천 서비스가 실패해 연쇄 장애를 야기하는 등 혼란을 일으킬 수 있다.
- 이 시나리오는 여러 이유로 일어날 수 있다.

- 고객 서비스가 과부화돼 실행 속도가 느리다.
- 고객 서비스에 버그가 있다.
- 네트워크 방화벽이 트래픽을 느리게 한다.
- 네트워크가 혼잡해 트래픽이 느려지고 있다.
- 네트워크에 하드웨어 오류가 발생해 트래픽을 다시 라우팅하고 있다.
- 고객 서비스의 네트워크 카드 하드웨어에 오류가 발생했다.
- 문제는 이것이 고객 서비스의 장애인지 여부를 추천 서비스가 구분할 수 없다는 것이다.
- 다시 말하지만, 하드웨어 및 소프트웨어 구성 요소가 수백만 개에 달하는 클라우드 환경에서 이런 시나리오는 항상 일어난다.
1.1.2 서비스 상호작용을 복원력 있게 만들기‣- 추천 서비스느 몇 가지를 시도할 수 있다.
- 이를테면 요청을 재시도할 수 있는데, 과부하 시나리오에서는 다운스트림에 문제를 더하기만 하는 꼴일 수 있다.
- 한편 요청을 재시도할 때는 이전 요청이 성공하지 못했다고 확신할 수 없다.
- 이럴 때는 일정 시간 후에 요청을 만료시키고 오류를 던질 수도 있다.
- 또한 다른 가용 영역에 위치할 수 있는 다른 고객 서비스 인스턴스에 재시도할 수 도 있다.
- 만약 고객 서비스가 이런 문제를 장기간 겪을 경우, 추천 서비스는 냉각 기간 동안 고객 서비스 호출을 완전히 멈출 수도 있다.
- 이런 시나리오를 완화하고 예기치 않은 장애에 대해 애플리케이션 복원력을 높이는데 도움이 되는 몇 가지 패턴이 발전해왔다.
- 클라이언트 측 로드 밸런싱 Client-site load balancing
- 클라이언트에게 엔드포인트 목록을 제공하고 어떤 엔드포인트를 호출할지를 클라이언트가 결정하도록 한다.
- 서비스 디스커버리 Service discovery
- 특정 논리적 서비스의 주기적으로 갱신되는 정상 엔드포인트 목록을 찾는 매커니즘이다.
- 서킷 브레이커 Circuit breaking
- 오동작하는 것으로 보이는 서비스에 일정 시간 부하를 차단한다.
- 격벽 Bulkheading
- 서비스 호출 시 클라이언트 리소스 사용량을 명시적 임계값으로 제한한다 (커넥션, 스레드, 세션 등)
- 타임아웃 Timeouts
- 서비스 호출 시 요청, 소켓, 활성 liveness 등에 시간 제한을 적용한다.
- 재시도 Retries
- 실패한 요청을 재시도한다.
- 재시도 예산 Retry budgets
- 재시도에 제한을 적용. 즉, 일정 기간의 재시도 횟수를 제한하는 것 (예. 10초 동안 호출의 50%까지만 재시도 가능)
- 데드라인 Deadlines
- 요청에 응답 유효 기간을 지정한다. 데드라인을 벗어나면 요청 처리를 무시한다.
⇒ 이런 유형의 패턴을 종합하면 애플리케이션 네트워킹으로 생각할 수 있다.
1.1.3 일어나고 있는 일 실시간으로 이해하기‣- 어떤 서비스가 서로 통신하고 있는지, 일반적인 서비스 부하가 어떤 형태인지, 예상하는 오동작 failure 수는 어는 정도인지, 서비스 오동작 시 어떤 일이 일어나는지, 서비스 상태가 어떤지 등 서비스 아키텍처를 아는 것은 대단히 중요하다.
- 새로운 코드나 설정을 배포해서 변화를 준다는 건 주요 메트릭에 부정적 영향을 미칠 수 있는 가능성을 도입하는 것이기도 하다.
- 메트릭, 로그, 트레이스로 시스템을 관찰하는 것은 서비스 아키텍처 운영에서 매우 중요한 부분이다.
1.2 이 과제를 애플리케이션 라이브러리로 해결해보기‣들어가며‣- 클라우드 환경에서 애플리케이션/서비스를 운영하는 방법을 최초로 알아낸 조직은 거대 인터넷 기업들이었고, 이 회사들은 모두가 사용해야 하는 일부 언어에 대한 라이브러리와 프레임워크를 구축하는 데 막대한 시간과 자원을 투자했고, 이는 클라우드 네이티브 아키텍처로 서비스를 운영할 때 생기는 문제를 해결하는 데 도움이 됐다.
- 구글은 stubby 같은 프레임워크를 구축했고,.. 등등 다음과 같은 클라우드 네이티브 문제를 처리한다.
- Hystrix—Circuit breaking and bulkheading
- Ribbon—Client-side load balancing
- Eureka—Service registration and discovery
- Zuul—Dynamic edge proxy
- 이 라이브러리는 자바 런타임을 대상으로 했기 때문에 자바 프로젝트에서만 사용할 수 있었다.
- 이러한 라이브러리를 사용하려면 해당 라이브러리에 대한 애플리케이션 의존성을 만들고, 클래스 경로를 가져온 다음, 애플리케이션 코드에서 사용해야 했다.
- NetflixOSS Hystrix 를 사용하는 다음 예제는 의존성 관리 시스템에 Hystrix 에 대한 의존성을 가져온다.
<dependency> <groupId>com.netflix.hystrix</groupId> <artifactId>hystrix-core</artifactId> <version>x.y.z</version> </dependency>- Hystrix 를 사용하려면 명령어를 기본 Hystrix 클래스인 HystrixCommand 로 래핑 wrapping 해야 한다.
public class CommandHelloWorld extends HystrixCommand<String> { private final String name; public CommandHelloWorld(String name) { super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup")); this.name = name; } @Override protected String run() { // a real example would do work like a network call here return "Hello " + name + "!"; } }- 만약 코드에 복원력을 구축할 책임이 각 애플리케이션에 있다면, 이런 문제에 대한 처리를 분산해 중앙 병목을 제거할 수 있다.
- 신뢰할 수 없는 클라우드 인프라에 대규모로 배포하는 경우, 이는 바람직한 시스템 특성이다.
1.2.1 애플리케이션 별 라이브러리의 단점‣- 새로운 도전 과제 1
- 모든 애플리케이션에서 예상되는 가정과 관련됨.
- 만약 아키텍처에 새 서비스를 도입하려 한다면, 예를 들어 Hystrix를 사용하려면 자바나 JVM 기반 기술을 사용해야만한다.
- 서킷 브레이커와 로드 밸런싱은 보통 함께 동작하므로, 두 복원력 라이브러리를 함께 사용해야 한다.
- 로드 밸런싱에 넷플릭스 Ribbon을 사용하고 싶다면, 서비스 엔드포인트 디스커버에 사용할 일종의 저장소가 필요한데, 이는 Eureka를 사용해야 한다는 의미일 수 있다.
- 이런 식으로 라이브러리를 사용하는 방법은, 시스템의 나머지 부분과 상호작용하는 프로토콜의 명확히 정의되지 않은 상태에서도 암묵적인 제약을 만들어 낸다.
- 새로운 도전 과제 2
- 서비스를 구현하려고 새로운 언어나 프레임워크를 도입하려고 할 때 발생한다.
- 사용자 대면 API를 구현하는 데 NodeJS가 적합하다고 판단했지만, 나머지 아키텍처는 자바와 NetflixOS를 사용하고 있다고 해보자.
- 당신은 복원력 패턴 구현용으로 다른 라이브러리 집합을 찾기로 할 수도 있다.
- 또는 relilient hystrixjs 와 같은 유사 패키지를 찾아볼 수 도 있다.
- 그러고는 도입하려는 언어를 알아보고, 입증하고, 개발 스택에 도입해야 한다.
- 이들 라이브러리 각각은 전제와 구현이 다를 것이다.
- 어떤 경우에는 각 프레임워크/언어 조합에 상응하는 유사 대체품을 찾지 못할 수도 있다.
- 결국 어떤 언어에서는 부분적으로 구현하게 돼 전반적으로 구현이 일괄적이지 않을 수 있는데, 이는 장애 시나리오에서 원인을 추론하기 어렵게 만들어 장애를 숨기거나 확산시키는 원인이 될 수 있다.
- 아래 그림은 서비스가 애플리케이션 네트워킹 관리 목적으로 동일한 라이브러리 집합을 구현하는 모습을 보여준다.

- 새로운 도전 과제 3
- 여러 프로그래밍 언어와 프레임워크에서 라이브러리를 소수로 유지하려면 많은 훈련이 필요하며 제대로 하기가 매우 어렵다.
- 핵심은 모두 구현이 일관되고 올바르다는 점을 보장하는 것이다.
- 하나의 차이만으로도 시스템의 예측 불가능성이 늘어난다.
- 동시에 여러 서비스에 업데이트를 수행하는 것도 벅찬 일이 될 수 있다.
- 클라우드 아키텍처에서는 애플리케이션 네트워킹을 분산하는 것이 낫지만, 그로 인해 늘어나는 시스템의 제약과 운영 부담은 대부분의 조직에서 감당하기 어려울 것이다.
- 설령 도전에 나선다고 해도 올바르게 수행하기는 더욱 어렵다.
- 애플리케이션을 임베디드 라이브러리로 유지 관리하고 운영하는 데 막대한 오버헤드 비용을 치르지 않고도 분산화의 이점을 누릴 수 있는 방법이 있다면 어떨까?
1.3 이런 관심사(애플리케이션 네트워킹)를 인프라에 전가하기‣들어가기‣1.3.1 애플케이션 인식 서비스 프록시‣- 프록시를 사용하는 것은 이런 관심사를 인프라로 옮기는 방법 중 하나다.
- 프록시란 커넥션을 다룰 수 있고 적절한 백엔드로 리다이렉트할 수 있는 중간 인프라 구성 요소다.
- 필요한 것은 애플리케이션을 인식할 수 있고 서비스를 대신해 애플리케이션 네트워킹을 수행할 수 있는 프록시다.

- 그렇게 하려면 서비스 프록시는 커넥션과 패킷을 이해하는 전통적 인프라 프록시와 달리 메시지와 요청 같은 애플리케이션 구조를 이해해야 한다.
- 즉 7계층 프록시가 필요하다.
1.3.2 엔보이 프록시 만나기‣- 엔보이 Envoy 는 오픈소스 애플리케이션 수준 프록시이다.
- 리프트에서 SOA 인프라의 일부로 개발됐으며, 언어나 프레임워크에 명시적 의존성 없이도 재시도, 타임아웃, 서킷 브레이커, 클라이언트 측 로드 밸런싱, 서비스 디스커버리, 보안, 메트릭 수집 등의 네트워크 관심사를 구현할 수 있다.
- 아래 그림에서 보듯이 엔보이는 이 모든 것을 애플리케이션 프로세스 외부에서 구현한다.

- 엔보이의 힘은 이런 애플리케이션 계층의 복원력 측면에서만 국한되지 않는다. 엔보이는 또한 초당 요청 수, 실패 횟수, 서킷 브레이커 이벤트와 같은 여려 애플리케이션 네트워킹 메트릭을 수집한다.
- 엔보이를 사용하면 서비스 간에 어떤 일이 일어나고 있는지 자동으로 알 수 있게 되는데, 바로 여기가 예상치 못한 복잡성을 많이 발견하는 되는 곳이다.
- 엔보이 프록시는 서비스 아키텍처에서 공통적인 서비스 간 신뢰성과 관찰 가능성 문제를 해결 할 수 있는 기반이여, 이 기반을 토대로 이런 문제를 애플리케이션에서 인프라로 이동시킬수 있다.
- 애플리케이션과 함께 서비스 프록시를 배포해 애플리케이션 외부에서 이런 기능들을 얻을 수 있지만, 세부적으로는 애플리케이션마다 다를 수 있다.
- 아래 그림은 이 모델에서 애플리케이션이 시스템의 다른 부분과 통신하는 방법을 보여주는데, 요청을 엔보이로 먼저 보내고 나서 엔보이가 업스트림으로의 통신을 처리한다.

- 또한 서비스 프록시는 분산 트레이싱 스팬 span을 수집해 특정 요청이 수행한 모든 단계를 연결할 수 있으며, 각 단계의 소요 시간을 확인하고 시스템의 잠재적인 병목 현상이나 버그를 찾아 낼 수 있다.
- 모든 애플리케이션이 자신의 프록시를 거쳐 외부 세계와 대화하고 애플리케이션으로 들어오는 모든 트래픽이 프록시를 거치면, 애플리케이션 코드를 한 줄도 바꾸지 않고 애플리케이션에 대한 중요한 기능을 얻을 수 있다.
- 이 프록시+애플리케이션 조합이 서비스 메시로 알려진 통신 버스의 토대가 된다.
- 엔보이 같은 서비스 프록시는 애플리케이션의 모든 인스턴스와 함께 단일 최소 단위 single atomic unit 로 배포할 수 있다.
- 예를 들어 쿠버네티스에서는 서비스 프록시와 애플리케이션 단일 파드로 함께 배포할 수 있다.
- 아래 그림은 메인 애플리케이션 인스턴스를 보완하기 위해 프록시를 배포하는 사이드카 배포 패턴을 그리고 있다.
1.4 서비스 메시란 무엇인가?‣들어가기
- 엔보이 같은 서비스 프록시는 클라우드 환경에서 동작하는 서비스 아키텍처에 중요한 기능을 추가하는 데 도움이 된다.
- 각 애플리케이션은 워크로드 목표를 감안해 프록시 동작 방식에 대해 자신만의 요구 사항이나 설정을 가질 수 있다.
- 애플리케이션과 서비스 수가 늘어남에 따라 많은 프록시를 설정하고 관리하는 것이 어려움 수 있다.
- 또한 각 애플리케이션 인스턴스에 프록시를 배치하면, 원래는 애플리케이션 스스로가 수행했어야 하는 흥미로운 고급 기능을 구축할 기회가 생긴다.
서비스 메시
- 서비스 메시란 애플리케이션 대신 프로세스 외부에서 투명하게 네트워크 트래픽을 처리하는 분산형 애플리케이션 인프라를 말한다.
- 아래 그림은 서비스 프록시가 데이터 플레인을 형성하는 방식을 보여준다. 데이터 플레인은 모든 트래픽을 처리하고 관찰하는 곳이다.

- 데이터 플레인은 메시를 거쳐가는 트래픽을 설정하고 보호하고 제어하는 책임을 맡는다.
- 데이터 플레인의 동작은 컨트롤 플레인이 설정한다.
- 컨트롤 플레인은 메시의 두뇌로, 운영자가 네트워크 동작을 조작할 수 있도록 API를 노출한다.
- 데이터 플레인과 컨트롤 플레인이 모여 모든 클라우드 네트워크 아키텍처에 필요한 다음과 같은 중요 기능을 제공한다.
- 서비스 복원력
- 관찰 가능성 신호
- 트래픽 제어 기능
- 보안
- 정책 강제 Policy enforcement
기능
- 서비스 메시는 재시도, 타임아웃, 서킷 브레이커 같은 기능을 구현해 서비스 통신이 장애에 복원력을 갖추게 만들 책임을 맡는다.
- 또한 서비스 디스커버리, 적응형 및 영역 인식 zone-aware 로드 밸런싱, 헬스 체크 같은 기능을 처리함으로써 변화하는 인프라 토폴로지를 처리할 수도 있다.
- 모든 트래픽이 메시를 통과하므로 운영자는 트래픽을 명시적으로 제어하고 지시할 수 있다.
- 트래픽이 메시를 통과하므로 요청 급증, 지연 시간, 처리량, 장애 등과 같은 메트릭을 추적함으로써 네트워크 동작에 대한 상세한 신호를 포착할 수 있다.
- 이 텔레메트리 telemetry 를 활용해 시스템에서 어떤 일이 일어나고 있는지 그려낼 수 있다.
- 마지막으로, 서비스 메시가 애플리케이션 간 네트워크 통신의 양쪽 끝을 제어하므로 상호 인증을 사용한 전송 계층 암호화 같은 강력한 보안을 적용할 수 있다.
- 구체적으로는 TLS 프로토콜을 사용할 수 있다.
정리
- 서비스 메시는 이 모든 기능을 애플리케이션 코드 변경이나 의존성 추가를 거의(혹은 전혀) 하지 않고도 서비스 운영자에게 제공한다.
- 일부 기능에서는 애플리케이션 코드와 약간의 협업이 필요하지만, 크고 복잡한 라이브러리 의존성을 피할 수 있다.
- 서비스 메시를 사용하면 애플리케이션을 구축하는 데 어떤 애플리케이션 프레임워크나 프로그래밍 언어를 사용했든지 상관없이 이런한 기능들이 일관되고 정확하게 구현되므로, 서비스 팀이 변화를 구현해 전달할 때 빠르고 안전하며 자신감 있게 움직일 수 있게 된다.
1.5 이스티오 서비스 메시 소개‣들어가며 : 이스티오 istio 는 그리스어로 ‘돛’을 의미하며, k8s 항해 용어들과 잘 어울림.‣- 이스티오는 서비스 메시의 오픈소스 구현체이며 구글, IBM, 리프트가 주도했다.
- 이스티오는 서비스 아키텍처에 복원력과 관찰 가능성을 투명한 방식으로 추가하는 데 도움이 된다.
- 이스티오를 사용하면 애플리케이션은 자신이 서비스 메시의 일부임을 인지하지 않아도 된다.
- 애플리케이션이 외부 세계와 의사소통할 때는 항상 이스티오가 애플리케이션 대신 네트워킹을 처리하기 때문이다.
- 이스티오의 데이터 플레인은 엔보이 프록시를 사용하며, 서비스 프록시 인스턴스가 함께 배포되도록 애플리케이션을 구성하는 데 도움이 된다.
- 이스티오의 컨트롤 플에인은 최종 사용자/운영자용 API, 프록시용 설정 API, 보안 설정, 정책 선언 등을 제공하는 몇 가지 구성 요소로 이뤄져 있다.
- 이스티오는 본래 쿠버네티스에서 실행할 목적으로 구축됐지만, 배포 플랫폼에 구애받지 않는 관점으로 작성됐다.
- 즉, 쿠버네티스, 오픈시프트와 같은 배포 플랫폼은 물론, 가상머신 같은 기존 배포 환경에서도 이스티오 기반 서비스 메시를 사용할 수 있다.
- 각 애플리케이션 인스턴스 옆에 서비스 프록시가 있으면 애플리케이션은 더 이상 서킷 브레이커, 시간 초과, 재시도, 서비스 디스커버리, 로드 밸런싱 등을 위해 언어별 복원력 라이브러리가 필요하지 않다.
- 또한 서비스 프록시는 메트릭 수집, 분산 트레이싱, 접근 제어도 처리한다.
- 서비스 메시의 트래픽이 이스티오 서비스 프록시를 거쳐 흐르는 덕분에 이스티오는 각 애플리케이션에서 네트워킹 동작에 영향을 주고 지시할 수 있는 제어 지점을 가진다.
- 이를 통해 운영자는 트래픽 흐름을 제어하고 카나리 릴리즈, 다크 런치, 단계적 롤아웃, A/B 스타일 테스트와 같은 세밀한 릴리즈를 구현할 수 있다.
- 트래픽은 이스티오 인그레스 게이트웨이를 통해 메시 외부의 클라이언트에서 클러스터로 들어온다.
- 트래픽이 쇼핑 카트 서비스로 이동한다. 트래픽은 먼저 해당 서비스 프록시를 통과한다.
- 서비스 프록시는 서비스에 타임아웃, 메트릭 수집, 보안 강제 등을 적용할 수 있다.
- 요청이 다양한 서비스를 거치므로, 이스티오의 서비스 프록시는 다양한 단계에서 요청을 가로채고 라우팅 결정을 내릴 수 있다.
- 이스티오의 컨트롤 플레인 istiod 는 라우팅, 보안, 텔레메트릭 수집, 복원력을 처리하는 이스티오 프록시를 설정하는 데 사용한다.
- 요청 메트릭은 주기적으로 다양한 수집 서비스로 전송된다. 분산 트레이싱 스팬은 트레이싱 저장소로 전송돼 시스템을 거치는 요청의 경로 및 지연 시간을 추후에 추적하는 용도로 사용할 수 있다.
- 어떤 서비스 기반 아키텍처에서도 중요한 요구 사항은 보안이다. 이스티오는 기본적으로 보안이 활성화돼 있다.
- 이스티오가 애플리케이션 네트워킹 경로의 양 끝단을 제어하는 덕분에 기본적으로 트래픽을 투명하게 암호화 할 수 있다.
- 이스티오는 서비스가 mTLS를 바로 사용할 수 있도록 키 및 인증서 발급, 설치, 로테이션을 관리할 수 있다.
- 이스티오는 워크로드에 ID를 부여하고 이를 인증서에 포함시킬 수 있다. 또한 ID를 사용해 강력한 접근 제어 정책을 구현할 수 있다.
- 마지막으로, 이스티오를 사용하면 할당량, 속도 제한, 조직 정책을 구현할 수 있다.
- 이스티오의 정책 강제 policy enforcement 를 사용하면, 어떤 서비스가 서로 상호작용할 수 있고 어떤 서비스가 상호작용할수 없는지에 대해 아주 세밀한 규칙을 만들 수 있다.
1.5.1 서비스 메시와 엔터프라이즈 서비스 버스 ESB 의 관계‣- 서비스 지향 아키텍처 SOA 시대의 엔터프라이즈 서비스 버스 ESB는 최소한 정신적으로는 서비스 메시와 유사하다.
- SOA 초기에 ESB가 본래 묘사됐던 방식을 살펴보면 다음과 같이 상당히 비슷한 표현을 볼 수 있다.
- 위 설명에서 ESB를 ‘과묵한 파트너’로 가정하고 있는데, 이는 애플리케이션이 ESB를 알지 못함을 의미한다.
- 서비스 메시에서도 비슷한 동작을 기대한다. 서비스 메시는 애플리케이션에게 투명해야 한다.
- 또한 ESB는 ‘서비스 호출 작업을 단순하게 만드는 데 핵심적인 요소’라고 한다.
- ESB의 경우 프로토콜 변환, 메시지 변환, 콘텐츠 기반 라우팅을 포함한다.
- 서비스 메시는 EBS가 하던 모든 일을 맡지는 않는다.
- 서비스 메시는 재시도, 타임아웃, 서킷 브레이커로 서비스 복원력을 제공하고, 이에 더해 서비스 디스커버리와 로드 밸런싱 같은 서비스를 제공한다.
- 전반적으로 서비스 메시와 ESB에는 몇가지 중요한 차이점이 있다.
- ESB는 기업 내에서 서비스 통합을 관리하는 새로운 구조를 조직에 도입했는데, 이 구조는 결국 격리된 시스템, 즉 사일로 silo 가 됐다.
- ESB는 매우 중앙화된 배포/구현이었다.
- ESB는 애플리케이션 네트워킹과 서비스 중재 문제를 혼합했다.
- ESB는 복잡한 독점 벤더 소프트웨어를 기반으로 하는 경우가 많았다.
- 아래 그림은 ESB가 애플리케이션을 통합하는 방법을 보여준다.
- ESB는 중앙에 위치하고 애플리케이션 비즈니스 로직을 애플리케이션 라우팅,변환,중재와 결합했다.
- 서비스 메시의 역할은 오직 애플리케이션 네트워킹 문제에만 해당된다.
- 복잡한 비즈니스 변환, 비즈니스 프로세스 오케스트레이션, 프로세스 예외, 서비스 오케스트레이션 등은 서비스 메시의 일이 아니다.
- 또한 서비스 메시의 데이트 플레인은 프록시를 애플리케이션에 붙이는 형태로 고도로 분산된다.
- 이를 통해 ESB 아키텍처에서 자주 나타나는 단일 장애 지점 혹은 병목 지점을 제거한다.
- 마지막으로 운영자와 서비스 팀 모두 서비스 수준 목표 SLO를 수립하고 이를 지원하도록 서비스 메시를 구성할 책임이 있다.
- 다른 시스템과 통합할 책임은 더 이상 일부 중앙집중식 팀의 영역이 아니다. 모든 서비스 개발자가 그 책임을 함께 진다.
1.5.2 서비스 메시와 API 게이트웨이의 관계‣- 이스티오와 서비스 메시 기술은 API 게이트웨이와도 몇 가지 유사점과 차이점을 공유한다.
- API 게이트웨이 인프라는 API 관리 제품군에서 조직의 공개 API에 외부에서 접근할 수 있는 엔드포인트를 제공하는 데 사용한다.
- API 게이트웨이의 역할은 크게 두 가지다.
- 첫 번째는 공개 API에 보안, 속도 제한, 할당량 관리, 메트릭 수집 기능을 제공하는 것이고,
- 두 번째는 API 계획 명세, 사용자 등록, 요금 청구와 기타 운영 문제를 포함하는 전반적 API 관리 솔루션에 공개 API를 연결하는 것이다.
- API 게이트웨이 아키텍처는 매우 다양하지만, 대부분 아키텍처의 경계에서 공개 API를 노출하는 데 사용됐다.
- 또한 보안, 정책, 메트릭 수집을 중앙화하기 위해 내부 API에도 사용돼 왔다.
- 그렇지만 API 게이트웨이는 트래픽이 흐르는 중앙집중 시스템을 만들기 때문에 ESB와 메시징 버스에서 설명했듯 병목 현상의 원인이 될 수 있다.
- 아래 그림은 내부 API에 API 게이트웨이를 사용할 때 서비스 간에 모든 내부 트래픽이 어떻게 API 게이트웨이를 거쳐가는지 보여준다.
- 그래프의 모든 서비스에서 홉 hop 이 두 번을 거치게 된다. 한번은 게이트웨이로 향하고, 한 번은 실제 서비스로 향하는 것이다.
- 이는 네트워크 오버헤드와 지연 시간 뿐 아니라 보안에도 영향을 미친다.
- 이런 다중 홉 아키텍처에서는 애플리케이션 관여 없이 API 게이트웨이가 단독으로 전송 매커니즘을 보호할 수 없다.
- 그리고 API 게이트웨이는 보통 서킷 브레이커나 격벽 같은 복원력 기능을 구현하지 않는다.
- 서비스 메시에서 프록시는 서비스와 함께 배치되므로 추가 홉을 거치지 않는다.
- 또한 서비스 메시는 탈중앙적이므로, 각 에플리케이션은 자신의 프록시를 자신의 워크로드에 맞게 설정할 수 있고 시끄러운 이웃 noisy neithbor 시나리오에 영향을 받지 않는다.
- 각 프록시는 짝 애플리케이션 인스턴스와 함께 있으므로, 애플리케이션이 알아차리거나 적극적으로 참여할 필요 없이 전송 매커니즘을 처음부터 끝까지 end-to-end 보호할 수 있다.
- 아래 그림은 서비스 프록시가 API 게이트웨이 기능을 구현하고 강제하는 장소가 되는 모습을 보여준다.
- 이스티오 같은 서비스 메시 기술이 계속 성숙하게 되면, API 관리가 서비스 메시 위에 구축되고 전문 API 게이트웨이 프록시가 필요하지 않게 될 것이다.
1.5.3 마이크로서비스가 아닌 아키텍처에도 이스티오를 사용할 수 있는가?‣- 이스티오의 힘이 빛을 발하는 것은 서비스 개수와 서비스 사이의 연결이 많고 네트워크가 신뢰할 수 없는 클라우드 인프라 위에 있으며 이런 구조가 여러 클러스터, 클라우드, 데이터센터에 걸쳐 확장되는 상황에서다.
- 게다가 이스티오가 애플리케이션 프로세스 외부에서 작동되므로, 기존 레거시 혹은 브라운필드 환경에서 배포해 메시에 통합할 수 있다.
- 이스티오에는 어떤 서비스와 통신할 수 있는지 강제하는 정책이 있는데, 이 기능은 온프레미스와 퍼블릭 클라우드를 모두 사용하는 하이브리드 클라우드 구조에서 대단히 유용해진다.
- 이스티오와 애플리케이션 둘 다 서킷 브레이커 같은 기능이 중복으로 구현했더라도, 더 제한적인 정책이 효과를 발휘해 모든 게 정상적으로 잘 작동할 것으므로 안심 할 수 있다.
1.5.4 이스티오가 분산 아키텍처에 적합한 경우‣- 구현에 사용할 기술은 당면한 문제와 필요한 기능을 고려해 선택해야 한다.
- 이스티오 같은 서비스 메시 기술은 강력한 인프라 기능이여 분산 아키텍처의 많은 영역에 영향을 미친다.
- 그렇지만 모든 문제에 적합한 것은 아니므로 모든 문제에 해결책으로 고려해서는 안된다.
- 아래 그림은 클라우드 아키텍처에서 애플리케이션 네트워킹 관심사를 이상적으로 분리하는 방법을 보여준다.
- 아키텍처의 하위 계층에는 배포 자동화 인프라가 있다.
- 이 인프라는 코드를 플랫폼에 배포하는 역할을 담당한다. 이스티오는 어떤 배포 자동화 도구를 사용해야 하는지를 규정하거나 침해하지 않는다.
- 상위 계층에는 애플리케이션 비즈니스 로직(코드)이 있다. 이 코드에는 비즈니스 도메인은 물론 어떤 서비스를 어떤 순서로 호출할지, 서비스 상호작용 응답을 어떻게 처리할지, 프로세스 실패 시 어떻게 처리할지 등이 포함된다.
- 이스티오는 어떤 비즈니스 로직도 구현하거나 대체하지 않는다. 또한 서비스 오케스트레이션, 비즈니스 페이로드 변환, 페이로드 강화, 분할 집계, 규칙 계산 등을 수행하지 않는다. 이런 기능은 애플리케이션 내부 라이브러리와 프레임워크에 맡기는 것이 가장 좋다.
- 이스티오는 배포 플랫폼과 애플리케이션 코드 사이의 연결 조직 역할을 한다.
- 복잡한 네트워킹 코드를 애플리케이션 외부로 꺼낼 수 있게 하는 것이다.
1.5.5 서비스 메시를 사용할 때의 단점은 무엇인가?‣- 첫 번째로, 서비스 메시를 사용하면 요청 경로에 미들웨어, 특히 프록시가 추가된다.
- 이 프록시가 많은 이점을 주기도 하지만, 프록시에 익숙하지 않은 이들에게는 블랙박스가 돼 애플리케이션의 동작을 디버깅하기 어렵게 만들 수 있다.
- 엔보이 프록시는 아주 디버깅하기 쉽도록, 네트워크상에서 발생하고 있는 일을 많이 노출하게 특별히 설계됐다.
- 그렇지만 엔보이를 운영하는 데 익숙하지 않은 사람들에게는 아주 복잡해 보일 수 있고, 기존 디버깅 방식을 방해할 수 있다.
- 두 번째로, 테넌시 측면이다.
- 메시는 메시 내에서 실행되는 서비스 만큼 가치가 있다. 즉, 메시 내에 서비스가 많을수록 그 서비스들을 운영하는 데 메시의 가치가 높아진다.
- 그러나 물리적 메시 배포의 테넌트 및 격리 모델에 적절한 정책, 자동화, 그리고 사전 고려 없이는 메시를 잘못 구성하면 많은 서비스에 영향을 미칠 수 있는 상황에 처할 수 있습니다. → 학습 필요. 잘 알고 설정 필요
- 마지막으로, 서비스 메시는 요청 경로에 위치하기 때문에 서비스 및 애플리케이션 아키텍처의 매우 중요한 요소가 된다.
- 서비스 메시는 보안, 관찰 가능성 및 라우팅 제어 자세를 개선할 수 있는 많은 기회를 제공할 수 있습니다.
- 단점은 메쉬가 또 다른 레이어와 또 다른 복잡성의 기회를 제공한다는 점입니다.
- 운영상 이슈(R&R) : 서비스 메시를 어떻게 설정하고 운영해야 하는지, 기존 조직의 절차와 거버넌스에는 어떻게 통합해야 하는지, 또한 팀 간에는 어떻게 통합해야 하는지 이해하기가 어려울 수 있다.
- 일반적으로 서비스 메시가 가져다주는 이점이 크지만, 그에 따른 트레이드오프가 없지 않다.
- 다른 도구나 플랫폼과 마찬가지로 사용자는 자신의 맥락 및 제약 조건에 비춰 트레이드오프를 평가하고, 서비스 메시가 자신의 상황에 적합한지 판단해야 한다.
- 만약 적합하다면 메시를 성공적으로 도입하기 위한 계획를 세워야 한다.
1.5.6. 요약 : 서비스 메시는 이런 공통 관심사(애플리케이션 네트워킹)를 애플리케이션 대신 외부에서 투명한 방식으로 구현하는 인프라‣- 클라우드에서 마이크로서비스를 운영하는 데는 여러 도전과제가 있다.
- 몇 가지를 꼽자면 신뢰할 수 없는 네트워크, 서비스 가용성, 이해하기 어려운 트래픽 흐름, 트래픽 암호화, 애플리케이션 상태, 성능 등이 있다.
- 이런 어려움들은 각 애플리케이션 내에서 라이브러리를 사용해 패턴(서비스 디스커버리 등)들을 구현함으로써 완화된다.
- 서비스들에 대한 관찰 가능성을 확보할 목적으로 메트릭과 트레이싱을 생성하고 배포하려면 추가적인 라이브러리와 서비스가 필요한다.
- 서비스 메시는 이런 공통 관심사를 애플리케이션 대신 프로세스 외부에서 투명한 방식으로 구현하는 인프라다.
- 이스티오는 다음과 같은 요소로 구성된 서비스 메시 구현체다.
- 데이터 플레인, 애플리케이션과 함께 배포되는 서비스 프록시로 구서오디며, 정책을 구현하고 트래픽을 제어하고 메트릭과 트레이싱을 생성하는 등 애플리케이션을 보완한다.
- 컨트롤 플레인, 운영자가 데이터 플레인의 네트워크 동작을 제어할 수 있도록 API를 노출한다.
- 이스티오는 엔보이를 서비스 프록시로 사용하는데, 기능이 다양하고 동적으로 설정할 수 있기 때문이다.
‣서비스 매시(Service Mesh)- 등장 배경 : 마이크로서비스 아키텍처 환경의 시스템 전체 모니터링의 어려움, 운영 시 시스템 장애나 문제 발생할 때 원인과 병목 구간 찾기 어려움

- 내부망 진입점에 역할을 하는 GW(예. API Gateway) 경우 모든 동작 처리에 무거워지거나, 내부망 내부 통신 제어는 어려움
- 개념 : 마이크로서비스 간에 매시 형태의 통신이나 그 경로를 제어 - 예) 이스티오(Istio), 링커드(Linkerd) - 링크
- 기본 동작 : 파드 간 통신 경로에 프록시를 놓고 트래픽 모니터링이나 트래픽 컨트롤 → 기존 애플리케이션 코드에 수정 없이 구성 가능!
- 기존 통신 환경

- 애플리케이션 수정 없이, 모든 애플리케이션 통신 사이에 Proxy 를 두고 통신 해보자

- 파드 내에 사이드카 컨테이너로 주입되어서 동작
- Proxy 컨테이너가 Application 트래픽을 가로채야됨 → iptables rule 구현 ⇒ 가능한 이유는?
- Proxy 는 결국 DataPlane 이니, 이를 중앙에서 관리하는 ControlPlane을 두고 중앙에서 관리를 하자

- Proxy 는 중앙에서 설정 관리가 잘되는 툴을 선택. 즉, 원격에서 동적인 설정 관리가 유연해야함 → 풍부한 API 지원이 필요 ⇒ Envoy
- '구글 IBM 리프트(Lyft)'가 중심이 되어 개발하고 있는 오픈 소스 소프트웨어이며, C++ 로 구현된 고성능 Proxy 인 엔보이(Envoy)
- 네트워크의 투명성을 목표, 다양한 필터체인 지원(L3/L4, HTTP L7), 동적 configuration API 제공, api 기반 hot reload 제공
- 중앙에서 어떤 동작/설정을 관리해야 될까? 라우팅, 보안 통신을 위한 mTLS 관련, 동기화 상태 정보 등
- 트래픽 모니터링 : 요청의 '에러율, 레이턴시, 커넥션 개수, 요청 개수' 등 메트릭 모니터링, 특정 서비스간 혹은 특정 요청 경로로 필터링 → 원인 파악 용이!
- 트래픽 컨트롤 : 트래픽 시프팅(Traffic shifting), 서킷 브레이커(Circuit Breaker), 폴트 인젝션(Fault Injection), 속도 제한(Rate Limit)
- 트래픽 시프팅(Traffic shifting) : 예시) 99% 기존앱 + 1% 신규앱 , 특정 단말/사용자는 신규앱에 전달하여 단계적으로 적용하는 카니리 배포 가능
- 서킷 브레이커(Circuit Breaker) : 목적지 마이크로서비스에 문제가 있을 시 접속을 차단하고 출발지 마이크로서비스에 요청 에러를 반환 (연쇄 장애, 시스템 전제 장애 예방)
- 폴트 인젝션(Fault Injection) : 의도적으로 요청을 지연 혹은 실패를 구현
- 속도 제한(Rate Limit) : 요청 개수를 제한
- 정환열님이 작성해서 공유해주신 Istio 사내 교육용 자료에서 가져왔습니다.

‣이스티오 소개- 파일럿(Pilot): 모든 Envoy 사이드카에서 프록시 라우팅 규칙을 관리하며, 서비스 디스커버리와 로드 밸런싱 설정을 제공합니다.
- 갤리(Galley): Istio와 쿠버네티스(TLS 연결 및 파일럿에 필요한 설정)를 연결해 주는 역할을 합니다. 서비스 메시 구성 데이터를 검증하고 변환합니다.
- 시타델(Citadel): 보안 기능을 담당하며, TLS 인증서 발급 및 관리를 통해 서비스 간 통신의 암호화를 수행합니다.
Istio 구성요소와 envoy : 컨트롤 플레인(istiod) , 데이터 플레인(istio-proxy > envoy)
- 이스티오는 각 파드 안에 사이드카로 엔보이 프록시가 들어가 있는 형태
- 모든 마이크로서비스간 통신은 엔보이를 통과하여, 메트릭을 수집하거나 트래픽 컨트롤을 할 수 있음
- 트래픽 컨트롤을 하기위해 엔보이 프록시에 전송 룰을 설정 → 컨트롤 플레인의 이스티오가 정의된 정보를 기반으로 엔보이 설정을 하게 함
- 마이크로서비스 간의 통신을 mutual TLS 인증(mTLS)으로 서로 TLS 인증으로 암호화 할 수 있음
- 각 애플리케이션은 파드 내의 엔보이 프록시에 접속하기 위해 localhost 에 TCP 접속을 함
- Istio 구성요소와 envoy : 컨트롤 플레인(istiod) - ADS 를 이용한 Configuration 동기화 - 데이터 플레인(istio-proxy → envoy)
- Cluster : envoy 가 트래픽을 포워드할 수 있는 논리적인 서비스 (엔드포인트 세트), 실제 요청이 처리되는 IP 또는 엔드포인트의 묶음을 의미.
- Endpoint : IP 주소, 네트워크 노드로 클러스터로 그룹핑됨, 실제 접근이 가능한 엔드포인트를 의미. 엔드포인트가 모여서 하나의 Cluster 가 된다.
- Listener : 무엇을 받을지 그리고 어떻게 처리할지 IP/Port 를 바인딩하고, 요청 처리 측면에서 다운스트림을 조정하는 역할.
- Route : Listener 로 들어온 요청을 어디로 라우팅할 것인지를 정의. 라우팅 대상은 일반적으로 Cluster 라는 것에 대해 이뤄지게 된다.
- Filter : Listener 로부터 서비스에 트래픽을 전달하기까지 요청 처리 파이프라인
- UpStream : envoy 요청을 포워딩해서 연결하는 백엔드 네트워크 노드 - 사이드카일때 application app, 아닐때 원격 백엔드
- DownStream : An entity connecting to envoy, In non-sidecar models this is a remote client
Envoy 용어 정리 : 정환열님이 작성해서 공유해주신 Istio 사내 교육용 자료 내용이 좋아서 가져왔습니다.


Envoy는 구성을 동적으로 관리하기 위한 강력한 API를 제공이 중요합니다.

- Service Mesh 솔루션이나, Gateway API 구현체들을 Enovy를 내부적으로 사용하고 있으며, Envoy가 제공하는 동적 구성을 위한 API (xDS Sync API)를 이용하여 다양한 네트워크 정책을 구성하게 됩니다.
- Envoy의 xDS Sync API는 아래와 같은 레이어에서 동작하게 됩니다.
- LDS - Listener Discovery Service
- RDS - Route Discovery Service
- CDS - Cluseter Discovery Service
- EDS - Endpoint Discovery Service

[추천 영상]LG ThinQ Cloud 에 Istio 운영 경험 사례 - Youtube- K8S ClusterIP 의 랜덤 부하분산 vs Istio Service Mesh 기반 Lease Request 방식 ⇒ vCPU 사용률 절감 및 안정화

- 애플리케이션 코드 수정 없는, 심리스한 트래픽 이전과 트래픽 미러링 등 활용

- 오픈소스 기반 L7 Telemetry 구축

- 보안 : mTLS 기반 통신

- 별도 구축 없는 mock server

- 적용 예정 기능 : app 로깅 최적화, DNS Proxying, Ambient Mdoe

- (참고) OpenTelemetry 구성



- Istio 기본 실습
2.1. kind(k8s) 소개 및 설치와 기본 사용 : macOS 사용자 , Windows (WSL2) 사용자‣kind 소개 : ‘도커 IN 도커 docker in docker’로 쿠버네티스 클러스터 환경을 구성 - Link‣kind 설치 : macOS 사용자‣- kind 및 툴 설치
- 필수 툴 설치
# Install Kind brew install kind kind --version # Install kubectl brew install kubernetes-cli kubectl version --client=true ## kubectl -> k 단축키 설정 echo "alias =kubecolor" >> ~/.zshrc # Install Helm brew install helm helm version- (권장) 유용한 툴 설치
# 툴 설치 brew install krew brew install kube-ps1 brew install kubectx # kubectl 출력 시 하이라이트 처리 brew install kubecolor echo "alias kubectl=kubecolor" >> ~/.zshrc echo "compdef kubecolor=kubectl" >> ~/.zshrc # krew 플러그인 설치 kubectl krew install neat sternkind 기본 사용 - 클러스터 배포 및 확인‣(옵션) 별도 kubeconfig 지정 후 사용‣# 방안1 : 환경변수 지정 export KUBECONFIG=/Users/<Username>/Downloads/kind/config # 방안2 : 혹은 --kubeconfig ./config 지정 가능 # 클러스터 생성 kind create cluster # kubeconfig 파일 확인 ls -l /Users/<Username>/Downloads/kind/config -rw------- 1 <Username> staff 5608 4 24 09:05 /Users/<Username>/Downloads/kind/config # 파드 정보 확인 kubectl get pod -A # 클러스터 삭제 kind delete cluster unset KUBECONFIG# 클러스터 배포 전 확인 docker ps # Create a cluster with kind kind create cluster # 클러스터 배포 확인 kind get clusters kind get nodes kubectl cluster-info # 노드 정보 확인 kubectl get node -o wide # 파드 정보 확인 kubectl get pod -A kubectl get componentstatuses # 컨트롤플레인 (컨테이너) 노드 1대가 실행 docker ps docker images # kube config 파일 확인 cat ~/.kube/config 혹은 cat $KUBECONFIG # KUBECONFIG 변수 지정 사용 시 # nginx 파드 배포 및 확인 : 컨트롤플레인 노드인데 파드가 배포 될까요? kubectl run nginx --image=nginx:alpine kubectl get pod -owide # 노드에 Taints 정보 확인 kubectl describe node | grep Taints Taints: <none> # 클러스터 삭제 kind delete cluster # kube config 삭제 확인 cat ~/.kube/config 혹은 cat $KUBECONFIG # KUBECONFIG 변수 지정 사용 시kind 설치 : Windows (WSL2) 사용자‣kind 로 k8s 배포 : macOS 사용자‣- 기본 정보 확인
# 클러스터 배포 전 확인 docker ps # 방안1 : 환경변수 지정 export KUBECONFIG=$PWD/kubeconfig # Create a cluster with kind : 1.29.14 , 1.30.10 , 1.31.6 , 1.32.2 kind create cluster --name myk8s --image kindest/node:v1.32.2 --config - <<EOF kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane extraPortMappings: - containerPort: 30000 hostPort: 30000 - containerPort: 30001 hostPort: 30001 - containerPort: 30002 hostPort: 30002 - containerPort: 30003 hostPort: 30003 kubeadmConfigPatches: - | kind: ClusterConfiguration controllerManager: extraArgs: bind-address: "0.0.0.0" etcd: local: extraArgs: listen-metrics-urls: "http://0.0.0.0:2381" scheduler: extraArgs: bind-address: "0.0.0.0" - | kind: KubeProxyConfiguration metricsBindAddress: "0.0.0.0" EOF # 확인 kind get nodes --name myk8s kubens default # kind 는 별도 도커 네트워크 생성 후 사용 : 기본값 172.18.0.0/16 docker network ls docker inspect kind | jq # k8s api 주소 확인 : 어떻게 로컬에서 접속이 되는 걸까? kubectl cluster-info Kubernetes control plane is running at https://127.0.0.1:50970 CoreDNS is running at https://127.0.0.1:50970/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. # docker 에서 local 50970 port를 6443으로 prot fowarding하고 있음 docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES bf3999d21be4 kindest/node:v1.32.2 "/usr/local/bin/entr…" 3 minutes ago Up 3 minutes 0.0.0.0:30000-30003->30000-30003/tcp, 127.0.0.1:50970->6443/tcp myk8s-control-plane # 노드 정보 확인 : CRI 는 containerd 사용 kubectl get node -o wide # 파드 정보 확인 : CNI 는 kindnet 사용 kubectl get pod -A -o wide # 네임스페이스 확인 >> 도커 컨테이너에서 배운 네임스페이스와 다릅니다! kubectl get namespaces # 컨트롤플레인노드(컨테이너) 확인 : 도커 컨테이너 이름은 myk8s-control-plane docker ps docker images docker exec -it myk8s-control-plane ss -tnlp # 디버그용 내용 출력에 ~/.kube/config 권한 인증 로드 kubectl get pod -v6 # kube config 파일 확인 cat $KUBECONFIG ls -l $KUBECONFIG- kube-ops-view

# kube-ops-view # helm show values geek-cookbook/kube-ops-view helm repo add geek-cookbook https://geek-cookbook.github.io/charts/ helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set service.main.type=NodePort,service.main.ports.http.nodePort=30000 --set env.TZ="Asia/Seoul" --namespace kube-system # 설치 확인 kubectl get deploy,pod,svc,ep -n kube-system -l app.kubernetes.io/instance=kube-ops-view # kube-ops-view 접속 URL 확인 (1.5 , 2 배율) open "http://127.0.0.1:30000/#scale=1.5" open "http://127.0.0.1:30000/#scale=2"- (참고) 클러스터 삭제
# 클러스터 삭제 kind delete cluster --name myk8s docker ps cat $KUBECONFIG unset KUBECONFIGkind 로 k8s 배포 : Windows (WSL2) 사용자‣(옵션) prometheus-stack 설치 by helm - Link‣# 모니터링 watch kubectl get pod,pvc,svc,ingress -n monitoring # repo 추가 helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update # 파라미터 파일 생성 cat <<EOT > monitor-values.yaml prometheus: service: type: NodePort nodePort: 30001 prometheusSpec: scrapeInterval: "15s" evaluationInterval: "15s" podMonitorSelectorNilUsesHelmValues: false serviceMonitorSelectorNilUsesHelmValues: false retention: 5d retentionSize: "10GiB" grafana: defaultDashboardsTimezone: Asia/Seoul adminPassword: prom-operator service: type: NodePort nodePort: 30002 defaultRules: create: false prometheus-windows-exporter: prometheus: monitor: enabled: false alertmanager: enabled: false EOT cat monitor-values.yaml # 배포 helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack --version 69.3.1 \ -f monitor-values.yaml --create-namespace --namespace monitoring # 각각 웹 접속 실행 ## Windows(WSL2) 사용자는 아래 주소를 자신의 웹 브라우저에서 기입 후 직접 접속, 이후에도 동일. open http://127.0.0.1:30001 # macOS open http://127.0.0.1:30002 # macOS # 확인 ## alertmanager-0 : 사전에 정의한 정책 기반(예: 노드 다운, 파드 Pending 등)으로 시스템 경고 메시지를 생성 후 경보 채널(슬랙 등)로 전송 ## grafana : 프로메테우스는 메트릭 정보를 저장하는 용도로 사용하며, 그라파나로 시각화 처리 ## prometheus-0 : 모니터링 대상이 되는 파드는 ‘exporter’라는 별도의 사이드카 형식의 파드에서 모니터링 메트릭을 노출, pull 방식으로 가져와 내부의 시계열 데이터베이스에 저장 ## node-exporter : 노드익스포터는 물리 노드에 대한 자원 사용량(네트워크, 스토리지 등 전체) 정보를 메트릭 형태로 변경하여 노출 ## operator : 시스템 경고 메시지 정책(prometheus rule), 애플리케이션 모니터링 대상 추가 등의 작업을 편리하게 할수 있게 CRD 지원 ## kube-state-metrics : 쿠버네티스의 클러스터의 상태(kube-state)를 메트릭으로 변환하는 파드 helm list -n monitoring kubectl get pod,svc,ingress,pvc -n monitoring kubectl get-all -n monitoring kubectl get prometheus,servicemonitors -n monitoring kubectl get crd | grep monitoring # 삭제 helm uninstall -n monitoring kube-prometheus-stack(옵션) Bookinfo 애플리케이션 배포 및 반복 접속‣# Bookinfo 애플리케이션 배포 kubectl apply -f https://raw.githubusercontent.com/istio/istio/refs/heads/master/samples/bookinfo/platform/kube/bookinfo.yaml # 확인 kubectl get all,sa # ratings 파드에서 product 웹 접속(Service:ClusterIP) 확인 kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>" # productpage 서비스 NodePort 30003 설정 cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Service metadata: name: productpage labels: app: productpage service: productpage spec: type: NodePort ports: - name: http nodePort: 30003 port: 9080 selector: app: productpage EOF # productpage 서비스 NodePort 30003 접속 ## Windows(WSL2) 사용자는 아래 주소를 자신의 웹 브라우저에서 기입 후 직접 접속, 이후에도 동일. echo "http://127.0.0.1:30003/productpage" open http://127.0.0.1:30003/productpage # 로그 kubectl stern -l app=productpage 혹은 kubectl log -l app=productpage -f # NodePort 를 통한 반복 접속 while true; do curl -s http://127.0.0.1:30003/productpage | grep -o "<title>.*</title>" ; echo "--------------" ; sleep 1; done for i in {1..100}; do curl -s http://127.0.0.1:30003/productpage | grep -o "<title>.*</title>" ; done # (참고) bookinfo 삭제 kubectl delete -f https://raw.githubusercontent.com/istio/istio/refs/heads/master/samples/bookinfo/platform/kube/bookinfo.yaml2.2. kind : k8s(1.23.17) 배포 → Istio 실습용 kind Cluster‣# git clone https://github.com/AcornPublishing/istio-in-action cd istio-in-action/book-source-code-master pwd # 각자 자신의 pwd 경로 code . # kind create cluster --name myk8s --image kindest/node:v1.23.17 --config - <<EOF kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane extraPortMappings: - containerPort: 30000 # Sample Application (istio-ingrssgateway) hostPort: 30000 - containerPort: 30001 # Prometheus hostPort: 30001 - containerPort: 30002 # Grafana hostPort: 30002 - containerPort: 30003 # Kiali hostPort: 30003 - containerPort: 30004 # Tracing hostPort: 30004 - containerPort: 30005 # kube-ops-view hostPort: 30005 extraMounts: - hostPath: /Users/gylee/Documents/Study/istio/week1/istio-in-action/book-source-code-master # 각자 자신의 pwd 경로로 설정 containerPath: /istiobook networking: podSubnet: 10.10.0.0/16 serviceSubnet: 10.200.1.0/24 EOF # 설치 확인 docker ps # 노드에 기본 툴 설치 docker exec -it myk8s-control-plane sh -c 'apt update && apt install tree psmisc lsof wget bridge-utils net-tools dnsutils tcpdump ngrep iputils-ping git vim -y'(옵션) 편의성 툴 설치‣# (옵션) kube-ops-view helm repo add geek-cookbook https://geek-cookbook.github.io/charts/ helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set service.main.type=NodePort,service.main.ports.http.nodePort=30005 --set env.TZ="Asia/Seoul" --namespace kube-system kubectl get deploy,pod,svc,ep -n kube-system -l app.kubernetes.io/instance=kube-ops-view ## kube-ops-view 접속 URL 확인 open "http://localhost:30005/#scale=1.5" open "http://localhost:30005/#scale=1.3" # (옵션) metrics-server helm repo add metrics-server https://kubernetes-sigs.github.io/metrics-server/ helm install metrics-server metrics-server/metrics-server --set 'args[0]=--kubelet-insecure-tls' -n kube-system kubectl get all -n kube-system -l app.kubernetes.io/instance=metrics-server2.3. Istio control plane 알아보기‣들어가며‣- Istio control plane 제공 기능
- 운영자가 원하는 라우팅/회복력 routing/resilience 동작을 지정할 수 있는 API
- 데이터 플레인 설정을 위한 API
- 데이터 플레인에 대한 서비스 검색 추상화 service discovery abstraction
- 사용자 정책 specifying usage policies 지정 API
- 인증서 발급 및 순환 Certificate issuance and rotation
- 워크로드 ID 할당 Workload identity assignment
- 통합 원격 측정 컬렉션 Unified telemetry collection
- 서비스 프록시 사이드카 주입 Service-proxy sidecar injection
- 네트워크 경계 지정 및 접근 방법 Specification of network boundaries and how to access them
- 위 기능 대부분은 istiod 라는 단일 컨트롤 플레인 구성 요소에 구현돼 있다.
2.3.1 istiod‣- 이스티오의 컨트롤 플레인 역할은 istiod로 구현된다.
- 이스티오 파일럿 istio pilot 이라고도 하는 istiod 는 사용자나 운영자가 지정한 Higher-Level 이스티오 설정을 받아 이르 각 데이터 플레인 서비스 프록시에 맞는 프록시 전용 설정으로 변환하는 역할을 한다.
- 이스티오는 ‘선언형 설정’을 해석해 서비스 프록시 전용 설정으로 적용된다.
- 이스티오는 서비스 프록시로 엔보이를 사용하므로 이 설정들은 엔보이 설정으로 변환된다.
- 예를 들어 아래 처럼 ‘선언형 설정’과 변환된 ‘엔보이 설정’
# istip api 선언형 설정 apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: catalog spec: hosts: - catalog http: - match: - headers: x-dark-launch: exact: "v2" route: - destination: host: catalog subset: version-v2 - route: - destination: host: catalog subset: version-v1# 변환된 ‘엔보이 설정’ "domains": [ "catalog.prod.svc.cluster.local" ], "name": "catalog.prod.svc.cluster.local:80", "routes": [ { "match": { "headers": [ { "name": "x-dark-launch", "value": "v2" } ], "prefix": "/" }, "route": { "cluster": "outbound|80|v2|catalog.prod.svc.cluster.local", "use_websocket": false } }, { "match": { "prefix": "/" }, "route": { "cluster": "outbound|80|v1|catalog.prod.svc.cluster.local", "use_websocket": false } } ]- istiod가 노출하는 이 데이터 플레인 API는 엔보이의 디스커버리 API를 구현한다.
- 서비스 디스커버리용(LDS, Listener Discovery Service), 엔드포인트용(EDS, Endpoint DS), 라우팅 큐칙용(RDS, Route DS) 등과 같은 이런 디스커버리 API를 xDS API라고 부른다.
- 이 API들이 있어서 데이터 플레인이 설정 방식을 분리할 수 있으며, 중지/재시작 없이 Envoy 에 동적으로 설정을 적용 할 수 있다.
- 이스티오의 핵심 기능 중 하나는 각 워크로드 인스턴스에 ID를 할당하고 서비스 간 네트워크 전송을 암호화하는 것이다.
- 이 기능은 서비스 메시가 요청 경로 양 끝단 모두에 위치한 덕분에 가능하다. 이때 이스티오는 트래픽 암호화에 X.509 인증서를 사용한다.
- 워크로드 ID는 SPIFFE 사양에 따라 이 인증서에 내장된다. https://spiffe.io/
- 덕분에 이스티오에서는 애플리케이션이 인증서, 공개/비밀키 등을 인지할 필요 없이 강력한 상호 인증(mTLS)을 사용할 수 있다.
- 이런 보안을 가능케 하는 인증서의 검증, 서명, 전달 및 로테이션은 istiod가 다룬다.
2.3.2 인그레스 및 이그레스 게이트웨이 Ingress and egress gateway‣

# myk8s-control-plane 진입 후 설치 진행 docker exec -it myk8s-control-plane bash ----------------------------------- # 코드 파일들 마운트 확인 tree /istiobook/ -L 1 # istioctl 설치 export ISTIOV=1.17.8 echo 'export ISTIOV=1.17.8' >> /root/.bashrc curl -s -L https://istio.io/downloadIstio | ISTIO_VERSION=$ISTIOV sh - tree istio-$ISTIOV -L 2 # sample yaml 포함 cp istio-$ISTIOV/bin/istioctl /usr/local/bin/istioctl istioctl version --remote=false # default 프로파일 컨트롤 플레인 배포 istioctl x precheck # 설치 전 k8s 조건 충족 검사 istioctl profile list istioctl install --set profile=default -y ✔ Istio core installed ✔ Istiod installed ✔ Ingress gateways installed ✔ Installation complete # 설치 확인 : istiod, istio-ingressgateway, crd 등 kubectl get istiooperators -n istio-system NAME REVISION STATUS AGE installed-state 4m49s kubectl get istiooperators -n istio-system -o yaml ... spec: components: base: enabled: true cni: enabled: false egressGateways: - enabled: false name: istio-egressgateway ingressGateways: - enabled: true name: istio-ingressgateway istiodRemote: enabled: false pilot: enabled: true hub: docker.io/istio meshConfig: defaultConfig: proxyMetadata: {} enablePrometheusMerge: true profile: default ... pilot: autoscaleEnabled: true autoscaleMax: 5 autoscaleMin: 1 configMap: true cpu: targetAverageUtilization: 80 deploymentLabels: null enableProtocolSniffingForInbound: true enableProtocolSniffingForOutbound: true env: {} image: pilot keepaliveMaxServerConnectionAge: 30m nodeSelector: {} podLabels: {} replicaCount: 1 traceSampling: 1 telemetry: enabled: true v2: enabled: true metadataExchange: wasmEnabled: false prometheus: enabled: true wasmEnabled: false stackdriver: configOverride: {} enabled: false logging: false monitoring: false topology: false kubectl get all,svc,ep,sa,cm,secret,pdb -n istio-system NAME READY STATUS RESTARTS AGE pod/istio-ingressgateway-996bc6bb6-c6g6v 1/1 Running 0 31s pod/istiod-7df6ffc78d-w7tr7 1/1 Running 0 47s ... kubectl get crd | grep istio.io | sort istioctl verify-install # 설치 확인 # 보조 도구 설치 kubectl apply -f istio-$ISTIOV/samples/addons # kubectl get pod -n istio-system NAME READY STATUS RESTARTS AGE grafana-b854c6c8-c7j4p 1/1 Running 0 64s istio-ingressgateway-996bc6bb6-c6g6v 1/1 Running 0 2m22s istiod-7df6ffc78d-w7tr7 1/1 Running 0 2m38s jaeger-5556cd8fcf-q79pw 1/1 Running 0 64s kiali-648847c8c4-pvkzj 1/1 Running 0 64s prometheus-7b8b9dd44c-v6jhm 2/2 Running 0 64s # 빠져나오기 exit ----------------------------------- # kubectl get cm -n istio-system istio -o yaml kubectl get cm -n istio-system istio -o yaml | kubectl neat2.5 Deploying your first application in the service mesh → 서비스 메시에 첫 애플리케이션 배포‣# kubectl create ns istioinaction # 방법1 : yaml에 sidecar 설정을 추가 cat services/catalog/kubernetes/catalog.yaml docker exec -it myk8s-control-plane istioctl kube-inject -f /istiobook/services/catalog/kubernetes/catalog.yaml ... - args: - proxy - sidecar - --domain - $(POD_NAMESPACE).svc.cluster.local - --proxyLogLevel=warning - --proxyComponentLogLevel=misc:error - --log_output_level=default:info - --concurrency - "2" env: - name: JWT_POLICY value: third-party-jwt - name: PILOT_CERT_PROVIDER value: istiod - name: CA_ADDR value: istiod.istio-system.svc:15012 - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name ... image: docker.io/istio/proxyv2:1.13.0 name: istio-proxy # 방법2 : namespace에 레이블을 추가하면 istiod (오퍼레이터)가 해당 namepsace의 pod spec에 자동으로 sidecar 설정을 주입 kubectl label namespace istioinaction istio-injection=enabled kubectl get ns --show-labels istioinaction Active 74s istio-injection=enabled,kubernetes.io/metadata.name=istioinaction # kubectl get mutatingwebhookconfiguration NAME WEBHOOKS AGE istio-revision-tag-default 4 9m24s # 특정 revision의 사이드카 주입 설정 관리 istio-sidecar-injector 4 9m45s # Istio는 각 애플리케이션 Pod에 Envoy 사이드카 프록시를 자동으로 주입 ## 네임스페이스나 Pod에 istio-injection=enabled 라벨이 있어야 작동 kubectl get mutatingwebhookconfiguration istio-sidecar-injector -o yaml # kubectl get cm -n istio-system istio-sidecar-injector -o yaml | kubectl neat
# cat services/catalog/kubernetes/catalog.yaml kubectl apply -f services/catalog/kubernetes/catalog.yaml -n istioinaction cat services/webapp/kubernetes/webapp.yaml kubectl apply -f services/webapp/kubernetes/webapp.yaml -n istioinaction # istio-injection에 의해서 envoy proxy container가 sidercar로 배치되어 container가 2개이다. kubectl get pod -n istioinaction NAME READY STATUS RESTARTS AGE catalog-6cf4b97d-jx8xw 2/2 Running 0 29s webapp-7685bcb84-zlxmv 2/2 Running 0 29s # catalog 디플로이먼트에서 파드 관련 spec kubectl get deploy -n istioinaction catalog -o jsonpath="{.spec.template.spec}" | jq # catalog 파드 관련 spec : 위 디플로이먼트와 파드 spec 을 비교해보자 kubectl get pod -n istioinaction -l app=catalog -o jsonpath="{.items[0].spec}" | jq # 접속 테스트용 netshoot 파드 생성 cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Pod metadata: name: netshoot spec: containers: - name: netshoot image: nicolaka/netshoot command: ["tail"] args: ["-f", "/dev/null"] terminationGracePeriodSeconds: 0 EOF # catalog 접속 확인 kubectl exec -it netshoot -- curl -s http://catalog.istioinaction/items/1 | jq { "id": 1, "color": "amber", "department": "Eyewear", "name": "Elinor Glasses", "price": "282.00" } # webapp 접속 확인 : webapp 서비스는 다른 서비스에서 데이터를 집계해 브라우저에 시각적으로 표시한다. ## 즉 webapp은 다른 백엔드 서비스의 파사드 facade 역할을 한다. kubectl exec -it netshoot -- curl -s http://webapp.istioinaction/api/catalog/items/1 | jq { "id": 1, "color": "amber", "department": "Eyewear", "name": "Elinor Glasses", "price": "282.00" }# 아래 방법 대신 임시 사용 kubectl port-forward -n istioinaction deploy/webapp 8080:8080 확인 후 CTRL+C 로 종료 # open http://localhost:8080- webapp 서비스는 다른 서비스에서 데이터를 집계해 브라우저에 시각적으로 표시한다.

2.6 Exploring the power of Istio with resilience, observability, and traffic control → 복원력, 관찰가능성, 트래픽 제어‣- 이스티오 프록시가 호출 경로 커넥션의 양쪽에 위치하는 덕분에, 이스티오는 애플리케이션 사이에 무슨 일이 일어나고 있는지에 대해 많은 텔레메트리를 수집하고 통찰력을 항샹시킬 수 있다. 이스티오의 서비스 프록시는 각 애플리케이션 곁에 사이드카로 배포되므로, 서비스 프록시가 수집하는 통찰력은 애플리케이션의 ‘프로세스 외부’에서 나온다. 즉, 대부분의 경우 애플리케이션은 이 수준의 관찰력을 얻기 위해 라이브러리나 프레임워크에 특정 구현을 추가할 필요가 없다. 프록시에게 애플리케이션은 블랙박스이며, 텔레메트리는 네트워크를 통해 관찰된 애플리케이션의 동작에 초점을 맞춘다.
- 이스티오가 생성하는 텔레메트리는 관찰 가능성의 2가지 주요 범주에 대한 것이다. 첫 번째는 주요 메트릭, 이를테면 초당 요청 수, 실패 횟수, 지연 시간 백분위수와 같은 것들이다. 이런 값들을 알면 시스템에서 문제가 시작되는 지점에 대한 훌륭한 통찰력을 얻을 수 있다. 두 번째로, 이스티오는 OpenTracing 와 같은 분산 트레이싱을 지원할 수 있다. 이스티오는 애플리케이션들이 신경 쓰지 않아도 분산 트레이싱 백엔드로 스팬을 보낼 수 있다. 이렇게 하면 특정 서비스 상호작용 중에 어떤 일이 일어났는지, 어디에서 지연이 발생했는지를 확인하고 전반적인 호출 지연에 대한 정보를 얻을 수 있다.

# istioctl proxy-status : 단축어 ps # 현재는 ingressgateway가 외부로 노출되어 있지 않으므로 RDS(Route Discovery Service)가 not sent 상태이다. docker exec -it myk8s-control-plane istioctl proxy-status NAME CLUSTER CDS LDS EDS RDS ECDS ISTIOD VERSION catalog-6cf4b97d-d5xbt.istioinaction Kubernetes SYNCED SYNCED SYNCED SYNCED NOT SENT istiod-7df6ffc78d-w7tr7 1.17.8 istio-ingressgateway-996bc6bb6-c6g6v.istio-system Kubernetes SYNCED SYNCED SYNCED NOT SENT NOT SENT istiod-7df6ffc78d-w7tr7 1.17.8 webapp-7685bcb84-h9t7q.istioinaction Kubernetes SYNCED SYNCED SYNCED SYNCED NOT SENT istiod-7df6ffc78d-w7tr7 1.17.8 docker exec -it myk8s-control-plane istioctl ps kubectl get po -n istio-system istio-ingressgateway-996bc6bb6-c6g6v -o yaml apiVersion: v1 kind: Pod metadata: annotations: prometheus.io/path: /stats/prometheus prometheus.io/port: "15020" prometheus.io/scrape: "true" sidecar.istio.io/inject: "false" creationTimestamp: "2025-04-11T15:18:42Z" generateName: istio-ingressgateway-996bc6bb6- labels: app: istio-ingressgateway chart: gateways heritage: Tiller install.operator.istio.io/owning-resource: unknown istio: ingressgateway # istio의 Gateway CR을 생성할때, selector를 통해서 해당 label을 선택해주게 된다. # cat ch2/ingress-gateway.yaml cat <<EOF | kubectl -n istioinaction apply -f - apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: outfitters-gateway namespace: istioinaction spec: selector: istio: ingressgateway # use istio default controller, istio-ingressgateway pod에 label로 설정이 되어있다 servers: - port: number: 80 name: http protocol: HTTP hosts: - "*" --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: webapp-virtualservice namespace: istioinaction spec: hosts: - "*" gateways: - outfitters-gateway http: - route: - destination: host: webapp port: number: 80 EOF # kubectl get gw,vs -n istioinaction NAME AGE gateway.networking.istio.io/outfitters-gateway 7s NAME GATEWAYS HOSTS AGE virtualservice.networking.istio.io/webapp-virtualservice ["outfitters-gateway"] ["*"] 7s # istioctl proxy-status : 단축어 ps # 이제 ingressgateway가 설정되었으므로, istio-ingressgateway의 RDS가 SYNCED로 변경되었다. docker exec -it myk8s-control-plane istioctl proxy-status NAME CLUSTER CDS LDS EDS RDS ECDS ISTIOD VERSION catalog-6cf4b97d-nccfj.istioinaction Kubernetes SYNCED SYNCED SYNCED SYNCED NOT SENT istiod-7df6ffc78d-bj7h7 1.17.8 istio-ingressgateway-996bc6bb6-mz544.istio-system Kubernetes SYNCED SYNCED SYNCED SYNCED NOT SENT istiod-7df6ffc78d-bj7h7 1.17.8 webapp-7685bcb84-c55ck.istioinaction Kubernetes SYNCED SYNCED SYNCED SYNCED NOT SENT istiod-7df6ffc78d-bj7h7 1.17.8 ISTIOIGW=istio-ingressgateway-996bc6bb6-c6g6v.istio-system WEBAPP=webapp-7685bcb84-h9t7q.istioinaction # istioctl proxy-config : 단축어 pc docker exec -it myk8s-control-plane istioctl proxy-config all $ISTIOIGW docker exec -it myk8s-control-plane istioctl proxy-config all $WEBAPP docker exec -it myk8s-control-plane istioctl proxy-config listener $ISTIOIGW docker exec -it myk8s-control-plane istioctl proxy-config route $ISTIOIGW docker exec -it myk8s-control-plane istioctl proxy-config cluster $ISTIOIGW docker exec -it myk8s-control-plane istioctl proxy-config endpoint $ISTIOIGW docker exec -it myk8s-control-plane istioctl proxy-config log $ISTIOIGW docker exec -it myk8s-control-plane istioctl proxy-config listener $WEBAPP docker exec -it myk8s-control-plane istioctl proxy-config route $WEBAPP docker exec -it myk8s-control-plane istioctl proxy-config cluster $WEBAPP docker exec -it myk8s-control-plane istioctl proxy-config endpoint $WEBAPP docker exec -it myk8s-control-plane istioctl proxy-config log $WEBAPP # envoy 가 사용하고 있는 인증서 정보 확인 docker exec -it myk8s-control-plane istioctl proxy-config secret $ISTIOIGW docker exec -it myk8s-control-plane istioctl proxy-config secret $WEBAPP # docker exec -it myk8s-control-plane istioctl proxy-config routes deploy/istio-ingressgateway.istio-system NAME DOMAINS MATCH VIRTUAL SERVICE http.8080 * /* webapp-virtualservice.istioinaction * /stats/prometheus* * /healthz/ready* # istio-ingressgateway 서비스 NodePort 변경 및 nodeport 30000로 지정 변경 kubectl get svc,ep -n istio-system istio-ingressgateway kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 8080, "nodePort": 30000}]}}' kubectl get svc -n istio-system istio-ingressgateway # istio-ingressgateway 서비스 externalTrafficPolicy 설정 : ClientIP 수집 확인 kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec":{"externalTrafficPolicy": "Local"}}' kubectl describe svc -n istio-system istio-ingressgateway # kubectl stern -l app=webapp -n istioinaction kubectl stern -l app=catalog -n istioinaction # curl -s http://127.0.0.1:30000/api/catalog | jq curl -s http://127.0.0.1:30000/api/catalog/items/1 | jq curl -s http://127.0.0.1:30000/api/catalog -I | head -n 1 # webapp 반복 호출 while true; do curl -s http://127.0.0.1:30000/api/catalog/items/1 ; sleep 1; echo; done while true; do curl -s http://127.0.0.1:30000/api/catalog -I | head -n 1 ; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; done while true; do curl -s http://127.0.0.1:30000/api/catalog -I | head -n 1 ; date "+%Y-%m-%d %H:%M:%S" ; sleep 0.5; echo; done ## 번외 # webapp용 virtualservice(= client에 노출되는 fe용 vs이다!)를 아래와 같이 hosts: [ "webapp" ]으로 설정하면 # client즉, local에서 127.0.0.1:30000으로 접근하면 접근이 불가하다. # 이유는 virtualservice에 의해 istio ingressgateway -> istio proxy(webapp)으로 전달 될때 host가 webapp이 아니라 127.0.0.1로 접근했기때문에 drop 된다. apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: webapp-virtualservice-2 namespace: istioinaction spec: gateways: - outfitters-gateway hosts: - webapp http: - route: - destination: host: webapp2 port: number: 8081 # 하지만, netshoot-pod에서 아래와 같이 webapp이라는 host로 해당 service에 접근하면 host rule에 의해 pass되어 정상적으로 접근되는것을 볼 수 있다. netshoot ~ curl -s http://webapp.istioinaction/api/catalog/ [{"id":1,"color":"amber","department":"Eyewear","name":"Elinor Glasses","price":"282.00"},{"id":2,"color":"cyan","department":"Clothing","name":"Atlas Shirt","price":"127.00"},{"id":3,"color":"teal","department":"Clothing","name":"Small Metal Shoes","price":"232.00"},{"id":4,"color":"red","department":"Watches","name":"Red Dragon Watch","price":"232.00"}2.6.1 Istio observability - Istio 관찰가능성‣
# NodePort 변경 및 nodeport 30001~30003으로 변경 : prometheus(30001), grafana(30002), kiali(30003), tracing(30004) kubectl patch svc -n istio-system prometheus -p '{"spec": {"type": "NodePort", "ports": [{"port": 9090, "targetPort": 9090, "nodePort": 30001}]}}' kubectl patch svc -n istio-system grafana -p '{"spec": {"type": "NodePort", "ports": [{"port": 3000, "targetPort": 3000, "nodePort": 30002}]}}' kubectl patch svc -n istio-system kiali -p '{"spec": {"type": "NodePort", "ports": [{"port": 20001, "targetPort": 20001, "nodePort": 30003}]}}' kubectl patch svc -n istio-system tracing -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 16686, "nodePort": 30004}]}}' # Prometheus 접속 : envoy, istio 메트릭 확인 open http://127.0.0.1:30001 # Grafana 접속 open http://127.0.0.1:30002 # Kiali 접속 1 : NodePort open http://127.0.0.1:30003 # (옵션) Kiali 접속 2 : Port forward kubectl port-forward deployment/kiali -n istio-system 20001:20001 & open http://127.0.0.1:20001 # tracing 접속 : 예거 트레이싱 대시보드 open http://127.0.0.1:30004그파라나 확인 : 대시보드 - Istio Service Dashboard ⇒ 상단 Service (webapp.. 선택) ← 트래픽 반복 접속 해둔 상태

오픈트레이싱을 통한 분산 트레이싱 : 예거 jaeger 트레이싱 대시보드 확인 - 가장 최근의 호출 목록과 그 호출의 분산 트레이싱 스팬 확인 가능.
- 이스티오 서비스 프록시가 서비스 간에 트레이싱 ID와 메타데이터를 전파하고 트레이싱 엔진(zipkin, jaeger)에 트레이싱 스팬 정보를 보냈다는 것만 이해하면 된다. 중요한 사실은 이 기능에 애플리케이션의 역할이 크지 않다는 점이다.
- 이스티오가 트레이스를 서비스 간에, 그리고 트레이싱 엔진에 전파할 수 있지만, 애플리케이션 내에서 트레이싱 메타데이터를 전파할 책임은 애플리케이션 자신에게 있다. 트레이싱 메타데이터는 보통 HTTP 헤더 집합으로 이뤄져 있고 들어오는 헤더와 나가는 요청을 연관시키는 것은 애플리케이션에게 달려 있다. 달리 말하면, 이스티오는 특정 서비스나 애플리케이션 내에서 무슨 일이 일어나는지 알 수 없으므로, 드나드는 요청이 어떻게 연결되는지(인과 관계)를 알 수 없다.
- 인과 관계를 알고 내보내는 요청에 헤더를 적절히 주입하는 것은 애플리케이션의 역할이다. 이스티오는 그 이후부터 해당 스팬들을 포착해 트레이싱 엔진으로 보낼 수 있다.


kiali 확인 : 메트릭(프로메테우스)과 트레이싱(zipkin, jaeger, tempo)을 수집하여 해당 정보를 기반으로 시각화!
- By default, Kiali assumes that Prometheus is available at the URL of the form
http://prometheus.<istio_namespace_name>:9090- Docs - By default, Kiali will try to reach Jaeger at the GRPC-enabled URL of the form
http://tracing.<istio_namespace_name>:16685/jaeger- Docs - Namespace 를 istioincation 로 선택 후 Graph (Traffic, Versioned app graph) 에서 Display 옵션 중 ‘Traffic Distribution’ 과 ‘Traffic Animation’ 활성화! , Service nods, Security 체크 해보자 (Last 1m, Evety 10s)
2.6.2 Istio for resiliency - catalog에 의도적으로 500에러를 재현하고 retry로 복원력 높이기‣만약 ‘간헐적/일시적 네트워크 오류’가 발생하여 webapp 은 catalog 요청 실패이 실패하는 경우가 발생 시, 애플리케이션 코드 수정 없이 복원력을 높여보자!
bin/chaos.sh {에러코드} {빈도} -‣chaos.sh 500 50(500에러를 50% 빈도로 재현)# docker exec -it myk8s-control-plane bash ---------------------------------------- # istioinaction 로 네임스페이스 변경 cat /etc/kubernetes/admin.conf kubectl config set-context $(kubectl config current-context) --namespace=istioinaction cat /etc/kubernetes/admin.conf cd /istiobook/bin/ ./chaos.sh 500 100 # 모니터링 : kiali, grafana, tracing ./chaos.sh 500 50 # 모니터링 : kiali, grafana, tracing kubectl config set-context $(kubectl config current-context) --namespace=default cat /etc/kubernetes/admin.conf ----------------------------------------

Tags 에 error=true 필터링Kiali 대시보드 - red (Error) / blue (total req.)

에러 발생 시 reslience 하게 retry 하도록 애플리케이션 코드 수정 없이 해보기!
Resiliency 하게 해보자 ⇒ proxy(envoy)에 endpoint(catalog) 5xx 에러 시 retry 적용
# catalog 3번까지 요청 재시도 할 수 있고, 각 시도에는 2초의 제한 시간이 있음. cat <<EOF | kubectl -n istioinaction apply -f - apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: catalog spec: hosts: - catalog http: - route: - destination: host: catalog retries: attempts: 3 retryOn: 5xx perTryTimeout: 2s EOF kubectl get vs -n istioinaction NAME GATEWAYS HOSTS AGE catalog ["catalog"] 5s webapp-virtualservice ["outfitters-gateway"] ["*"] 24m결과적으로 client 에 응답 성공율이 높아졌다!

그라파나 (Istio Mesh Dashboard) : retry 적용 후 Success Rate은 증가하고 5xx 에러는 감소하는 것을 확인할 수 있습니다
2.6.3 Istio for Traffic Routing - 새 기능 추가 시나리오 대응‣
특정 사용자 집단만 새 배포로 라우팅하도록, 릴리즈에 단계적 접근 : catalog v2 에 imageUrl 새 속성 추가
# catalog v2 배포 cat <<EOF | kubectl -n istioinaction apply -f - apiVersion: apps/v1 kind: Deployment metadata: labels: app: catalog version: v2 name: catalog-v2 spec: replicas: 1 selector: matchLabels: app: catalog version: v2 template: metadata: labels: app: catalog version: v2 spec: containers: - env: - name: KUBERNETES_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: SHOW_IMAGE value: "true" image: istioinaction/catalog:latest imagePullPolicy: IfNotPresent name: catalog ports: - containerPort: 3000 name: http protocol: TCP securityContext: privileged: false EOF # (옵션) 500 에러 발생 꺼두기 docker exec -it myk8s-control-plane bash ---------------------------------------- cd /istiobook/bin/ ./chaos.sh 500 delete exit ---------------------------------------- # kubectl get deploy,pod,svc,ep -n istioinaction kubectl get gw,vs -n istioinaction # v1, v2 catalog pod가 존재하고 kubectl get po -n istioinaction -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES catalog-6cf4b97d-d5xbt 2/2 Running 0 43m 10.10.0.13 myk8s-control-plane <none> <none> catalog-v2-6df885b555-pdcts 2/2 Running 0 103s 10.10.0.16 myk8s-control-plane <none> <none> # catalog service는 rb로 v1, v2 catalog pod로 접근 kubectl get ep -n istioinaction NAME ENDPOINTS AGE endpoints/catalog 10.10.0.13:3000,10.10.0.16:3000 42m endpoints/webapp 10.10.0.14:8080 42m # 반복 접속 종료해두기

v1만 접속 설정
# host가 catalog인 service에 대해서 destinationrule 설정 # version-1 subset은 v1 catalog로 version-2라는 subset은 v2 catalog로 cat <<EOF | kubectl -n istioinaction apply -f - apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: catalog spec: host: catalog subsets: - name: version-v1 labels: version: v1 - name: version-v2 labels: version: v2 EOF # kubectl get gw,vs,dr -n istioinaction # 반복 접속 : v1,v2 분산 접속 확인 while true; do curl -s http://127.0.0.1:30000/api/catalog | jq; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; done # v1 라우팅 VS 수정(업데이트) cat <<EOF | kubectl -n istioinaction apply -f - apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: catalog spec: hosts: - catalog http: - route: - destination: host: catalog subset: version-v1 EOF # 반복 접속 : v1 접속 확인 # image url이 없는 v1로만 traffic이 흐른것을 볼 수 있다. while true; do curl -s http://127.0.0.1:30000/api/catalog | jq; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; done 2025-04-12 01:15:38 [ { "id": 1, "color": "amber", "department": "Eyewear", "name": "Elinor Glasses", "price": "282.00" }, { "id": 2, "color": "cyan", "department": "Clothing", "name": "Atlas Shirt", "price": "127.00" }, { "id": 3, "color": "teal", "department": "Clothing", "name": "Small Metal Shoes", "price": "232.00" }, { "id": 4, "color": "red", "department": "Watches", "name": "Red Dragon Watch", "price": "232.00" } ] ...
특정 헤더는 v2, 그외에는 v1 접속 설정
# 라우팅 VS 수정(업데이트) cat <<EOF | kubectl -n istioinaction apply -f - apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: catalog spec: hosts: - catalog http: - match: - headers: x-dark-launch: exact: "v2" route: - destination: host: catalog subset: version-v2 - route: - destination: host: catalog subset: version-v1 EOF # kubectl get gw,vs,dr -n istioinaction # 반복 접속 : v1 접속 확인 while true; do curl -s http://127.0.0.1:30000/api/catalog | jq; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; done # 반복 접속 : v2 접속 확인 while true; do curl -s http://127.0.0.1:30000/api/catalog -H "x-dark-launch: v2" | jq; date "+%Y-%m-%d %H:%M:%S" ; sleep 1; echo; done # 다시 roundrobin(50:50)으로 routing되도록 vs 수정 # subset을 삭제하면 원래대로 rb로 v1, v2 반복 접속 됨 cat <<EOF | kubectl -n istioinaction apply -f - apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: catalog spec: hosts: - catalog http: - route: - destination: host: catalog- Istio 최신 버전 실습
- 실습 환경 : docker (kind - k8s 1.32.2) , istio 1.25.1
3.1. kind : k8s(1.23.17) 배포‣# kind create cluster --name myk8s --image kindest/node:v1.32.2 --config - <<EOF kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane extraPortMappings: - containerPort: 30000 # Sample Application hostPort: 30000 - containerPort: 30001 # Prometheus hostPort: 30001 - containerPort: 30002 # Grafana hostPort: 30002 - containerPort: 30003 # Kiali hostPort: 30003 - containerPort: 30004 # Tracing hostPort: 30004 - containerPort: 30005 # kube-ops-view hostPort: 30005 networking: podSubnet: 10.10.0.0/16 serviceSubnet: 10.200.1.0/24 EOF # 설치 확인 docker ps # 노드에 기본 툴 설치 docker exec -it myk8s-control-plane sh -c 'apt update && apt install tree psmisc lsof wget bridge-utils net-tools dnsutils tcpdump ngrep iputils-ping git vim -y'(옵션) 편의성 툴 설치‣# (옵션) kube-ops-view helm repo add geek-cookbook https://geek-cookbook.github.io/charts/ helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set service.main.type=NodePort,service.main.ports.http.nodePort=30005 --set env.TZ="Asia/Seoul" --namespace kube-system kubectl get deploy,pod,svc,ep -n kube-system -l app.kubernetes.io/instance=kube-ops-view ## kube-ops-view 접속 URL 확인 open "http://localhost:30005/#scale=1.5" open "http://localhost:30005/#scale=1.3" # (옵션) metrics-server helm repo add metrics-server https://kubernetes-sigs.github.io/metrics-server/ helm install metrics-server metrics-server/metrics-server --set 'args[0]=--kubelet-insecure-tls' -n kube-system kubectl get all -n kube-system -l app.kubernetes.io/instance=metrics-server3.2. istio 1.25.1 설치 - GettingStarted , install , profile , brew , Github‣방법 1 : mac‣brew install istioctl istioctl version --remote=false # export ISTIOV=1.25.1 curl -s -L https://istio.io/downloadIstio | ISTIO_VERSION=$ISTIOV sh - # 샘플 코드 확인 cd istio-$ISTIOV tree code . # default 프로파일 배포 cat <<EOF | istioctl install -y -f - apiVersion: install.istio.io/v1alpha1 kind: IstioOperator spec: profile: demo components: ingressGateways: - name: istio-ingressgateway enabled: true egressGateways: - name: istio-egressgateway enabled: false EOF방법 2 : Linux os WSL2 (Ubuntu)‣공통 설정 : addon 등 설치‣# 설치 확인 : istiod(데몬, 컨트롤플레인), istio-ingressgateway, crd 등 kubectl get all,svc,ep,sa,cm,secret,pdb -n istio-system kubectl get crd | grep istio.io | sort # istio-ingressgateway 서비스 NodePort 변경 및 nodeport 30000로 지정 변경 kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 8080, "nodePort": 30000}]}}' kubectl get svc -n istio-system istio-ingressgateway # istio-ingressgateway 서비스 externalTrafficPolicy 설정 : ClientIP 수집 확인 용도 # externalTrafficPolicy: Local이면, node1의 nodeport로 들어온 request는 node1의 pod로 가도록 iptables rule이 설정된다. node2의 nodeport로 들어오면 node2의 pod로 routing됨. kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec":{"externalTrafficPolicy": "Local"}}' kubectl describe svc -n istio-system istio-ingressgateway # default 네임스페이스에 istio-proxy sidecar 주입 설정 - Docs kubectl label namespace default istio-injection=enabled kubectl get ns --show-labels # addon 설치 kubectl apply -f samples/addons kubectl rollout status deployment/kiali -n istio-system # kubectl get pod,svc -n istio-system # NodePort 변경 및 nodeport 30001~30003으로 변경 : prometheus(30001), grafana(30002), kiali(30003), tracing(30004) kubectl patch svc -n istio-system prometheus -p '{"spec": {"type": "NodePort", "ports": [{"port": 9090, "targetPort": 9090, "nodePort": 30001}]}}' kubectl patch svc -n istio-system grafana -p '{"spec": {"type": "NodePort", "ports": [{"port": 3000, "targetPort": 3000, "nodePort": 30002}]}}' kubectl patch svc -n istio-system kiali -p '{"spec": {"type": "NodePort", "ports": [{"port": 20001, "targetPort": 20001, "nodePort": 30003}]}}' kubectl patch svc -n istio-system tracing -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 16686, "nodePort": 30004}]}}' # Prometheus 접속 : envoy, istio 메트릭 확인 open http://127.0.0.1:30001 # Grafana 접속 open http://127.0.0.1:30002 # Kiali 접속 1 : NodePort open http://127.0.0.1:30003 # (옵션) Kiali 접속 2 : Port forward kubectl port-forward deployment/kiali -n istio-system 20001:20001 & open http://127.0.0.1:20001 # tracing 접속 : 예거 트레이싱 대시보드 open http://127.0.0.1:300043.3. Bookinfo sample application 배포 - Docs‣# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml # 확인 : 서비스 어카운트(sa)는 spiffe 에 svid 에 사용됨 kubectl get all,sa # product 웹 접속 확인 kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>" # productpage 파드 로그 kubectl logs -l app=productpage -c istio-proxy --tail=-1 kubectl logs -l app=productpage -c productpage -f3.4. Open the application to outside traffic‣# 현재 cluster에 배포되어있는 istio-ingressgateway pod 정보 # label에 istio=ingressgateway 설정이 되어있다. # 이후에 istio ingressgateway 생성시 해당 label을 selector로 등록해서 생성하면 해당 Ingressgateway pod(=use istio default controller)가 traffic을 받아 routing 한다. # Gateway는 VirtualService에 등록된 .spec.http[].match 및 .spec.http[].route 설정대로 traffic을 routing 한다. kubectl describe po -n istio-system istio-ingressgateway-7ffc97b8c6-qqjvs Name: istio-ingressgateway-7ffc97b8c6-qqjvs Namespace: istio-system Priority: 0 Service Account: istio-ingressgateway-service-account Node: myk8s-control-plane/172.19.0.2 Start Time: Sat, 12 Apr 2025 21:16:19 +0900 Labels: app=istio-ingressgateway app.kubernetes.io/instance=istio app.kubernetes.io/managed-by=Helm app.kubernetes.io/name=istio-ingressgateway app.kubernetes.io/part-of=istio app.kubernetes.io/version=1.0.0 chart=gateways helm.sh/chart=istio-ingress-1.0.0 heritage=Tiller install.operator.istio.io/owning-resource=unknown istio=ingressgateway istio.io/dataplane-mode=none istio.io/rev=default operator.istio.io/component=IngressGateways pod-template-hash=7ffc97b8c6 release=istio service.istio.io/canonical-name=istio-ingressgateway service.istio.io/canonical-revision=latest sidecar.istio.io/inject=false ... # Istio Gateway/VirtualService 설정 # default istio controller(pod)를 사용하는 bookinfo-gateway와 해당 gateway와 mapping되는 bookinfo virtualservice 생성 # bookinfo virtualservice는 모든 match되는 rule에 대해서 productpage service로 traffic을 routing 한다. cat samples/bookinfo/networking/bookinfo-gateway.yaml apiVersion: networking.istio.io/v1 kind: Gateway metadata: name: bookinfo-gateway spec: # The selector matches the ingress gateway pod labels. # If you installed Istio using Helm following the standard documentation, this would be "istio=ingress" selector: istio: ingressgateway # use istio default controller servers: - port: number: 8080 name: http protocol: HTTP hosts: - "*" --- apiVersion: networking.istio.io/v1 kind: VirtualService metadata: name: bookinfo spec: hosts: - "*" gateways: - bookinfo-gateway http: - match: - uri: exact: /productpage - uri: prefix: /static - uri: exact: /login - uri: exact: /logout - uri: prefix: /api/v1/products route: - destination: host: productpage port: number: 9080 kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml # Istio Gateway/VirtualService 설정 확인 kubectl get gw,vs istioctl proxy-status # productpage 파드의 istio-proxy 로그 확인 Access log 가 출력 - Default access log format : 링크 kubectl logs -l app=productpage -c istio-proxy -f kubectl stern -l app=productpage # productpage 웹 접속 : 새로고침 open http://127.0.0.1:30000/productpage curl -v -s http://127.0.0.1:30000/productpage | grep -o "<title>.*</title>" # 반복 접속 for i in {1..10}; do curl -s http://127.0.0.1:30000/productpage | grep -o "<title>.*</title>" ; done for i in {1..100}; do curl -s http://127.0.0.1:30000/productpage | grep -o "<title>.*</title>" ; done while true; do curl -s http://127.0.0.1:30000/productpage | grep -o "<title>.*</title>" ; echo "--------------" ; sleep 1; done while true; do curl -s http://127.0.0.1:30000/productpage | grep -o "<title>.*</title>" ; echo "--------------" ; sleep 0.5; done while true; do curl -s http://127.0.0.1:30000/productpage | grep -o "<title>.*</title>" ; echo "--------------" ; sleep 0.1; done
- versioned app graph로 변경
- display: Traffic Rate, Traffic Animation, Security enable 하기
위의 결과에서 보면 reviews가 v1, v2, v3 새가지 버전이 있다. 그리고 kiali의 traffic graph를 보면 roundrobin하게 균등하게 traffic이 흐르는것을 볼 수 있다.
이는 현재 review service에 대한 virtualservice가 설정되어있지 않고 productpage에서 review로 service(ex> http://review:9080)를 통해서 통신하기 때문에 service의 기본 설정대로 iptables에 33:33:33으로 설정되어 균등하게 v1, v2, v3으로 traffic이 분산되기 때문이다.
그럼 review에 대한 virtualservice 설정을 통해 traffic 흐름을 살펴보자!
# destination-rule-reviews.yaml # destinationrule을 통해서 reviews service에 mapping된 upstream pod들에 대해서 lable별로 subsets을 설정 할 수 있다. # 이를 통해서 VirtualService에서 해당 subset name을 통해서 routing을 설정 할 수 있다. apiVersion: networking.istio.io/v1 kind: DestinationRule metadata: name: reviews spec: host: reviews trafficPolicy: loadBalancer: simple: RANDOM subsets: - name: v1 # subset.name=v1 reviews-v1 pod를 subset으로 등록 labels: version: v1 - name: v2 # subset.name=v2 reviews-v2 pod를 subset으로 등록 labels: version: v2 - name: v3 # subset.name=v3 reviews-v3 pod를 subset으로 등록 labels: version: v3 # virtual-service-reviews-50-v3.yaml # productpage -> reviews v1에 50% / productpage -> reviews v3에 50% traffic을 보냄 # productpage -> reviews v2에는 0% 즉 traffic이 안흐름 apiVersion: networking.istio.io/v1 kind: VirtualService metadata: name: reviews spec: hosts: - reviews http: - route: - destination: host: reviews subset: v1 weight: 50 - destination: host: reviews subset: v3 weight: 50
이전에 reviews에 대한 DestinationRule과 VirtualService없이 default로 productpage → reviews로의 traffic 흐름과 달리 reviews v2에는 전혀 traffic이 흐르지 않아서 versioned app graph상에서 삭제 된것을 볼 수 있다.
이번에는 특정 header 기반으로 routing하도록 VirtualService를 설정해보자!
# virtual-service-review-jason-v2-v3.yaml # http header에 end-user: jason이라는 header를 포함하고 있으면 reviews-v2 pod로 # 나머지는 reviews-v3로 routing 하도록 설정한다. # DestinationRule은 위에 이미 설정했다! apiVersion: networking.istio.io/v1 kind: VirtualService metadata: name: reviews spec: hosts: - reviews http: - match: - headers: # header가 end-user: jason이면 end-user: exact: jason route: - destination: host: reviews subset: v2 # review-v2로 routing - route: - destination: host: reviews subset: v3현재 위에서 아래와 같이 while문을 통해서 productpage web으로 반복접근 중이고, 해당 request는 아무 http header를 포함하고 있지 않기 때문에 kiali versioned app graph상에는 reviews-v3으로만 traffic이 흐르는것으로 보인다!
while true; do curl -s http://127.0.0.1:30000/productpage | grep -o "<title>.*</title>" ; echo "--------------" ; sleep 1; done
# netshoot pod 접속 kubectl exec -it netshoot -- zsh # 반복 접속 : v2 접속 확인 netshoot ~ while true; do curl -s http://reviews:9080/reviews/0 -H "end-user: jason" | jq .; echo "--------------" ; sleep 1; done
기존에 productpage로 향하던 반복 요청을 중단하고 netshoot pod에서 “end-user: jason” http header를 담아서 reviews service에 직접 요청하면 위와 같이 모든 request가 reviews-v2 pod로 가는것을 확인 할 수 있다!
(참고) istio-ingressgateway 에 istio-proxy 에도 로깅 변경 해보자‣kubectl exec -it deploy/istio-ingressgateway -n istio-system -- curl -X POST http://localhost:15000/logging kubectl exec -it deploy/istio-ingressgateway -n istio-system -- curl -X POST http://localhost:15000/logging?http=debug kubectl exec -it deploy/istio-ingressgateway -n istio-system -- curl -X POST http://localhost:15000/logging?http=info(참고) istio-proxy 파드에 envoy 컨테이너 admin 페이지 접속‣# istio-proxy 파드에 envoy 컨테이너 admin 접속 포트 포워딩 설정 kubectl port-forward deployment/deploy-websrv 15000:15000 & # envoy 컨테이너 admin 페이지 접속 open http://localhost:15000'Kubernetes' 카테고리의 다른 글
[IHOS 1기] 6주차 - 운영, 튜닝 (1) 2025.05.18 [IHOS 1기] 5주차 - 마이크로서비스 통신 보안 (1) 2025.05.11 [IHOS 1기] 4주차 - Observability (1) 2025.05.03 [IHOS 1기] 3주차 - Traffic control, Resilience (0) 2025.04.27 [IHOS 1기] 2주차 - Envoy, IstioGateway (0) 2025.04.19




















