ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [IHOS 1기] 1주차 - Istio소개, 첫걸음
    Kubernetes 2025. 4. 12. 21:03
    • Service Mesh 소개
    1.1 속도를 높이며 마주하는 문제들
    ACME 회사 K8S 도입 사례
    image
    • 문제 발생
      • 서비스들의 요청 처리 시간이 매우 불규칙
      • 배포를 자동화할 때 자동화된 테스트에서 잡히지 않은 버그가 발생
      • 팀 별 다른 보안 정책 사용 : A팀(인증서, 개인 키), B팀(토큰, 서명 검증), C팀(방화벽 뒷단으로 별도 보안 없음)
    • 해결 필요점 도출
      • 장애가 격리 경계를 넘어 확산하는 것을 방지
      • 환경 변화에 대응할 수 있는 애플리케이션/서비스 구축
      • 부분적 장애 상태에서도 동작할 수 있는 시스템 구축
      • 끊임없이 변화하고 발전하는 전체 시스템의 상태 파악
      • 시스템의 런타임 동작을 제어할 수 없는 문제
      • 공격 표면이 커짐에 따라 강력한 보안 구현하기
      • 시스템 변경의 위험성 낮추기
      • 시스템의 구성 요소를 누가(무엇이) /언제 사용할 수 있는지 정책 강제
     
    1.1.1 클라우드 인프라는 신뢰할 수 없다
      • 클라우드에서는 인프라가 일시적이며 간혹 사용할 수 없다는 가정 아래 앱을 구축해야 한다. 이런 일시성은 아키텍처에서 미리 고려해야 한다.
      • 예를 들어, 고객 선호도를 관리하는 추천 서비스가 고객 서비스를 호출한다고 해보자.
      • 아래 그림에서 추천 서비스는 고객 서비스를 호출해 일부 고객 데이터를 업데이트 하는데, 메시지를 보낼 때 극심한 성능 저하를 경험한다.
      • 이런 성능 정하는 어떤 영향을 미치는가?
      • 의존하는 다운스트림이 느리면 추천 서비스가 실패해 연쇄 장애를 야기하는 등 혼란을 일으킬 수 있다.
      • 이 시나리오는 여러 이유로 일어날 수 있다.
    image
        1. 고객 서비스가 과부화돼 실행 속도가 느리다.
        2. 고객 서비스에 버그가 있다.
        3. 네트워크 방화벽이 트래픽을 느리게 한다.
        4. 네트워크가 혼잡해 트래픽이 느려지고 있다.
        5. 네트워크에 하드웨어 오류가 발생해 트래픽을 다시 라우팅하고 있다.
        6. 고객 서비스의 네트워크 카드 하드웨어에 오류가 발생했다.
     
    • 문제는 이것이 고객 서비스의 장애인지 여부를 추천 서비스가 구분할 수 없다는 것이다.
    • 다시 말하지만, 하드웨어 및 소프트웨어 구성 요소가 수백만 개에 달하는 클라우드 환경에서 이런 시나리오는 항상 일어난다.
     
    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 와 같은 유사 패키지를 찾아볼 수 도 있다.
        • 그러고는 도입하려는 언어를 알아보고, 입증하고, 개발 스택에 도입해야 한다.
        • 이들 라이브러리 각각은 전제와 구현이 다를 것이다.
        • 어떤 경우에는 각 프레임워크/언어 조합에 상응하는 유사 대체품을 찾지 못할 수도 있다.
        • 결국 어떤 언어에서는 부분적으로 구현하게 돼 전반적으로 구현이 일괄적이지 않을 수 있는데, 이는 장애 시나리오에서 원인을 추론하기 어렵게 만들어 장애를 숨기거나 확산시키는 원인이 될 수 있다.
        • 아래 그림은 서비스가 애플리케이션 네트워킹 관리 목적으로 동일한 라이브러리 집합을 구현하는 모습을 보여준다.
    image
     
    • 새로운 도전 과제 3
      • 여러 프로그래밍 언어와 프레임워크에서 라이브러리를 소수로 유지하려면 많은 훈련이 필요하며 제대로 하기가 매우 어렵다.
      • 핵심은 모두 구현이 일관되고 올바르다는 점을 보장하는 것이다.
      • 하나의 차이만으로도 시스템의 예측 불가능성이 늘어난다.
      • 동시에 여러 서비스에 업데이트를 수행하는 것도 벅찬 일이 될 수 있다.
      • 클라우드 아키텍처에서는 애플리케이션 네트워킹을 분산하는 것이 낫지만, 그로 인해 늘어나는 시스템의 제약과 운영 부담은 대부분의 조직에서 감당하기 어려울 것이다.
      • 설령 도전에 나선다고 해도 올바르게 수행하기는 더욱 어렵다.
      • 애플리케이션을 임베디드 라이브러리로 유지 관리하고 운영하는 데 막대한 오버헤드 비용을 치르지 않고도 분산화의 이점을 누릴 수 있는 방법이 있다면 어떨까?
     
     
    1.3 이런 관심사(애플리케이션 네트워킹)를 인프라에 전가하기
    들어가기
      • 이런 기본적인 애플리케이션 네트워킹 문제는 특정 애플리케이션, 언어, 프레임워크만의 전유물이 아니다.
      • 재시도, 타임아웃, 클라이언트 측 로드 밸런싱, 서킷 브레이킹 등이 애플리케이션 기능을 차별화하는 것도 아니다
      • 이들이 서비스의 일부로 고려해야 하는 대단히 중요한 과제인 것은 맞지만, 사용하기로 한 모든 언어마다 구현하려고 막대한 시간과 자원을 투자하는 것은 시간 낭비다.
    https://istio.io/latest/docs/examples/bookinfo/
    • 우리가 진정으로 원하는 점은 이런 과제를 구현해 애플리케이션이 자체적으로 처리해야 하는 부담을 덜어주면서도 기술에 구애받지 않는 방법이다.
     
    1.3.1 애플케이션 인식 서비스 프록시
      • 프록시를 사용하는 것은 이런 관심사를 인프라로 옮기는 방법 중 하나다.
      • 프록시커넥션을 다룰 수 있고 적절한 백엔드로 리다이렉트할 수 있는 중간 인프라 구성 요소다.
      • 필요한 것은 애플리케이션을 인식할 수 있고 서비스를 대신해 애플리케이션 네트워킹을 수행할 수 있는 프록시다.
    image
     
    • 그렇게 하려면 서비스 프록시는 커넥션과 패킷을 이해하는 전통적 인프라 프록시와 달리 메시지와 요청 같은 애플리케이션 구조를 이해해야 한다.
    • 7계층 프록시가 필요하다.
     
    1.3.2 엔보이 프록시 만나기
      • 엔보이 Envoy 는 오픈소스 애플리케이션 수준 프록시이다.
      • 리프트에서 SOA 인프라의 일부로 개발됐으며, 언어나 프레임워크에 명시적 의존성 없이도 재시도, 타임아웃, 서킷 브레이커, 클라이언트 측 로드 밸런싱, 서비스 디스커버리, 보안, 메트릭 수집 등의 네트워크 관심사를 구현할 수 있다.
      • 아래 그림에서 보듯이 엔보이는 이 모든 것을 애플리케이션 프로세스 외부에서 구현한다.
    image
     
      • 엔보이의 힘은 이런 애플리케이션 계층의 복원력 측면에서만 국한되지 않는다. 엔보이는 또한 초당 요청 수, 실패 횟수, 서킷 브레이커 이벤트와 같은 여려 애플리케이션 네트워킹 메트릭을 수집한다.
      • 엔보이를 사용하면 서비스 간에 어떤 일이 일어나고 있는지 자동으로 알 수 있게 되는데, 바로 여기가 예상치 못한 복잡성을 많이 발견하는 되는 곳이다.
      • 엔보이 프록시 서비스 아키텍처에서 공통적인 서비스 간 신뢰성과 관찰 가능성 문제를 해결 할 수 있는 기반이여, 이 기반을 토대로 이런 문제를 애플리케이션에서 인프라로 이동시킬수 있다.
     
      • 애플리케이션과 함께 서비스 프록시를 배포해 애플리케이션 외부에서 이런 기능들을 얻을 수 있지만, 세부적으로는 애플리케이션마다 다를 수 있다.
      • 아래 그림은 이 모델에서 애플리케이션이 시스템의 다른 부분과 통신하는 방법을 보여주는데, 요청을 엔보이로 먼저 보내고 나서 엔보이가 업스트림으로의 통신을 처리한다.
    image
     
    • 또한 서비스 프록시는 분산 트레이싱 스팬 span을 수집해 특정 요청이 수행한 모든 단계를 연결할 수 있으며, 각 단계의 소요 시간을 확인하고 시스템의 잠재적인 병목 현상이나 버그를 찾아 낼 수 있다.
    • 모든 애플리케이션이 자신의 프록시를 거쳐 외부 세계와 대화하고 애플리케이션으로 들어오는 모든 트래픽이 프록시를 거치면, 애플리케이션 코드를 한 줄도 바꾸지 않고 애플리케이션에 대한 중요한 기능을 얻을 수 있다.
    • 이 프록시+애플리케이션 조합이 서비스 메시로 알려진 통신 버스의 토대가 된다.
     
      • 엔보이 같은 서비스 프록시는 애플리케이션의 모든 인스턴스와 함께 단일 최소 단위 single atomic unit 로 배포할 수 있다.
      • 예를 들어 쿠버네티스에서는 서비스 프록시와 애플리케이션 단일 파드로 함께 배포할 수 있다.
      • 아래 그림은 메인 애플리케이션 인스턴스를 보완하기 위해 프록시를 배포하는 사이드카 배포 패턴을 그리고 있다.
    image
     
     
     
    1.4 서비스 메시란 무엇인가?

    들어가기

    • 엔보이 같은 서비스 프록시는 클라우드 환경에서 동작하는 서비스 아키텍처에 중요한 기능을 추가하는 데 도움이 된다.
    • 각 애플리케이션은 워크로드 목표를 감안해 프록시 동작 방식에 대해 자신만의 요구 사항이나 설정을 가질 수 있다.
    • 애플리케이션과 서비스 수가 늘어남에 따라 많은 프록시를 설정하고 관리하는 것이 어려움 수 있다.
    • 또한 각 애플리케이션 인스턴스에 프록시를 배치하면, 원래는 애플리케이션 스스로가 수행했어야 하는 흥미로운 고급 기능을 구축할 기회가 생긴다.
     

    서비스 메시

      • 서비스 메시란 애플리케이션 대신 프로세스 외부에서 투명하게 네트워크 트래픽을 처리하는 분산형 애플리케이션 인프라를 말한다.
      • 아래 그림은 서비스 프록시가 데이터 플레인을 형성하는 방식을 보여준다. 데이터 플레인은 모든 트래픽을 처리하고 관찰하는 곳이다.
    https://kimdoky.github.io/devops/2025/04/10/study-istio-week1/
    image
     
    • 데이터 플레인은 메시를 거쳐가는 트래픽을 설정하고 보호하고 제어하는 책임을 맡는다.
    • 데이터 플레인의 동작은 컨트롤 플레인이 설정한다.
    • 컨트롤 플레인은 메시의 두뇌로, 운영자가 네트워크 동작을 조작할 수 있도록 API를 노출한다.
    • 데이터 플레인과 컨트롤 플레인이 모여 모든 클라우드 네트워크 아키텍처에 필요한 다음과 같은 중요 기능을 제공한다.
      • 서비스 복원력
      • 관찰 가능성 신호
      • 트래픽 제어 기능
      • 보안
      • 정책 강제 Policy enforcement
     

    기능

    • 서비스 메시는 재시도, 타임아웃, 서킷 브레이커 같은 기능을 구현해 서비스 통신이 장애에 복원력을 갖추게 만들 책임을 맡는다.
    • 또한 서비스 디스커버리, 적응형 및 영역 인식 zone-aware 로드 밸런싱, 헬스 체크 같은 기능을 처리함으로써 변화하는 인프라 토폴로지를 처리할 수도 있다.
    • 모든 트래픽이 메시를 통과하므로 운영자는 트래픽을 명시적으로 제어하고 지시할 수 있다.
    • 트래픽이 메시를 통과하므로 요청 급증, 지연 시간, 처리량, 장애 등과 같은 메트릭을 추적함으로써 네트워크 동작에 대한 상세한 신호를 포착할 수 있다.
    • 텔레메트리 telemetry 를 활용해 시스템에서 어떤 일이 일어나고 있는지 그려낼 수 있다.
    • 마지막으로, 서비스 메시가 애플리케이션 간 네트워크 통신의 양쪽 끝을 제어하므로 상호 인증을 사용한 전송 계층 암호화 같은 강력한 보안을 적용할 수 있다.
    • 구체적으로는 TLS 프로토콜을 사용할 수 있다.
     

    정리

    • 서비스 메시는 이 모든 기능을 애플리케이션 코드 변경이나 의존성 추가를 거의(혹은 전혀) 하지 않고도 서비스 운영자에게 제공한다.
    • 일부 기능에서는 애플리케이션 코드와 약간의 협업이 필요하지만, 크고 복잡한 라이브러리 의존성을 피할 수 있다.
    • 서비스 메시를 사용하면 애플리케이션을 구축하는 데 어떤 애플리케이션 프레임워크나 프로그래밍 언어를 사용했든지 상관없이 이런한 기능들이 일관되고 정확하게 구현되므로, 서비스 팀이 변화를 구현해 전달할 때 빠르고 안전하며 자신감 있게 움직일 수 있게 된다.
     
    1.5 이스티오 서비스 메시 소개
    들어가며 : 이스티오 istio 는 그리스어로 ‘돛’을 의미하며, k8s 항해 용어들과 잘 어울림.
    • 이스티오는 서비스 메시의 오픈소스 구현체이며 구글, IBM, 리프트가 주도했다.
    • 이스티오는 서비스 아키텍처에 복원력과 관찰 가능성투명한 방식으로 추가하는 데 도움이 된다.
    • 이스티오를 사용하면 애플리케이션은 자신이 서비스 메시의 일부임을 인지하지 않아도 된다.
    • 애플리케이션이 외부 세계와 의사소통할 때는 항상 이스티오가 애플리케이션 대신 네트워킹을 처리하기 때문이다.
    • 이스티오의 데이터 플레인은 엔보이 프록시를 사용하며, 서비스 프록시 인스턴스가 함께 배포되도록 애플리케이션을 구성하는 데 도움이 된다.
    • 이스티오의 컨트롤 플에인은 최종 사용자/운영자용 API, 프록시용 설정 API, 보안 설정, 정책 선언 등을 제공하는 몇 가지 구성 요소로 이뤄져 있다.
    • 이스티오는 본래 쿠버네티스에서 실행할 목적으로 구축됐지만, 배포 플랫폼에 구애받지 않는 관점으로 작성됐다.
    • 즉, 쿠버네티스, 오픈시프트와 같은 배포 플랫폼은 물론, 가상머신 같은 기존 배포 환경에서도 이스티오 기반 서비스 메시를 사용할 수 있다.
     
      • 각 애플리케이션 인스턴스 옆에 서비스 프록시가 있으면 애플리케이션은 더 이상 서킷 브레이커, 시간 초과, 재시도, 서비스 디스커버리, 로드 밸런싱 등을 위해 언어별 복원력 라이브러리가 필요하지 않다.
      • 또한 서비스 프록시는 메트릭 수집, 분산 트레이싱, 접근 제어도 처리한다.
      • 서비스 메시의 트래픽이 이스티오 서비스 프록시를 거쳐 흐르는 덕분에 이스티오는 각 애플리케이션에서 네트워킹 동작에 영향을 주고 지시할 수 있는 제어 지점을 가진다.
      • 이를 통해 운영자는 트래픽 흐름을 제어하고 카나리 릴리즈, 다크 런치, 단계적 롤아웃, A/B 스타일 테스트와 같은 세밀한 릴리즈를 구현할 수 있다.
    https://kimdoky.github.io/devops/2025/04/10/study-istio-week1/
        1. 트래픽은 이스티오 인그레스 게이트웨이를 통해 메시 외부의 클라이언트에서 클러스터로 들어온다.
        2. 트래픽이 쇼핑 카트 서비스로 이동한다. 트래픽은 먼저 해당 서비스 프록시를 통과한다.
          • 서비스 프록시는 서비스에 타임아웃, 메트릭 수집, 보안 강제 등을 적용할 수 있다.
        3. 요청이 다양한 서비스를 거치므로, 이스티오의 서비스 프록시는 다양한 단계에서 요청을 가로채고 라우팅 결정을 내릴 수 있다.
        4. 이스티오의 컨트롤 플레인 istiod 는 라우팅, 보안, 텔레메트릭 수집, 복원력을 처리하는 이스티오 프록시를 설정하는 데 사용한다.
        5. 요청 메트릭은 주기적으로 다양한 수집 서비스로 전송된다. 분산 트레이싱 스팬은 트레이싱 저장소로 전송돼 시스템을 거치는 요청의 경로 및 지연 시간을 추후에 추적하는 용도로 사용할 수 있다.
     
      • 어떤 서비스 기반 아키텍처에서도 중요한 요구 사항은 보안이다. 이스티오는 기본적으로 보안이 활성화돼 있다.
      • 이스티오가 애플리케이션 네트워킹 경로의 양 끝단을 제어하는 덕분에 기본적으로 트래픽을 투명하게 암호화 할 수 있다.
      • 이스티오는 서비스가 mTLS를 바로 사용할 수 있도록 키 및 인증서 발급, 설치, 로테이션을 관리할 수 있다.
      • 이스티오는 워크로드에 ID를 부여하고 이를 인증서에 포함시킬 수 있다. 또한 ID를 사용해 강력한 접근 제어 정책을 구현할 수 있다.
     
      • 마지막으로, 이스티오를 사용하면 할당량, 속도 제한, 조직 정책을 구현할 수 있다.
      • 이스티오의 정책 강제 policy enforcement 를 사용하면, 어떤 서비스가 서로 상호작용할 수 있고 어떤 서비스가 상호작용할수 없는지에 대해 아주 세밀한 규칙을 만들 수 있다.
     
     
     
    1.5.1 서비스 메시와 엔터프라이즈 서비스 버스 ESB 의 관계
      • 서비스 지향 아키텍처 SOA 시대의 엔터프라이즈 서비스 버스 ESB는 최소한 정신적으로는 서비스 메시와 유사하다.
      • SOA 초기에 ESB가 본래 묘사됐던 방식을 살펴보면 다음과 같이 상당히 비슷한 표현을 볼 수 있다.
    👉🏻

    The enterprise service bus (ESB) is a silent partner in the SOA logical architecture. Its presence in the architecture is transparent to the services of your SOA application. However, the presence of an ESB is fundamental to simplifying the task of invoking services—making the use of services wherever they are needed, independent of the details of locating those services and transporting service requests across the network to invoke those services wherever they reside within your enterprise. (http://mng.bz/5K7D)

     
      • 위 설명에서 ESB를 ‘과묵한 파트너’로 가정하고 있는데, 이는 애플리케이션이 ESB를 알지 못함을 의미한다.
      • 서비스 메시에서도 비슷한 동작을 기대한다. 서비스 메시는 애플리케이션에게 투명해야 한다.
      • 또한 ESB는 ‘서비스 호출 작업을 단순하게 만드는 데 핵심적인 요소’라고 한다.
      • ESB의 경우 프로토콜 변환, 메시지 변환, 콘텐츠 기반 라우팅을 포함한다.
      • 서비스 메시는 EBS가 하던 모든 일을 맡지는 않는다.
      • 서비스 메시는 재시도, 타임아웃, 서킷 브레이커로 서비스 복원력을 제공하고, 이에 더해 서비스 디스커버리와 로드 밸런싱 같은 서비스를 제공한다.
      • 전반적으로 서비스 메시와 ESB에는 몇가지 중요한 차이점이 있다.
        • ESB는 기업 내에서 서비스 통합을 관리하는 새로운 구조를 조직에 도입했는데, 이 구조는 결국 격리된 시스템, 즉 사일로 silo 가 됐다.
        • ESB는 매우 중앙화된 배포/구현이었다.
        • ESB는 애플리케이션 네트워킹과 서비스 중재 문제를 혼합했다.
        • ESB는 복잡한 독점 벤더 소프트웨어를 기반으로 하는 경우가 많았다.
      • 아래 그림은 ESB가 애플리케이션을 통합하는 방법을 보여준다.
      • ESB는 중앙에 위치하고 애플리케이션 비즈니스 로직을 애플리케이션 라우팅,변환,중재와 결합했다.
    https://kimdoky.github.io/devops/2025/04/10/study-istio-week1/
     
    • 서비스 메시의 역할은 오직 애플리케이션 네트워킹 문제에만 해당된다.
    • 복잡한 비즈니스 변환, 비즈니스 프로세스 오케스트레이션, 프로세스 예외, 서비스 오케스트레이션 등은 서비스 메시의 일이 아니다.
    • 또한 서비스 메시의 데이트 플레인은 프록시를 애플리케이션에 붙이는 형태로 고도로 분산된다.
    • 이를 통해 ESB 아키텍처에서 자주 나타나는 단일 장애 지점 혹은 병목 지점을 제거한다.
    • 마지막으로 운영자와 서비스 팀 모두 서비스 수준 목표 SLO를 수립하고 이를 지원하도록 서비스 메시를 구성할 책임이 있다.
    • 다른 시스템과 통합할 책임은 더 이상 일부 중앙집중식 팀의 영역이 아니다. 모든 서비스 개발자가 그 책임을 함께 진다.
     
    1.5.2 서비스 메시 API 게이트웨이의 관계
    • 이스티오와 서비스 메시 기술은 API 게이트웨이와도 몇 가지 유사점과 차이점을 공유한다.
    • API 게이트웨이 인프라는 API 관리 제품군에서 조직의 공개 API에 외부에서 접근할 수 있는 엔드포인트를 제공하는 데 사용한다.
    • API 게이트웨이의 역할은 크게 두 가지다.
    • 첫 번째는 공개 API에 보안, 속도 제한, 할당량 관리, 메트릭 수집 기능을 제공하는 것이고,
    • 두 번째는 API 계획 명세, 사용자 등록, 요금 청구와 기타 운영 문제를 포함하는 전반적 API 관리 솔루션에 공개 API를 연결하는 것이다.
    • API 게이트웨이 아키텍처는 매우 다양하지만, 대부분 아키텍처의 경계에서 공개 API를 노출하는 데 사용됐다.
    • 또한 보안, 정책, 메트릭 수집을 중앙화하기 위해 내부 API에도 사용돼 왔다.
    • 그렇지만 API 게이트웨이는 트래픽이 흐르는 중앙집중 시스템을 만들기 때문에 ESB와 메시징 버스에서 설명했듯 병목 현상의 원인이 될 수 있다.
     
      • 아래 그림은 내부 API에 API 게이트웨이를 사용할 때 서비스 간에 모든 내부 트래픽이 어떻게 API 게이트웨이를 거쳐가는지 보여준다.
    https://kimdoky.github.io/devops/2025/04/10/study-istio-week1/
     
    • 그래프의 모든 서비스에서 홉 hop 이 두 번을 거치게 된다. 한번은 게이트웨이로 향하고, 한 번은 실제 서비스로 향하는 것이다.
    • 이는 네트워크 오버헤드와 지연 시간 뿐 아니라 보안에도 영향을 미친다.
    • 이런 다중 홉 아키텍처에서는 애플리케이션 관여 없이 API 게이트웨이가 단독으로 전송 매커니즘을 보호할 수 없다.
    • 그리고 API 게이트웨이는 보통 서킷 브레이커나 격벽 같은 복원력 기능을 구현하지 않는다.
     
    • 서비스 메시에서 프록시는 서비스와 함께 배치되므로 추가 홉을 거치지 않는다.
    • 또한 서비스 메시는 탈중앙적이므로, 각 에플리케이션은 자신의 프록시를 자신의 워크로드에 맞게 설정할 수 있고 시끄러운 이웃 noisy neithbor 시나리오에 영향을 받지 않는다.
    • 각 프록시는 짝 애플리케이션 인스턴스와 함께 있으므로, 애플리케이션이 알아차리거나 적극적으로 참여할 필요 없이 전송 매커니즘을 처음부터 끝까지 end-to-end 보호할 수 있다.
     
      • 아래 그림은 서비스 프록시가 API 게이트웨이 기능을 구현하고 강제하는 장소가 되는 모습을 보여준다.
    https://kimdoky.github.io/devops/2025/04/10/study-istio-week1/
     
    • 이스티오 같은 서비스 메시 기술이 계속 성숙하게 되면, API 관리가 서비스 메시 위에 구축되고 전문 API 게이트웨이 프록시가 필요하지 않게 될 것이다.
     
    1.5.3 마이크로서비스가 아닌 아키텍처에도 이스티오를 사용할 수 있는가?
    • 이스티오의 힘이 빛을 발하는 것은 서비스 개수와 서비스 사이의 연결이 많고 네트워크가 신뢰할 수 없는 클라우드 인프라 위에 있으며 이런 구조가 여러 클러스터, 클라우드, 데이터센터에 걸쳐 확장되는 상황에서다.
    • 게다가 이스티오가 애플리케이션 프로세스 외부에서 작동되므로, 기존 레거시 혹은 브라운필드 환경에서 배포해 메시에 통합할 수 있다.
    • 이스티오에는 어떤 서비스와 통신할 수 있는지 강제하는 정책이 있는데, 이 기능은 온프레미스와 퍼블릭 클라우드를 모두 사용하는 하이브리드 클라우드 구조에서 대단히 유용해진다.
    • 이스티오와 애플리케이션 둘 다 서킷 브레이커 같은 기능이 중복으로 구현했더라도, 더 제한적인 정책이 효과를 발휘해 모든 게 정상적으로 잘 작동할 것으므로 안심 할 수 있다.
     
    1.5.4 이스티오가 분산 아키텍처에 적합한 경우
      • 구현에 사용할 기술은 당면한 문제와 필요한 기능을 고려해 선택해야 한다.
      • 이스티오 같은 서비스 메시 기술은 강력한 인프라 기능이여 분산 아키텍처의 많은 영역에 영향을 미친다.
      • 그렇지만 모든 문제에 적합한 것은 아니므로 모든 문제에 해결책으로 고려해서는 안된다.
      • 아래 그림은 클라우드 아키텍처에서 애플리케이션 네트워킹 관심사를 이상적으로 분리하는 방법을 보여준다.
    https://kimdoky.github.io/devops/2025/04/10/study-istio-week1/
     
    • 아키텍처의 하위 계층에는 배포 자동화 인프라가 있다.
    • 이 인프라는 코드를 플랫폼에 배포하는 역할을 담당한다. 이스티오는 어떤 배포 자동화 도구를 사용해야 하는지를 규정하거나 침해하지 않는다.
    • 상위 계층에는 애플리케이션 비즈니스 로직(코드)이 있다. 이 코드에는 비즈니스 도메인은 물론 어떤 서비스를 어떤 순서로 호출할지, 서비스 상호작용 응답을 어떻게 처리할지, 프로세스 실패 시 어떻게 처리할지 등이 포함된다.
    • 이스티오는 어떤 비즈니스 로직도 구현하거나 대체하지 않는다. 또한 서비스 오케스트레이션, 비즈니스 페이로드 변환, 페이로드 강화, 분할 집계, 규칙 계산 등을 수행하지 않는다. 이런 기능은 애플리케이션 내부 라이브러리와 프레임워크에 맡기는 것이 가장 좋다.
     
    • 이스티오는 배포 플랫폼과 애플리케이션 코드 사이의 연결 조직 역할을 한다.
    • 복잡한 네트워킹 코드를 애플리케이션 외부로 꺼낼 수 있게 하는 것이다.
     
    1.5.5 서비스 메시를 사용할 때의 단점은 무엇인가?
    1. 첫 번째로, 서비스 메시를 사용하면 요청 경로에 미들웨어, 특히 프록시가 추가된다.
      • 이 프록시가 많은 이점을 주기도 하지만, 프록시에 익숙하지 않은 이들에게는 블랙박스가 돼 애플리케이션의 동작을 디버깅하기 어렵게 만들 수 있다.
      • 엔보이 프록시는 아주 디버깅하기 쉽도록, 네트워크상에서 발생하고 있는 일을 많이 노출하게 특별히 설계됐다.
      • 그렇지만 엔보이를 운영하는 데 익숙하지 않은 사람들에게는 아주 복잡해 보일 수 있고, 기존 디버깅 방식을 방해할 수 있다.
    2. 두 번째로, 테넌시 측면이다.
      • 메시는 메시 내에서 실행되는 서비스 만큼 가치가 있다. 즉, 메시 내에 서비스가 많을수록 그 서비스들을 운영하는 데 메시의 가치가 높아진다.
      • 그러나 물리적 메시 배포의 테넌트 및 격리 모델에 적절한 정책, 자동화, 그리고 사전 고려 없이는 메시를 잘못 구성하면 많은 서비스에 영향을 미칠 수 있는 상황에 처할 수 있습니다. → 학습 필요. 잘 알고 설정 필요
    3. 마지막으로, 서비스 메시는 요청 경로에 위치하기 때문에 서비스 및 애플리케이션 아키텍처의 매우 중요한 요소가 된다.
      • 서비스 메시는 보안, 관찰 가능성 및 라우팅 제어 자세를 개선할 수 있는 많은 기회를 제공할 수 있습니다.
      • 단점은 메쉬가 또 다른 레이어와 또 다른 복잡성의 기회를 제공한다는 점입니다.
      • 운영상 이슈(R&R) : 서비스 메시를 어떻게 설정하고 운영해야 하는지, 기존 조직의 절차와 거버넌스에는 어떻게 통합해야 하는지, 또한 팀 간에는 어떻게 통합해야 하는지 이해하기가 어려울 수 있다.
     
    • 일반적으로 서비스 메시가 가져다주는 이점이 크지만, 그에 따른 트레이드오프가 없지 않다.
    • 다른 도구나 플랫폼과 마찬가지로 사용자는 자신의 맥락 및 제약 조건에 비춰 트레이드오프를 평가하고, 서비스 메시가 자신의 상황에 적합한지 판단해야 한다.
    • 만약 적합하다면 메시를 성공적으로 도입하기 위한 계획를 세워야 한다.
     
    1.5.6. 요약 : 서비스 메시는 이런 공통 관심사(애플리케이션 네트워킹)애플리케이션 대신 외부에서 투명한 방식으로 구현하는 인프라
    • 클라우드에서 마이크로서비스를 운영하는 데는 여러 도전과제가 있다.
      • 몇 가지를 꼽자면 신뢰할 수 없는 네트워크, 서비스 가용성, 이해하기 어려운 트래픽 흐름, 트래픽 암호화, 애플리케이션 상태, 성능 등이 있다.
    • 이런 어려움들은 각 애플리케이션 내에서 라이브러리를 사용해 패턴(서비스 디스커버리 등)들을 구현함으로써 완화된다.
    • 서비스들에 대한 관찰 가능성을 확보할 목적으로 메트릭과 트레이싱을 생성하고 배포하려면 추가적인 라이브러리와 서비스가 필요한다.
    • 서비스 메시는 이런 공통 관심사를 애플리케이션 대신 프로세스 외부에서 투명한 방식으로 구현하는 인프라다.
    • 이스티오는 다음과 같은 요소로 구성된 서비스 메시 구현체다.
      • 데이터 플레인, 애플리케이션과 함께 배포되는 서비스 프록시로 구서오디며, 정책을 구현하고 트래픽을 제어하고 메트릭과 트레이싱을 생성하는 등 애플리케이션을 보완한다.
      • 컨트롤 플레인, 운영자가 데이터 플레인의 네트워크 동작을 제어할 수 있도록 API를 노출한다.
    • 이스티오는 엔보이를 서비스 프록시로 사용하는데, 기능이 다양하고 동적으로 설정할 수 있기 때문이다.
     
     
    서비스 매시(Service Mesh)
      • 등장 배경 : 마이크로서비스 아키텍처 환경의 시스템 전체 모니터링의 어려움, 운영 시 시스템 장애나 문제 발생할 때 원인과 병목 구간 찾기 어려움
    image
        1. 내부망 진입점에 역할을 하는 GW(예. API Gateway) 경우 모든 동작 처리에 무거워지거나, 내부망 내부 통신 제어는 어려움
     
      • 개념 : 마이크로서비스 간에 매시 형태의 통신이나 그 경로제어 - 예) 이스티오(Istio), 링커드(Linkerd) - 링크
      • 기본 동작 : 파드 간 통신 경로에 프록시를 놓고 트래픽 모니터링이나 트래픽 컨트롤 → 기존 애플리케이션 코드에 수정 없이 구성 가능!
        1. 기존 통신 환경
    image
     
        1. 애플리케이션 수정 없이, 모든 애플리케이션 통신 사이에 Proxy 를 두고 통신 해보자
    image
          1. 파드 내에 사이드카 컨테이너로 주입되어서 동작
          2. Proxy 컨테이너가 Application 트래픽을 가로채야됨 → iptables rule 구현 ⇒ 가능한 이유는?
     
        1. Proxy 는 결국 DataPlane 이니, 이를 중앙에서 관리하는 ControlPlane을 두고 중앙에서 관리를 하자
    image
          1. Proxy 는 중앙에서 설정 관리가 잘되는 툴을 선택. 즉, 원격에서 동적인 설정 관리가 유연해야함 → 풍부한 API 지원이 필요 ⇒ Envoy
            • '구글 IBM 리프트(Lyft)'가 중심이 되어 개발하고 있는 오픈 소스 소프트웨어이며, C++ 로 구현된 고성능 Proxy엔보이(Envoy)
            • 네트워크의 투명성을 목표, 다양한 필터체인 지원(L3/L4, HTTP L7), 동적 configuration API 제공, api 기반 hot reload 제공
          2. 중앙에서 어떤 동작/설정을 관리해야 될까? 라우팅, 보안 통신을 위한 mTLS 관련, 동기화 상태 정보 등
     
    • 트래픽 모니터링 : 요청의 '에러율, 레이턴시, 커넥션 개수, 요청 개수' 등 메트릭 모니터링, 특정 서비스간 혹은 특정 요청 경로로 필터링 → 원인 파악 용이!
    • 트래픽 컨트롤 : 트래픽 시프팅(Traffic shifting), 서킷 브레이커(Circuit Breaker), 폴트 인젝션(Fault Injection), 속도 제한(Rate Limit)
      • 트래픽 시프팅(Traffic shifting) : 예시) 99% 기존앱 + 1% 신규앱 , 특정 단말/사용자는 신규앱에 전달하여 단계적으로 적용하는 카니리 배포 가능
      • 서킷 브레이커(Circuit Breaker) : 목적지 마이크로서비스에 문제가 있을 시 접속을 차단하고 출발지 마이크로서비스에 요청 에러를 반환 (연쇄 장애, 시스템 전제 장애 예방)
      • 폴트 인젝션(Fault Injection) : 의도적으로 요청을 지연 혹은 실패를 구현
      • 속도 제한(Rate Limit) : 요청 개수를 제한
     
    • 정환열님이 작성해서 공유해주신 Istio 사내 교육용 자료에서 가져왔습니다.
    image
    image
     
    이스티오 소개
    https://istio.io/latest/docs/ops/deployment/architecture/
    https://devlos.tistory.com/100
    • 파일럿(Pilot): 모든 Envoy 사이드카에서 프록시 라우팅 규칙을 관리하며, 서비스 디스커버리와 로드 밸런싱 설정을 제공합니다.
    • 갤리(Galley): Istio와 쿠버네티스(TLS 연결 및 파일럿에 필요한 설정)를 연결해 주는 역할을 합니다. 서비스 메시 구성 데이터를 검증하고 변환합니다.
    • 시타델(Citadel): 보안 기능을 담당하며, TLS 인증서 발급 및 관리를 통해 서비스 간 통신의 암호화를 수행합니다.
     

    Istio 구성요소와 envoy : 컨트롤 플레인(istiod) , 데이터 플레인(istio-proxy > envoy)

      • istiod : Pilot(데이터 플레인과 통신하면서 라우팅 규칙을 동기화, ADS), Gally(Istio 와 K8S 연동, Endpoint 갱신 등), Citadel(연결 암호화, 인증서 관리 등)
    https://istio.io/latest/docs/concepts/security/
    • Istio proxy : Golang 으로 작성되었고 envoy 래핑한 Proxy, istiod와 통신하고 서비스 트래픽을 통제, 옵저버빌리티를 위한 메트릭 제공
     
    • 이스티오는 각 파드 안에 사이드카엔보이 프록시가 들어가 있는 형태
    • 모든 마이크로서비스간 통신은 엔보이를 통과하여, 메트릭을 수집하거나 트래픽 컨트롤을 할 수 있음
    • 트래픽 컨트롤을 하기위해 엔보이 프록시에 전송 룰을 설정 → 컨트롤 플레인이스티오가 정의된 정보를 기반으로 엔보이 설정을 하게 함
    • 마이크로서비스 간의 통신을 mutual TLS 인증(mTLS)으로 서로 TLS 인증으로 암호화 할 수 있음
    • 각 애플리케이션은 파드 내의 엔보이 프록시에 접속하기 위해 localhost 에 TCP 접속을 함
     
    Envoy 소개 : L4/7 Proxy , Istio 의 Sidecar proxy 로 사용* - 링크 주요 용어
    • Istio 구성요소와 envoy : 컨트롤 플레인(istiod) - ADS 를 이용한 Configuration 동기화 - 데이터 플레인(istio-proxy → envoy)
    https://blog.naver.com/alice_k106/222000680202
    https://www.anyflow.net/sw-engineer/istio-internals-by-xds
    https://www.envoyproxy.io/docs/envoy/latest/intro/life_of_a_request
    • 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 사내 교육용 자료 내용이 좋아서 가져왔습니다.

    image
    image
     

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

    image
    • 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
    https://blog.naver.com/yu3papa/223614975957
    image
    [추천 영상] LG ThinQ Cloud 에 Istio 운영 경험 사례 - Youtube
     
      1. K8S ClusterIP랜덤 부하분산 vs Istio Service Mesh 기반 Lease Request 방식 ⇒ vCPU 사용률 절감 및 안정화
    image
     
      1. 애플리케이션 코드 수정 없는, 심리스한 트래픽 이전과 트래픽 미러링 등 활용
    image
     
      1. 오픈소스 기반 L7 Telemetry 구축
    image
     
      1. 보안 : mTLS 기반 통신
    image
     
      1. 별도 구축 없는 mock server
    image
     
      1. 적용 예정 기능 : app 로깅 최적화, DNS Proxying, Ambient Mdoe
    image
     
      • (참고) OpenTelemetry 구성
    image
    image
     
    image
     
     
     
    • Istio 기본 실습
    2.1. kind(k8s) 소개 및 설치와 기본 사용 : macOS 사용자 , Windows (WSL2) 사용자
    kind 소개 : ‘도커 IN 도커 docker in docker’로 쿠버네티스 클러스터 환경을 구성 - Link

     

    image
    • kind or kubernetes in docker is a suite of tooling for local Kubernetes “clusters” where each “node” is a Docker container
    • kind is targeted at testing Kubernetes , kind supports multi-node (including HA) clusters
    • kind uses kubeadm to configure cluster nodes.
    그림 출처:
     
    kind 설치 : macOS 사용자
      1. Docker Desktop 설치 - Link
        • 실습 환경 : Kind 사용하는 도커 엔진 리소스에 최소 vCPU 4, Memory 8GB 할당을 권고 - 링크
     
      1. 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 stern
     
    kind 기본 사용 - 클러스터 배포 및 확인
    🚫

    회사에서 사용 중인 kubeconfig 가 있다면, 미리 kubeconfig 백업 후 kind 실습을 하시거나 혹은 아래 kubeconfig 변수 지정 사용 권장

    (옵션) 별도 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
    image
    # 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 KUBECONFIG
     
    kind 로 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.yaml
    
     
    2.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-server
     
    2.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 라는 단일 컨트롤 플레인 구성 요소에 구현돼 있다.
    https://kimdoky.github.io/devops/2025/04/10/study-istio-week1/
     
    2.3.1 istiod
      • 이스티오의 컨트롤 플레인 역할은 istiod로 구현된다.
      • 이스티오 파일럿 istio pilot 이라고도 하는 istiod 는 사용자나 운영자가 지정한 Higher-Level 이스티오 설정을 받아 이르 각 데이터 플레인 서비스 프록시에 맞는 프록시 전용 설정으로 변환하는 역할을 한다.
    https://kimdoky.github.io/devops/2025/04/10/study-istio-week1/
      • 이스티오는 ‘선언형 설정’을 해석해 서비스 프록시 전용 설정으로 적용된다.
      • 이스티오는 서비스 프록시로 엔보이를 사용하므로 이 설정들은 엔보이 설정으로 변환된다.
      • 예를 들어 아래 처럼 ‘선언형 설정’과 변환된 ‘엔보이 설정’
    # 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 관리 Identity Management

    https://kimdoky.github.io/devops/2025/04/10/study-istio-week1/
    image
    • 이스티오의 핵심 기능 중 하나는 각 워크로드 인스턴스에 ID를 할당하고 서비스 간 네트워크 전송을 암호화하는 것이다.
    • 이 기능은 서비스 메시가 요청 경로 양 끝단 모두에 위치한 덕분에 가능하다. 이때 이스티오는 트래픽 암호화에 X.509 인증서를 사용한다.
    • 워크로드 ID는 SPIFFE 사양에 따라 이 인증서에 내장된다. https://spiffe.io/
    • 덕분에 이스티오에서는 애플리케이션이 인증서, 공개/비밀키 등을 인지할 필요 없이 강력한 상호 인증(mTLS)을 사용할 수 있다.
    • 이런 보안을 가능케 하는 인증서의 검증, 서명, 전달 및 로테이션istiod가 다룬다.
     
    2.3.2 인그레스 및 이그레스 게이트웨이 Ingress and egress gateway
    https://kimdoky.github.io/devops/2025/04/10/study-istio-week1/
    • 이스티오가 동작하는 K8S 클러스터 내부망에 들어오거나 빠져나갈때 동작하는 구성요소인 Ingress/Egress Gateway.
    • 이 두 구성요소는 이스티오 설정을 이해할 수 있는 엔보이 프록시이다.
    • 애플리케이션과 함께 작동하는 이스티오 서비스 프록시와 매우 유사하게 설정된다.
    • 차이점은 어떤 애플리케이션 워크로드에도 독립적이며 트래픽이 클러스터로 드나드는 것을 허용하는 역할뿐이라는 점이다.
     
     
    2.4 Getting to know the Istio control plane → istio 1.17.8 설치 - Docs , Install , profile
    image
    image
    # 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 neat
    https://kimdoky.github.io/devops/2025/04/10/study-istio-week1/
     
    2.5 Deploying your first application in the service mesh → 서비스 메시에 첫 애플리케이션 배포
    https://kimdoky.github.io/devops/2025/04/10/study-istio-week1/
    #
    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
    
    image
     
    #
    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 서비스다른 서비스에서 데이터를 집계해 브라우저에 시각적으로 표시한다.
    image
    image
     
    2.6 Exploring the power of Istio with resilience, observability, and traffic control → 복원력, 관찰가능성, 트래픽 제어
    • 이스티오 프록시가 호출 경로 커넥션의 양쪽에 위치하는 덕분에, 이스티오는 애플리케이션 사이에 무슨 일이 일어나고 있는지에 대해 많은 텔레메트리를 수집하고 통찰력을 항샹시킬 수 있다. 이스티오의 서비스 프록시는 각 애플리케이션 곁에 사이드카로 배포되므로, 서비스 프록시가 수집하는 통찰력은 애플리케이션의 ‘프로세스 외부’에서 나온다. 즉, 대부분의 경우 애플리케이션은 이 수준의 관찰력을 얻기 위해 라이브러리나 프레임워크에 특정 구현을 추가할 필요가 없다. 프록시에게 애플리케이션은 블랙박스이며, 텔레메트리는 네트워크를 통해 관찰된 애플리케이션의 동작에 초점을 맞춘다.
    • 이스티오가 생성하는 텔레메트리는 관찰 가능성의 2가지 주요 범주에 대한 것이다. 첫 번째는 주요 메트릭, 이를테면 초당 요청 수, 실패 횟수, 지연 시간 백분위수와 같은 것들이다. 이런 값들을 알면 시스템에서 문제가 시작되는 지점에 대한 훌륭한 통찰력을 얻을 수 있다. 두 번째로, 이스티오는 OpenTracing 와 같은 분산 트레이싱을 지원할 수 있다. 이스티오는 애플리케이션들이 신경 쓰지 않아도 분산 트레이싱 백엔드로 스팬을 보낼 수 있다. 이렇게 하면 특정 서비스 상호작용 중에 어떤 일이 일어났는지, 어디에서 지연이 발생했는지를 확인하고 전반적인 호출 지연에 대한 정보를 얻을 수 있다.
    image
    # 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 관찰가능성
    image
    # 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.. 선택) ← 트래픽 반복 접속 해둔 상태

    image
     

    오픈트레이싱을 통한 분산 트레이싱 : 예거 jaeger 트레이싱 대시보드 확인 - 가장 최근의 호출 목록과 그 호출의 분산 트레이싱 스팬 확인 가능.

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

    kiali 확인 : 메트릭(프로메테우스)과 트레이싱(zipkin, jaeger, tempo)을 수집하여 해당 정보를 기반으로 시각화!

    https://kiali.io/docs/architecture/architecture/
    • 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
    • Namespaceistioincation 로 선택 후 Graph (Traffic, Versioned app graph) 에서 Display 옵션 중 ‘Traffic Distribution’ 과 ‘Traffic Animation’ 활성화! , Service nods, Security 체크 해보자 (Last 1m, Evety 10s)
    image
     
    2.6.2 Istio for resiliency - catalog에 의도적으로 500에러를 재현하고 retry로 복원력 높이기

    만약 ‘간헐적/일시적 네트워크 오류’가 발생하여 webapp 은 catalog 요청 실패이 실패하는 경우가 발생 시, 애플리케이션 코드 수정 없이 복원력을 높여보자!

    image
    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
    ----------------------------------------
    
    image
    image
    Tags 에 error=true 필터링Tags 에 error=true 필터링
     

    Kiali 대시보드 - red (Error) / blue (total req.)

    image
     

    에러 발생 시 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 에 응답 성공율이 높아졌다!

    image

    그라파나 (Istio Mesh Dashboard) : retry 적용 후 Success Rate은 증가하고 5xx 에러는 감소하는 것을 확인할 수 있습니다

    image
     
    2.6.3 Istio for Traffic Routing - 새 기능 추가 시나리오 대응
    image

    특정 사용자 집단만 새 배포로 라우팅하도록, 릴리즈에 단계적 접근 : 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
    
    # 반복 접속 종료해두기
    image
    image
     

    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"
      }
    ]
    ...
    image
     

    특정 헤더는 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
    1. 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-server
     
    3.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:30004
    
     
    3.3. Bookinfo sample application 배포 - Docs
    https://istio.io/latest/docs/examples/bookinfo/
    #
    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 -f
    
     
    3.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
    
    image
    • 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
    
    image

    이전에 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
    image
    # 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
    image

    기존에 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
Designed by Tistory.