콘텐츠로 이동

Envoy Gateway v1.36.3 오프라인 설치 가이드

폐쇄망 환경에서 Envoy Gateway를 Kubernetes 위에 설치하는 절차를 안내합니다.

0. 오프라인 설치 자산 준비 (인터넷 환경)

폐쇄망에 반입할 Helm 차트와 컨테이너 이미지(.tar)가 charts/images/ 디렉토리에 없는 경우, 인터넷이 연결된 외부 PC(리눅스)에서 아래 스크립트를 실행하여 자산을 다운로드해야 합니다.

주의: 이 작업은 폐쇄망 내부가 아닌, 외부망에서 사전에 수행되어야 합니다. (Docker 또는 containerd(ctr), helm CLI 설치 필수)

# 컴포넌트 스크립트 디렉토리로 이동
cd scripts/

# 실행 권한 부여 및 다운로드 스크립트 실행
chmod +x ./scripts/download_assets_offline.sh
sudo ./scripts/download_assets_offline.sh

스크립트 실행이 완료되면 charts/ 디렉토리에 .tgz 차트 파일이, images/ 디렉토리에 .tar 이미지 파일들이 생성됩니다. 전체 프로젝트 폴더를 압축하여 폐쇄망 내부로 반입하십시오.

전제 조건

  • Kubernetes 클러스터 구성 완료
  • Helm v3.14.0 설치 완료
  • kubectl CLI 사용 가능
  • Harbor 레지스트리 접근 가능 (<NODE_IP>:30002)

아키텍처 개요

쿠버네티스 보안 및 네트워크 표준을 준수하는 구성입니다.

  • Network: hostNetwork: false (Pod는 K8s 내부망 사용, 노드 네트워크와 격리)
  • Service: type: LoadBalancer 또는 type: NodePort (외부 트래픽 진입점)
  • 트래픽 흐름 (LoadBalancer):
Client → External IP (LB) → Service (80/443) → Envoy Pod → Backend Pod
  • 트래픽 흐름 (NodePort + VIP):
Client → VIP (HAProxy) → Worker Node IP:30080/30443 → Envoy Pod → Backend Pod

1단계: 이미지 Harbor 업로드

모든 작업은 컴포넌트 루트 디렉토리에서 실행합니다.

# upload_images_to_harbor_v3-lite.sh 상단 Config 수정
# IMAGE_DIR      : ./images
# HARBOR_REGISTRY: <NODE_IP>:30002

chmod +x images/upload_images_to_harbor_v3-lite.sh
./images/upload_images_to_harbor_v3-lite.sh

하버가 없다면 모든 노드에서 아래 절차를 시행합니다.

chmod +x images/load_images_locally.sh
sudo ./images/load_images_locally.sh

2단계: 설치 및 운영 설정 (values.yaml)

루트 디렉토리의 설정 파일들을 환경에 맞게 수정합니다.

파일명 용도 비고
values-controller.yaml Envoy Gateway Controller 설정 이미지 경로 및 리소스 제한 등
values-infra.yaml Infrastructure (Gateway) 설정 서비스 타입(LB/NodePort), 포트 등
manifests/policy-global.yaml 전역 보안 및 트래픽 정책 EnvoyPatchPolicy 등

3단계: TLS 사전 구성 (HTTPS 사용 시)

HTTPS를 사용할 경우 Helm 배포 전 Gateway 네임스페이스에 TLS Secret을 생성합니다.

# 네임스페이스 생성 (없는 경우)
kubectl create ns envoy-gateway-system --dry-run=client -o yaml | kubectl apply -f -

# TLS Secret 생성
kubectl create secret tls gateway-tls \
  --cert=cert.pem \
  --key=key.pem \
  --namespace envoy-gateway-system

추가 인증서가 있으면 Secret을 각각 생성한 뒤 manifests/gateway.yamllisteners 항목에 추가합니다.

HTTP만 사용하는 경우 chart/gateway-infra/values.yaml에서 HTTPS 리스너를 제거하고, values-infra.yaml에서 TLS 설정을 주석 처리합니다.

4단계: 설치 실행

chmod +x scripts/install.sh
./scripts/install.sh

스크립트 실행 중 다음 항목을 선택합니다.

  1. 설치 모드: 1 (LoadBalancer) 또는 2 (NodePort)
  2. 노드 고정: Envoy Proxy를 배치할 특정 노드 이름 입력 (선택)
  3. 전역 정책: manifests/policy-global.yaml 적용 여부

5단계: 배포 후 네트워크 구성

배포 완료 후 설치 모드에 따라 아래 Case를 확인합니다.

Case A: LoadBalancer — 자동 할당 완료

클라우드 환경이거나 MetalLB가 구성된 경우입니다.

kubectl get svc -n envoy-gateway-system
# EXTERNAL-IP 필드에 IP 주소가 표시되면 정상

별도 조치 없이 표시된 IP로 접속합니다.

Case B: LoadBalancer — MetalLB 연동 (권장: 온프레미스 VIP 구성)

온프레미스(Bare-metal) 환경에서는 외부 트래픽을 수신하고 장애 전환(ARP Failover) 및 실 IP 보존을 보장하기 위해 MetalLB(L2 모드)를 구축하여 로드밸런서 IP를 광고하는 것을 강력히 권장합니다.

1) MetalLB 설치 및 IP 풀 설정: - 본 레포의 metallb-0.16.1 컴포넌트를 참고하여 설치하고, 노드 대역의 유휴 IP(예: 10.10.10.81-10.10.10.81)를 IPAddressPool로 등록합니다. - 서비스 타입이 LoadBalancer 상태로 배포되면, MetalLB가 생성된 Envoy Proxy 서비스에 IP풀의 VIP(10.10.10.81)를 EXTERNAL-IP로 자동 할당하게 됩니다.

2) 게이트웨이(Gateway) 리소스 주소 바인딩: 서비스에 IP가 할당된 후 Gateway 리소스의 주소를 바인딩하여 상태를 동기화(Programmed: True)합니다.

# 할당된 VIP(예: 10.10.10.81)를 Gateway 리소스에 바인딩
kubectl patch gateway cluster-gateway -n envoy-gateway-system --type='merge' \
  -p '{"spec":{"addresses":[{"type":"IPAddress","value":"10.10.10.81"}]}}'


⚠️ [참고] externalIPs 수동 할당 (비권장 - 임시 검증용) MetalLB 같은 로드밸런서 컨트롤러가 없는 경우에 임시로 노드 IP를 통해 외부 트래픽을 받기 위한 우회 방법입니다. (ARP 광고 및 고가용성이 보장되지 않으며, 실 IP 보존이 불가능합니다.)

서비스(Service) 외부 IP 등록:

SVC_NAME=$(kubectl get svc -n envoy-gateway-system -o jsonpath='{.items[?(@.spec.type=="LoadBalancer")].metadata.name}')

# 전체 워커 노드 IP를 externalIPs에 일괄 등록
kubectl patch svc -n envoy-gateway-system $SVC_NAME --type merge \
  -p '{"spec":{"externalIPs":["{WORKER1_IP}","{WORKER2_IP}"]}}'

게이트웨이(Gateway) 주소 바인딩:

# 위에서 등록한 노드 IP들을 Gateway 리소스에도 바인딩
kubectl patch gateway cluster-gateway -n envoy-gateway-system --type='merge' \
  -p '{"spec":{"addresses":[
    {"type":"IPAddress","value":"{WORKER1_IP}"},
    {"type":"IPAddress","value":"{WORKER2_IP}"}
  ]}}'

Case C: NodePort — VIP(HAProxy) 연동

NodePort 모드 설치 시 HTTP 30080, HTTPS 30443 포트로 고정됩니다.

kubectl get svc -n envoy-gateway-system
# 출력 확인: 80:30080/TCP, 443:30443/TCP

L4 스위치(Hardware LB) 연동 시:

네트워크 담당자에게 워커 노드 IP와 고정 포트(30080, 30443)를 L4 장비의 Real Server로 등록 요청합니다. 사용자는 L4 장비의 VIP(80/443)로 접속합니다.

트래픽 흐름:

Client → VIP(L4) → Worker Node IP:30080/30443 → Envoy → Backend

L4 장비 없는 경우 (Keepalived + HAProxy):

워커 노드에 Keepalived(VIP 관리) + HAProxy(포트 포워딩)를 구성합니다.

# HAProxy 설정 예시 (/etc/haproxy/haproxy.cfg)
# VIP: 10.10.10.200, 워커 노드: 10.10.10.73~75
frontend envoy-http
    bind 10.10.10.200:80
    mode tcp
    default_backend envoy-workers-http

backend envoy-workers-http
    mode tcp
    balance roundrobin
    server worker1 10.10.10.73:30080 check
    server worker2 10.10.10.74:30080 check
    server worker3 10.10.10.75:30080 check

frontend envoy-https
    bind 10.10.10.200:443
    mode tcp
    default_backend envoy-workers-https

backend envoy-workers-https
    mode tcp
    balance roundrobin
    server worker1 10.10.10.73:30443 check
    server worker2 10.10.10.74:30443 check
    server worker3 10.10.10.75:30443 check

L4 없이 단일 노드 직접 접속:

HTTP  : http://<NODE_IP>:30080
HTTPS : https://<NODE_IP>:30443

방화벽에서 30080, 30443 포트가 허용되어야 합니다.

6단계: 서비스 노출 (HTTPRoute)

신규 서비스를 Envoy를 통해 노출하려면 HTTPRoute 리소스를 생성합니다.

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: my-app-route
  namespace: default
spec:
  parentRefs:
    - name: cluster-gateway
      namespace: envoy-gateway-system
  hostnames:
    - "my-app.devops.internal"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: my-app-service
          port: 80

7단계: HTTPRoute 트러블슈팅

503 / Connection Refused — 백엔드 포트 불일치

Envoy는 Service ClusterIP 포트가 아닌 Pod의 실제 컨테이너 포트로 연결을 시도합니다.

# 파드가 실제로 열고 있는 포트 확인
kubectl get pod <POD_NAME> -n <NAMESPACE> -o yaml | grep containerPort

확인한 포트로 HTTPRoute의 backendRefs.port를 수정합니다.

kubectl patch httproute <ROUTE_NAME> -n <NAMESPACE> --type='json' \
  -p='[{"op":"replace","path":"/spec/rules/0/backendRefs/0/port","value":8080}]'

404 — URL Rewrite 필요

앱이 하위 경로(Context Path)를 인식하지 못해 404가 발생하는 경우 URLRewrite 필터를 적용합니다.

rules:
  - matches:
      - path:
          type: PathPrefix
          value: /myapp
    filters:
      - type: URLRewrite
        urlRewrite:
          path:
            type: ReplacePrefixMatch
            replacePrefixMatch: /
    backendRefs:
      - name: my-app-service
        port: 8080

Gateway 연결 상태 확인

# Gateway 상태 (attachedRoutes 수, Programmed 상태 확인)
kubectl get gateway cluster-gateway -n envoy-gateway-system -o yaml

# 전체 HTTPRoute 연결 상태 요약
kubectl get httproute -A

# 특정 HTTPRoute 상세 원인 조회
kubectl describe httproute <ROUTE_NAME> -n <NAMESPACE>

주요 실패 원인:

  • parentRefs.name이 실제 Gateway 이름(cluster-gateway)과 불일치
  • Gateway Listener의 allowedRoutes.namespaces 설정으로 해당 네임스페이스가 차단됨

운영 — 로그 확인

# Envoy Proxy (Data Plane) 로그 — 실제 트래픽, 접속 오류 확인
kubectl logs -n envoy-gateway-system -f \
  -l gateway.envoyproxy.io/owning-gateway-name=cluster-gateway

# Gateway Controller (Control Plane) 로그 — 설정 변환, 배포 실패 원인 확인
kubectl logs -n envoy-gateway-system -f \
  -l app.kubernetes.io/name=envoy-gateway

(심화) 와일드카드 TLS 인증서 적용

*.devops.internal 와일드카드 인증서 하나로 모든 서브도메인의 HTTPS를 통합 관리합니다.

1단계: Secret 생성

kubectl create secret tls wildcard-tls-secret \
  --cert=fullchain.pem \
  --key=privkey.pem \
  -n envoy-gateway-system

2단계: Gateway 리스너 설정

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: cluster-gateway
  namespace: envoy-gateway-system
spec:
  gatewayClassName: eg-cluster-entry
  listeners:
    - name: http
      protocol: HTTP
      port: 80
      allowedRoutes:
        namespaces:
          from: All
    - name: https
      port: 443
      protocol: HTTPS
      hostname: "*.devops.internal"
      tls:
        mode: Terminate
        certificateRefs:
          - name: wildcard-tls-secret
            kind: Secret
      allowedRoutes:
        namespaces:
          from: All

3단계: HTTPRoute 추가

와일드카드 범위 내 도메인이라면 HTTPRoute만 추가하면 자동으로 HTTPS가 적용됩니다. Secret을 새로 만들 필요가 없습니다.

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: nexus-route
  namespace: nexus
spec:
  parentRefs:
    - name: cluster-gateway
      namespace: envoy-gateway-system
  hostnames:
    - "nexus.devops.internal"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: nexus-nexus-repository-manager
          port: 8081

검증

# SSL Handshake 및 인증서 확인
curl -v https://nexus.devops.internal \
  --resolve nexus.devops.internal:443:<GATEWAY_IP>

성공 기준: Server certificate: 항목에 CN=*.devops.internal 확인, 연결 성공.

삭제

./scripts/uninstall.sh