이스티오의 가상머신 지원
Istio는 원래 쿠버네티스(Kubernetes) 환경에서 동작하도록 설계된 서비스 메시 프레임워크다. 그러나 현실의 인프라는 쿠버네티스로만 구성되어 있지 않다. 온프레미스에 존재하는 레거시 서버, 클라우드 상의 EC2와 같은 VM 인스턴스, 때로는 물리 서버까지 다양한 형태의 워크로드가 함께 운영되는 경우가 많다.
이런 하이브리드 환경에서도 일관된 트래픽 제어, 인증, 관측 기능을 제공하기 위해 Istio는 가상머신(VM) 지원 기능을 제공한다. 이를 통해 쿠버네티스 밖에 있는 VM 워크로드도 쿠버네티스 내부 Pod와 동일한 방식으로 제어 및 관찰할 수 있다.
가상머신을 Istio 메시(mesh)에 연결하면 다음과 같은 이점이 생긴다:
- 서비스 간 mTLS 기반의 보안 통신
- 정책 기반 라우팅 및 트래픽 분할
- 분산 트레이싱 및 메트릭 수집 등 가시성 확보
- 메시 내부 서비스와의 동등한 서비스 디스커버리 및 DNS 해석
Istio는 이를 위해 VM 전용 리소스인 WorkloadGroup, WorkloadEntry를 제공하며, istioctl을 통해 초기 설정 파일을 쉽게 생성할 수 있도록 지원한다.
동시에 istiod가 사이드카 프록시를 위한 부트스트랩 설정, 인증서 발급, DNS 프록시 구성 등을 처리해주기 때문에 쿠버네티스와 유사한 통합 운영이 가능하다.
이번 포스팅에서는 VM 환경에서도 Istio를 운영할 수 있는
Istio는 초기부터 가상머신(VM)을 서비스 메시로 통합하는 기능을 지원해왔다. 하지만 초창기에는 직접적인 제어 평면 바깥에서 수동 설정과 별도 자동화 도구가 필요했기 때문에 운영 난이도가 높았다.
그러다 Istio 1.9.0부터 VM 지원 관련 핵심 기능들이 정식으로 도입되었고, 관련 API도 안정화되면서 VM 통합 기능이 베타(Beta)로 승격되었다. 이때 도입된 주요 변화는 다음과 같다:
- 사이드카 프록시 설치 및 설정 간소화
istioctl 명령어를 통해 VM에 사이드카 프록시를 쉽게 설치하고 구성 가능 - VM 기반 워크로드의 고가용성 구성 지원 WorkloadGroup, WorkloadEntry 리소스를 통해 고가용성 구성이 가능
- 클러스터 내부 DNS 해석 기능 제공 사이드카 프록시에 로컬 DNS 프록시 기능이 포함되어 FQDN 해석 가능
이번 포스팅에서는 Istio와 가상머신(VM)을 통합하는 방법에 대해 알아보자.
가상머신에서의 사이드카 프록시 설치 및 설정 단순화하기
VM을 메시 구성원으로 만들기 위해 필요한 작업은 다음과 같다:
- 네트워크 트래픽을 프록시할 사이드카 설치
- 사이드카가 istiod와 연결되어 설정을 수신할 수 있도록 구성
- ID 토큰을 VM에 제공하여 인증 수행
쿠버네티스에서는 이런 작업들이 대부분 자동화되어 있다. 파드는 웹훅이나 istioctl로 사이드카가 자동 주입되고, ID 토큰도 자동으로 주입된다.
그러나 VM은 쿠버네티스 외부 리소스이기 때문에 이러한 자동화가 적용되지 않는다.
즉, VM 운영자는 사이드카 설치부터 ID 전달까지 모든 작업을 수동으로 수행해야 한다.
쿠버네티스에서도 유사한 과정을 거치지만, 대부분 자동화되어 있다. 웹훅이나 istioctl을 통해 사이드카가 주입되고, 파드는 자동으로 ID 토큰을 주입받는다. 그러나 쿠버네티스 외부에 있는 VM에는 이런 자동화가 제공되지 않는다.
결국 VM 운영자는 사이드카 설치부터 ID 전달까지 모든 작업을 직접 수행해야 한다
네트워크 아키텍처에 따른 구성 방식
Single-network architecture
쿠버네티스 클러스터와 VM이 같은 L3 네트워크에 속해 있는 경우, VM은 istiod와 직접 통신할 수 있다.
- 게이트웨이를 거치지 않고 메시 설정 및 트래픽 흐름이 구성됨
- auto-registration 기능을 사용하면 VM 부팅 시 istiod 또는 게이트웨이에 접속하고, 미리 정의된 WorkloadGroup을 기반으로 WorkloadEntry가 자동 생성됨
Multi-network architecture
VM과 클러스터가 서로 다른 네트워크에 존재하는 경우, Pod는 VM IP로 직접 접근할 수 없다. 이때는 Istio east-west 게이트웨이 또는 cross-network 게이트웨이를 사용해 트래픽을 중계해야 한다.
- 제어 플레인과 데이터 플레인 모두 게이트웨이를 통해 통신
- VM은 게이트웨이 주소를 알고 있어야 하며, 이를 통해 istiod와 mTLS 터널을 설정함
멀티 네트워크 환경에서는 초기 구성 난이도가 높아지며, 사이드카 설치 전략도 달라진다. 다음 절에서는 이러한 구성에서 ID 토큰을 VM에 어떻게 제공하고 인증하는지를 구체적으로 살펴본다.
가상머신의 ID는 어떻게 만들어질까?
Istio는 VM이 메시 안에서 안전하게 통신할 수 있도록 신원을 인증해주는 메커니즘을 갖고 있다.
그런데 이 신원(ID)을 만드는 기준이 바로 쿠버네티스다. 쉽게 말하면, Istio는 VM의 신원을 쿠버네티스가 인정해준 것만 신뢰하겠다는 것이다.
좀 더 구체적으로 설명하면, 쿠버네티스에서 ServiceAccount(서비스 계정)을 만들고, 거기서 나온 ID 토큰을 가상머신에 복사해 넣는다.
이 토큰을 받은 VM 안의 istio-agent가 “계정이 맞아”라고 istiod에 인증을 요청하면, 메시에 참여할 수 있는 공식 신분증(SVID)을 발급받게 되는 구조다.
쿠버네티스 vs 가상머신: ID 주는 방식이 다르다
동작 원리는 비슷하다. ID 토큰을 가지고 istiod에 인증하고, 신분증(SVID)을 받는다는 점에서는 같지만, 자동화 수준이 완전히 다르다.
쿠버네티스 워크로드 (자동)
- 파드가 뜰 때 자동으로 서비스 계정 토큰이 들어감
- 별다른 설정 없이 자동으로 인증 → 메시 참여
- 파드에 서비스 어카운트 토큰이 자동 주입됨
- 해당 토큰을 기반으로 istiod에 인증하고 SVID를 획득
- 서비스 어카운트를 수동 생성
- 토큰을 VM에 직접 복사
- istio-agent가 토큰으로 인증하고 SVID를 발급받음
수동 방식의 문제점
처음엔 단순해 보일 수 있지만, 운영 관점에선 꽤 번거롭다.
- 토큰을 직접 만들고, 안전하게 VM에 넣는 작업을 매번 수작업으로 해야 함
- VM이 많아지거나, 클러스터가 여러 개, 클라우드도 여러 개로 늘어나면 복잡도가 폭발함
- 결과적으로는 대규모 운영에는 어울리지 않는 방식
실습에서는 수작업 방식으로 따라가자
Istio는 요즘 클라우드 제공자들이 제공하는 플랫폼 기반 ID 시스템과 연동하는 기능도 점점 더 발전시키고 있다.
(예: AWS IAM, GCP Workload Identity 등)
하지만 이번 실습에서는 그런 자동화 기능까지 다루지 않고, 가장 기본적인 방식으로 따라간다.
즉, 쿠버네티스에서 만든 토큰을 우리가 직접 VM에 복사해 넣는 방식이다.
이런 방식은 설정 흐름을 하나하나 따라가며 이해하는 데는 오히려 도움이 된다.
가상머신에서도 고가용성(HA)이 가능할까?
Istio는 쿠버네티스처럼 장애가 나도 서비스가 끊기지 않는 구조, 즉 고가용성(HA)을 가상머신 환경에서도 구현할 수 있도록 설계되어 있다.
이를 위해 쿠버네티스의 구조를 그대로 가져와 VM에 맞게 재해석한 두 가지 리소스를 사용한다.
쿠버네티스에서의 고가용성 구조
쿠버네티스는 기본적으로 아래 두 가지 리소스를 통해 워크로드의 안정성을 보장한다.
- Deployment : 파드가 몇 개 떠야 하는지, 어떤 설정으로 만들어야 하는지를 정의하는 설계도 같은 역할
- Pod: Deployment를 기반으로 실제로 뜨는 실행 단위. 고유 상태가 없기 때문에 장애가 나면 새로 쉽게 교체할 수 있다
이 구조 덕분에 파드에 장애가 나도 자동으로 새로 만들어서 서비스를 계속 이어갈 수 있다.
이 구조 덕분에 장애가 발생해도 파드를 폐기하고 다시 생성하여 서비스 연속성을 유지할 수 있다.
Istio에서 VM을 위한 고가용성 구조
VM 환경에서는 Deployment → Pod 구조 대신, 아래 두 가지 Istio 리소스를 활용한다.
- WorkloadGroup (→ Deployment 역할)
하나의 VM 그룹을 대표하는 템플릿으로, 공통 속성을 정의한다.- 애플리케이션 포트
- 서비스 어카운트
- 레이블
- 상태 확인용 프로브 등
- WorkloadEntry (→ Pod 역할)
실제 개별 가상머신 인스턴스를 나타낸다. WorkloadGroup에서 정의한 공통 속성을 그대로 물려받고,- VM의 고유 IP 주소
- 현재 상태 등 고유 정보만 따로 지정한다.
자동 등록 기능으로 운영 부담 줄이기
가상머신이 서비스 메시의 일원이 되기 위해서는 단순히 연결만 되는 것이 아니라, 제어 플레인에 신뢰할 수 있는 방식으로 등록되어야 한다. 이를 자동으로 처리하는 방식이 바로 워크로드 자동 등록이다.
자동 등록의 동작 방식
WorkloadEntry는 수동으로도 생성할 수 있지만, Istio는 자동 등록(auto-registration) 방식을 더 추천한다.
이 기능을 사용하면, VM이 부팅될 때 자동으로 WorkloadGroup 정보를 기반으로 WorkloadEntry가 생성된다.
즉, 운영자가 일일이 등록하지 않아도, VM이 메시 안으로 자동 합류하게 된다.
결과적으로 가상머신도 쿠버네티스처럼 서비스를 안정적으로 유지할 수 있는 구조를 갖출 수 있다.
WorkloadEntry가 중요한 이유
WorkloadEntry는 단순히 VM을 메시 안에 등록하는 수단 그 이상이다.
이 리소스를 활용하면 쿠버네티스의 Service나 Istio의 ServiceEntry 같은 리소스들이 라벨 셀렉터를 통해 VM을 백엔드 대상으로 인식할 수 있게 된다.
예를 들어, 클라이언트가 reviews.default.svc.cluster.local처럼 도메인(FQDN) 기반으로 트래픽을 보낼 경우, 다음과 같은 장점이 생긴다.
- 비정상 상태(unhealthy)인 VM을 자동으로 서비스에서 제거할 수 있음
- VM 인스턴스를 수요에 따라 수평 확장하거나 종료해도 트래픽에 영향 없음
- 클라이언트 입장에서는 백엔드 변경을 전혀 인식할 필요 없음
즉, WorkloadEntry는 VM을 쿠버네티스 네이티브 서비스처럼 취급할 수 있게 해주는 핵심 장치다.
실무에서 유용한 시나리오: 마이그레이션
가장 대표적인 활용 사례는 레거시 VM 기반 워크로드를 쿠버네티스로 점진적으로 이전할 때다.
- VM과 Pod를 동시에 실행
- Istio의 트래픽 분할 기능을 통해 트래픽 일부를 Pod로 전환
- 오류율이 높아지면 다시 VM으로 롤백 가능
이렇게 VM과 Pod를 하나의 서비스 셀렉터로 묶어서 운영하면, 다운타임 없이 점진적으로 마이그레이션할 수 있다.
운영 리스크를 최소화하면서도 새로운 플랫폼으로 이전할 수 있는 유연성을 확보할 수 있는 전략이다.
자동 등록(auto-registration)은 왜 중요한가?
VM을 메시에 넣을 때 자동 등록 기능은 단순한 편의 기능이 아니다.
이 기능을 활용하면 다음과 같은 효과를 누릴 수 있다:
- 운영자가 직접 WorkloadEntry를 생성하지 않아도 됨
- VM이 부팅되면 자동으로 메시 참여
- 확장성과 유지보수 측면에서 훨씬 효율적
이번 실습에서는 WorkloadGroup과 자동 등록 기능을 같이 설정해보고, 실제로 VM이 메시에서 어떻게 인식되고 상태가 반영되는지 확인할 예정이다.
Istio는 언제 VM에 트래픽을 보내는가? (헬스 체크 구조 이해하기)
VM이 메시에 등록됐다고 해서 곧바로 트래픽을 받는 건 아니다.
Istio는 먼저 해당 워크로드가 정상적으로 트래픽을 받을 준비가 되었는지 확인한 뒤, 라우팅을 허용한다.
이 과정을 Readiness Probe라고 부르며, 쿠버네티스와 유사한 구조로 동작한다.
Istio의 헬스 체크 구성
- Readiness Probe
워크로드가 기동 완료 후, 트래픽을 받을 준비가 되었는지 주기적으로 확인
→ 준비되지 않은 워크로드는 라우팅 대상에서 제외됨 - Liveness Probe
워크로드가 살아 있는지 지속적으로 확인
→ 비정상 상태일 경우 재시작 등의 복구 조치를 유발
중요한 포인트는: Istio는 readiness까지만 관리한다는 점이다.
Liveness는 쿠버네티스나 클라우드 플랫폼 같은 실행 환경이 책임진다.
가상머신에서 Readiness 프로브는 어떻게 작동할까?
VM에 설치된 istio-agent가 WorkloadGroup에서 설정한 헬스 체크 방식에 따라 애플리케이션 상태를 계속 모니터링한다.
상태가 바뀌면 이를 istiod에 보고하고, 그 결과에 따라 트래픽 라우팅이 결정된다.
예시 흐름:
- 애플리케이션 상태: 정상 → 비정상
→ 메시에서 해당 VM을 제거 - 상태: 비정상 → 정상
→ 다시 메시에 등록
이렇게 워크로드 상태를 기반으로 동적으로 라우팅을 조절할 수 있기 때문에, 오류를 일으키는 인스턴스로 트래픽이 전달되는 상황을 방지할 수 있다.
Readiness vs Liveness: 책임 분리
정리하자면,
- Readiness Probe
→ Istio가 담당 (메시 내부의 라우팅 결정 기준) - Liveness Probe
→ 쿠버네티스나 클라우드 플랫폼에서 담당 (실행 환경의 생존 여부 판단)
VM 환경이라면 GCP의 MIG, AWS의 Auto Scaling Group, Azure의 VMSS 등 플랫폼 수준의 헬스 체크 기능을 반드시 함께 사용해야 한다.
설정 팁: 공격적인 readiness, 보수적인 liveness
실제 운영에서는 다음과 같은 전략을 추천한다.
- Readiness Probe는 빠르게 실패하도록 설정
→ 오류 응답을 즉시 감지해 트래픽에서 빠르게 제외 - Liveness Probe는 여유 있게 설정
→ 일시적인 오류로 인한 조기 종료를 막음
이렇게 구성하면 문제 발생 시, 먼저 해당 인스턴스를 서비스에서 제거하고, 일정 시간 관찰 후 재시작 여부를 판단할 수 있다.
서비스 안정성과 사용자 경험을 동시에 고려한 최적의 설정 방식이다.
메시 내 서비스의 DNS 해석
왜 DNS가 중요할까?
가상머신은 쿠버네티스 클러스터 바깥에 존재한다.
그래서 기본적으로는 kube-dns나 CoreDNS 같은 내부 DNS 서버에 접근할 수 없다.
문제는 여기서 끝나지 않는다.
VM이 클러스터 내부 서비스의 FQDN(예: reviews.default.svc.cluster.local)을 해석하지 못한다는 것 자체가 서비스 메시 통합의 큰 걸림돌이 된다.
DNS가 안 되면, 프록시까지 트래픽이 절대 도달하지 못한다.
사이드카 프록시는 라우팅 정보를 모두 알고 있어도, 애플리케이션이 목적지의 호스트 이름을 IP로 바꾸지 못하면, 프록시로 트래픽을 보낼 수가 없다.
결국 DNS 해석 실패는 메시 통신 자체를 끊어버리는 핵심 장애 요인이다.
기존 방식: 프라이빗 DNS + 외부 컨트롤러
과거에는 다음과 같은 방법으로 문제를 우회했다.
- 클러스터 내부 서비스 정보를 담은 프라이빗 DNS 서버를 따로 구성
- VM은 이 DNS 서버를 참조해서 서비스 이름을 해석
- DNS 레코드 변경을 외부에서 감지하려면 external-dns 같은 툴을 추가로 사용
👉 외부 DNS 컨트롤러 예시: kubernetes-sigs/external-dns
이 방식은 어느 정도 작동하긴 했지만,
- 운영이 복잡하고
- 보안 설정도 따로 필요하며
- 쿠버네티스 변경사항과 DNS 간의 동기화 지연도 있었다
즉, 근본적인 해결책은 아니었던 셈이다.
Istio DNS 프록시로 해결
이 문제를 해결하기 위해 Istio 1.8부터 로컬 DNS 프록시 기능이 도입되었다.
이제는 가상머신에서도 클러스터 내부의 서비스 이름을 자연스럽게 인식할 수 있게 된 것.
동작 방식은 다음과 같다:
- 가상머신의 DNS 쿼리는 iptables 규칙을 통해 사이드카 내 istio-agent로 리다이렉션됨
- istio-agent는 내부적으로 DNS 프록시 기능을 수행하며, 클러스터 내 서비스 레코드를 해석
- 이 DNS 프록시는 istiod로부터 구성 정보를 동기화받음
- 결과적으로, VM에서도 클러스터 FQDN 해석이 자동으로 가능해짐
📖 관련 블로그: Istio DNS Proxy 공식 포스팅
NDS: 더 똑똑한 DNS 동기화를 위한 확장
DNS 프록시는 여기서 끝나지 않는다.
Istio는 이를 지속적으로 발전시키기 위해 NDS(Name Discovery Service)라는 새로운 API를 도입했다.
이 기능을 통해 다음이 가능해진다:
- 쿠버네티스 서비스나 Istio ServiceEntry가 생성되면
- istiod는 해당 정보를 자동으로 사이드카 DNS 프록시에 전달
- VM은 수동 설정 없이도 항상 최신 DNS 레코드를 참조할 수 있음
이건 VM만을 위한 기능이 아니다.
Istio DNS 프록시는 메시 전체에서 DNS 기반 트래픽 흐름을 정밀하게 제어할 수 있는 핵심 컴포넌트다.
인프라 준비하기: 가상머신 + 쿠버네티스 통합 구조
이번 실습에서는 쿠버네티스 클러스터와 가상머신을 함께 구성하여 서비스 메시 내에서 통합된 네트워크 환경을 만드는 방법을 다룬다.
- webapp, catalog 서비스는 쿠버네티스 클러스터(k3s-s)에 배포
- forum 서비스는 가상머신(test-pc)에 배
- 두 환경은 서로 다른 네트워크에 존재하기 때문에
→ east-west 게이트웨이 설정이 필수
Istio 설치 및 메시 구성
Step1, Istio 실습소스코드 및 istioctl 설치
# 소스코드 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
Step2, 네임스페이스 및 네트워크 레이블 설정
클러스터와 VM이 서로 다른 네트워크에 있으므로, Istio 네임스페이스에 네트워크 레이블을 부여해야 한다.
# 클러스터와 가상머신이 다른 네트워크에 있으므로, 이스티오를 설치한 네임스페이스에 네트워크 정보 레이블을 지정해야 한다.
kubectl create namespace istio-system
kubectl label namespace istio-system topology.istio.io/network=west-network
Step3, 컨트롤 플레인 설치 (demo 프로파일)
# 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
- meshID: usmesh
- clusterName: west-cluster
- network: west-network
Step4, Istio Addon 구성 (관측 도구 설치)
kubectl apply -f istio-$ISTIOV/samples/addons
kubectl get pod -n istio-system
NAME READY STATUS RESTARTS AGE
grafana-545465bf4c-bsfpx 1/1 Running 0 53s
istio-ingressgateway-84699b8dcb-8666t 1/1 Running 0 85s
istiod-7f6f768dc8-wppsf 1/1 Running 0 94s
jaeger-7cf8c7c56d-l4zwz 1/1 Running 0 53s
kiali-8f985c677-gxlb8 1/1 Running 0 53s
prometheus-7f467df8b6-mkfpg 2/2 Running 0 53s
Step5, NodePort 수동 설정 (외부 접근 하도록)
# 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}]}}'
서비스 배포 및 라우팅 테스트
1.cool-store 서비스/gw/vs 배포 및 http 요청 확인
kubectl create ns istioinaction
kubectl label namespace istioinaction istio-injection=enabled
kubectl get ns --show-labels
2.서비스 및 게이트웨이 리소스 배포
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
kubectl get deploy,svc -n istioinaction
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/catalog 1/1 1 1 24s
deployment.apps/webapp 1/1 1 1 20s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/catalog ClusterIP 10.10.200.225 <none> 80/TCP 24s
service/webapp ClusterIP 10.10.200.143 <none> 80/TCP 20s
3.외부에서 HTTP 요청 테스트
쿠버네티스 노드 IP를 이용해 Gateway를 통해 요청을 보낸다.
(⎈|default:default) root@k3s-s:~# APP_IP=13.125.68.38
(⎈|default:default) root@k3s-s:~# curl -s -H "Host: webapp.istioinaction.io" http://$APP_IP:30000/api/catalog/items/1 | jq
{
"id": 1,
"color": "amber",
"department": "Eyewear",
"name": "Elinor Glasses",
"price": "282.00"
}
4.가상머신 연결 테스트
# VM
VM_IP=3.38.162.233
curl $VM_IP -I
이제 Istio가 설치된 쿠버네티스 클러스터와 외부 VM이 서로 다른 네트워크에 있음에도 불구하고, 하나의 서비스 메시 안에서 통합된 구조로 동작할 수 있는 준비가 끝났다.
다음 단계에서는 VM을 메시에 참여시키고, 트래픽을 어떻게 연결할지 다뤄보자.
가상머신까지 메시 확장 확인하기
컨트롤 플레인 업데이트
가상머신을 Istio 서비스 메시에 통합하려면, 몇 가지 기능이 필요하다.
하지만 이 기능들은 기본 Istio 설치에는 포함돼 있지 않다.
즉, IstioOperator 설정을 업데이트해 가상머신 통합 관련 옵션들을 명시적으로 활성화해야 한다.
업데이트된 IstioOperator 설정에는 다음과 같은 핵심 옵션들이 포함된다.
# 컨트롤 플레인 업데이트 Mesh expansion to VMs
# istio-in-action/book-source-code-master/ch13/controlplane/cluster-in-west-network-with-vm-features.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
...
meshConfig:
defaultConfig:
proxyMetadata:
ISTIO_META_DNS_CAPTURE: "true" # DNS 쿼리가 캡처돼 DNS 프록시로 리다이렉트된다
values:
polit:
env:
PILOT_ENABLE_WORKLOAD_ENTRY_AUTOREGISTRATION: true # 워크로드를 컨트롤 플레인에 자동 등록할 수 있다
PILOT_ENABLE_WORKLOAD_ENTRY_HEALTHCHECKS: true # 가상머신 워크로드의 상태를 검사한다
...
컨트롤 플레인 재설치 (VM 통합 기능 포함)
- NodePort 타입으로 외부 노출도 설정한다:
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 쿼리를 직접 처리하므로, VM도 클러스터 서비스 이름으로 접근 가능 - 운영 자동화
→ WorkloadEntry를 수동으로 만들지 않아도 VM이 자동 등록됨 - 상태 기반 트래픽 제어
→ VM이 정상인지 아닌지에 따라 istiod가 트래픽 라우팅 여부를 결정할 수 있음
이 기능들이 잘 작동하려면, 가상머신이 반드시 istiod와 통신할 수 있어야 한다.
즉, 클러스터의 컨트롤 플레인과 연결된 상태여야 설정을 내려받고 ID 토큰을 갱신할 수 있다.
이 연결이 안 되면, 자동 등록도 헬스 체크도 작동하지 않는다.
따라서 VM과 istiod 간 네트워크경로(East-West Gateway 또는 내부 피어링 등)는 반드시 확보해두자.
istiod와 클러스터 서비스를 VM에 노출하기
왜 게이트웨이가 필요할까?
가상머신이 Istio 메시의 구성원이 되려면, 가장 먼저 해야 할 일은 컨트롤 플레인과 통신할 수 있도록 만드는 것이다.
즉, 가상머신이 istiod에 접근할 수 있어야 하고, 클러스터 내부의 서비스들과도 트래픽을 주고받을 수 있어야 한다.
- 같은 네트워크일 경우엔 별다른 설정 없이도 연결이 된다.
- 하지만 이번 실습처럼 서로 다른 네트워크(VM ↔ 클러스터)에 위치한 경우엔, 트래픽을 중계해줄 east-west 게이트웨이가 필요하다.
east-west 게이트웨이 설치하기
이 게이트웨이는 기본 Istio Ingress와는 다르게 istiod와 VM 간 통신을 위한 전용 통로 역할을 한다.
15012, 15017, 15443 포트를 통해 istiod 및 메시 트래픽을 노출한다.
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 # 기본 Istio Operator 명과다름.
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"
# The network to which traffic is routed
- 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
#
IstioOperator로 east-west gateway 구성
istioctl install -f istio-in-action/book-source-code-master/ch13/gateways/cluster-east-west-gw.yaml -y
게이트웨이 Pod 확인:
kubectl get pod -n istio-system -l chart=gateways
NAME READY STATUS RESTARTS AGE
istio-eastwestgateway-86f6cb4699-pvz9z 1/1 Running 0 12s
istio-ingressgateway-7b7ccd6454-kcq57 1/1 Running 0 98s
# 실습 LoadBalancer 설정이 필요(k3 lb)
kubectl get svc -n istio-system -l istio.io/rev=default
istio-eastwestgateway LoadBalancer 10.10.200.252 192.168.10.10 15021:32278/TCP,15443:31099/TCP,15012:31437/TCP,15017:32573/TCP 178m
게이트웨이 포트 노출 설정
east-west 게이트웨이를 설치하면 다음 포트들이 외부로 노출된다:
15443 | 메시 트래픽 (mTLS 터널) |
15012 | istiod xDS 통신 (SDS 등 포함) |
15017 | 인증 webhook |
메시 트래픽 포워딩: cross-network Gateway 리소스 생성
VM에서 메시 내부 서비스로 향하는 요청이 15443 포트를 통해 프록시되도록 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
NAMESPACE NAME AGE
istio-system gateway.networking.istio.io/cross-network-gateway 11s
istioinaction gateway.networking.istio.io/coolstore-gateway 6m23s
NAMESPACE NAME GATEWAYS HOSTS AGE
istioinaction virtualservice.networking.istio.io/webapp-virtualservice ["coolstore-gateway"] ["webapp.istioinaction.io"] 6m23s
istiod 통신 포트 노출: Gateway + VirtualService 설정
이제 VM이 istiod에 인증 및 설정 요청을 보낼 수 있도록 15012 / 15017 포트를 라우팅하도록 설정한다.
#
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
NAMESPACE NAME AGE
istio-system gateway.networking.istio.io/cross-network-gateway 83s
istio-system gateway.networking.istio.io/istiod-gateway 5s
istioinaction gateway.networking.istio.io/coolstore-gateway 7m35s
NAMESPACE NAME GATEWAYS HOSTS AGE
istio-system virtualservice.networking.istio.io/istiod-vs ["istiod-gateway"] ["*"] 5s
istioinaction virtualservice.networking.istio.io/webapp-virtualservice ["coolstore-gateway"] ["webapp.istioinaction.io"] 7m35
여기까지 다음 작업을 마쳤다:
- east-west 게이트웨이 설치 및 포트 오픈
- 메시 트래픽(15443) 및 istiod 통신 포트(15012, 15017) 노출
- 외부(VM)에서 메시 내부로 안전하게 연결할 수 있는 통로 확보
이제 진짜 마지막 단계, WorkloadGroup만 설정하면 가상머신이 메시에 참여할 준비가 끝난다.
다음 단계에서는 VM을 대표하는 WorkloadGroup 리소스를 만들고, 실제로 가상머신이 메시 안에서 어떻게 동작하는지 확인해본다
WorkloadGroup으로 가상머신 워크로드 정의하기
가상머신이 Istio 메시에 참여하려면, 먼저 해당 워크로드를 대표하는 WorkloadGroup 리소스를 정의해야 한다.
이 리소스는 쿠버네티스의 Deployment처럼 여러 인스턴스(VM)에 공통으로 적용될 속성을 설정하는 역할을 한다.
왜 WorkloadGroup이 중요한가?
WorkloadGroup에는 다음과 같은 정보들이 포함된다:
- 애플리케이션 포트 정보
- Readiness 상태 확인 방식
- 워크로드가 속한 네트워크
- 사용할 서비스 어카운트
쉽게 말해, VM이 메시에 참여하려면 “나는 누구이며, 어디에 있고, 준비가 되었는지”를 WorkloadGroup을 통해 설명해야 한다.
예시: forum 서비스용 WorkloadGroup
아래는 forum 가상머신 워크로드를 위한 WorkloadGroup 정의 예시다.
#
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 # 워크로드가 이 워크로드 그룹에 등록하려면 forum-sa 인증 토큰을 보유하고 있어야 한다
network: vm-network # 이스티오가 동일한 네트워크에 있는 워크로드 사이의 직접 접근을 설정할 수 있도록 한다
probe: # 이 워크로드 그룹의 인스턴스에서 실행되는 istio-agent는 HTTP GET 요청을 8080 포트의 /api/healthz 경로로 보내 앱의 준비 상태를 확인한다
periodSeconds: 5
initialDelaySeconds: 1
httpGet:
port: 8080
path: /api/healthz
- labels: 클러스터 내 서비스가 이 워크로드를 라벨 셀렉터로 선택할 수 있게 해줌
- network: 해당 VM이 속한 네트워크 이름을 명시 (→ 게이트웨이 선택에 영향)
- serviceAccount: 메시 인증을 위한 신원(ID) 정보
- probe: Readiness 상태 확인을 위한 HTTP 헬스체크 설정 (포트 8080, /api/healthz)
실제 적용해보기
1.네임스페이스 및 서비스 어카운트 생성
#
kubectl create namespace forum-services
kubectl create serviceaccount forum-sa -n forum-services
2.WorkloadGroup 리소스 적용
kubectl apply -f istio-in-action/book-source-code-master/ch13/workloadgroup.yaml
3.적용 확인
#
kubectl get-all -n forum-services
kubectl get workloadgroup -n forum-services
NAME AGE
forum 6s
적용 후 무슨 일이 벌어질까?
이제 클러스터는 다음 조건을 만족하는 VM이 부팅되면, 자동으로 해당 인스턴스를 WorkloadEntry로 등록한다:
- forum-sa 서비스 어카운트의 유효한 토큰을 가지고 있고
- forum WorkloadGroup에 정의된 네트워크와 일치하며
- 애플리케이션이 정상 상태(Readiness probe 성공)일 경우
즉, 가상머신이 별도 수동 작업 없이 메시에 자동 등록될 수 있는 기반이 마련된 것이다.
가상머신의 사이드카용 설정 만들기
WorkloadGroup에서 사이드카 설정까지
앞서 만든 WorkloadGroup은 단순히 가상머신 정보를 정의하는 것에서 그치지 않는다.
Istio는 이 정보를 바탕으로 사이드카가 메시 구성원으로 동작하는 데 필요한 설정 파일 전체를 자동으로 생성할 수 있다.
이 과정은 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 # 워크로드를 자동으로 등록하도록 설정한다.
이 명령은 다음과 같은 작업을 자동으로 수행한다:
• WorkloadGroup에 정의된 값을 기반으로 사이드카용 설정 생성
• 클러스터에 질의하여 서비스 어카운트 토큰, 루트 인증서 등을 함께 구성
• --autoregister 옵션으로 VM 부팅 시 자동 등록 지원
VM에서 최초 istiod와의 통신 시, 필요한 엔드포인트를 hosts 파일로 사용
생성된 파일 구성
chown ubuntu:ubuntu -R /tmp/my-workload-files/
tree /tmp/my-workload-files/
├── cluster.env # 프록시 환경 설정 정보
├── hosts # istiod를 찾기 위한 호스트 파일 (east-west gateway IP 사용)
├── istio-token # 서비스 어카운트 토큰 (ID 인증용)
├── mesh.yaml # 메시 메타데이터, 레이블, readiness 설정 등
└── root-cert.pem # 루트 인증서 (istiod 인증서 검증용)
여기서 192.168.10.10은 east-west 게이트웨이의 External IP로, VM이 이 경유지를 통해 istiod에 연결한다.
cat /tmp/my-workload-files/hosts
192.168.10.10 istiod.istio-system.svc # East-west gateway의 노출된(External) IP <- 실습의 경우 k3 이기 때문에 호스트 PC의 이더넷 IP
생성된 구성 파일의 의미
이 설정 파일들은 사이드카가 메시에 참여할 수 있게 만드는 핵심 조각들이다. 각각의 역할은 다음과 같다:
• 루트 인증서: istiod가 제시하는 TLS 인증서의 진위를 검증
• 토큰: 해당 VM이 forum-sa 서비스 어카운트 기반이라는 것을 증명
• 메시 정보: 클러스터 ID, 네트워크 이름, 워크로드 이름 등 식별자 및 프로브 설정 포함
이 설정이 갖춰지면, 사이드카는 메시와 보안 커넥션을 수립하고, SVID를 발급받으며, 이후 xDS를 통해 설정을 받아 서비스 메시의 구성원이 된다.
생성된 파일을 가상머신을 전송하기
이제 생성된 설정 파일들을 실제 VM에 옮겨야 한다.
이 안에는 토큰 같은 민감 정보도 포함되어 있으므로, 실습에선 SSH를 사용해 수동으로 전송하지만, 실제 운영 환경에서는 자동화된 안전한 배포 방식이 필수다.
# 임시로, 자신의 로컬 PC에 위 파일들 복사 : 바로 vm_ip 에 복사해도 되지만, 현재 실습 환경 편리성으로 경유 복사.
APP_IP=13.125.68.38
mkdir my-workload-files
scp -i ~/.ssh/jdg-keypair.pem ubuntu@$APP_IP:/tmp/my-workload-files/\* ./my-workload-files # macOS
ls -al
openssl x509 -in ./my-workload-files/root-cert.pem -noout -text # istio CA 인증서
jwt decode $(cat ./my-workload-files/istio-token) # 토큰
...
Token claims
------------
{
"aud": [
"istio-ca"
],
"exp": 1748724427,
"iat": 1748720827,
"iss": "https://kubernetes.default.svc.cluster.local",
"kubernetes.io": {
"namespace": "forum-services",
"serviceaccount": {
"name": "forum-sa",
"uid": "94d3f79a-a15d-4a28-8271-9d2ba482f590"
}
},
"nbf": 1748720827,
"sub": "system:serviceaccount:forum-services:forum-sa"
cat ./my-workload-files/mesh.yaml
defaultConfig:
discoveryAddress: istiod.istio-system.svc:15012
meshId: usmesh
proxyMetadata:
CANONICAL_REVISION: latest
CANONICAL_SERVICE: forum
ISTIO_META_AUTO_REGISTER_GROUP: forum
ISTIO_META_CLUSTER_ID: west-cluster
ISTIO_META_DNS_CAPTURE: "true"
ISTIO_META_MESH_ID: usmesh
ISTIO_META_NETWORK: vm-network
ISTIO_META_WORKLOAD_NAME: forum
ISTIO_METAJSON_LABELS: '{"app":"forum","service.istio.io/canonical-name":"forum","service.istio.io/canonical-revision":"latest"}'
POD_NAMESPACE: forum-services
SERVICE_ACCOUNT: forum-sa
TRUST_DOMAIN: cluster.local
readinessProbe:
httpGet:
path: /api/healthz
port: 8080
initialDelaySeconds: 1
periodSeconds: 5
tracing:
zipkin:
address: zipkin.istio-system:9411
# 로컬 PC의 파일들을 forum-vm로 복사
FORUM_IP=3.38.162.233
scp -i ~/.ssh/jdg-keypair.pem ./my-workload-files/cluster.env ubuntu@$FORUM:/tmp/
scp -i ~/.ssh/jdg-keypair.pem ./my-workload-files/istio-token ubuntu@$FORUM:/tmp/
scp -i ~/.ssh/jdg-keypair.pem ./my-workload-files/mesh.yaml ubuntu@$FORUM:/tmp/
scp -i ~/.ssh/jdg-keypair.pem ./my-workload-files/root-cert.pem ubuntu@$FORUM:/tmp/
# forum-vm 에서 파일 확인
ls -l /tmp
-rwxr--r-- 1 ubuntu ubuntu 714 May 24 19:08 cluster.env
-rwxr--r-- 1 ubuntu ubuntu 844 May 24 19:08 istio-token
-rwxr--r-- 1 ubuntu ubuntu 792 May 24 19:08 mesh.yaml
-rwxr--r-- 1 ubuntu ubuntu 1094 May 24 19:08 root-cert.pem
...
설정 파일이 VM으로 안전하게 전달되었으므로, 이제 남은 일은 사이드카(Envoy + istio-agent)를 설치하고 실행하는 것뿐이다.
이 과정을 통해 VM은 메시의 정식 구성원으로 편입된다.
이제 서비스 간 통신, 트래픽 라우팅, 보안 정책 등이 모두 메시의 통제 하에 있게 된다.
가상머신에 istio-agent 설치 및 설정하기
이제 가상머신이 메시의 일원이 되기 위한 마지막 단계다.
바로 istio-agent를 설치하고, 이전에 생성했던 설정 파일을 활용해 사이드카가 메시와 연결되도록 만드는 작업이다.
1.설치 전 환경 확인
먼저 DNS 설정과 iptables 상태를 점검해두자. 이는 이후 사이드카의 트래픽 리다이렉션과 DNS 캡처에 영향을 줄 수 있다.
#
cat /etc/resolv.conf
nameserver 127.0.0.53
...
ss -tnlp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=357,fd=14))
ss -unlp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=357,fd=13))
resolvectl status
...
resolv.conf mode: stub # stub 모드로 설정, 127.0.0.53(local stub resolver)을 가리키며, systemd-resolved가 이 요청을 처리함
Link 2 (ens5)
Current Scopes: DNS
Protocols: +DefaultRoute +LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
Current DNS Server: 192.168.0.2
...
# 설치 전 확인
iptables -t nat -L -n -v
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
아직 iptables에는 별다른 정보가 존재하지 않는다.
2.istio-agent 설치
# 데비안 패키지 형식으로 다운로드 후 설치
curl -LO https://storage.googleapis.com/istio-release/releases/1.17.8/deb/istio-sidecar.deb
dpkg -i istio-sidecar.deb
# 확인
which pilot-agent
pilot-agent version
which envoy
envoy --version
tree /etc/istio
/etc/istio
├── config
│ └── mesh
├── envoy
│ ├── cluster.env
│ ├── envoy_bootstrap_tmpl.json
│ └── sidecar.env
├── extensions
│ ├── metadata-exchange-filter.compiled.wasm
│ ├── metadata-exchange-filter.wasm
│ ├── stats-filter.compiled.wasm
│ └── stats-filter.wasm
└── proxy
tree /var/lib/istio/
/var/lib/istio/
├── config
│ └── mesh
├── envoy
│ ├── envoy_bootstrap_tmpl.json
│ └── sidecar.env
├── extensions
│ ├── metadata-exchange-filter.compiled.wasm
│ ├── metadata-exchange-filter.wasm
│ ├── stats-filter.compiled.wasm
│ └── stats-filter.wasm
└── proxy
3.사이드카 설정 파일 위치 지정
이전에 생성한 설정 파일을 가상머신의 정해진 디렉토리에 복사해야 한다.
# istio-agent 는 특정 위치에서 설정 파일을 읽으므로, 복사해둔 파일을 옮겨보자
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
4./etc/hosts 설정 (DNS 프록시 이전 단계
사이드카가 메시 설정을 수신하기 전에는 DNS 항목을 모르기 때문에, 초기 연결을 위해 hosts 파일에 istiod를 정적 등록해줘야 한다.
# istiod.istio-system.svc 요청을 istiod 인스턴스로 프록시하는 east-weat 게이트웨이 IP 주소로 정적으로 해석하도록 한다.
cat /etc/hosts
echo "192.168.10.10 istiod.istio-system.svc" | sudo sh -c 'cat >> /etc/hosts'
cat /etc/hosts
# istio-agent가 호스트네임 해석을 방해하지 않도록 hosts 파일에 forum-vm 머신의 호스트네임을 하드코딩하자 : 설정되어 있음
echo "$(hostname --all-ip-addresses | cut -d ' ' -f 1) $(hostname)" | sudo sh -c 'cat >> /etc/hosts'
cat /etc/hosts
192.168.10.200 forum-vm
5.권한 설정
사이드카는 전용 사용자(istio-proxy)로 실행되므로, 해당 디렉터리에 읽기/쓰기 권한을 줘야 한다.
#
chown -R istio-proxy /var/lib/istio /etc/certs /etc/istio/proxy /etc/istio/config /var/run/secrets /etc/certs/root-cert.pem
6.사이드카(istio-agent) 서비스 시작
#
systemctl status istio
systemctl start istio
systemctl enable istio
systemctl status istio
...
● istio.service - istio-sidecar: The Istio sidecar
Loaded: loaded (/lib/systemd/system/istio.service; enabled; vendor preset: enabled)
Active: active (running) since Sun 2025-06-01 05:01:16 KST; 55s ago
Docs: http://istio.io/
Main PID: 3297 (sudo)
Tasks: 21 (limit: 2272)
Memory: 35.8M
CPU: 1.032s
CGroup: /system.slice/istio.service
├─3297 sudo -E -u istio-proxy -s /bin/bash -c "ulimit -n 1024; INSTANCE_IP=192.168.10.200 POD_NAME=forum-vm POD_NAMESPACE=forum-services exec /usr/local/bin/pilot-agent proxy 2>> ./var/log/istio/istio.err.log >> ./var/log/istio/istio.lo>
├─3423 /usr/local/bin/pilot-agent proxy
└─3431 /usr/local/bin/envoy -c etc/istio/proxy/envoy-rev.json --drain-time-s 45 --drain-strategy immediate --local-address-ip-version v4 --file-flush-interval-msec 1000 --disable-hot-restart --allow-unknown-static-fields --log-format "%Y>
...
7.동작 확인
# 로그 확인
journalctl -u istio -f
# 프로세스 확인
ps aux | grep istio
# iptables 룰 확인
iptables -t nat -L -n -v
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
2 152 ISTIO_INBOUND tcp -- * * 0.0.0.0/0 0.0.0.0/0
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
29 1776 ISTIO_OUTPUT tcp -- * * 0.0.0.0/0 0.0.0.0/0
6 422 RETURN udp -- * * 0.0.0.0/0 0.0.0.0/0 udp dpt:53 owner UID match 998
0 0 RETURN udp -- * * 0.0.0.0/0 0.0.0.0/0 udp dpt:53 owner GID match 998
0 0 REDIRECT udp -- * * 0.0.0.0/0 127.0.0.53 udp dpt:53 redir ports 15053
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain ISTIO_INBOUND (1 references)
pkts bytes target prot opt in out source destination
0 0 RETURN tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:15008
2 152 RETURN tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22
0 0 RETURN tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:15090
0 0 RETURN tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:15021
0 0 RETURN tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:15020
0 0 ISTIO_IN_REDIRECT tcp -- * * 0.0.0.0/0 0.0.0.0/0
Chain ISTIO_IN_REDIRECT (3 references)
pkts bytes target prot opt in out source destination
0 0 REDIRECT tcp -- * * 0.0.0.0/0 0.0.0.0/0 redir ports 15006
Chain ISTIO_OUTPUT (1 references)
pkts bytes target prot opt in out source destination
22 1320 RETURN all -- * lo 127.0.0.6 0.0.0.0/0
0 0 ISTIO_IN_REDIRECT tcp -- * lo 0.0.0.0/0 !127.0.0.1 tcp dpt:!53 owner UID match 998
0 0 RETURN tcp -- * lo 0.0.0.0/0 0.0.0.0/0 tcp dpt:!53 ! owner UID match 998
6 360 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0 owner UID match 998
0 0 ISTIO_IN_REDIRECT all -- * lo 0.0.0.0/0 !127.0.0.1 owner GID match 998
0 0 RETURN tcp -- * lo 0.0.0.0/0 0.0.0.0/0 tcp dpt:!53 ! owner GID match 998
0 0 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0 owner GID match 998
0 0 REDIRECT tcp -- * * 0.0.0.0/0 127.0.0.53 tcp dpt:53 redir ports 15053
0 0 RETURN all -- * * 0.0.0.0/0 127.0.0.1
1 96 ISTIO_REDIRECT all -- * * 0.0.0.0/0 0.0.0.0/0
Chain ISTIO_REDIRECT (1 references)
pkts bytes target prot opt in out source destination
1 96 REDIRECT tcp -- * * 0.0.0.0/0 0.0.0.0/0 redir ports 150
에이전트 로그 확인하기
Istio 사이드카가 제대로 작동하고 있는지 확인하려면, 가장 먼저 로그를 보는 게 기본이다.
가상머신에서는 사이드카 프로세스인 istio-agent가 다음 두 위치에 로그를 기록한다:
- 표준 출력 로그: /var/log/istio/istio.log
- 표준 에러 로그: /var/log/istio/istio.err
연결 여부 확인 예시
cat /var/log/istio/istio.log | grep xdsproxy
정상적인 연결이 되었다면 다음과 같은 로그를 볼 수 있다:
2025-05-25T01:09:42.094214Z info xdsproxy Initializing with upstream address "istiod.istio-system.svc:15012" and cluster "west-cluster"
2025-05-25T01:09:42.227661Z info xdsproxy connected to upstream XDS server: istiod.istio-system.svc:15012
# 만약 로그 파일이 생성되지 않았다면? 서비스 시작이 실패한 경우에 그럴 수 있다. 아래 처럼 systemd 로그를 확인하자
journalctl -u istio -f
워크로드가 메시에 등록됐는지 확인하기
WorkloadGroup과 --autoregister 설정이 제대로 작동했다면, VM이 부팅되자마자 메시의 멤버로 자동 등록된다.
등록 확인
→ VM의 IP 주소와 함께 자동 등록된 WorkloadEntry가 나타나면 성공
#
kubectl get workloadentries -n forum-services
NAME AGE ADDRESS
forum-192.168.10.200-vm-network 2m29s 192.168.10.200
상태 상세 확인 (헬스 체크 포함)
여기서 status.conditions 항목을 보면, istio-agent가 수행한 readiness probe 결과도 함께 확인할 수 있다.
kubectl get workloadentries -n forum-services -o yaml
...
status:
conditions:
- lastProbeTime: "2025-05-31T20:01:18.197210121Z"
lastTransitionTime: "2025-05-31T20:01:18.197211145Z"
message: 'Get "http://192.168.10.200:8080/api/healthz": dial tcp 127.0.0.6:0->192.168.10.200:8080:
connect: connection refused'
status: "False"
type: Healthy
...
현재 애플리케이션이 아직 준비되지 않아서 health check에 실패한 상태. 이는 후속 실습에서 애플리케이션을 배포하거나 포트를 열어 해결할 수 있다
사이드카 상태 확인 (proxy-status)
VM이 컨트롤 플레인과 동기화되었는지도 확인할 수 있다:
istioctl proxy-status | grep -i forum
forum-vm.forum-services west-cluster SYNCED SYNCED SYNCED SYNCED NOT SENT istiod-d6549b9fc-c922p 1.17.0
...
→ SYNCED 상태라면 설정 수신 및 xDS 통신이 정상적으로 이루어지고 있다는 뜻이다.
클러스터 서비스로 트래픽 라우팅하기
이제 가상머신이 서비스 메시의 일원이 되었으니, 실제로 클러스터 내부 서비스(webapp)로 트래픽이 잘 전달되는지 확인해보자.
이 과정을 통해 사이드카, DNS 프록시, iptables, east-west 게이트웨이 등 모든 구성요소가 제대로 작동하는지 검증할 수 있다.
1.가상머신에서 webapp으로 요청 보내기
먼저 VM에서 서비스 이름이 잘 해석되는지 확인한다:
dig +short webapp.istioinaction
# → 결과 예시: 10.10.200.143
정상적으로 IP가 반환된다면, DNS 프록시가 작동하고 있다는 의미다.
이제 실제 요청을 보내본다:
curl -s webapp.istioinaction/api/catalog/items/1 | jq
# 반복 요청
watch curl -s webapp.istioinaction/api/catalog/items/1
# 신규 터미널 : 15443 연결하는 envoy 프로세스(데이터 플래인) 확인!
watch -d ss -tnp
watch -d 'ss -tnp | grep envoy'
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
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))
...
# 신규 터미널 :
watch -d iptables -t nat -L -n -v
watch -d iptables -t raw -L -n -v
# k3s-s
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
2.흐름 확인: 트래픽 경로 추적
DNS 프록시 → iptables → envoy → east-west 게이트웨이 → 서비스
1. 트래픽이 애플리케이션을 떠나려면 먼저 그 **호스
- DNS 해석
- → webapp.istioinaction 도메인이 클러스터 IP로 변환됨 (DNS 프록시가 담당)
- 아웃바운드 트래픽 캡처
- → iptables 규칙이 애플리케이션의 요청을 envoy 프록시로 리다이렉션
- 프록시 경유
- → envoy가 트래픽을 east-west 게이트웨이(15443 포트)로 전달
- 서비스 내부 전달webapp은 내부적으로 catalog 서비스에 요청을 보냄
- → 게이트웨이가 트래픽을 webapp 서비스로 프록시하고,
- (옵션) 자신의 PC에서 webapp 반복 접속 후 확인
while true; do curl -s -H "Host: webapp.istioinaction.io" http://$APP_IP:30000/api/catalog/ ; echo; date; sleep 1; done
VM을 위한 Istio 트래픽 라우팅 구성하기
WorkloadEntry 대상으로 트래픽 연결
가상머신을 서비스로 연결하려면 먼저 Kubernetes Service 리소스를 만들어야 한다. 이 서비스는 가상머신을 대표하는 stub-service로, selector가 실제 pod가 아닌 가상머신에 대응되는 WorkloadEntry와 연결된다.
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
서비스를 만들고 나면, kubectl get svc,ep로 확인했을 때 Endpoints는 비어 있는 상태다. 이는 아직 연결 가능한 백엔드가 없다는 의미.
istioctl proxy-config route deploy/webapp.istioinaction
istioctl proxy-config route deploy/webapp.istioinaction --name 80 -o json
...
"name": "forum.forum-services.svc.cluster.local:80",
"domains": [
"forum.forum-services.svc.cluster.local",
"forum.forum-services",
"forum.forum-services.svc",
"10.10.200.72"
],
"routes": [
{
"name": "default",
"match": {
"prefix": "/"
},
"route": {
"cluster": "outbound|80||forum.forum-services.svc.cluster.local",
...
#
istioctl proxy-config cluster deploy/webapp.istioinaction
istioctl proxy-config cluster deploy/webapp.istioinaction --fqdn forum.forum-services.svc.cluster.local -o json
istioctl proxy-config cluster deploy/webapp.istioinaction --fqdn forum.forum-services.svc.cluster.local
SERVICE FQDN PORT SUBSET DIRECTION TYPE DESTINATION RULE
forum.forum-services.svc.cluster.local 80 - outbound EDS
# 아직 없다.
istioctl proxy-config endpoint deploy/webapp.istioinaction
istioctl proxy-config endpoint deploy/webapp.istioinaction | grep forum
#
istioctl proxy-config listener deploy/istio-eastwestgateway.istio-system
istioctl proxy-config route deploy/istio-eastwestgateway.istio-system
istioctl proxy-config cluster deploy/istio-eastwestgateway.istio-system
istioctl proxy-config endpoint deploy/istio-eastwestgateway.istio-system
istioctl proxy-config endpoint deploy/istio-eastwestgateway.istio-system | grep forum
Istio는 이 stub-service를 기반으로 Envoy 프록시에 클러스터와 라우트 구성을 만든다. istioctl proxy-config 명령어를 통해 webapp에 적용된 라우팅 구성을 보면 forum.forum-services.svc.cluster.local로의 트래픽 경로가 생성되어 있는 걸 확인할 수 있다.
하지만 문제는 실제로 이 클러스터에 연결 가능한 엔드포인트가 없다는 것. istioctl proxy-config endpoint로 확인하면 forum 서비스에 연결 가능한 엔드포인트가 없어 503 에러가 발생한다.
VM 내부 Envoy 설정 확인
가상머신 내부에서도 Envoy가 사이드카 역할을 하며 동작한다. istioctl을 설치한 후, curl localhost:15000/config_dump로 Envoy 구성을 덤프하고 proxy-config 명령으로 시각화할 수 있다. 이를 통해 가상머신의 Envoy가 현재 어떤 라우트, 클러스터, 엔드포인트 정보를 갖고 있는지 확인할 수 있다
# [testpc] 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
#
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 -
RESOURCE NAME TYPE STATUS VALID CERT SERIAL NUMBER NOT AFTER NOT BEFORE
default Cert Chain ACTIVE true 179319319685397330609558149319058937538 2025-06-01T20:01:17Z 2025-05-31T19:59:17Z
ROOTCA CA ACTIVE true 27707270319675654470222769950986365912 2035-05-29T19:32:45Z 2025-05-31T19:32:45Z
- 서비스가 만들어지면 WorkloadEntry 엔드포인트가 선택되고, 이를 사용해 istiod가 데이터 플레인을 설정한다.
- forum 서비스 요청 시도를 해보자
#
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-31T20:11:30.334Z] "GET /api/users HTTP/1.1" 503 UH no_healthy_upstream - "-" 0 19 0 - "13.125.68.38" "beegoServer" "e048787f-ff29-4f2e-b054-484750439cd3" "forum.forum-services:80" "-" outbound|80||forum.forum-services.svc.cluster.local - 10.10.200.220:80 13.125.68.38:0 - default
[2025-05-31T20:11:30.333Z] "GET /api/users HTTP/1.1" 500 - via_upstream - "-" 0 27 10 10 "13.125.68.38" "curl/7.81.0" "e048787f-ff29-4f2e-b054-484750439cd3" "webapp.istioinaction.io" "172.16.0.13:8080" inbound|8080|| 127.0.0.6:33329 172.16.0.13:8080 13.125.68.38:0 outbound_.80_._.webapp.istioinaction.svc.cluster.local default
# 자신의 PC
curl -s -H "Host: webapp.istioinaction.io" http://$APP_IP:30000/api/catalog/
while true; do curl -s -H "Host: webapp.istioinaction.io" http://$APP_IP:30000/api/catalog/ ; echo; date; sleep 1; done
curl -s -H "Host: webapp.istioinaction.io" http://$APP_IP:30000/api/users
curl -s -H "Host: webapp.istioinaction.io" http://$APP_IP:30000/api/users -I
HTTP/1.1 500 Internal Server Error
readiness 상태가 false인 이유
WorkloadEntry는 기본적으로 readiness probe를 통해 트래픽 수신 여부를 판단한다. forum VM이 아직 8080 포트에서 애플리케이션을 실행하지 않았기 때문에 "connect: connection refused" 에러와 함께 Healthy 상태가 False로 나타난다.
kubectl get workloadentries -n forum-services -o yaml
...
status:
conditions:
- lastProbeTime: "2025-05-31T20:01:18.197210121Z"
lastTransitionTime: "2025-05-31T20:01:18.197211145Z"
message: 'Get "http://192.168.10.200:8080/api/healthz": dial tcp 127.0.0.6:0->192.168.10.200:8080:
connect: connection refused'
status: "False"
type: Healthy
...
# testpc : 아직 8080 서비스가 실행되지 않았다!
ss -tnlp | grep 8080
forum VM에서 애플리케이션을 실행한 후, 클러스터 내 webapp에서 API 요청을 보내면 정상적으로 200 응답이 반환된다. Envoy 로그에서도 가상머신의 IP로 라우팅된 것을 확인할 수 있다.
# forum-vm
wget -O forum https://git.io/J3QrT
file forum
chmod +x forum
./forum
# forum-vm
curl http://localhost:8080/api/healthz -v
ss -tnlp | grep 8080
LISTEN 0 4096 *:8080 *:* users:(("forum",pid=3689,fd=3))
istioctl proxy-config endpoint deploy/webapp.istioinaction --cluster 'outbound|80||forum.forum-services.svc.cluster.local'
ENDPOINT STATUS OUTLIER CHECK CLUSTER
192.168.10.200:8080 HEALTHY OK outbound|80||forum.forum-services.svc.cluster.local
kubectl get workloadentries -n forum-services -o yaml
status:
conditions:
- lastProbeTime: "2025-05-31T20:15:23.198147662Z"
lastTransitionTime: "2025-05-31T20:15:23.198148218Z"
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-31T20:19:48.186Z] "GET /api/users HTTP/1.1" 200 - via_upstream - "-" 0 5645 18 17 "13.125.68.38" "beegoServer" "8dfd4188-f331-4c22-b0ca-c82890a4dba7" "forum.forum-services:80" "192.168.10.200:8080" outbound|80||forum.forum-services.svc.cluster.local 172.16.0.13:42108 10.10.200.220:80 13.125.68.38:0 - default
[2025-05-31T20:19:48.185Z] "GET /api/users HTTP/1.1" 200 - via_upstream - "-" 0 3679 20 20 "13.125.68.38" "curl/7.81.0" "8dfd4188-f331-4c22-b0ca-c82890a4dba7" "webapp.istioinaction.io" "172.16.0.13:8080" inbound|8080|| 127.0.0.6:35963 172.16.0.13:8080 13.125.68.38:0 outbound_.80_._.webapp.istioinaction.svc.cluster.local default
이 과정을 통해 stub-service → WorkloadEntry → forum VM으로 트래픽이 정상적으로 연결됨을 검증했다. 또한 readiness probe가 실패한 상태에서는 Envoy가 해당 엔드포인트를 아예 데이터 플레인에 포함하지 않는다는 것도 확인할 수 있었다.
PeerAuthentication으로 상호 인증 적용하기
기본적으로 VM은 8080 포트를 외부에 노출하고 있기 때문에, Istio 메시 외부에서도 직접 접근이 가능하다. 이를 차단하려면 mTLS를 강제하는 PeerAuthentication 정책을 적용해야 한다
# 자신의 PC에서 요청
curl -is $FORUM:8080/api/users | grep HTTP
HTTP/1.1 200 OK
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
NAMESPACE NAME MODE AGE
istio-system default STRICT 4s
curl -is $FORUM:8080/api/users -v
* Trying 3.38.162.233:8080...
* Connected to 3.38.162.233 (3.38.162.233) port 8080
> GET /api/users HTTP/1.1
> Host: 3.38.162.233:8080
> User-Agent: curl/8.7.1
> Accept: */*
>
* Request completely sent off
* Recv failure: Connection reset by peer
* Closing connection
while true; do curl -s -H "Host: webapp.istioinaction.io" http://$APP_IP:30000/api/users ; echo; date; sleep 1; done
이 정책을 적용하면, 이제 메시 외부에서 포트 8080으로 직접 접근할 경우 연결이 거절된다. 반면 메시 내부에서의 요청(webapp → forum)은 mTLS로 보호되며 정상적으로 동작한다.
이처럼 VM도 사이드카 프록시를 통해 메시 트래픽에 완전히 참여하게 되고, 클러스터 환경과 동일한 보안 정책, 라우팅 제어를 적용할 수 있다. 결국 가상머신이든 컨테이너든 동일한 서비스 메시에 녹여서 관리할 수 있는 게 Istio의 강력한 장점이다.
DNS 프록시 이해하기: Istio에서 호스트네임은 어떻게 해석될까?
Istio는 사이드카 프록시뿐 아니라 DNS 요청 처리 방식도 다르게 동작한다. 특히 가상머신(VM)에서 Kubernetes 클러스터 내부 서비스로 접근할 때, DNS 프록시가 중요한 역할을 한다. 이번에는 webapp.istioinaction 같은 호스트네임이 어떻게 해석되는지 과정을 따라가면서 확인해보자.
DNS 프록시가 클러스터 호스트네임을 해석하는 방법
- 애플리케이션이 webapp.istioinaction으로 DNS 요청을 보낸다.
- OS는 우선 /etc/hosts 파일을 확인하고, 없으면 시스템 기본 DNS 리졸버에게 요청을 넘긴다.
- Ubuntu 기준 기본 리졸버는 systemd-resolved로, 127.0.0.53 포트에서 리스닝한다.
- 하지만 이 요청은 실제로 systemd-resolved로 가지 않고, iptables 규칙에 의해 Istio DNS 프록시로 리다이렉트된다.
- DNS 프록시는 서비스 메시 안에서 알려진 서비스 이름을 해석한다. 예를 들어, webapp.istioinaction은 클러스터 서비스로 인식되어 IP로 변환된다.
- 만약 클러스터 서비스가 아니라면, DNS 프록시는 resolv.conf에 지정된 네임서버로 요청을 넘기고, 거기서 해석되거나 실패한다.
이 흐름에서 핵심은 운영체제 수준에서 일어나는 DNS 요청이 Istio가 설정한 프록시 포트(15053)로 리다이렉트된다는 점이다.
# [forum-vm]
# Iptables 규칙 확인 : proxyConfig.proxyMetadata ISTIO_META_DNS_CAPTURE="true" 설정 시 아래 규칙 추가됨
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
결과를 보면 127.0.0.53:53으로 향하는 요청이 모두 15053 포트로 리디렉션되는 걸 확인할 수 있다. 그리고 해당 포트는 pilot-agent가 수신 중이다.
root@forum-vm:~# netstat -ltunp | egrep 'PID|15053'
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:15053 0.0.0.0:* LISTEN 3423/pilot-agent
udp 0 0 127.0.0.1:15053 0.0.0.0:* 3423/pilot-agent
# 해당 주소로 DNS 쿼리해보자
10.10.200.143
root@forum-vm:~# dig +short @localhost -p 15053 catalog.istioinaction
DNS 쿼리를 직접 날려보면, webapp이나 forum 같은 서비스 이름이 실제 IP로 잘 변환되는 것도 확인할 수 있다.
dig +short @localhost -p 15053 forum.forum-services
10.10.200.225
10.10.200.220
(옵션) 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
...
[INFO] 172.16.0.18:42364 - 50709 "A IN zipkin.istio-system.istio-system.svc.cluster.local. udp 68 false 512" NXDOMAIN qr,aa,rd 161 0.000103657s
[INFO] 172.16.0.18:42364 - 35613 "A IN zipkin.istio-system.svc.cluster.local. udp 55 false 512" NOERROR qr,aa,rd 108 0.000104857s
- 예상대로 15053 포트에서 수신 중인 pilot-agent 가 FQDN 을 해석한다. 우리 예제는 요청을 해석하기 위해 DNS 서버를 직접 지정했는데, 그럴 필요가 없다.
- 애플리케이션이 호스트네임을 해석할 때는 Iptable 규칙에 따라 요청이 자동으로 이 포트로 리다이렉트된다.
- 다음으로는 컨트롤 플레인이 DNS 프록시에 어떤 항목을 설정했는지 알아보자.
DNS 프록시가 인식하는 서비스 목록은 어디서 오는가?
그렇다면 DNS 프록시는 어떤 기준으로 서비스를 알고 있을까? 이건 Istio 컨트롤 플레인(istiod)이 VM에게 전달한 NDS(Name Discovery Service) 설정에 기반한다. 다음 명령으로 특정 워크로드(VM)의 NDS 설정을 확인할 수 있다.
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.225"
],
"registry": "Kubernetes",
"shortname": "catalog",
"namespace": "istioinaction"
},
"forum.forum-services.svc.cluster.local": {
"ips": [
"10.10.200.220"
],
"registry": "Kubernetes",
"shortname": "forum",
"namespace": "forum-services"
},
"webapp.istioinaction.svc.cluster.local": {
"ips": [
"10.10.200.143"
],
"registry": "Kubernetes",
"shortname": "webapp",
"namespace": "istioinaction"
}
출력 결과에는 catalog, forum, webapp 등 여러 서비스 FQDN이 IP와 함께 나타난다. 여기서 주목할 점은 webapp.istioinaction.svc.cluster.local과 같은 풀 도메인만 존재하고, webapp.istioinaction처럼 짧은 이름은 보이지 않는다는 것.
하지만 istioctl proxy-config route로 라우팅 설정을 확인해 보면 다음처럼 다양한 도메인 변형이 존재한다.
그리고 모두 동일한 IP 목록 주소, 즉, 앞 선 목록에서 봤던 10.10.200.143로 해석된다.
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.143"
],
Istio 사용 시 장점도 있지만, 없을 경우 대비 비용(지연 추가, 프로세싱 추가, 복잡한 구조 등)**이 추가됩니다.
Istio의 DNS 프록시는 단순한 프록시가 아니다. 내부적으로 다음과 같은 구조로 동작한다.
- 클러스터 내 서비스 이름을 프록시가 직접 해석
- 짧은 도메인도 자동 지원 (webapp, webapp.istioinaction 등)
- 클러스터 외부 요청은 기존 네임서버로 위임
- iptables를 통해 로컬 DNS 요청을 프록시로 리다이렉트
이 구조 덕분에 VM도 마치 Kubernetes Pod처럼 서비스 이름을 통해 안정적으로 통신할 수 있다. 단순히 프록시를 넘어서, Istio는 클러스터 DNS까지 일관되게 통합하고 있다는 점이 인상 깊다.
VM에서 Istio 에이전트 설정 커스터마이징하기
가상머신에 설치된 Istio 에이전트는 다양한 설정을 커스터마이징할 수 있다. 로그 레벨, 인증서 수명, DNS 프록시 동작 등 주요 동작 방식을 설정 파일을 통해 제어할 수 있다.
예를 들어 다음 두 가지를 설정해보자.
- DNS 프록시의 로그 레벨을 debug로 변경
- 인증서의 수명을 12시간으로 설정
-사이드카용 설정 파일인 /var/lib/istio/envoy/sidecar.env
를 업데이트하면 된다.
[forum vm]
cat /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
- DNS 프록시의 로그 레벨을 debug로 변경
- 인증서의 수명을 12시간으로 설정
이를 위해 VM 내부의 /var/lib/istio/envoy/sidecar.env 파일을 수정하면 된다.
# 변경 사항 적용
systemctl restart istio
디버깅 로그 확인
설정이 적용되면 /var/log/istio/istio.log에서 DNS 프록시 동작 로그를 확인할 수 있다. 아래는 www.daum.net에 대한 쿼리가 프록시에서 처리되지 않아 상위 DNS 서버로 위임되는 과정이다.
# www.daum.net 도메인은 질의 처리를 하지 못해서, 로컬에 resolver DNS 서버를 통해 질의 로그 확인.
tail -f /var/log/istio/istio.log
[2025-05-31T20:34:51.554Z] "GET / HTTP/1.1" 200 - via_upstream - "-" 0 3121 1 1 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36" "4c69441e-1c23-4c42-bc03-0daf69f370f3" "3.38.162.233" "192.168.10.200:80" InboundPassthroughClusterIpv4 127.0.0.6:52503 192.168.10.200:80 45.156.128.43:40493 - default
2025-05-31T20:34:56.347997Z debug dns request ;; opcode: QUERY, status: NOERROR, id: 45482
;; flags: rd ad; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version 0; flags: ; udp: 1232
; COOKIE: 34a54977b6569d4d
;; QUESTION SECTION:
;www.daum.net. IN A
protocol=udp edns=true id=17b57df3-c7ba-453f-acba-f9f497ec1065
2025-05-31T20:34:56.348049Z debug dns response for hostname "www.daum.net." not found in dns proxy, querying upstream
2025-05-31T20:34:56.352516Z debug dns upstream response for hostname "www.daum.net." : ;; opcode: QUERY, status: NOERROR, id: 45482
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version 0; flags: ; udp: 65494
;; QUESTION SECTION:
;www.daum.net. IN A
;; ANSWER SECTION:
www.daum.net. 201 IN CNAME daum-4vdtymgd.kgslb.com.
daum-4vdtymgd.kgslb.com. 10 IN A 121.53.105.193
로컬 DNS 서버가 처리하지 못한 요청은 resolv.conf에 지정된 네임서버로 위임되고, upstream DNS 서버의 응답이 다시 반환된다.
또한 /etc/certs/cert-chain.pem 파일을 열어 새 인증서의 만료 시간을 확인할 수 있다.
WorkloadEntry 자동 정리: 가상머신 종료 시 메시에서 제거하기
Istio는 가상머신이 종료되면 해당 WorkloadEntry를 자동으로 정리한다. 아래와 같이 EC2 인스턴스를 종료한 후 WorkloadEntry가 사라지는지 확인해보자.
#
watch kubectl get workloadentries -A
kubectl get workloadentries -A
No resources found
조금 기다리면 "No resources found" 메시지를 확인할 수 있다. 이는 클라우드 네이티브 환경에서 자주 바뀌는 워크로드 특성에 맞춰 Istio가 일시적인 가상머신 자원도 자동으로 관리하고 있다는 의미다.
쿠버네티스와 VM의 메시 통합 방식 비교
프록시 설치 | 자동 또는 수동 주입 | 수동 설치 |
프록시 설정 | 사이드카 주입 시 구성 | WorkloadGroup 생성 후 VM에 전달 |
Workload ID 부트스트랩 | SA 토큰 자동 주입 | SA 토큰 수동 전달 |
헬스 체크 | Liveness/Readiness Probe | WorkloadGroup에 Readiness Probe 지정 |
메시 등록 | 자동 등록 | 자동 등록 (WorkloadGroup 기반) |
DNS 해석 | 클러스터 DNS 서버 또는 프록시 선택 | DNS 프록시 필수 사용 |
실전에서 중요한 것: 자동화
이번 실습은 가상머신을 메시에 통합하는 과정을 직접 따라가며 내부 구조를 이해하는 데 도움이 된다. 하지만 실제 운영 환경에서는 수작업 등록은 현실적이지 않다.
보통은 다음과 같은 도구를 활용한다.
• Packer: VM 이미지를 자동으로 빌드
• Ansible: 설정 스크립트를 자동 실행
• Terraform: 인프라 자원 생성과 배포 자동화
이미 자동화 기반이 있는 조직이라면 Istio 설정만 기존 스크립트에 추가하면 된다.
'Kubernetes > Istio' 카테고리의 다른 글
Istio 시리즈 # 13 - Istio Ambient Mode 살펴보기 (4) | 2025.06.09 |
---|---|
Istio 시리즈 # 11 - EnvoyFilter로 요청 처리 로직 확장하기 (0) | 2025.05.25 |
Istio 시리즈 # 10 - Istio로 구현하는 다중 클러스터 서비스 메시 (Multi-Cluster) (0) | 2025.05.25 |
Istio 시리즈 # 9 – Istio 성능 튜닝 가이드(Istio Tuning) (0) | 2025.05.18 |
Istio 시리즈 # 8 - Istio 트러블 슈팅 가이드(Istio Troubleshooting) (1) | 2025.05.17 |