[Istio] VM Support

xgro·2025년 5월 30일
0

Istio

목록 보기
15/17
post-thumbnail

📌 Notice

Istio Hands-on Study (=Istio)
직접 실습을 통해 Isito를 배포 및 설정하는 내용을 정리한 블로그입니다.

CloudNet@에서 스터디를 진행하고 있습니다.

Gasida님께 다시한번 🙇 감사드립니다.

EKS 관련 이전 스터디 내용은 아래 링크를 통해 확인할 수 있습니다.



📌 Overview

Istio는 원래 쿠버네티스 환경을 중심으로 설계되었지만, 가상머신(이하 VM)까지 메시에 통합할 수 있도록 기능을 확장하고 있습니다.
이번 블로그에서는 VM을 서비스 메시로 통합하는 데 필요한 핵심 개념들과 실습 과정을 중심으로 다루었습니다.

특히 Istio 1.9.0 이후 도입된 WorkloadGroupWorkloadEntry 리소스를 통해,
가상머신 환경에서도 쿠버네티스와 유사한 방식으로 워크로드를 관리하고 자동화할 수 있는 기반이 마련되었습니다.

또한, 사이드카 프록시 설치 및 설정, DNS 프록시를 통한 서비스 탐색,
그리고 istio-agent 동작 커스터마이징과 자동 제거 기능까지 전반적인 메시 통합 흐름을 실습 위주로 학습했습니다.

본 블로그는 실습을 중심으로 "가상머신을 메시에 어떻게 안전하고 효과적으로 통합할 수 있는가?"에 대한 실전적 인사이트를 제공합니다.

📌 Istio - VM Support

👉 Step 01. 이스티오의 가상머신 지원

가상머신(VM)을 Istio 메시 네트워크에 통합하는 기능은 Istio의 초기 버전부터 제공되어 왔지만, 실제 운영 환경에서는 제어 평면(Control Plane) 외부에서 해결해야 할 과제들이 많았고 자동화가 미흡한 상황이었습니다.

Istio 1.9.0 버전부터는 이러한 VM 지원 기능이 핵심 기능 일부가 구현되면서 API 접근법이 안정화되어 베타(Beta) 단계로 승격되었습니다.


🔸 Istio 1.9.0에서 도입된 핵심 기능

  • 사이드카 프록시의 설치 및 설정 자동화:
    VM 환경에서도 사이드카 프록시를 손쉽게 설치하고 설정할 수 있도록 istioctl 명령어를 통해 간소화되었습니다.

  • 가상머신의 고가용성 보장:
    새로운 Istio 리소스인 WorkloadGroupWorkloadEntry를 통해 VM 환경에서도 고가용성을 지원할 수 있게 되었습니다.

  • 메시 내 서비스에 대한 DNS 해석 지원:
    VM 내 사이드카와 함께 로컬 DNS 프록시를 설정함으로써, 메시 내부의 서비스 이름을 해석할 수 있게 되었습니다.


이번 장에서는 위 기능들을 먼저 고수준에서 개념적으로 이해한 후, 실제로 가상머신을 메시 네트워크에 통합하고 작동시키는 예제를 통해 실습해볼 것입니다.


✅ 가상머신에서의 사이드카 프록시 설치 및 설정 단순화하기

가상머신이 Istio 메시의 일부가 되기 위해서는 다음과 같은 작업이 필요합니다.

  1. 네트워크 트래픽을 관리할 사이드카 프록시를 설치해야 합니다.
  2. 프록시가 Istiod에 연결해 메시 설정을 수신할 수 있도록 구성해야 합니다.
  3. ID 토큰을 가상머신에 제공하여 Istiod에 대한 인증을 수행해야 합니다.

아래 그림 13.1은 이러한 작업이 성공적으로 수행되기 위해 필요한 전제 조건을 시각화한 것입니다.

쿠버네티스 환경의 워크로드도 유사한 과정을 거치지만, 자동화된 도구들이 이를 처리합니다.

  • webhook이나 istioctl을 통해 사이드카 설치 및 설정이 자동으로 이루어지고,
  • ID 토큰은 쿠버네티스가 파드에 자동으로 주입합니다.

하지만 이와 같은 편의 기능은 쿠버네티스 외부의 워크로드, 즉 가상머신에는 적용되지 않습니다.
따라서 가상머신 사용자 혹은 운영자는 사이드카를 직접 설치하고 구성해야 하며, 워크로드 ID를 위한 부트스트랩 토큰도 수작업으로 전달해야 합니다.


🔸 Single-network architecture

  • 쿠버네티스 클러스터와 VM 워크로드가 동일한 L3 네트워크 상에 있을 경우, VM은 Istiod 및 파드들과 직접 IP로 통신할 수 있습니다.
  • 이 경우에도 제어 평면 트래픽을 istio-ingressgateway와 같은 게이트웨이로 우회시킬 수 있지만, 필수는 아닙니다.
  • Auto-registration 기능을 활용하면, VM은 시작 시 Istiod에 연결하여 사전에 정의한 WorkloadGroup 템플릿을 기반으로 자동으로 WorkloadEntry 리소스를 생성할 수 있습니다.

출처 - https://academy.tetrate.io/courses/take/istio-fundamentals/


🔸 Multi-network architecture

VM이 쿠버네티스 클러스터와 다른 네트워크에 존재하는 경우, 클러스터의 파드는 VM의 IP에 직접 접근할 수 없습니다.

이 경우 Istio east-west gateway 또는 교차 네트워크 트래픽을 위한 Ingress/Egress gateway가 두 네트워크 간의 다리를 형성합니다.

제어 평면 통신뿐 아니라 데이터 플레인 트래픽 모두가 게이트웨이를 통해 흐르게 되며, VM은 해당 게이트웨이의 주소를 활용해 Istiod에 안전하게 연결하고 mTLS 터널을 구성해야 합니다.

출처 - https://academy.tetrate.io/courses/take/istio-fundamentals/


🔸 가상머신의 ID 프로비저닝 방식

Istio는 가상머신에 신뢰할 수 있는 ID를 제공하기 위해 쿠버네티스를 신뢰의 근원(Source of Trust) 으로 사용합니다.

쿠버네티스에서 토큰을 생성한 후, 이를 수작업으로 VM에 전달합니다.

이 토큰은 VM에 설치된 istio-agent가 Istiod에 인증하는 데 사용되며, 결과적으로 Istiod는 SVID(Spiffe Verifiable Identity Document) 형태의 ID를 발급합니다.


쿠버네티스는 파드에 토큰을 자동 주입하지만, VM의 경우 수작업으로 안전하게 토큰을 전달해야 합니다.

이 솔루션의 단점은 서비스 메시 운영자가 수동으로 ID를 관리해야 하며, 특히 멀티 클라우드 환경에서는 운영 비용이 증가한다는 점입니다.


🔸 (참고) 플랫폼이 할당한 ID 사용

Istio 커뮤니티에서는 클라우드 플랫폼이 자동으로 할당하는 ID를 신뢰의 근원으로 사용하는 방법을 개발 중입니다.

VM이 클라우드 플랫폼으로부터 받은 ID를 기반으로 인증하고, istio-agent가 이를 활용해 Istiod와 통신하는 구조입니다.

이 방식을 사용하면 각 VM의 ID는 해당 클라우드 플랫폼이 부여한 것으로, 인증과 ID 관리를 더 자동화할 수 있습니다.


(자세한 설계 문서는 여기 참고)


✅ 가상머신 고가용성 (Virtual Machine High Availability)

가상머신(VM) 환경에서도 서비스의 고가용성(HA, High Availability)을 보장하기 위해, Istio는 쿠버네티스에서 컨테이너 워크로드가 사용하는 접근 방식을 유사하게 모방하고 있습니다.


🔸 쿠버네티스에서의 고가용성 방식

  • Deployment:
    고수준 리소스로, 애플리케이션의 복제본을 몇 개 만들지, 어떤 방식으로 배포할지를 설정합니다.

  • Pod:
    Deployment 설정에 따라 생성되는 개별 실행 단위입니다.
    Pod는 상태가 이상할 경우 폐기 및 재생성을 통해 손쉽게 복원할 수 있으며, 이를 통해 전체 서비스의 가용성을 유지합니다.


🔸 Istio에서의 가상머신 고가용성 구성

Istio는 쿠버네티스의 위 개념을 VM 환경에도 적용할 수 있도록 다음과 같은 두 리소스를 도입했습니다:

  • WorkloadGroup:
    Kubernetes의 Deployment와 유사한 리소스로, 여러 VM 워크로드에 공통으로 적용될 설정의 템플릿 역할을 합니다.

    이 템플릿에는 다음과 같은 정보가 포함됩니다:

    • 애플리케이션이 노출하는 포트 정보
    • 각 인스턴스에 적용될 레이블
    • 서비스 메시에서 사용될 서비스 어카운트
    • 헬스 체크용 상태 프로브 방법 등
  • WorkloadEntry:
    Kubernetes의 Pod와 유사한 리소스로, 하나의 실제 VM 인스턴스를 나타냅니다.

    이 리소스는 WorkloadGroup에서 정의한 공통 속성 외에도:

    • VM의 IP 주소
    • 상태 등 고유한 정보도 포함하고 있습니다.

🔸 수동 vs 자동 등록 방식

  • WorkloadEntry수동으로 생성할 수도 있지만,
    Istio에서는 워크로드 자동 등록(Workload Auto-Registration) 방식을 권장합니다.

  • 자동 등록을 사용할 경우, 새로 프로비저닝된 VM은 시작 시점에 Istiod에 접속해
    사전에 정의된 WorkloadGroup 템플릿을 기반으로 자동으로 WorkloadEntry가 생성됩니다.

이러한 구조를 통해 VM 환경에서도 Pod 기반 환경처럼 유연하게 인스턴스를 교체하거나 확장할 수 있으며,
전체 서비스의 고가용성을 확보할 수 있습니다.


🔹 워크로드 자동 등록 이해하기 (Understanding Workload Auto-Registration)

워크로드 자동 등록은 가상머신이 WorkloadGroup의 일부로 자동으로 메시 네트워크에 참여하도록 돕는 중요한 기능입니다.

  • 가상머신은 제공받은 설정을 기반으로 제어 평면(Istiod)에 연결하고, ID 토큰을 사용해 자신이 해당 WorkloadGroup의 구성원임을 인증합니다.
  • 인증이 성공하면 Istiod는 자동으로 이 VM을 나타내는 WorkloadEntry 리소스를 생성합니다.


🔸 WorkloadEntry로의 표현이 중요한 이유

메시 내부에서 가상머신을 WorkloadEntry로 표현하는 것은 다양한 측면에서 중요합니다.

Kubernetes 서비스 또는 Istio의 ServiceEntry 리소스가 label selector를 통해 이 워크로드를 선택하고, 백엔드로 사용할 수 있습니다.

이 구조를 통해 클라이언트는 실제 VM의 주소를 몰라도 되고, 클러스터 내 FQDN만으로 워크로드에 트래픽을 라우팅할 수 있습니다.

결과적으로 다음과 같은 이점이 생깁니다:

  • 비정상 워크로드를 쉽게 폐기할 수 있습니다.
  • 수요 증가 시, 새로운 워크로드 인스턴스를 쉽게 추가할 수 있습니다.
  • 이러한 변화는 클라이언트 측에는 투명하게 적용됩니다.

🔸 레거시 → 현대화 마이그레이션 지원

이 구조는 특히 레거시 VM 기반 워크로드를 Kubernetes 기반 워크로드로 이전할 때 유용합니다.

워크로드를 병렬로 실행한 뒤, 서비스 메시의 트래픽 전환 기능(5장에서 설명됨)을 활용해 점진적으로 VM → Pod로 트래픽을 이전할 수 있습니다.

문제가 발생할 경우, 트래픽을 다시 VM으로 롤백할 수 있어 리스크 완화에 유리합니다.


🔹 이스티오가 수행하는 헬스 체크 이해하기 (Understanding the Health Checks Performed by Istio)

서비스 메시의 일부가 된 워크로드는 클라이언트 요청을 수신할 준비가 되어 있어야 하며, Istio는 이를 확인하기 위해 헬스 체크를 수행합니다.


🔸 두 가지 헬스 체크 방식

Istio는 고가용성을 유지하기 위해 다음 두 가지 헬스 체크를 적용합니다. 이는 쿠버네티스의 방식과 유사합니다.

  1. Readiness Probe (준비 상태 확인)

    • 워크로드가 시작된 후, 트래픽을 수신할 준비가 되었는지 확인합니다.
    • 메시의 사이드카 프록시는 readiness 상태가 확인된 워크로드에만 트래픽을 전달합니다.
  2. Liveness Probe (생존 상태 확인)

    • 애플리케이션이 실행 중일 때 정상적으로 동작하는지 확인합니다.
    • 비정상일 경우, 워크로드를 재시작해야 할 필요가 있습니다.

🔸 liveness 프로브는 메시의 역할이 아님

  • Istio는 readiness 체크만 관심을 가지며, liveness 체크는 담당하지 않습니다.
  • 워크로드가 살아있는지 여부는 메시가 아닌, 실행 중인 플랫폼의 책임입니다.

예시:

  • Kubernetes에서는 Deployment 리소스 내에서 정의된 liveness 프로브를 통해 워크로드 상태를 모니터링하고, 필요 시 자동 재시작합니다.
  • Cloud VM에서는 클라우드 서비스가 제공하는 기능을 통해 liveness 상태를 검사하고, 실패 시 자동 복구(Auto Healing) 를 수행합니다.

🔸 주요 클라우드 제공자의 liveness & auto-healing 문서

다음은 각 클라우드 플랫폼에서 liveness 체크 및 자동 복구 기능을 구현하는 방법에 대한 공식 문서입니다.

  • Microsoft Azure
    VM 스케일셋에 대해 자동 인스턴스 수리를 지원
    👉 Azure Docs

  • Amazon Web Services (AWS)
    오토스케일 그룹 내 인스턴스를 대상으로 헬스 체크 및 자동 대체 수행
    👉 AWS Docs

  • Google Cloud Platform (GCP)
    관리형 인스턴스 그룹(MIG)을 위한 헬스 체크 및 자동 복구 기능 제공
    👉 GCP Docs

정리하자면, Istio는 readiness에 집중하고, liveness는 플랫폼의 책임으로 위임함으로써 플랫폼 고유의 인프라 복구 메커니즘과 서비스 메시의 기능을 효율적으로 분리하고 있습니다.


🔹 이스티오가 가상머신에서 readiness 프로브를 구현하는 방법

(How Istio Performs Readiness Probes in VMs)

가상머신에서 실행 중인 애플리케이션이 트래픽을 수신할 준비가 되었는지 여부WorkloadGroup 리소스에 정의된 설정에 따라
istio-agent가 주기적으로 검사합니다.

  • istio-agent는 애플리케이션의 상태를 모니터링하고, 상태 변화(정상 ↔ 비정상)를 Istiod에 보고합니다.


🔸 제어 플레인의 동작 방식

  • Istiod는 보고받은 상태 정보(health status)를 바탕으로
    해당 워크로드(즉, VM)에 트래픽을 라우팅할지 여부를 결정합니다.

  • 예시:

    • 워크로드가 정상일 경우 → VM의 엔드포인트가 데이터 플레인에 추가되어 트래픽을 수신
    • 워크로드가 비정상일 경우 → 엔드포인트가 제거되어 트래픽 전달 차단

🔸 서비스 메시 운영자의 역할

운영자는 다음과 같은 작업을 통해 readinessliveness를 모두 관리해야 합니다.

  • WorkloadGroup 내에 readiness 프로브 설정 → Istio가 수행
  • 클라우드 인프라 계층에서 liveness 프로브 설정 → 클라우드 플랫폼이 수행

🔸 readiness vs liveness 설정 권장 방식

항목수행 주체권장 특성목적
Readiness ProbeIstio (istio-agent)공격적오류 응답을 하는 인스턴스에 트래픽 전달 방지
Liveness Probe클라우드 제공자보수적인스턴스가 복구할 시간을 확보
  • readiness 프로브는 빠르게 감지하고 우회하기 위한 것이며,
  • liveness 프로브는 신중하게 판단하고 복구 기회를 주는 것이 중요합니다.

🔸 인스턴스를 성급하게 종료하지 말 것

  • 인스턴스를 너무 빨리 종료하면 in-flight 요청을 유예 기간(grace period) 없이 중단하게 되어
    최종 사용자에게 오류가 노출될 수 있습니다.
  • 따라서 좋은 운영 전략은 readiness가 liveness보다 먼저 실패하도록 설정하는 것입니다.

이렇게 하면 시스템은 먼저 트래픽을 차단하고, 이후에도 상태가 복구되지 않을 때만 인스턴스를 종료합니다.
이는 서비스의 안정성과 사용자 경험 모두를 지키는 방식입니다.


✅ 메시 내 서비스의 DNS 해석

가상머신은 쿠버네티스 클러스터 외부에 있기 때문에 클러스터 내부 DNS에 접근할 수 없습니다.
이로 인해 메시 내 서비스의 호스트네임을 해석할 수 없고, 트래픽이 프록시로 전달되지 않아 메시 통합이 불완전해집니다.

DNS 해석이 실패하므로 아웃바운드 트래픽은 절대 엔보이 프록시에 도달하지 않는다.

과거에는 프라이빗 DNS 서버를 별도로 구성하여 가상머신이 DNS 쿼리를 보내도록 설정했고, 이를 external-dns 같은 컨트롤러로 동기화했습니다. 하지만 이는 임시방편일 뿐 완전한 메시 통합 방식은 아니었습니다.

Istio 1.8 이상에서는 istio-agent로컬 DNS 프록시가 추가되었고, istiod가 메시 내 서비스 정보를 이 프록시에 자동으로 설정합니다.

DNS 쿼리는 iptables 규칙을 통해 이 프록시로 리다이렉트되며, 애플리케이션은 Kubernetes 서비스 이름을 그대로 사용할 수 있게 됩니다.

DNS 쿼리는 해석을 위해 DNS 프록시로 리다이렉트된다.

또한 Istio는 NDS(Name Discovery Service)를 도입해, 서비스가 추가되면 새로운 DNS 항목을 자동으로 동기화합니다.

이 DNS 프록시는 가상머신뿐만 아니라 클러스터 내부 워크로드에도 동일하게 활용 가능하며, DNS 기반 트래픽 제어나 가시성 개선에도 기여합니다.

이로써 가상머신도 클러스터 내부 서비스와 동일한 방식으로 FQDN 기반 통신이 가능해지며, 완전한 메시 통합이 실현됩니다.



👉 Step 02. 가상머신을 포함한 메시 환경 구성

✅ 서비스 메시 준비하기

이번 실습에서는 cool-store 애플리케이션을 구성합니다.

webappcatalog는 쿠버네티스 클러스터에, forum은 가상머신에 배포되며, 두 환경은 서로 다른 네트워크에 위치해 있습니다.

따라서 클러스터에서 VM으로의 트래픽 전달을 위한 east-west 게이트웨이 구성이 중요합니다.

Istio 1.17.8 설치
공식 문서istioctl 설치

# (옵션) 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=30007 --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 확인
echo -e "http://$(curl -s ipinfo.io/ip):30007/#scale=1.5"
echo -e "http://$(curl -s ipinfo.io/ip):30007/#scale=1.3"

# 소스코드 clone
git clone https://github.com/AcornPublishing/istio-in-action
tree istio-in-action/book-source-code-master -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 -
cp istio-$ISTIOV/bin/istioctl /usr/local/bin/istioctl
istioctl version --remote=false

# 클러스터와 가상머신이 다른 네트워크에 있으므로, 이스티오를 설치한 네임스페이스에 네트워크 정보 레이블을 지정해야 한다.
kubectl create namespace istio-system
kubectl label namespace istio-system topology.istio.io/network=west-network

# demo 프로파일 컨트롤 플레인 배포
cat istio-in-action/book-source-code-master/ch13/controlplane/cluster-in-west-network.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  name: istio-controlplane
  namespace: istio-system
spec:
  profile: demo
  components:
    egressGateways:
    - name: istio-egressgateway
      enabled: false
  values:
    global:
      meshID: usmesh
      multiCluster:
        clusterName: west-cluster
      network: west-network

istioctl install -f istio-in-action/book-source-code-master/ch13/controlplane/cluster-in-west-network.yaml --set values.global.proxy.privileged=true -y


# 보조 도구 설치
kubectl apply -f istio-$ISTIOV/samples/addons
kubectl apply -f istio-$ISTIOV/samples/addons # nodePort 충돌 시 한번 더 입력


# 설치 확인 : istiod, istio-ingressgateway, crd 등
kubectl get istiooperators -n istio-system -o yaml
kubectl get all,svc,ep,sa,cm,secret,pdb -n istio-system
kubectl get cm -n istio-system istio -o yaml
kubectl get crd | grep istio.io | sort

# 실습을 위한 네임스페이스 설정
kubectl create ns istioinaction
kubectl label namespace istioinaction istio-injection=enabled
kubectl get ns --show-labels

# istio-ingressgateway 서비스 : NodePort 변경 및 nodeport 지정 변경 , externalTrafficPolicy 설정 (ClientIP 수집)
kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec": {"type": "NodePort", "ports": [{"port": 80, "targetPort": 8080, "nodePort": 30000}]}}'
kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec": {"type": "NodePort", "ports": [{"port": 443, "targetPort": 8443, "nodePort": 30005}]}}'
kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec":{"externalTrafficPolicy": "Local"}}'
kc describe svc -n istio-system istio-ingressgateway

# 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 메트릭 확인
echo -e "http://$(curl -s ipinfo.io/ip):30001"

# Grafana 접속
echo -e "http://$(curl -s ipinfo.io/ip):30002"

# Kiali 접속 : NodePort
echo -e "http://$(curl -s ipinfo.io/ip):30003"

# tracing 접속 : 예거 트레이싱 대시보드
echo -e "http://$(curl -s ipinfo.io/ip):30004"

kiali가 ec2의 public ip를 통해 정상적으로 호스팅되는것을 확인할 수 있습니다.

cool-store 서비스/gw/vs 배포 및 http 요청 확인

# cool-store 서비스/gw/vs 배포
kubectl -n istioinaction apply -f istio-in-action/book-source-code-master/ch12/webapp-deployment-svc.yaml
kubectl -n istioinaction apply -f istio-in-action/book-source-code-master/ch12/webapp-gw-vs.yaml
kubectl -n istioinaction apply -f istio-in-action/book-source-code-master/ch12/catalog.yaml

# 확인
kc get deploy,svc -n istioinaction
kc get gw,vs -n istioinaction

http 요청확인

# k3s-s
curl -s -H "Host: webapp.istioinaction.io" http://192.168.10.10:30000/api/catalog/ | jq
curl -s -H "Host: webapp.istioinaction.io" http://192.168.10.10:30000/api/catalog/items/1 | jq

# [forum-vm] k8s cool-store 요청 시도 확인
APP_IP=43.202.64.8 # k8s-s 의 공인 IP
curl -s -H "Host: webapp.istioinaction.io" http://$APP_IP:30000/api/catalog/items/1 | jq
while true; do curl -s -H "Host: webapp.istioinaction.io" http://$APP_IP:30000/api/catalog/ ; echo; date; sleep 1; done

# [자신의 PC] k8s cool-store 요청 시도 확인
바로 위 [testpc]와 동일 요청

# [k8s-s] forum-vm web 요청 시도 확인
curl 192.168.10.200
curl 192.168.10.200 -I

VM_IP=15.165.15.104 # testpc 의 공인 IP
curl $VM_IP
curl $VM_IP -I

✅ 가상머신 프로비저닝

  • VM 운영체제: Ubuntu
  • 접근: 공인 IP를 통한 SSH
  • 서비스: forum 애플리케이션을 포트 8080으로 노출

가상머신은 클러스터와 다른 네트워크에 존재하므로, 이후 단계에서는 WorkloadGroup, WorkloadEntry, DNS 프록시, east-west gateway 등을 구성하여 메시 통합을 완성합니다.


👉 Step 03. 가상머신까지 메시 확인

✅ 컨트롤 플레인 업데이트 Mesh expansion to VMs

가상머신을 Istio 메시로 통합하기 위해서는 몇 가지 기능이 필요합니다.
이 기능들은 아직 베타 단계이며 기본적으로는 활성화되어 있지 않기 때문에,
이를 위해 IstioOperator 정의를 업데이트하여 기존 컨트롤 플레인을 수정해야 합니다.
기능 단계 문서 참고

이 업데이트를 통해 다음 기능들이 활성화됩니다:

  • 워크로드 자동 등록 (Workload Auto Registration)
  • 헬스 체크 (Health Checks)
  • DNS 쿼리 캡처 및 DNS 프록시 리다이렉션

이러한 기능들은 앞서 설명한 것처럼 가상머신을 메시와 통합하는 데 필수 요소입니다.

# 컨트롤 플레인 업데이트 Mesh expansion to VMs
cat istio-in-action/book-source-code-master/ch13/controlplane/cluster-in-west-network-with-vm-features.yaml
*apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  name: istio-controlplane
  namespace: istio-system
spec:
  profile: demo
  components:
    egressGateways:
    - name: istio-egressgateway
      enabled: false
  meshConfig:
    defaultConfig:
      proxyMetadata:
        ISTIO_META_DNS_CAPTURE: "true" # DNS 쿼리가 캡처돼 DNS 프록시로 리다이렉트된다
  values:
    pilot:
      env:
        PILOT_ENABLE_WORKLOAD_ENTRY_AUTOREGISTRATION: true # 워크로드를 컨트롤 플레인에 자동 등록할 수 있다
        PILOT_ENABLE_WORKLOAD_ENTRY_HEALTHCHECKS: true     # 가상머신 워크로드의 상태를 검사한다
    global:
      meshID: usmesh
      multiCluster:
        clusterName: west-cluster
      network: west-network*

istioctl install -f istio-in-action/book-source-code-master/ch13/controlplane/cluster-in-west-network-with-vm-features.yaml --set values.global.proxy.privileged=true -y
kubectl patch svc istio-ingressgateway -n istio-system -p '{"spec": {"type": "NodePort"}}'

업데이트된 컨트롤 플레인은 서비스 프록시가 DNS 쿼리를 캡처하여 사이드카 내부 DNS 프록시로 리다이렉트하도록 설정합니다.
또한 워크로드는 자동 등록되고, 헬스 체크 결과를 istiod에 주기적으로 보고할 수 있습니다.

단, 이 기능들을 사용하려면 가상머신이 istiod에 접근 가능해야 하며, 설정과 ID 정보를 정상적으로 받아올 수 있어야 합니다.


✅ istiod와 클러스터 서비스들을 가상머신에 노출하기

가상머신이 메시의 일부가 되기 위해서는 istiod와 클러스터 내부 서비스에 접근할 수 있어야 합니다.

같은 네트워크에 있다면 문제없이 동작하지만, 현재 구성처럼 별도의 네트워크에 위치한 경우에는 east-west 게이트웨이를 통해 트래픽을 프록시해야 합니다. 공식 문서 참고

먼저 east-west 게이트웨이를 설치해 봅니다:

cat istio-in-action/book-source-code-master/ch13/gateways/cluster-east-west-gw.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  name: istio-eastwestgateway
  namespace: istio-system
spec:
  profile: empty
  components:
    ingressGateways:
    - name: istio-eastwestgateway
      label:
        istio: eastwestgateway
        app: istio-eastwestgateway
        topology.istio.io/network: west-network
      enabled: true
      k8s:
        env:
        - name: ISTIO_META_ROUTER_MODE
          value: "sni-dnat"
        - name: ISTIO_META_REQUESTED_NETWORK_VIEW
          value: west-network
        service:
          ports:
          - name: status-port
            port: 15021
            targetPort: 15021
          - name: mtls
            port: 15443
            targetPort: 15443
          - name: tcp-istiod
            port: 15012
            targetPort: 15012
          - name: tcp-webhook
            port: 15017
            targetPort: 15017  
  values:
    global:
      meshID: usmesh
      multiCluster:
        clusterName: west-cluster
      network: west-network

istioctl install -f istio-in-action/book-source-code-master/ch13/gateways/cluster-east-west-gw.yaml -y

게이트웨이가 설치되면 가상머신이 메시의 엔드포인트로 접근할 수 있는 포트들이 노출됩니다.

그 중 15443 포트는 가상머신에서 메시 내 서비스로 향하는 트래픽을 리버스 프록시 해주는 mTLS 포트입니다. <Image: istiod와 클러스터 서비스들은 가상머신에 노출하는 포트들>

해당 포트를 Gateway 리소스를 통해 외부로 노출합니다:

cat istio-in-action/book-source-code-master/ch13/expose-services.yaml 
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: cross-network-gateway
  namespace: istio-system
spec:
  selector:
    istio: eastwestgateway
  servers:
    - port:
        number: 15443
        name: tls
        protocol: TLS
      tls:
        mode: AUTO_PASSTHROUGH
      hosts:
        - "*.local"

kubectl apply -f istio-in-action/book-source-code-master/ch13/expose-services.yaml 
kubectl get gw,vs -A

다음으로는 istiod 제어 평면에 대한 포트(15012, 15017)를 노출합니다.
Gateway와 VirtualService를 함께 구성합니다:

cat istio-in-action/book-source-code-master/ch13/expose-istiod.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: istiod-gateway
spec:
  selector:
    istio: eastwestgateway
  servers:
    - port:
        name: tls-istiod
        number: 15012
        protocol: tls
      tls:
        mode: PASSTHROUGH        
      hosts:
        - "*"
    - port:
        name: tls-istiodwebhook
        number: 15017
        protocol: tls
      tls:
        mode: PASSTHROUGH          
      hosts:
        - "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: istiod-vs
spec:
  hosts:
  - "*"
  gateways:
  - istiod-gateway
  tls:
  - match:
    - port: 15012
      sniHosts:
      - "*"
    route:
    - destination:
        host: istiod.istio-system.svc.cluster.local
        port:
          number: 15012
  - match:
    - port: 15017
      sniHosts:
      - "*"
    route:
    - destination:
        host: istiod.istio-system.svc.cluster.local
        port:
          number: 443

kubectl apply -f istio-in-action/book-source-code-master/ch13/expose-istiod.yaml -n istio-system

정상적으로 적용되었는지 아래 명령어로 확인할 수 있습니다:

kc get gw,vs -A

이제 인프라와 게이트웨이 구성이 완료되었으며, 가상머신이 istiod 및 클러스터 서비스들과 통신할 준비가 마무리되었습니다.


✅ WorkloadGroup으로 워크로드 그룹 나타내기

WorkloadGroup은 메시 외부(예: VM)에 있는 동일한 속성을 가진 워크로드 집합을 정의하는 리소스입니다.
예를 들어 forum 가상머신 워크로드의 공통 속성은 다음과 같이 정의됩니다:

cat istio-in-action/book-source-code-master/ch13/workloadgroup.yaml
apiVersion: networking.istio.io/v1alpha3
kind: WorkloadGroup
metadata:
  name: forum
  namespace: forum-services
spec:
  metadata:
    annotations: {}
    labels:
      app: forum
  template:
    serviceAccount: forum-sa
    network: vm-network
  probe:
    periodSeconds: 5
    initialDelaySeconds: 1
    httpGet:
      port: 8080
      path: /api/healthz
  • labels: 서비스가 이 레이블을 기반으로 WorkloadEntry를 선택할 수 있게 합니다.
  • network: 제어 플레인이 프록시 라우팅 시 해당 네트워크 정보로 동작하게 합니다.
  • serviceAccount: 가상머신 워크로드가 이 그룹의 멤버로 등록되기 위한 인증 토큰 주체입니다.

이제 이 WorkloadGroup을 클러스터에 적용해 봅니다:

kubectl create namespace forum-services
kubectl create serviceaccount forum-sa -n forum-services
kubectl apply -f istio-in-action/book-source-code-master/ch13/workloadgroup.yaml

kubectl get-all -n forum-services
kubectl get workloadgroup -n forum-services

이제 이 그룹에 속하는 가상머신이 자동 등록되고 메시의 구성원이 될 수 있도록 준비되었습니다.


🔹 가상머신 사이드카용 설정 생성하기

이제 istioctl 명령어를 통해 해당 워크로드에 필요한 사이드카 설정을 생성합니다:

istioctl x workload entry configure -f istio-in-action/book-source-code-master/ch13/workloadgroup.yaml \
  -o /tmp/my-workload-files/ \
  --clusterID "west-cluster" \
  --autoregister

생성된 파일들은 다음과 같습니다:

tree /tmp/my-workload-files/
/tmp/my-workload-files/
├── cluster.env
├── hosts
├── istio-token
├── mesh.yaml
└── root-cert.pem
  • hosts: east-west 게이트웨이 경유로 istiod 접근 주소
  • root-cert.pem: istiod 인증서 검증용 루트 인증서
  • istio-token: 서비스 어카운트 인증 토큰
  • mesh.yaml: 메시 설정 및 readinessProbe 정보 포함
  • cluster.env: 서비스 프록시용 환경 변수 설정


🔹 생성된 파일을 VM으로 전송하기

다음 명령어로 로컬 PC 또는 테스트 노드에서 VM으로 파일을 전송합니다:

# 로컬에서 파일 확인
openssl x509 -in ./my-workload-files/root-cert.pem -noout -text
jwt decode $(cat ./my-workload-files/istio-token)

# forum-vm으로 복사
FORUM=54.180.240.239
scp -i ~/.ssh/kp-gasida.pem ./my-workload-files/cluster.env ubuntu@$FORUM:/tmp/
scp -i ~/.ssh/kp-gasida.pem ./my-workload-files/istio-token ubuntu@$FORUM:/tmp/
scp -i ~/.ssh/kp-gasida.pem ./my-workload-files/mesh.yaml ubuntu@$FORUM:/tmp/
scp -i ~/.ssh/kp-gasida.pem ./my-workload-files/root-cert.pem ubuntu@$FORUM:/tmp/

VM 내부에서 파일이 정상적으로 존재하는지 확인합니다:

ls -l /tmp

이제 사이드카를 설치하고, 클러스터와의 보안 통신 설정을 적용할 준비가 완료되었습니다.


✅ 가상머신에 istio-agent 설치 및 설정하기

가상머신 forum-vm에 Istio 사이드카인 istio-agent를 설치하고, 메시와 통합하기 위한 설정을 진행합니다. 대부분의 설정은 VM 내 파일 복사 및 서비스 시작으로 구성되며, 각 명령은 그대로 따라 실행하면 됩니다.

# DNS 관련 설정 확인
cat /etc/resolv.conf
ss -tnlp
ss -unlp
resolvectl status

# iptables 상태 확인
iptables -t nat -L -n -v
iptables -t filter -L -n -v
iptables -t mangle -L -n -v
iptables -t raw -L -n -v

# istio-agent 다운로드 및 설치
curl -LO https://storage.googleapis.com/istio-release/releases/1.17.8/deb/istio-sidecar.deb
file istio-sidecar.deb
dpkg -i istio-sidecar.deb
which pilot-agent
pilot-agent version
which envoy
envoy --version

# 설치된 디렉터리 구조 확인
tree /etc/istio
tree /var/lib/istio/

# 설정 파일 위치에 맞게 복사
mkdir -p /etc/certs
mkdir -p /var/run/secrets/tokens

cp /tmp/root-cert.pem /etc/certs/root-cert.pem
cp /tmp/istio-token /var/run/secrets/tokens/istio-token
cp /tmp/cluster.env /var/lib/istio/envoy/cluster.env
cp /tmp/mesh.yaml /etc/istio/config/mesh

# istiod 주소를 /etc/hosts 에 등록
echo "192.168.10.10 istiod.istio-system.svc" | sudo sh -c 'cat >> /etc/hosts'
cat /etc/hosts

# istio-agent 실행 전 권한 설정
cat /etc/passwd | tail -n 3
chown -R istio-proxy /var/lib/istio /etc/certs /etc/istio/proxy /etc/istio/config /var/run/secrets /etc/certs/root-cert.pem

# istio-agent 서비스 시작
systemctl start istio
systemctl enable istio
systemctl status istio
journalctl -u istio -f

# 에이전트가 사용하는 스크립트 확인
which istio-start.sh
cat /usr/local/bin/istio-start.sh

# 인증서 위치 확인
tree /etc/certs/

# 프로세스 및 iptables 상태 재확인
ps aux |grep istio
iptables -t nat -L -n -v
iptables -t filter -L -n -v
iptables -t mangle -L -n -v
iptables -t raw -L -n -v

위 작업을 완료하면 istio-agent가 정상적으로 동작하며, 메시와 연결 준비가 완료됩니다.


✅ 에이전트 로그 확인 및 메시 등록 상태 검증

에이전트가 컨트롤 플레인(istiod)에 연결됐는지 확인하려면 아래 로그를 확인합니다.

cat /var/log/istio/istio.log | grep xdsproxy
journalctl -u istio -f

워크로드가 메시에 자동 등록되면 WorkloadEntry 리소스가 생성됩니다.

kubectl get workloadentries -n forum-services
kc get workloadentries -n forum-services -o yaml

status.conditionsHealthy 상태가 False인 경우, 헬스 체크 실패로 인한 연결 오류를 나타냅니다.

추가적으로 istioctl proxy-status 명령을 통해 메시와 싱크 상태를 확인할 수 있습니다.

istioctl proxy-status

이로써 VM이 Istio 메시의 멤버로 등록되었고, 트래픽 라우팅 전 단계까지 구성이 완료됩니다.


✅ 클러스터 서비스로 트래픽 라우팅하기

가상머신에서 클러스터 내 서비스(webapp)로 트래픽이 잘 전달되는지 확인하는 단계입니다. 다음과 같은 순서로 트래픽 흐름과 동작을 검증합니다.

# [forum-vm] 신규 터미널 : 패킷 모니터링 도구 termshark 실행
tcpdump -i any -w - udp port 53 | termshark
## CTRL+C 로 취소 후 수집된 패킷은 termshark UI에서 확인 가능

# [forum-vm] : 도메인 해석 정상 여부 확인
dig +short webapp.istioinaction
# 출력 예시: 10.10.200.48

# webapp 서비스로 API 요청
curl -s webapp.istioinaction/api/catalog/items/1 | jq
watch curl -s webapp.istioinaction/api/catalog/items/1

# envoy 프로세스를 통해 15443 포트로 연결되는지 확인
watch -d 'ss -tnp | grep envoy'
# 출력 예시:
# ESTAB 0 0 192.168.10.200:41238 192.168.10.10:15443 users:(("envoy",pid=3203,fd=40))
# ESTAB 0 0 192.168.10.200:41242 192.168.10.10:15443 users:(("envoy",pid=3203,fd=41))

# iptables 상태 지속 확인
watch -d iptables -t nat -L -n -v
watch -d iptables -t raw -L -n -v

# [k3s-s]에서 webapp 서비스 및 엔드포인트 확인
kubectl get svc,ep -n istioinaction webapp
# 출력 예시:
# NAME             TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
# service/webapp   ClusterIP   10.10.200.48   <none>        80/TCP    148m
#
# NAME               ENDPOINTS         AGE
# endpoints/webapp   172.16.0.8:8080   148m


가상머신에서 클러스터 서비스로 트래픽이 도달하는 과정

  1. 애플리케이션이 트래픽을 보내기 위해 먼저 호스트네임을 해석합니다. 이때 DNS 쿼리는 iptables 규칙에 의해 DNS 프록시(127.0.0.53)로 리다이렉트됩니다.
  2. 도메인이 IP 주소로 해석되면, 애플리케이션은 해당 IP로 아웃바운드 요청을 보냅니다. 이 요청 역시 iptables를 통해 envoy 사이드카 프록시로 리다이렉트됩니다.
  3. envoy 프록시는 이 요청을 east-west 게이트웨이로 라우팅합니다.
  4. east-west 게이트웨이는 이를 받아 webapp 서비스로 프록시합니다. 이후 webapp은 catalog 서비스로 내부 요청을 수행합니다.

이 과정을 통해 VM에서 클러스터 내부 서비스까지 트래픽이 어떻게 흘러가는지 확인할 수 있으며, DNS 해석 → 프록시 리다이렉션 → 게이트웨이 전달 → 서비스 응답의 전체 흐름을 검증하게 됩니다.

DNS 프록시 설정과 envoy의 리디렉션 동작은 서비스 메시 내에서 핵심적인 라우팅 메커니즘입니다.


✅ (옵션) 외부 PC에서 webapp 접근 테스트

클러스터 외부에서 접근 가능한 IP와 포트를 알고 있다면 아래 명령어로 반복 요청을 보내면서 응답을 관찰할 수 있습니다.

while true; do curl -s -H "Host: webapp.istioinaction.io" http://$APP_IP:30000/api/catalog/ ; echo; date; sleep 1; done

반복 요청을 통해 서비스 응답 안정성이나 로드 밸런싱 상태 등을 확인할 수 있습니다.


✅ 트래픽을 WorkloadEntry로 라우팅하기

이번 단계에서는 클러스터 내부에서 가상머신에 존재하는 서비스(forum)로 트래픽을 라우팅하는 과정을 확인합니다. 앞 절과 반대 방향으로, 즉 클러스터 → 가상머신으로 트래픽이 흐르는 시나리오입니다.


WorkloadEntry로 트래픽을 보내는 방식

  • 가상머신의 IP 주소로 직접 요청을 보내는 것이 아니라, Kubernetes 서비스로 추상화된 WorkloadEntry의 라벨을 이용해 트래픽을 라우팅합니다.
  • Istio는 이 Kubernetes 서비스를 기반으로 적절한 Envoy 데이터 플레인 구성을 수행합니다.
# forum 서비스를 위한 Kubernetes 서비스 생성
cat istio-in-action/book-source-code-master/services/forum/kubernetes/forum-svc.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app: forum
  name: forum
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: forum

# 서비스 적용
kubectl apply -f istio-in-action/book-source-code-master/services/forum/kubernetes/forum-svc.yaml -n forum-services

# 서비스 및 엔드포인트 확인
kubectl get svc,ep -n forum-services
# NAME            TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
# service/forum   ClusterIP   10.10.200.72   <none>        80/TCP    20s
#
# NAME              ENDPOINTS   AGE
# endpoints/forum   <none>      20s

Istio proxy-config 정보 확인

# webapp에서 forum 서비스로의 라우팅 정보 확인
istioctl proxy-config route deploy/webapp.istioinaction --name 80 -o json
# "domains": [ "forum.forum-services.svc.cluster.local", ... ]
# "cluster": "outbound|80||forum.forum-services.svc.cluster.local"

# 클러스터 정보 확인
istioctl proxy-config cluster deploy/webapp.istioinaction --fqdn forum.forum-services.svc.cluster.local

# 아직 endpoint 정보는 없음
istioctl proxy-config endpoint deploy/webapp.istioinaction | grep forum

# eastwest gateway에서도 확인
istioctl proxy-config endpoint deploy/istio-eastwestgateway.istio-system | grep forum

가상머신 내 Envoy 확인 및 istioctl 설치

# forum-vm 내부에서 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 -
cp istio-$ISTIOV/bin/istioctl /usr/local/bin/istioctl

# Envoy 설정 확인
curl -s localhost:15000/config_dump | istioctl proxy-config listener --file -
curl -s localhost:15000/config_dump | istioctl proxy-config route --file -
curl -s localhost:15000/config_dump | istioctl proxy-config clusters --file -
curl -s localhost:15000/config_dump | istioctl proxy-config endpoint --file -
curl -s localhost:15000/config_dump | istioctl proxy-config secret --file -


요청 실패 시 로그 확인

# 트래픽 요청 및 에러 로그 확인
istioctl proxy-config cluster deploy/webapp.istioinaction --fqdn forum.forum-services.svc.cluster.local
istioctl proxy-config endpoint deploy/webapp.istioinaction | grep forum

# 로그 모니터링
kubectl logs -n istioinaction deploy/webapp -c istio-proxy -f
# [2025-05-25T04:53:18.841Z] "GET /api/users HTTP/1.1" 503 UH no_healthy_upstream ...

  • UH 응답은 정상적인 업스트림 엔드포인트가 없음을 의미합니다.
  • forum 워크로드가 아직 Healthy 상태가 아니라 데이터 플레인에 등록되지 않았기 때문입니다.

forum 워크로드 상태 확인하기

# WorkloadEntry 상태 확인
kc get workloadentries -n forum-services -o yaml
# message: 'Get "http://192.168.10.200:8080/api/healthz": connect: connection refused'
# status: "False"

# VM에서 서비스 포트 확인
ss -tnlp | grep 8080
# 아직 서비스가 구동되지 않음


forum 애플리케이션 실행

# forum-vm
wget -O forum https://git.io/J3QrT
file forum
chmod +x forum
./forum

# 실행 확인
curl http://localhost:8080/api/healthz -v
ss -tnlp | grep 8080
# LISTEN *:8080

# 다시 데이터 플레인에 엔드포인트 반영 확인
istioctl proxy-config cluster deploy/webapp.istioinaction --fqdn forum.forum-services.svc.cluster.local
istioctl proxy-config endpoint deploy/webapp.istioinaction --cluster 'outbound|80||forum.forum-services.svc.cluster.local' -o json
# 192.168.10.200:8080     HEALTHY

# WorkloadEntry 상태도 정상
kc get workloadentries -n forum-services -o yaml
# status: "True"
# type: Healthy

요청 재시도 및 정상 처리 확인

# 자신의 PC에서 요청
curl -s -H "Host: webapp.istioinaction.io" http://$APP_IP:30000/api/users
while true; do curl -s -H "Host: webapp.istioinaction.io" http://$APP_IP:30000/api/users ; echo; date; sleep 1; done

# 로그 모니터링
kubectl logs -n istioinaction deploy/webapp -c istio-proxy -f
# [2025-05-25T05:05:51.328Z] "GET /api/users HTTP/1.1" 200 - via_upstream ...


이 실습을 통해 다음을 확인할 수 있습니다:

  • 클러스터 서비스가 WorkloadEntry 엔드포인트를 활용해 트래픽을 정상 라우팅하는 방식
  • 비정상 워크로드는 데이터 플레인에서 제외됨으로써 안전한 트래픽 분산 보장
  • 정상 상태 전환 이후에는 즉시 트래픽 대상에 포함되어 요청을 처리함

이 구조는 운영 환경에서 오류 응답을 방지하고 안정적인 서비스 연속성을 보장하는 데 매우 유용합니다.


✅ 컨트롤 플레인이 가상머신 설정: 상호 인증 강제

VMs are configured by the control plane: Enforcing mutual authentication

가상머신이 메시에 통합되어 사이드카 프록시가 네트워크 트래픽을 관리하게 되면, 이스티오의 다양한 기능을 그대로 가상머신에도 적용할 수 있습니다.
이번에는 트래픽 상호 인증(mTLS)을 강제하는 PeerAuthentication 리소스를 적용하여 보안을 강화해 보겠습니다.

현재는 가상머신의 8080 포트가 외부에 노출되어 있어서, 아무나(메시에 속하지 않은 사용자도) 해당 포트에 접근할 수 있는 상태입니다.
이를 테스트하기 위해 로컬 컴퓨터(메시 외부)에서 직접 요청을 보내 확인해 봅니다.

# 자신의 PC에서 요청
curl -is $FORUM:8080/api/users | grep HTTP
# HTTP/1.1 200 OK

현재는 아무 제약 없이 요청이 처리되고 있는 상태입니다.
이제부터는 메시에 속하지 않은 요청은 모두 차단되도록 설정하겠습니다.

이를 위해, 메시에 속한 트래픽만 허용하는 정책을 다음과 같이 구성합니다.

# strict-peer-auth.yaml
cat istio-in-action/book-source-code-master/ch13/strict-peer-auth.yaml
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: istio-system
spec:
  mtls:
    mode: STRICT

# 적용
kubectl apply -f istio-in-action/book-source-code-master/ch13/strict-peer-auth.yaml
kubectl get peerauthentication -A

정책이 적용되어 데이터 플레인까지 전파되기를 잠시 기다립니다.
이후, 메시에 속하지 않은 요청이 차단되는지 다시 한 번 확인해 봅니다.

# 자신의 PC에서 요청
curl -is $FORUM:8080/api/users -v

# istio-ingressgateway 경유 요청 
while true; do curl -s -H "Host: webapp.istioinaction.io" http://$APP_IP:30000/api/users ; echo; date; sleep 1; done

이제 로컬에서의 직접 요청은 실패하지만, 이스티오 메시 안의 webapp → forum 요청은 정상적으로 처리됩니다.
이는 가상머신에 대한 설정이 컨트롤 플레인에 의해 적용되고, 메시 내부에서만 허용된다는 것을 의미합니다.

이처럼 PeerAuthentication은 하나의 예시일 뿐이며, 모든 이스티오 정책(API)을 사용하여 가상머신의 프록시 동작을 제어할 수 있습니다.



👉 Step 04. DNS 프록시 이해하기

✅ DNS 프록시가 클러스터 호스트네임을 해석하는 방법

How the DNS proxy resolves cluster hostnames

이번 실습에서는 가상머신에서 webapp.istioinaction 같은 클러스터 호스트네임이 어떻게 해석되는지, DNS 프록시가 개입하는 과정을 단계별로 살펴봅니다.

클러스터 서비스 호스트네임 해석의 흐름

  1. 클라이언트 애플리케이션은 webapp.istioinaction을 해석하기 위해 DNS 쿼리를 생성합니다.
  2. 운영체제가 DNS 쿼리를 처리하며, 먼저 hosts 파일을 확인하고, 없으면 기본 DNS 리졸버로 요청을 넘깁니다.
  3. 기본 리졸버는 보통 우분투에서 systemd-resolved이며, 127.0.0.53:53 포트에서 수신하지만,
    • Istio의 iptables 규칙에 의해 이 요청은 실제로는 127.0.0.1:15053으로 리다이렉트됩니다.
  4. DNS 프록시는 메시 내 알려진 서비스 목록을 가지고 있고, 해당 항목이 있으면 바로 IP로 해석됩니다.
    • webapp.istioinaction은 클러스터 서비스로 등록되어 있기 때문에 IP를 반환합니다.
  5. 만약 해당 항목이 없다면, 프록시는 요청을 resolv.conf에 정의된 외부 DNS 서버로 넘깁니다.

이 흐름을 검증해보겠습니다.

# [forum-vm] DNS 포트 리다이렉션 iptables 규칙 확인
iptables-save | grep 'to-ports 15053'
# -A OUTPUT -d 127.0.0.53/32 -p udp -m udp --dport 53 -j REDIRECT --to-ports 15053
# -A ISTIO_OUTPUT -d 127.0.0.53/32 -p tcp -m tcp --dport 53 -j REDIRECT --to-ports 15053

DNS 쿼리는 실제로 Istio DNS 프록시가 리스닝 중인 127.0.0.1:15053으로 이동합니다.
해당 포트에서 어떤 프로세스가 리스닝하고 있는지 확인해보겠습니다.

# DNS 프록시 포트 확인
netstat -ltunp | egrep 'PID|15053'
# tcp        0      0 127.0.0.1:15053     0.0.0.0:*     LISTEN   3195/pilot-agent
# udp        0      0 127.0.0.1:15053     0.0.0.0:*               3195/pilot-agent

Istio의 pilot-agent가 해당 포트에서 DNS 쿼리를 처리하고 있는 것을 확인할 수 있습니다.
직접 DNS 요청을 보내보면 다음과 같이 해석됩니다.

# DNS 프록시를 통해 서비스 IP 해석
dig +short @localhost -p 15053 webapp.istioinaction
# 10.10.200.48

dig +short @localhost -p 15053 catalog.istioinaction
dig +short @localhost -p 15053 forum.forum-services

# (옵션) 외부 DNS 요청도 확인 가능
dig +short @localhost -p 15053 www.daum.net
# daum-xxxx.kgslb.com.
# 121.53.105.xxx

또한 CoreDNS 로그를 통해 DNS 요청 로그를 확인할 수도 있습니다.

# CoreDNS 로그 설정 (옵션)
KUBE_EDITOR="nano" kubectl edit cm -n kube-system coredns

# 아래 항목 추가
apiVersion: v1
data:
  Corefile: |
    .:53 {
        log
        errors
        health
        ...
    }

# 로그 출력 확인
kubectl logs -n kube-system -l k8s-app=kube-dns -f

요약하자면, 애플리케이션이 DNS 쿼리를 보낼 때,

  • 운영체제는 127.0.0.53:53으로 요청하지만,
  • iptables가 이를 127.0.0.1:15053Istio DNS 프록시(pilot-agent)로 리다이렉트합니다.
  • 프록시는 메시 서비스 목록에서 찾거나, 외부 DNS로 전달하여 응답을 반환합니다.

✅ DNS 프록시가 인식하는 호스트네임은 무엇인가?

Which hostnames is the DNS proxy aware of?

DNS 프록시가 실제로 어떤 호스트네임을 인식하는지는 Istiod의 디버그 엔드포인트를 통해 확인할 수 있습니다. 이 과정에서는 각 워크로드 사이드카에 전달된 NDS(NameTable Discovery Service) 정보를 쿼리하게 됩니다.

먼저 대상이 되는 워크로드(forum-vm)를 확인해봅니다.

# 프록시 워크로드 목록 확인
istioctl proxy-status | awk '{print $1}'

# 출력 예시
catalog-77fdb4997c-f8qj4.istioinaction
istio-eastwestgateway-86f6cb4699-4xfsn.istio-system
istio-ingressgateway-7b7ccd6454-pv8zp.istio-system
forum-vm.forum-services
webapp-684c568c59-vrj97.istioinaction

그 다음, NDS 설정을 직접 조회해봅니다. forum-vm.forum-services 이름을 proxyID로 사용합니다.

# forum-vm 의 NDS(NameTable) 설정 확인
kubectl -n istio-system exec deploy/istiod -- \
curl -Ls "localhost:8080/debug/ndsz?proxyID=forum-vm.forum-services" | jq

출력 예시:

{
  "resource": {
    "@type": "type.googleapis.com/istio.networking.nds.v1.NameTable",
    "table": {
      "catalog.istioinaction.svc.cluster.local": {
        "ips": [ "10.10.200.138" ],
        "registry": "Kubernetes",
        "shortname": "catalog",
        "namespace": "istioinaction"
      },
      "forum.forum-services.svc.cluster.local": {
        "ips": [ "10.10.200.72" ],
        "registry": "Kubernetes",
        "shortname": "forum",
        "namespace": "forum-services"
      },
      "webapp.istioinaction.svc.cluster.local": {
        "ips": [ "10.10.200.48" ],
        "registry": "Kubernetes",
        "shortname": "webapp",
        "namespace": "istioinaction"
      },
      ...
    }
  }
}

이 출력에서 webapp.istioinaction.svc.cluster.local 주소가 등록된 것을 확인할 수 있습니다. 하지만, 우리가 curl 등에 사용한 webapp.istioinaction 같은 짧은 도메인 형태는 직접 명시되어 있지 않습니다.

그럼에도 불구하고 왜 짧은 이름이 해석될까요?

바로 istio-agent가 이러한 짧은 형태의 변형을 자동으로 생성하기 때문입니다.

  • webapp.istioinaction
  • webapp.istioinaction.svc
  • webapp.istioinaction.svc.cluster

이 모든 변형은 같은 IP 주소(예: 10.10.200.48)로 해석됩니다.

이 내용을 실제 라우팅 설정을 통해서도 확인할 수 있습니다:

# webapp 사이드카에 전달된 라우팅 도메인 확인
istioctl proxy-config route deploy/webapp.istioinaction –name 80 -o json

출력 예시 중 일부:

"name": "webapp.istioinaction.svc.cluster.local:80",
"domains": [
  "webapp.istioinaction.svc.cluster.local",
  "webapp",
  "webapp.istioinaction.svc",
  "webapp.istioinaction",
  "10.10.200.48"
]

DNS 프록시는 Istiod가 알고 있는 서비스 목록(NDS)을 기반으로 구성됩니다.

Istio-agent는 Kubernetes 환경에서 익숙한 짧은 호스트네임 형태들을 자동 생성합니다.

이런 변형들은 모두 같은 IP로 해석되며, 클러스터 내에서 서비스 이름으로 접근할 수 있게 해줍니다.
반면, 클러스터 외부 도메인(e.g., www.google.com)은 기존에 설정된 네임서버로 쿼리됩니다.


✅ 에이전트 동작 커스터마이징하기

Customizing the agent’s behavior

Istio 에이전트는 다음과 같은 다양한 설정을 통해 동작을 커스터마이징할 수 있습니다:

  • 로그 출력 레벨 및 포맷
  • 인증서 요청 주기
  • DNS 프록시 설정 등

이번 예제에서는 두 가지 항목을 수정해보겠습니다.

  • DNS 프록시의 로그 레벨을 debug로 설정
  • 인증서 수명을 12시간으로 설정

이 설정은 사이드카 에이전트용 환경 설정 파일인 /var/lib/istio/envoy/sidecar.env 파일을 통해 수행할 수 있습니다.

# 기존 설정 파일 내용 확인
cat /var/lib/istio/envoy/sidecar.env
grep "^[^#]" /var/lib/istio/envoy/sidecar.env  # 주석 제외한 실제 설정만 보기

# 설정 추가
echo 'ISTIO_AGENT_FLAGS="--log_output_level=dns:debug"' >> /var/lib/istio/envoy/sidecar.env
echo 'SECRET_TTL="12h0m0s"' >> /var/lib/istio/envoy/sidecar.env

# 변경된 설정 확인
grep "^[^#]" /var/lib/istio/envoy/sidecar.env

# 출력 예시
ISTIO_AGENT_FLAGS="--log_output_level=dns:debug"
SECRET_TTL="12h0m0s"

이제 변경 사항을 적용하기 위해 에이전트를 재시작합니다.

# Istio 에이전트 재시작
systemctl restart istio

디버그 로그를 확인하여 설정이 잘 적용되었는지 확인합니다. 예를 들어, 도메인 질의가 DNS 프록시에서 어떻게 처리되는지 로그에서 볼 수 있습니다.

# 로그 확인
tail -f /var/log/istio/istio.log

# 출력 예시
2025-05-25T07:23:03.660035Z  debug  dns  response for hostname "www.daum.net." not found in dns proxy, querying upstream
2025-05-25T07:23:03.662845Z  debug  dns  upstream response for hostname "www.daum.net." : ;; opcode: QUERY, status: NOERROR, id: 30399
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; QUESTION SECTION:
;www.daum.net.	IN	A
;; ANSWER SECTION:
www.daum.net.	77	IN	CNAME	daum-4vdtymgd.kgslb.com.
daum-4vdtymgd.kgslb.com.	5	IN	A	121.53.105.193

로컬 DNS 프록시가 질의를 처리했는지도 직접 확인해볼 수 있습니다.

dig +short @localhost -p 15053 www.daum.net

이외에도 인증서 TTL을 변경한 설정이 적용되었는지는 /etc/certs/cert-chain.pem 경로에서 인증서 만료 시간을 확인하여 검증할 수 있습니다.

📌 더 많은 설정 옵션은 Istio 공식 문서인 pilot-agent CLI 문서를 참조하세요.


✅ 메시에서 WorkloadEntry 제거하기

Removing a WorkloadEntry from the mesh

가상머신이 메시(Mesh)에 자동으로 등록된 것처럼, 삭제되면 WorkloadEntry도 자동으로 정리됩니다.

실습 예시

  • AWS EC2 가상머신을 종료하거나 삭제
  • 시간이 조금 지나면 아래 명령어로 해당 리소스가 제거된 것을 확인할 수 있습니다:

watch kubectl get workloadentries -A
kubectl get workloadentries -A
# 출력 예시
No resources found

포인트

  • 클라우드 네이티브 워크로드의 일시성을 지원하려면 워크로드 항목을 자동 정리(삭제) 하는 것이 자동 등록만큼 중요합니다.

쿠버네티스와 가상머신 통합 방식 비교

기능별 비교 요약

기능쿠버네티스 구현가상머신 구현
프록시 설치istioctl 주입 또는 웹훅 자동 주입수동 다운로드 및 설치
프록시 설정사이드카 주입 중 완료istioctl + WorkloadGroup으로 설정 생성 및 전송
워크로드 ID 부트스트랩쿠버네티스가 SA 토큰 자동 주입SA 토큰 수동 전송 필요
헬스 체크Readiness / Liveness Probe 사용WorkloadGroup의 Readiness 설정 사용
등록 처리쿠버네티스가 자동 처리WorkloadGroup을 통한 자동 등록
DNS 해석 방식클러스터 내 FQDN 해석 (DNS 프록시 사용은 선택)istiod가 DNS 프록시 설정 후 FQDN 해석 수행

실제 운영에서의 고려사항

핵심 요점

  • 이번 장에서는 수작업 방식으로 사이드카를 설치하고 통합해보며 메시 동작을 상세히 파악했습니다.
  • 그러나 실제 운영에서는 자동화가 필수입니다.

리스크 예시

"새벽 3시에 가상머신을 재구성하고 메시 등록하라는 요청을 받는 상황"

권장 자동화 도구

자동화의 장점

  • 이미 자동화된 배포 스크립트가 있다면 사이드카 설치 및 설정만 추가하면 됩니다.



📌 Conclusion

이번 블로그에서는 가상머신(VM)을 Istio 서비스 메시로 통합하는 전체 과정을 실습을 통해 단계별로 확인해보았습니다.

WorkloadEntry를 활용한 VM 자동 등록, DNS 프록시를 통한 서비스 해석, istio-agent의 동작 커스터마이징 그리고 워크로드 자동 제거 기능까지 이어지는 흐름은 하이브리드 인프라 환경에서도 일관된 메시 정책을 적용할 수 있는 가능성을 잘 보여주었습니다.

가장 흥미로웠던 부분은 DNS 프록시의 동작 구조와 리다이렉트 메커니즘이었습니다.

로컬에서 127.0.0.53 포트로 향하는 DNS 요청을 iptables 규칙을 통해 15053 포트의 istio-agent로 리디렉션하고 이를 통해 클러스터 서비스의 다양한 호스트네임 변형(webapp, webapp.svc 등)을 자동으로 해석하는 방식은 운영자 입장에서 매우 인상 깊은 구조였습니다.

pilot-agent의 로그 수준을 설정하거나 인증서 TTL을 조정하는 방식처럼 운영 환경에 맞게 메시 동작을 정밀하게 튜닝할 수 있는 유연성도 Istio의 강점 중 하나임을 실감할 수 있었습니다.

마지막 단계에서 WorkloadEntry가 VM이 종료됨과 동시에 자동으로 정리되는 메커니즘은 동적인 클라우드 환경에서 메시의 상태를 안정적으로 유지하기 위한 중요한 설계 포인트로서 작용할것 같습니다.

profile
안녕하세요! DevOps 엔지니어 이재찬입니다. 블로그에 대한 피드백은 언제나 환영합니다! 기술, 개발, 운영에 관한 다양한 주제로 함께 나누며, 더 나은 협업과 효율적인 개발 환경을 만드는 과정에 대해 인사이트를 나누고 싶습니다. 함께 여행하는 기분으로, 즐겁게 읽어주시면 감사하겠습니다! 🚀

0개의 댓글