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 - 링크