• Home
  • About
    • lahuman photo

      lahuman

      열심히 사는 아저씨

    • Learn More
    • Facebook
    • LinkedIn
    • Github
  • Posts
    • All Posts
    • All Tags
  • Projects

#8 istio

08 Mar 2022

Reading time ~9 minutes

istio

실습 환경은 K8S v1.23.4 , 노드 OS(Ubuntu 20.04.3) , CNI(Calico v3.21.4, Direct mode) , IPTABLES proxy mode , Istio v1.13.1(Envoy v1.21.0)

# 배포
curl -O https://raw.githubusercontent.com/gasida/KANS/main/8/Vagrantfile
vagrant up

# metrics-server 확인
kubectl top node
kubectl top pod
kubectl top pod -A

1. istio 소개

  • 서비스 매시(Service Mesh)
    • 등장 배경 : 마이크로서비스 아키텍처 환경의 시스템 전체 모니터링의 어려움, 운영 시 시스템 문제 발생할 때 원인과 병목 구간 찾기 어려움
    • 개념 : 마이크로서비스 간에 매시 형태의 통신이나 그 경로를 제어 - 예) 이스티오(Istio), 링커드(Linkerd), AWS App Mesh - 링크
    • 기본 동작 : 파드 간 통신 경로에 프록시를 놓고 트래픽 모니터링이나 트래픽 컨트롤 → 기존 애플리케이션 코드에 수정 없이 구성 가능!
    • 트래픽 모니터링 : 요청의 ‘에러율, 레이턴시, 커넥션 개수, 요청 개수’ 등 메트릭 모니터링, 특정 서비스간 혹은 특정 요청 경로로 필터링 → 원인 파악 용이!
    • 트래픽 컨트롤 : 트래픽 시프팅(Traffic shifting), 서킷 브레이커(Circuit Breaker), 폴트 인젝션(Fault Injection), 속도 제한(Rate Limit)
      • 트래픽 시프팅(Traffic shifting) : 예시) 99% 기존앱 + 1% 신규앱 , 특정 단말/사용자는 신규앱에 전달하여 단계적으로 적용하는 카니리 배포 가능
      • 서킷 브레이커(Circuit Breaker) : 목적지 마이크로서비스에 문제가 있을 시 접속을 차단하고 출발지 마이크로서비스에 요청 에러를 반환 (연쇄 장애, 시스템 전제 장애 예방)
      • 폴트 인젝션(Fault Injection) : 의도적으로 요청을 지연 혹은 실패를 구현
      • 속도 제한(Rate Limit) : 요청 개수를 제한
  • 이스티오 소개 : ‘구글 IBM 리프트(Lyft)’가 중심이 되어 개발하고 있는 오픈 소스 소프트웨어이며, C++ 로 만들어진 엔보이(Envoy)를 사용하여 서비스 매시를 구성


https://istio.io/latest/docs/ops/deployment/architecture/

  • Istio 구성요소와 envoy : 컨트롤 플레인(istiod) , 데이터 플레인(istio-proxy > envoy)
    • istiod : Pilot(데이터 플레인과 통신하면서 라우팅 규칙을 동기화, ADS), Gally(Istio 와 K8S 연동, Endpoint 갱신 등), Citadel(연결 암호화, 인증서관리 등)


https://istio.io/latest/docs/concepts/security/

  • Envoy proxy : C++ 구현된 고성능 프록시, 네트워크의 투명성을 목표, 다양한 필터체인 지원(L3/L4, HTTP L7), 동적 configuration API 제공 - 링크
  • 이스티오는 각 파드 안에 사이드카로 엔보이 프록시가 들어가 있는 형태
  • 모든 마이크로서비스간 통신은 엔보이를 통과하여, 메트릭을 수집하거나 트래픽 컨트롤을 할 수 있음
  • 트래픽 컨트롤을 하기위해 엔보이 프록시에 전송 룰을 설정 → 컨트롤 플레인의 이스티오가 정의된 정보를 기반으로 엔보이 설정을 하게 함
  • 마이크로서비스 간의 통신을 mutual TLS 인증(mTLS)으로 서로 TLS 인증으로 암호화 할 수 있음
  • 각 애플리케이션은 파드 내의 엔보이 프록시에 접속하기 위해 localhost 에 TCP 접속을 함

2. Envoy

  • 소개 : L7 Proxy , Istio 의 Sidecar proxy 로 사용 - 링크 주요 용어
    • Istio 구성요소와 envoy : 컨트롤 플레인(istiod) - ADS 를 이용한 Configuration 동기화 - 데이터 플레인(istio-proxy > envoy)

    https://blog.naver.com/alice_k106/222000680202

    https://www.envoyproxy.io/docs/envoy/latest/intro/life_of_a_request

    • Cluster : envoy 가 트래픽을 포워드할 수 있는 논리적인 서비스 (엔드포인트 세트), 실제 요청이 처리되는 IP 또는 엔드포인트의 묶음을 의미.
    • Endpoint : IP 주소, 네트워크 노드로 클러스터로 그룹핑됨, 실제 접근이 가능한 엔드포인트를 의미. 엔드포인트가 모여서 하나의 Cluster 가 된다.
    • Listener : 무엇을 받을지 그리고 어떻게 처리할지 IP/Port 를 바인딩하고, 요청 처리 측면에서 다운스트림을 조정하는 역할.
    • Route : Listener 로 들어온 요청을 어디로 라우팅할 것인지를 정의. 라우팅 대상은 일반적으로 Cluster 라는 것에 대해 이뤄지게 된다.
    • Filter : Listener 로부터 서비스에 트래픽을 전달하기까지 요청 처리 파이프라인
    • UpStream : envoy 요청을 포워딩해서 연결하는 백엔드 네트워크 노드 - 사이드카일때 application app, 아닐때 원격 백엔드
    • DownStream : An entity connecting to envoy, In non-sidecar models this is a remote client
  • k8s-pc 에 Envoy 설치 (미리 설치 되어 있음) - 링크
# 설치 : 미리 설치 되어 있음
apt update
apt install apt-transport-https gnupg2 curl lsb-release -y
curl -sL 'https://deb.dl.getenvoy.io/public/gpg.8115BA8E629CC074.key' | sudo gpg --dearmor -o /usr/share/keyrings/getenvoy-keyring.gpg
echo a077cb587a1b622e03aa4bf2f3689de14658a9497a9af2c427bba5f4cc3c4723 /usr/share/keyrings/getenvoy-keyring.gpg | sha256sum --check
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/getenvoy-keyring.gpg] https://deb.dl.getenvoy.io/public/deb/ubuntu $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/getenvoy.list
apt update
apt install -y getenvoy-envoy

# 확인
envoy --version
envoy  version: d362e791eb9e4efa8d87f6d878740e72dc8330ac/1.18.2/clean-getenvoy-76c310e-envoy/RELEASE/BoringSSL

# 도움말
envoy --help
  • Envoy proxy 실습
    • envoy-demo.yaml
static_resources:

  listeners:
  - name: listener_0
    address:
      socket_address:
        address: 0.0.0.0
        port_value: 10000
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_http
          access_log:
          - name: envoy.access_loggers.stdout
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
          http_filters:
          - name: envoy.filters.http.router
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  host_rewrite_literal: www.envoyproxy.io
                  cluster: service_envoyproxy_io

  clusters:
  - name: service_envoyproxy_io
    type: LOGICAL_DNS
    # Comment out the following line to test on v6 networks
    dns_lookup_family: V4_ONLY
    connect_timeout: 5s
    load_assignment:
      cluster_name: service_envoyproxy_io
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: www.envoyproxy.io
                port_value: 443
    transport_socket:
      name: envoy.transport_sockets.tls
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
        sni: www.envoyproxy.io
# 데모 config 적용하여 실행
curl -O https://www.envoyproxy.io/docs/envoy/latest/_downloads/92dcb9714fb6bc288d042029b34c0de4/envoy-demo.yaml
envoy -c envoy-demo.yaml

# 에러 출력되면서 실행 실패
error initializing configuration 'envoy-demo.yaml': Field 'connect_timeout' is missing in: name: "service_envoyproxy_io"

# (터미널1) connect_timeout 추가 후 다시 실행
sed -i'' -r -e "/dns_lookup_family/a\    connect_timeout: 5s" envoy-demo.yaml
envoy -c envoy-demo.yaml
## 출력 로그
[2021-12-13T12:20:25.981Z] "GET / HTTP/1.1" 200 - 0 4472 1140 1080 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36" "a6999dc1-5e5e-4029-89b7-331b081fca27" "www.envoyproxy.io" "52.220.193.16:443"
[2021-12-13T12:22:21.634Z] "GET / HTTP/1.1" 200 - 0 17228 247 121  "-" "curl/7.74.0" "39b7b07d-3f79-4e61-81b4-2944bd041535" "www.envoyproxy.io" "167.99.78.230:443"

# (터미널2) 정보 확인
ss -tnlp
State    Recv-Q  Send-Q    Local Address:Port   Peer Address:Port    Process
LISTEN   0       4096      0.0.0.0:10000        0.0.0.0:*            users:(("envoy",pid=8007,fd=18),("envoy",pid=8007,fd=16))

# 접속 테스트
curl -s http://127.0.0.1:10000 | grep -o "<title>.*</title>"
curl -s http://127.0.0.1:10000 | grep -o "<title>.*</title>" # k8s-m, k8s-wN 에서 접속 테스트
<title>Envoy Proxy - Home</title>

# 웹브라우저에서 http://192.168.10.254:10000 접속 확인!

# 연결 정보 확인
ss -tnp

# (터미널1) envoy 실행 취소(CTRL+C) 후 (관리자페이지) 설정 덮어쓰기 - [링크](https://www.envoyproxy.io/docs/envoy/latest/start/quick-start/run-envoy#override-the-default-configuration)
cat <<EOT> envoy-override.yaml
admin:
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 9902
EOT
envoy -c envoy-demo.yaml --config-yaml "$(cat envoy-override.yaml)"

# 웹브라우저에서 http://192.168.10.254:9902 접속 확인!

clusters 클릭 확인 endpoint) , listeners 클릭 확인

  • myhome.yaml
cat <<EOT> myhome.yaml
admin:
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 9902

static_resources:

  listeners:
  - name: listener_1
    address:
      socket_address:
        address: 0.0.0.0
        port_value: 20000
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_http
          access_log:
          - name: envoy.access_loggers.stdout
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
          http_filters:
          - name: envoy.filters.http.router
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: myhome

  clusters:
  - name: myhome
    type: STATIC
    dns_lookup_family: V4_ONLY
    connect_timeout: 5s
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: myhome
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: 127.0.0.1
                port_value: 80
EOT
# (터미널1) envoy 실행
envoy -c myhome.yaml

# (터미널2) 정보 확인
curl -s http://127.0.0.1:20000
<h1>Web Server : k8s-rtr</h1>

# 웹브라우저에서 http://192.168.10.254:9902 접속 확인!

3. istio 설치

  • Istio Operator Install - 링크
# istioctl 설치
#curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.12.3 sh -
curl -L https://istio.io/downloadIstio | sh -

#ISTIO_VERSION=1.12.4
ISTIO_VERSION=1.13.1
cp istio-$ISTIO_VERSION/bin/istioctl /usr/bin/istioctl
# export PATH=$PWD/bin:$PATH # 실행 경로를 환경 변수에 추가 << cp 대신 PATH 도 가능

# init : istio-operator 네임스페이스 생성, istio-operator 디플로이먼트 생성 - [링크](https://istio.io/latest/docs/setup/install/operator/)
istioctl operator init

# demo profile - [링크](https://istio.io/latest/docs/setup/additional-setup/config-profiles/)
kubectl apply -f - <<EOF
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  namespace: istio-system
  name: example-istiocontrolplane
spec:
  profile: demo
EOF

# 버전 확인
istioctl version

# Auto Injection with namespace label : 해당 네임스페이스에 생성되는 모든 파드들은 istio 사이드카가 자동으로 injection 됨
kubectl label ns default istio-injection=enabled

# istio-ingressgateway 의 svc 설정 변경
## LoadBalancer type 을 굳이 NodePort 로 변경하지 않아도 되지만, 깔끔한 보기를 위해서 설정함
## externalTrafficPolicy":"Local" 과 기본값 일때의 차이점을 직접 확인해보세요!
kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec":{"type":"NodePort"}}'
kubectl patch svc -n istio-system istio-ingressgateway -p '{"spec":{"externalTrafficPolicy":"Local"}}'

# istio-ingressgateway 의 envoy 버전 확인
kubectl exec -it deploy/istio-ingressgateway -n istio-system -c istio-proxy -- envoy --version
envoy  version: a971bfa7fddce41c1795fe2ce279735131c08878/**1.21.0**/Clean/RELEASE/BoringSSL
  • Istio 접속 테스트를 위한 변수 지정
k8s-pc, k8s-m 에서 아래 실행
# istio ingress gw NodePort(HTTP 접속용) 변수 지정 : 아래 ports[0] 은 어떤 용도의 포트일까요?
IGWHTTP=<각자 자신의 NodePort>
export IGWHTTP=$(kubectl get service -n istio-system istio-ingressgateway -o jsonpath='{.spec.ports[1].nodePort}')
echo $IGWHTTP

## istio-ingressgateway 파드 정보 확인
ISTIOINGRSS=$(kubectl get pods -n istio-system -l app=istio-ingressgateway -o jsonpath='{.items[0].metadata.name}')
kubectl get pod -n istio-system $ISTIOINGRSS -owide

## istio-ingressgateway 파드가 배치된 노드
ISTIONODE=$(kubectl get pod -n istio-system $ISTIOINGRSS -o jsonpath={.spec.nodeName})
echo $ISTIONODE

## istio-ingressgateway 파드가 배치된 노드의 IP
ISTIONODEIP=$(kubectl get node $ISTIONODE -o jsonpath={.status.addresses[0].address})
echo $ISTIONODEIP

# /etc/hosts 파일 수정 >> istio-ingressgateway 파드가 있는 워커 노드의 IP를 지정
MYDOMAIN=<각자 자신의 도메인>
echo "<istio-ingressgateway 파드가 있는 워커 노드> $MYDOMAIN" >> /etc/hosts

MYDOMAIN=<각자 자신의 도메인>
MYDOMAIN=www.gasida.dev
echo "$ISTIONODEIP $MYDOMAIN" >> /etc/hosts

# istio ingress gw 접속 테스트 : 아직은 설정이 없어서 접속 실패가 된다
curl -v -s $MYDOMAIN:$IGWHTTP

4. Istio 통한 외부 노출

  • Nginx 디플로이먼트와 서비스 배포
cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-websrv
spec:
  replicas: 1
  selector:
    matchLabels:
      app: deploy-websrv
  template:
    metadata:
      labels:
        app: deploy-websrv
    spec:
      terminationGracePeriodSeconds: 0
      containers:
      - name: deploy-websrv
        image: nginx:alpine
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: svc-clusterip
spec:
  ports:
    - name: svc-webport
      port: 80
      targetPort: 80
  selector:
    app: deploy-websrv
  type: ClusterIP
EOF
# 사이드카 컨테이너 배포 확인
kubectl get pod,svc -o wide
kubectl describe pod
  • Istio Gateway/VirtualService 설정 - Host 기반 트래픽 라우팅 설정
    • 클라이언트 PC → Istio ingressgateway 파드 → (Gateway, VirtualService, Service 는 Bypass) → Endpoint(파드 : 사이드카 - Nginx)
    • Gateway : 지정한 인그레스 게이트웨이로부터 트래픽이 인입, 프로토콜 및 포트, HOSTS, Proxy 등 설정 가능
    • VirtualService : 인입 처리할 hosts 설정, L7 PATH 별 라우팅, 목적지에 대한 정책 설정 가능 (envoy route config)
cat <<EOF | kubectl create -f -
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: test-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*****"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: nginx-service
spec:
  hosts:
  - "**$MYDOMAIN**"
  gateways:
  - test-gateway
  http:
  - route:
    - destination:
        host: svc-clusterip
        port:
          number: 80
EOF
# Istio Gateway(=gw)/VirtualService(=vs) 설정 정보를 확인
# virtual service 는 다른 네임스페이스의 서비스(ex. svc-nn.<ns>)도 참조할 수 있다
kubectl get gw,vs
NAME                                       AGE
gateway.networking.istio.io/test-gateway   21s

NAME                                               GATEWAYS           HOSTS                AGE
virtualservice.networking.istio.io/nginx-service   ["test-gateway"]   ["**www.gasida.dev**"]   4m9s
  • Istio 를 통한 Nginx 파드 접속 테스트
# k8s-pc, k8s-m 에서 아래 실행
# istio ingress gw 를 통한 접속 테스트
curl -s $MYDOMAIN:$IGWHTTP | grep -o "<title>.*</title>"
curl -v -s $MYDOMAIN:$IGWHTTP

# k8s-m 에서 nginx 컨테이너 로그 확인 >> 출력 로그에 IP 는 각각 무엇일까요?
kubetail -l app=deploy-websrv -c deploy-websrv -f

마치며

좋은 자료 제공과 양질의 컨텐츠를 제공 받아서 스터디를 잘 했습니다. 8주가 끝나니 더 많이 알지 못해서 아쉬운게 너무 많네요.

참고자료

  • istio : 공홈 - 링크 / Docs - 링크 Architecture Models Requirements / Bookinfo - 링크 / 5분 설명
  • istio Youtube 채널 - 링크 / IstioCon 2021 Workshop
  • Service Mesh Landscape - 링크
  • 호롤리님* : envoy proxy / Service Mesh Architecture & Istio
  • DaddyProgrammer* : Istio / 서비스 메시 / AWS App Mesh
  • Ssup님* : Architecture 2 / Istio Sidecar / Traffic Mgmt
  • 용찬호님* : istio envoy 기초 사용 방법 / istio tracing / gRPC LB
  • freepsw님* : Udemy Istio 정리
  • HyperConnect 기술블로그 - istio1 istio2 istio3
  • JIMMY SONG* - traffic flow / Route traffic / istio handbook (중국어) / Blog
  • Life of a packet through Istio by Matt Turner (2018) - 링크
  • Envoy - 링크
  • A Deep Dive into Iptables and Netfilter Architecture - 링크
  • 기술 세미나 - NAVER_Istio_L7LB / 당근마켓_Istio운영 / 토스_모니터링
  • Service Mesh 소개 영상(한글) - 링크
  • Envoy 무료 교육* - 링크
  • Protect Kubernetes workloads from Apache Log4j vulnerabilities - 링크
  • [CNCF Blog] Service mesh 101 - 링크 & Service mesh 102 - 링크


kangistio Share Tweet +1