WorkloadEntry
검토 버전: Istio 1.31.0 마지막 업데이트: 2026년 9월 11일
WorkloadEntry는 Virtual Machine (VM)이나 베어메탈 서버를 Istio 서비스 메시에 등록하기 위한 리소스입니다. 이를 통해 Kubernetes 외부의 워크로드도 메시의 트래픽 관리, 보안, 관찰성 기능을 활용할 수 있습니다.
목차
- 개요
- WorkloadEntry vs Kubernetes Pod
- 아키텍처
- 기본 사용법
- ServiceEntry 통합
- VM 등록 실전 가이드
- 보안 설정 (mTLS)
- 헬스체크 및 모니터링
- 고급 구성
- 문제 해결
- 모범 사례
개요
WorkloadEntry는 워크로드를 기술합니다. 생성만으로 Envoy 설치, ID 초기화, 네트워크 연결, DNS 레코드가 만들어지지는 않습니다. 이 장은 Sidecar 모드 VM 통합을 사용합니다. 각 예제는 독립적이며 ServiceEntry, 선택할 WorkloadEntry, ServiceAccount의 네임스페이스를 맞추세요. 그림은 등록/구성 관계이며 추가 네트워크 홉이 아닙니다.
WorkloadEntry란?
WorkloadEntry는 Istio Custom Resource Definition (CRD)으로, 메시 외부에 있는 워크로드(VM, 베어메탈)를 Istio 서비스 메시에 등록합니다.
사용 시나리오
주요 사용 사례:
- 점진적 마이그레이션: 레거시 애플리케이션을 단계적으로 Kubernetes로 이전
- 하이브리드 아키텍처: VM과 컨테이너를 동시에 운영
- 데이터베이스 통합: 외부 데이터베이스를 메시에 포함
- 고성능 워크로드: GPU 서버 등 특수 하드웨어 활용
WorkloadEntry vs Kubernetes Pod
비교표
| 특성 | Kubernetes Pod | WorkloadEntry (VM) |
|---|---|---|
| 배포 위치 | 클러스터 내부 | 클러스터 외부 |
| Envoy 주입 | 자동 (사이드카) | 수동 설치 |
| 서비스 디스커버리 | 자동 (Service) | 수동 (WorkloadEntry) |
| IP 관리 | Kubernetes CNI | 수동 지정 |
| mTLS | 자동 | 자동 (인증서 배포 필요) |
| 헬스체크 | 자동 (Liveness/Readiness) | 수동 구성 |
| 스케일링 | HPA | 수동 |
| 운영 복잡도 | 낮음 | 높음 |
| 사용 시나리오 | 클라우드 네이티브 앱 | 레거시 앱, 특수 하드웨어 |
트래픽 흐름 비교
아키텍처
VM 워크로드 아키텍처
주요 구성 요소
- WorkloadEntry: VM 정보 등록 (IP, 포트, 레이블)
- ServiceEntry: 서비스 정의 및 WorkloadEntry 참조
- Envoy Proxy: VM에 수동 설치된 사이드카
- istiod: 구성 배포 및 인증서 관리
- Service Account: VM의 신원 인증
기본 사용법
WorkloadEntry 리소스 정의
apiVersion: networking.istio.io/v1
kind: WorkloadEntry
metadata:
name: legacy-api-vm-1
namespace: production
spec:
# VM의 IP 주소
address: 192.168.1.100
# 서비스 선택을 위한 레이블
labels:
app: legacy-api
version: v1.0
tier: backend
# mTLS 인증을 위한 서비스 계정
serviceAccount: legacy-api-sa
# 노출할 포트
ports:
http: 8080
https: 8443
metrics: 9090
# 로컬리티 정보 (선택적)
locality: us-west-2/us-west-2a
# 가중치 (로드 밸런싱용, 선택적)
weight: 100
# 네트워크 (멀티 네트워크 환경, 선택적)
network: vm-network필수 필드 설명
| 필드 | 설명 | 예시 |
|---|---|---|
| address | 엔드포인트 주소 (IP 또는 DNS resolution의 DNS명; 구성된 원격 network는 생략 가능) | 192.168.1.100 |
| labels | ServiceEntry 매칭용 레이블 | app: legacy-api |
| serviceAccount | mTLS 인증용 SA | legacy-api-sa |
| ports | 노출할 포트 맵 | http: 8080 |
여러 VM 등록
# VM 1
apiVersion: networking.istio.io/v1
kind: WorkloadEntry
metadata:
name: api-vm-1
namespace: production
spec:
address: 192.168.1.101
labels:
app: api-service
version: v1
serviceAccount: api-sa
ports:
http: 8080
---
# VM 2
apiVersion: networking.istio.io/v1
kind: WorkloadEntry
metadata:
name: api-vm-2
namespace: production
spec:
address: 192.168.1.102
labels:
app: api-service
version: v1
serviceAccount: api-sa
ports:
http: 8080
---
# VM 3 (다른 버전)
apiVersion: networking.istio.io/v1
kind: WorkloadEntry
metadata:
name: api-vm-3
namespace: production
spec:
address: 192.168.1.103
labels:
app: api-service
version: v2 # 새 버전
serviceAccount: api-sa
ports:
http: 8080ServiceEntry 통합
WorkloadEntry는 항상 ServiceEntry와 함께 사용됩니다.
기본 통합 패턴
# 1. ServiceEntry로 서비스 정의
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: legacy-api
namespace: production
spec:
hosts:
- api.legacy.internal
addresses:
- 240.240.1.1 # 가상 IP
ports:
- number: 8080
name: http
protocol: HTTP
location: MESH_INTERNAL
resolution: STATIC
workloadSelector:
labels:
app: legacy-api # WorkloadEntry의 레이블과 매칭
---
# 2. WorkloadEntry로 VM 등록
apiVersion: networking.istio.io/v1
kind: WorkloadEntry
metadata:
name: legacy-api-vm-1
namespace: production
spec:
address: 192.168.1.100
labels:
app: legacy-api # ServiceEntry와 매칭
version: v1
serviceAccount: legacy-api-sa
ports:
http: 8080동작 흐름
로드 밸런싱
여러 WorkloadEntry가 있을 때 자동 로드 밸런싱됩니다:
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: database-cluster
namespace: vm-workloads
spec:
hosts:
- db.cluster.internal
ports:
- number: 5432
name: postgresql
protocol: TCP
location: MESH_INTERNAL
resolution: STATIC
workloadSelector:
labels:
app: postgres
tier: database
role: primary
---
# Separate read-only replica service
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: database-replicas
namespace: vm-workloads
spec:
hosts:
- db-replicas.cluster.internal
ports:
- number: 5432
name: postgresql
protocol: TCP
location: MESH_INTERNAL
resolution: STATIC
workloadSelector:
labels:
app: postgres
tier: database
role: replica
---
# Primary DB
apiVersion: networking.istio.io/v1
kind: WorkloadEntry
metadata:
name: postgres-primary
namespace: vm-workloads
spec:
serviceAccount: vm-postgres-sa
address: 10.0.1.100
labels:
app: postgres
tier: database
role: primary
weight: 100 # 가중치
---
# Replica DB 1
apiVersion: networking.istio.io/v1
kind: WorkloadEntry
metadata:
name: postgres-replica-1
namespace: vm-workloads
spec:
serviceAccount: vm-postgres-sa
address: 10.0.1.101
labels:
app: postgres
tier: database
role: replica
weight: 50
---
# Replica DB 2
apiVersion: networking.istio.io/v1
kind: WorkloadEntry
metadata:
name: postgres-replica-2
namespace: vm-workloads
spec:
serviceAccount: vm-postgres-sa
address: 10.0.1.102
labels:
app: postgres
tier: database
role: replica
weight: 50쓰기는 primary 서비스로 보내고 복제 의미를 허용하는 읽기만 replica 서비스로 보내세요. 일반 엔드포인트 가중치는 PostgreSQL 역할을 이해하지 않습니다. 같은 포트의 서비스에는 DNS 캡처/고유 VIP를 준비하고 각 VM을 해당 ServiceAccount로 초기화하세요.
VM 등록 실전 가이드
사전 요구사항
VM 요구사항:
- 네트워크: Kubernetes 클러스터와 통신 가능
- OS/CPU: 선택한 sidecar 패키지가 지원하는 Linux 배포판/아키텍처; 아래는 Debian 패키지 예제
- 연결: 노출한 VM 게이트웨이를 통해 istiod xDS/CA(일반적으로 15012)에 접근하고 선택한 토폴로지로 워크로드 트래픽을 라우팅. 15017은 Kubernetes webhook 포트이며 VM 앱 요구사항이 아님.
Kubernetes 준비:
- Istio 설치 완료
- VM이 사용할 네임스페이스 생성
- ServiceAccount 생성
초기 파일 생성 전에 공식 VM 설치 절차로 기존 Control Plane을 VM에 노출하세요. 클러스터 전용 istiod Service만으로는 부족합니다. 아래는 하나의 논리 네트워크에서 Pod와 VM의 라우팅이 가능한 구성이며 분리된 네트워크는 문서의 east-west/network 설정을 적용해야 합니다. 생성할 cluster ID는 istiod 구성과 일치해야 합니다.
1단계: ServiceAccount 생성
# 네임스페이스 생성
kubectl create namespace vm-workloads
# ServiceAccount 생성
kubectl create serviceaccount vm-postgres-sa -n vm-workloads
# VM ID 초기화에 Kubernetes Secret 목록 조회 권한은 필요하지 않습니다.2단계: WorkloadGroup 초기 입력 준비
WorkloadGroup은 여러 WorkloadEntry의 템플릿 역할을 합니다:
apiVersion: networking.istio.io/v1
kind: WorkloadGroup
metadata:
name: postgres-vms
namespace: vm-workloads
spec:
metadata:
labels:
app: postgres
version: v14
template:
serviceAccount: vm-postgres-sa
network: "" # Same logical network in this walkthrough
ports:
postgresql: 5432
metrics: 91873단계: VM에 Envoy 설치
자동 설치 스크립트 생성
# istioctl로 VM 등록 파일 생성
umask 077
istioctl x workload entry configure \
-f workloadgroup.yaml \
-o vm-postgres-1 \
--clusterID Kubernetes
# 생성된 파일들:
# - cluster.env: 클러스터 정보
# - istio-token: 인증 토큰
# - mesh.yaml: 메시 구성
# - root-cert.pem: 루트 인증서
# - hosts: /etc/hosts 항목VM에서 설치 실행
# Run on the administration workstation before entering the VM shell
ssh user@192.168.1.100 'install -d -m 700 "$HOME/istio-bootstrap"'
scp vm-postgres-1/* user@192.168.1.100:istio-bootstrap/
ssh user@192.168.1.100
# From this point, run on the VM
VM_BOOTSTRAP_DIR="$HOME/istio-bootstrap"
curl -fsSLo istio-sidecar.deb \
https://blob.istio.io/istio-release/releases/1.31.0/deb/istio-sidecar.deb
sudo dpkg -i istio-sidecar.deb
sudo install -d -o istio-proxy -m 0750 \
/etc/certs /var/run/secrets/tokens /var/lib/istio/envoy /etc/istio/config /etc/istio/proxy
sudo install -o istio-proxy -m 0644 "$VM_BOOTSTRAP_DIR/root-cert.pem" /etc/certs/root-cert.pem
sudo install -o istio-proxy -m 0600 "$VM_BOOTSTRAP_DIR/istio-token" /var/run/secrets/tokens/istio-token
sudo install -o istio-proxy -m 0600 "$VM_BOOTSTRAP_DIR/cluster.env" /var/lib/istio/envoy/cluster.env
sudo install -o istio-proxy -m 0600 "$VM_BOOTSTRAP_DIR/mesh.yaml" /etc/istio/config/mesh
# Review/merge once; replace stale istiod entries rather than appending duplicates
cat "$VM_BOOTSTRAP_DIR/hosts" | sudo tee -a /etc/hosts >/dev/null
sudo systemctl enable --now istio
sudo systemctl status istio4단계: WorkloadEntry 등록
위 명령은 수동 등록 방식입니다. VM 에이전트 초기화 후 아래 WorkloadEntry를 적용하세요. 자동 등록된 VM에 같은 주소의 수동 항목을 중복 생성하지 마세요:
apiVersion: networking.istio.io/v1
kind: WorkloadEntry
metadata:
name: postgres-vm-1
namespace: vm-workloads
spec:
address: 192.168.1.100
labels:
app: postgres
version: v14
serviceAccount: vm-postgres-sa
ports:
postgresql: 5432
metrics: 9187kubectl apply -f workloadentry.yaml5단계: ServiceEntry 생성
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: postgres-service
namespace: vm-workloads
spec:
hosts:
- postgres.vm.internal
addresses:
- 240.240.2.1
ports:
- number: 5432
name: postgresql
protocol: TCP
- number: 9187
name: metrics
protocol: HTTP
location: MESH_INTERNAL
resolution: STATIC
workloadSelector:
labels:
app: postgreskubectl apply -f serviceentry.yaml6단계: 연결 테스트
apiVersion: v1
kind: Pod
metadata:
name: pg-client
namespace: vm-workloads
labels:
sidecar.istio.io/inject: "true"
annotations:
proxy.istio.io/config: |
proxyMetadata:
ISTIO_META_DNS_CAPTURE: "true"
spec:
containers:
- name: postgres
image: postgres:14
command: ["sleep", "infinity"]kubectl apply -f pg-client.yaml
kubectl wait -n vm-workloads --for=condition=Ready pod/pg-client --timeout=120s
kubectl exec -it pg-client -n vm-workloads -c postgres -- \
psql -h postgres.vm.internal -U dbuser -d mydbPod 매니페스트를 pg-client.yaml로 저장하세요. PostgreSQL 클라이언트 버전은 Istio 버전과 별개인 앱 예시입니다. DB 자격 증명은 대화형으로 제공하세요. 아래 제한 정책 적용 후에는 허용된 ServiceAccount로 검사해야 하며 기본 테스트 ID는 거부됩니다. 완료 후 테스트 Pod를 제거하세요.
보안 설정 (mTLS)
mTLS 자동 활성화
선언한 ServiceAccount로 VM 에이전트를 초기화하면 메시 프록시가 자동 mTLS를 사용할 수 있습니다. WorkloadEntry만으로 일반 VM이 메시 참여자가 되지는 않습니다:
# PeerAuthentication으로 mTLS 강제
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: default
namespace: vm-workloads
spec:
mtls:
mode: STRICT # VM과 파드 모두 mTLS 필수VM 신원 확인
Pod Sidecar 초기화와 달리 VM 통합은 발급한 인증서/키를 /etc/certs에 보존하고 기존 mTLS ID로 갱신합니다. 성공적인 초기화 후 파일이 생성됩니다. 키를 보호하고 원인을 확인한 복구 절차에서 초기 자료를 재생성하며 자격 증명을 로그에 출력하지 마세요.
# VM에서 인증서 확인
sudo ls -la /etc/certs/
# cert-chain.pem: 인증서 체인
# key.pem: 개인 키
# root-cert.pem: 루트 CA
# 인증서 내용 확인
sudo openssl x509 -in /etc/certs/cert-chain.pem -text -noout
# Subject Alternative Name (SAN) 확인:
# spiffe://cluster.local/ns/vm-workloads/sa/vm-postgres-sa접근 제어 (AuthorizationPolicy)
# PostgreSQL 접근 제어
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: postgres-access
namespace: vm-workloads
spec:
selector:
matchLabels:
app: postgres # WorkloadEntry의 레이블
action: ALLOW
rules:
# API 서비스만 접근 허용
- from:
- source:
principals:
- cluster.local/ns/production/sa/api-service-sa
to:
- operation:
ports: ["5432"]
# 모니터링 서비스 접근 허용
- from:
- source:
principals:
- cluster.local/ns/istio-system/sa/prometheus
to:
- operation:
ports: ["9187"] # postgres_exportermTLS 검증
# Use a PostgreSQL client in an authorized mesh workload; PostgreSQL is not HTTPS
kubectl exec -it <authorized-client-pod> -n production -c <app-container> -- \
psql -h postgres.vm.internal -U dbuser -d mydb
# Inspect the client proxy's TLS transport and certificates separately
istioctl proxy-config clusters <authorized-client-pod> -n production --fqdn postgres.vm.internal -o json
istioctl proxy-config secret <authorized-client-pod> -n production
# On the VM, inspect public certificate information through its local admin interface
curl -fsS http://127.0.0.1:15000/certs헬스체크 및 모니터링
헬스체크 구성
선택적 자동화 방식의 Control Plane 플래그는 PILOT_ENABLE_WORKLOAD_ENTRY_AUTOREGISTRATION, PILOT_ENABLE_WORKLOAD_ENTRY_HEALTHCHECKS입니다. 문서에 따라 기존 설치 설정에 병합하세요.
WorkloadGroup은 readiness probe를 지원합니다. 문서의 자동 등록/상태 점검 방식은 istiod 플래그 활성화, WorkloadGroup 적용, --autoregister를 사용한 초기 파일 생성이 필요하며 위 수동 경로와 구분되는 선택적 방식입니다. 아래 DestinationRule은 능동 probe가 아닌 연결 실패의 수동 관찰입니다:
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: postgres-healthcheck
namespace: vm-workloads
spec:
host: postgres.vm.internal
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
outlierDetection:
consecutive5xxErrors: 5 # 5회 연속 실패 시
interval: 30s # 30초마다 확인
baseEjectionTime: 30s # 30초 동안 제외
maxEjectionPercent: 50 # 최대 50%까지 제외
minHealthPercent: 0 # Panic fail-open 임계값 해제# Optional WorkloadGroup probe fragment for the documented auto-registration workflow
spec:
probe:
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
tcpSocket:
host: 127.0.0.1
port: 5432VM 헬스체크 엔드포인트
VM 애플리케이션에 헬스체크 엔드포인트를 추가하세요:
# Python Flask 예시
from flask import Flask, jsonify
import psycopg2
app = Flask(__name__)
@app.route('/health', methods=['GET'])
def health():
try:
# 데이터베이스 연결 확인
conn = psycopg2.connect("dbname=mydb user=dbuser", connect_timeout=3)
conn.close()
return jsonify({"status": "healthy"}), 200
except psycopg2.Error:
return jsonify({"status": "unhealthy"}), 503
if __name__ == '__main__':
app.run(host='127.0.0.1', port=8080)Prometheus 메트릭 수집
ServiceMonitor는 WorkloadEntry/ServiceEntry가 아닌 Kubernetes Service/엔드포인트를 찾습니다. 이 VM에는 9187의 postgres_exporter를 설치하고 WorkloadEntry/ServiceEntry에 같은 포트를 등록한 뒤 기존 수집기 설정에 명시적 scrape job을 추가하세요. 수집기는 가상 호스트 DNS 조회, 메시 mTLS, exporter AuthorizationPolicy에서 허용한 ID가 필요합니다.
# Fragment for the existing Prometheus scrape_configs
- job_name: workloadentry-postgres
scrape_interval: 30s
metrics_path: /metrics
static_configs:
- targets: ["postgres.vm.internal:9187"]Grafana 대시보드 쿼리
# Native PostgreSQL traffic has TCP counters, not HTTP status/latency metrics
sum(rate(istio_tcp_connections_opened_total{reporter="source",destination_service="postgres.vm.internal"}[5m]))
sum(rate(istio_tcp_sent_bytes_total{reporter="source",destination_service="postgres.vm.internal"}[5m]))
# Collector/exporter health; inspect the actual emitted labels
up{job="workloadentry-postgres"}
pg_up{job="workloadentry-postgres"}고급 구성
멀티 네트워크 환경
network 이름은 토폴로지 식별자입니다. 연결성과 east-west 게이트웨이, 일치하는 mesh network 데이터를 별도 구성해야 하며 VPC 라우트·피어링·게이트웨이를 생성하지 않습니다. Locality는 region/zone/subzone이며 클라이언트 프록시와 맞는 실제 값을 사용하세요.
서로 다른 네트워크에 있는 VM 등록:
# 네트워크 A의 VM
apiVersion: networking.istio.io/v1
kind: WorkloadEntry
metadata:
name: api-vm-network-a
spec:
address: 192.168.1.100
labels:
app: api-service
serviceAccount: api-sa
network: network-a
ports:
http: 8080
---
# 네트워크 B의 VM
apiVersion: networking.istio.io/v1
kind: WorkloadEntry
metadata:
name: api-vm-network-b
spec:
address: 10.0.1.100
labels:
app: api-service
serviceAccount: api-sa
network: network-b
ports:
http: 8080Locality-aware 로드 밸런싱
apiVersion: networking.istio.io/v1
kind: WorkloadEntry
metadata:
name: api-vm-us-west
spec:
address: 192.168.1.100
labels:
app: api-service
locality: us-west-2/us-west-2a
weight: 100
---
apiVersion: networking.istio.io/v1
kind: WorkloadEntry
metadata:
name: api-vm-us-east
spec:
address: 10.0.1.100
labels:
app: api-service
locality: us-east-1/us-east-1a
weight: 100
---
# DestinationRule로 locality-aware 라우팅
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: api-locality-lb
spec:
host: api.service.internal
trafficPolicy:
loadBalancer:
localityLbSetting:
enabled: true
distribute:
- from: us-west-2/*
to:
"us-west-2/*": 80
"us-east-1/*": 20
- from: us-east-1/*
to:
"us-east-1/*": 80
"us-west-2/*": 20Canary 배포
WorkloadEntry에서도 Canary 배포를 적용할 수 있습니다:
# v1 버전 VM
apiVersion: networking.istio.io/v1
kind: WorkloadEntry
metadata:
name: api-vm-v1
spec:
address: 192.168.1.100
labels:
app: api-service
version: v1
serviceAccount: api-sa
---
# v2 버전 VM (Canary)
apiVersion: networking.istio.io/v1
kind: WorkloadEntry
metadata:
name: api-vm-v2
spec:
address: 192.168.1.101
labels:
app: api-service
version: v2
serviceAccount: api-sa
---
# VirtualService로 트래픽 분할
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: api-service-canary
spec:
hosts:
- api.service.internal
http:
- route:
- destination:
host: api.service.internal
subset: v1
weight: 90
- destination:
host: api.service.internal
subset: v2
weight: 10
---
# DestinationRule로 서브셋 정의
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: api-service-subsets
spec:
host: api.service.internal
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2문제 해결
WorkloadEntry가 등록되지 않음
증상: kubectl get workloadentry에 리소스가 보이지만 트래픽이 라우팅되지 않음
확인 사항:
# 1. WorkloadEntry 상태 확인
kubectl get workloadentry -n vm-workloads -o yaml
# 2. ServiceEntry의 workloadSelector 확인
kubectl get serviceentry -n vm-workloads -o yaml | grep -A 5 workloadSelector
# 3. 레이블 매칭 확인
# WorkloadEntry labels:
# app: postgres
# ServiceEntry workloadSelector:
# labels:
# app: postgres # 일치해야 함
# 4. Envoy 구성 확인
istioctl proxy-config endpoints <pod-name> -n production
# 출력에 WorkloadEntry의 IP가 포함되어야 함:
# ENDPOINT STATUS CLUSTER
# 192.168.1.100:5432 HEALTHY outbound|5432||postgres.vm.internal해결 방법:
# 레이블이 정확히 일치하도록 수정
apiVersion: networking.istio.io/v1
kind: WorkloadEntry
metadata:
name: postgres-vm-1
namespace: vm-workloads
spec:
address: 192.168.1.100
serviceAccount: vm-postgres-sa
labels:
app: postgres # ServiceEntry와 동일해야 함
version: v14VM에서 mTLS 연결 실패
증상: connection refused 또는 TLS handshake failed
확인 사항:
# VM에서 Envoy 로그 확인
sudo journalctl -u istio -f | grep -i tls
# 인증서 확인
sudo ls -la /etc/certs/
sudo openssl x509 -in /etc/certs/cert-chain.pem -text -noout
# 인증서 만료 확인
sudo openssl x509 -in /etc/certs/cert-chain.pem -noout -dates
# ServiceAccount 토큰 확인
sudo ls -la /var/run/secrets/tokens/
sudo stat /var/run/secrets/tokens/istio-token해결 방법:
# 관리 워크스테이션에서 초기 입력 재생성; 이 명령 자체가 인증서를 발급하지 않음
umask 077
istioctl x workload entry configure \
-f workloadgroup.yaml \
-o vm-postgres-1 \
--clusterID Kubernetes
# VM에 복사 및 Envoy 재시작
scp vm-postgres-1/* user@192.168.1.100:istio-bootstrap/
# Reapply all reviewed runtime files and permissions using the VM installation steps,
# including the token and mesh configuration; then restart istio. Do not replace only the root CA.헬스체크 실패로 트래픽이 가지 않음
증상: Envoy가 WorkloadEntry를 UNHEALTHY로 표시
확인 사항:
# Envoy 엔드포인트 상태 확인
istioctl proxy-config endpoints <pod-name> -n production | grep postgres
# 출력:
# 192.168.1.100:5432 UNHEALTHY outbound|5432||postgres.vm.internal
# DestinationRule의 outlierDetection 확인
kubectl get destinationrule -n vm-workloads -o yaml해결 방법:
# OutlierDetection 설정 조정
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: postgres-healthcheck
namespace: vm-workloads
spec:
host: postgres.vm.internal
trafficPolicy:
outlierDetection:
consecutive5xxErrors: 10 # 더 관대하게
interval: 60s # 체크 간격 늘림
baseEjectionTime: 60s
maxEjectionPercent: 50 # 제외 비율 제한; 100이면 전체 제외 허용DNS 조회 실패
ServiceEntry VIP만으로 CoreDNS 레코드가 생성되지 않습니다. 호출하는 Sidecar의 DNS 캡처를 활성화하고 Pod를 재생성하거나 실제 DNS 레코드를 제공하세요. VM 초기화의 DNS 프록시가 모든 Kubernetes 클라이언트의 캡처를 자동으로 켜지는 않습니다.
증상: 파드에서 postgres.vm.internal 조회 실패
확인 사항:
# ServiceEntry 확인
kubectl get serviceentry -n vm-workloads
# DNS 조회 테스트
kubectl exec pg-client -n vm-workloads -c postgres -- getent hosts postgres.vm.internal
# Istio DNS Proxy 활성화 확인
kubectl get pod <pod-name> -o yaml | grep ISTIO_META_DNS_CAPTURE해결 방법:
# ServiceEntry에 addresses 추가
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: postgres-service
namespace: vm-workloads
spec:
hosts:
- postgres.vm.internal
addresses:
- 240.240.2.1 # 가상 IP 명시
ports:
- number: 5432
name: postgresql
protocol: TCP
location: MESH_INTERNAL
resolution: STATIC
workloadSelector:
labels:
app: postgres모범 사례
1. 네이밍 규칙
# WorkloadEntry 이름: <app>-<role>-<id>
name: postgres-primary-1
name: postgres-replica-2
name: api-backend-vm-3
# ServiceEntry 이름: <app>-service
name: postgres-service
name: api-service
# ServiceAccount 이름: <app>-sa
name: postgres-sa
name: api-sa2. 레이블 전략
spec:
labels:
# 필수 레이블
app: postgres # 애플리케이션 이름
version: v14 # 버전
# 선택 레이블
tier: database # 계층 (frontend, backend, database)
role: primary # 역할 (primary, replica, canary)
environment: production # 환경
team: platform # 팀3. ServiceAccount 관리
# 네임스페이스별 ServiceAccount 분리
kubectl create sa db-sa -n databases
kubectl create sa api-sa -n applications
kubectl create sa cache-sa -n middleware
# 최소 권한 원칙
kubectl create role db-limited \
--verb=get \
--resource=configmaps \
-n databases4. 모니터링 및 알림
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: workloadentry-alerts
namespace: vm-workloads
spec:
groups:
- name: workloadentry
rules:
- alert: VMExporterScrapeDown
expr: up{job="workloadentry-postgres"} == 0 or absent(up{job="workloadentry-postgres"})
for: 5m
labels:
severity: critical
annotations:
summary: "VM exporter scrape target is unavailable"
- alert: PostgresExporterReportsDown
expr: pg_up{job="workloadentry-postgres"} == 0
for: 5m
labels:
severity: warning5. 문서화
각 WorkloadEntry에 대한 문서를 유지하세요:
apiVersion: networking.istio.io/v1
kind: WorkloadEntry
metadata:
name: postgres-primary-1
annotations:
description: "Primary PostgreSQL database for production"
owner: "platform-team@example.com"
provisioned-date: "2025-11-26"
os: "Ubuntu 22.04 LTS"
location: "us-west-2a"
runbook: "https://wiki.example.com/postgres-vm-runbook"
spec:
address: 192.168.1.100
labels:
app: postgres
version: v146. 백업 및 재해 복구
진단용 export와 별도로 원본 WorkloadGroup/ServiceEntry/수동 WorkloadEntry 파일과 메시 버전을 보존하세요. VM의 보존된 ID 자료는 필요한 보안 백업 절차를 따릅니다. Export에는 서버 metadata/status가 있어 복구 전 검토해야 하며 자동 등록 항목은 컨트롤러가 재생성하도록 하고 수동 중복을 만들지 마세요. 네임스페이스·계정·Control Plane 연결성을 먼저 복구합니다.
# WorkloadEntry 백업
kubectl get workloadentry -n vm-workloads -o yaml > workloadentries-backup.yaml
# ServiceEntry 백업
kubectl get serviceentry -n vm-workloads -o yaml > serviceentries-backup.yaml
# 복원
kubectl apply -f serviceentry.yaml
# Manual-registration path only: use the reviewed declarative source, not raw status snapshots
kubectl apply -f workloadentry.yaml7. 점진적 마이그레이션 전략
단계 시작 전에 레거시 VM ID를 초기화하고 아래 공유 ServiceEntry/subset을 생성하세요. Kubernetes 배포도 vm-workloads에 app=api, version=k8s 레이블로 만들고 프록시/DNS를 준비한 뒤 트래픽을 옮깁니다.
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: api-migration-service
namespace: vm-workloads
spec:
hosts: [api.internal]
addresses: [240.240.4.1]
ports:
- number: 8080
name: http
protocol: HTTP
location: MESH_INTERNAL
resolution: STATIC
workloadSelector:
labels:
app: api
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: api-migration-subsets
namespace: vm-workloads
spec:
host: api.internal
subsets:
- name: legacy
labels:
version: legacy
- name: k8s
labels:
version: k8s1단계: VM 메시 등록
# WorkloadEntry 등록
apiVersion: networking.istio.io/v1
kind: WorkloadEntry
metadata:
name: legacy-api-vm
namespace: vm-workloads
spec:
serviceAccount: api-sa
address: 192.168.1.100
labels:
app: api
version: legacy2단계: 트래픽 분할 (100% VM)
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: api-migration
namespace: vm-workloads
spec:
hosts:
- api.internal
http:
- route:
- destination:
host: api.internal
subset: legacy
weight: 1003단계: Kubernetes 배포
kubectl apply -n vm-workloads -f kubernetes-deployment.yaml4단계: 점진적 트래픽 전환
# 10% Kubernetes
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: api-migration
namespace: vm-workloads
spec:
hosts:
- api.internal
http:
- route:
- destination:
host: api.internal
subset: legacy # VM
weight: 90
- destination:
host: api.internal
subset: k8s # Kubernetes
weight: 105단계: VM 제거
# 트래픽 100% Kubernetes로 전환 후
kubectl delete workloadentry legacy-api-vm -n vm-workloads



