이 Codelab 정보
1. 환영합니다
Google의 Istio 멀티 클라우드 버스트 Codelab에 참여해 주셔서 감사합니다.이 Codelab을 완료하려면 Kubernetes, Node, Go에 대한 초급 수준의 실무 경험이 필요합니다. 필요한 항목
|
학습할 내용
- GKE에서 Kubernetes 클러스터를 만드는 방법
- Helm을 사용하여 Kubernetes 클러스터에 Istio를 설치하는 방법
- Helm을 사용하여 Istio 멀티클러스터를 설치하는 방법
- 소스에서 Kubernetes로 웹 애플리케이션 배포
- Istio에 트래픽 라우팅 규칙 작성 및 적용
- Prometheus 측정항목
- Kubernetes 클러스터 내에서 컨테이너 이미지 빌드 및 푸시
2. 설정
다음 중 하나에서 이 Codelab을 진행할 수 있습니다.
- Google Cloud Shell (권장): 브라우저 내 셸로, 설치된 도구가 함께 제공됨
- 노트북 (아래 안내 참고)
Google Cloud Platform으로 시작하기
- GCP 계정이 없는 경우 강사로부터 무료 사용자 계정 카드를 받습니다.
- Google Cloud 콘솔로 이동하여 '프로젝트 선택'을 클릭합니다.
- 프로젝트의 'ID'를 어딘가에 기록한 다음 프로젝트를 클릭하여 선택합니다.
옵션 1: Google Cloud Shell 사용 (권장)
Cloud Shell은 브라우저 내에서 필요한 도구가 설치되고 Google Cloud Platform 계정에 자동으로 인증된 명령줄 셸을 제공합니다. Cloud Shell에서 이 연습을 실행하지 않으려면 다음 섹션으로 건너뜁니다.
Cloud 콘솔로 이동하여 오른쪽 상단 툴바에서 'Cloud Shell 활성화'를 클릭합니다.
Cloud Shell에 도구 추가
또는 다음 명령어를 실행하여 두 가지를 모두 ~/.bin
에 설치하고 $PATH에 추가합니다.
mkdir -p ~/.bin && \
cd ~/.bin && \
curl -LO https://raw.githubusercontent.com/ahmetb/kubectx/master/kubectx && \
chmod +x kubectx && \
curl -LO https://raw.githubusercontent.com/ahmetb/kubectx/master/kubens && \
chmod +x kubens && \
curl -LO https://storage.googleapis.com/kubernetes-helm/helm-v2.12.0-linux-amd64.tar.gz && \
tar xzf helm-v2.12.0-linux-amd64.tar.gz && \
rm helm-v2.12.0-linux-amd64.tar.gz && \
mv linux-amd64/helm ./helm && \
rm -r linux-amd64 && \
export PATH=${HOME}/.bin:${PATH}
Cloud Shell을 더 쉽게 사용할 수 있는 몇 가지 도움말을 소개합니다.
1. 셸을 새 창에 분리합니다. | |
2. 파일 편집기 사용: 오른쪽 상단의 연필 아이콘을 클릭하여 브라우저 내 파일 편집기를 실행합니다. 코드 스니펫을 파일에 복사할 때 유용합니다. | |
3. 새 탭 시작: 터미널 프롬프트가 두 개 이상 필요한 경우 | |
4. 텍스트 크게: Cloud Shell의 기본 글꼴 크기가 너무 작아 읽기 어려울 수 있습니다. | Linux/Windows의 경우 Ctrl-+, macOS의 경우 ⌘-+ |
옵션 2: 노트북 설정하기 (권장하지 않음)
Cloud Shell보다 자체 워크스테이션 환경을 사용하는 것이 더 편하다면 다음 도구를 설정하세요.
gcloud:
를 설치합니다 (Cloud Shell에 사전 설치됨). 안내에 따라 플랫폼에gcloud
를 설치합니다. 이를 사용하여 Kubernetes 클러스터를 만듭니다.kubectl:
를 설치합니다(Cloud Shell에 사전 설치됨). 다음 명령어를 실행하여 설치합니다.
gcloud components install kubectl
다음 명령어를 실행하여 gcloud를 인증합니다. Google 계정으로 로그인하라는 메시지가 표시됩니다. 그런 다음 사전 생성된 프로젝트 (위 참고)를 기본 프로젝트로 선택합니다. 컴퓨팅 영역 구성은 건너뛰어도 됩니다.
gcloud init
3. GCP 프로젝트 설정
프로젝트에서 GKE (Google Kubernetes Engine), GCR (Google Container Registry), GCB (Google Cloud Build) API를 사용 설정합니다.
gcloud services enable \ cloudapis.googleapis.com \ container.googleapis.com \ containerregistry.googleapis.com \ cloudbuild.googleapis.com
환경 변수 설정
설정하는 동안 Google Cloud 프로젝트를 많이 사용할 예정이므로 빠른 참조를 위해 환경 변수를 설정해 보겠습니다.
export GCLOUD_PROJECT=$(gcloud config get-value project)
이 워크샵에서는 코드와 구성 파일을 만들 예정이므로 프로젝트 디렉터리를 만들고 해당 디렉터리로 이동하겠습니다.
mkdir -p src/istio-burst && \ cd src/istio-burst && \ export proj=$(pwd)
4. '기본' Kubernetes 클러스터 만들기
Google Kubernetes Engine (GKE)을 사용하면 관리형 Kubernetes 클러스터를 쉽게 만들 수 있습니다.
다음 명령어는 Kubernetes 클러스터를 만듭니다.
- 이름이 'primary'인
- us-west1-a 영역에서
- 사용 가능한 최신 Kubernetes 버전
- 초기 노드 4개
export cluster=primary
export zone=us-west1-a
gcloud container clusters create $cluster --zone $zone --username "admin" \
--cluster-version latest --machine-type "n1-standard-2" \
--image-type "COS" --disk-size "100" \
--scopes "https://www.googleapis.com/auth/compute",\
"https://www.googleapis.com/auth/devstorage.read_only",\
"https://www.googleapis.com/auth/logging.write",\
"https://www.googleapis.com/auth/monitoring",\
"https://www.googleapis.com/auth/servicecontrol",\
"https://www.googleapis.com/auth/service.management.readonly",\
"https://www.googleapis.com/auth/trace.append" \
--num-nodes "4" --network "default" \
--enable-cloud-logging --enable-cloud-monitoring --enable-ip-alias
(약 5분 정도 걸릴 수 있습니다. Cloud 콘솔에서 클러스터가 생성되는 것을 볼 수 있습니다.)
Kubernetes 클러스터가 생성되면 gcloud
는 클러스터를 가리키는 사용자 인증 정보로 kubectl
를 구성합니다.
gcloud container clusters get-credentials $cluster --zone=$zone
이제 새 클러스터에서 kubectl
를 사용할 수 있습니다.
다음 명령어를 실행하여 클러스터의 Kubernetes 노드를 나열합니다 (상태가 '준비됨'으로 표시됨).
kubectl get nodes
사용 편의를 위해 Kubeconfig 이름 수정
컨텍스트 간에 자주 전환할 예정이므로 클러스터의 짧은 별칭을 지정하는 것이 좋습니다.
이 명령어는 방금 만든 kubeconfig 항목의 이름을 primary
로 바꿉니다.
kubectx ${cluster}=gke_${GCLOUD_PROJECT}_${zone}_${cluster}
권한 설정:
Istio를 배포하려면 클러스터 관리자여야 합니다. 이 명령어를 사용하면 Google Cloud 계정과 연결된 이메일을 클러스터 관리자로 설정할 수 있습니다.
kubectl create clusterrolebinding cluster-admin-binding \ --clusterrole=cluster-admin \ --user=$(gcloud config get-value core/account)
5. '버스트' 클러스터 만들기
다음 명령어는 Kubernetes 클러스터를 만듭니다.
- 이름이 'burst'인
- us-west1-a 영역에서
- 사용 가능한 최신 Kubernetes 버전
- 초기 노드 1개 포함
- 최대 5개의 노드에 자동 확장 사용 설정
export cluster=burst
export zone=us-west1-a
gcloud container clusters create $cluster --zone $zone --username "admin" \
--cluster-version latest --machine-type "n1-standard-2" \
--image-type "COS" --disk-size "100" \
--scopes "https://www.googleapis.com/auth/compute",\
"https://www.googleapis.com/auth/devstorage.read_only",\
"https://www.googleapis.com/auth/logging.write",\
"https://www.googleapis.com/auth/monitoring",\
"https://www.googleapis.com/auth/servicecontrol",\
"https://www.googleapis.com/auth/service.management.readonly",\
"https://www.googleapis.com/auth/trace.append" \
--num-nodes "1" --enable-autoscaling --min-nodes=1 --max-nodes=5 \
--network "default" \
--enable-cloud-logging --enable-cloud-monitoring --enable-ip-alias
(약 5분 정도 걸릴 수 있습니다. Cloud 콘솔에서 클러스터가 생성되는 것을 볼 수 있습니다.)
Kubernetes 클러스터가 생성되면 gcloud
는 클러스터를 가리키는 사용자 인증 정보로 kubectl
를 구성합니다.
gcloud container clusters get-credentials $cluster --zone=$zone
이제 새 클러스터에서 kubectl
를 사용할 수 있습니다.
다음 명령어를 실행하여 클러스터의 Kubernetes 노드를 나열합니다 (상태가 '준비됨'으로 표시됨).
kubectl get nodes
사용 편의를 위해 Kubeconfig 이름 수정
이 명령어는 방금 만든 kubeconfig 항목을 burst
로 수정합니다.
kubectx ${cluster}=gke_${GCLOUD_PROJECT}_${zone}_${cluster}
권한 설정:
Istio 원격을 배포하려면 클러스터 관리자여야 합니다. 이 명령어를 사용하면 Google Cloud 계정과 연결된 이메일을 클러스터 관리자로 설정할 수 있습니다.
kubectl create clusterrolebinding cluster-admin-binding \
--clusterrole=cluster-admin \
--user=$(gcloud config get-value core/account)
6. 방화벽 규칙 적용
두 클러스터가 서로 통신하려면 방화벽 규칙을 만들어야 합니다.
다음 명령어를 실행하여 Google Cloud Platform에서 클러스터가 통신할 수 있는 방화벽 규칙을 만듭니다.
function join_by { local IFS="$1"; shift; echo "$*"; }
ALL_CLUSTER_CIDRS=$(gcloud container clusters list \
--filter="(name=burst OR name=primary) AND zone=$zone" \
--format='value(clusterIpv4Cidr)' | sort | uniq)
ALL_CLUSTER_CIDRS=$(join_by , $(echo "${ALL_CLUSTER_CIDRS}"))
ALL_CLUSTER_NETTAGS=$(gcloud compute instances list \
--filter="(metadata.cluster-name=burst OR metadata.cluster-name=primary) AND metadata.cluster-location=us-west1-a" \
--format='value(tags.items.[0])' | sort | uniq)
ALL_CLUSTER_NETTAGS=$(join_by , $(echo "${ALL_CLUSTER_NETTAGS}"))
gcloud compute firewall-rules create istio-multicluster-test-pods \
--allow=tcp,udp,icmp,esp,ah,sctp \
--direction=INGRESS \
--priority=900 \
--source-ranges="${ALL_CLUSTER_CIDRS}" \
--target-tags="${ALL_CLUSTER_NETTAGS}" --quiet
이제 두 클러스터가 모두 설정되었으며 애플리케이션과 Istio를 배포할 준비가 되었습니다.
7. Istio 소개
Istio란 무엇인가요?
Istio는 '서비스를 연결, 보호, 제어, 관찰'하는 것을 목표로 하는 서비스 메시 제어 영역입니다. Cloud Service Mesh는 다양한 방법으로 이를 수행하지만 주로 프록시 컨테이너 ( Envoy)를 배포된 각 Kubernetes 포드에 사이드카로 추가하는 방식을 사용합니다. 프록시 컨테이너는 범용 정책 및 원격 분석 허브 ( Mixer)와 함께 마이크로서비스 간의 모든 네트워크 통신을 제어합니다.
이러한 정책은 Kubernetes 배포 및 서비스와 별개로 적용할 수 있습니다. 즉, 네트워크 운영자는 연결된 애플리케이션을 다시 배포하지 않고도 네트워크 활동을 관찰하고, 네트워크 정책을 제한, 리디렉션 또는 재작성할 수 있습니다.
Istio에서 지원하는 트래픽 관리 기능은 다음과 같습니다.
- 회로 차단기
- 비율 기반 트래픽 분할
- URL 재작성
- TLS 종료
- 상태 점검
- 부하 분산
이 워크숍에서는 비율 기반 트래픽 분할에 중점을 둘 것입니다.
사용할 Istio 용어
VirtualService
VirtualService는 호스트가 처리될 때 적용할 트래픽 라우팅 규칙 집합을 정의합니다.
게이트웨이
게이트웨이는 들어오거나 나가는 HTTP/TCP 연결을 수신하는 메시지의 에지에서 작동하는 부하 분산기입니다. 게이트웨이는 포트, SNI 구성 등을 지정할 수 있습니다.
DestinationRule
DestinationRule은 라우팅이 발생한 후 서비스용 트래픽에 적용되는 정책을 정의합니다. 부하 분산 구성, 사이드카의 연결 풀 크기, 이상치 감지 설정을 지정합니다.
Istio 멀티클러스터
두 클러스터를 만들 때 primary
클러스터는 자동 확장 없이 노드 4개로, burst
클러스터는 최대 5개 노드까지 자동 확장되는 노드 1개로 구성되었음을 확인했을 것입니다.
이러한 구성에는 두 가지 이유가 있습니다.
먼저 '온프레미스'에서 Cloud로의 시나리오를 시뮬레이션해 보겠습니다. 온프레미스 환경에서는 고정된 인프라가 있으므로 자동 확장 클러스터에 액세스할 수 없습니다.
두 번째로, 4노드 설정 (위에서 정의)은 Istio를 실행하는 데 필요한 최소 요구사항입니다. 여기서 궁금한 점은 Istio에 노드가 4개 이상 필요한데 burst
클러스터는 노드 1개로 Istio를 실행할 수 있는지입니다. 그 이유는 Istio 멀티클러스터가 훨씬 적은 수의 Istio 서비스를 설치하고 기본 클러스터의 Istio 설치와 통신하여 정책 규칙을 검색하고 원격 분석 정보를 게시하기 때문입니다.
8. 애플리케이션 아키텍처 개요
구성요소 개요
NodeJS 및 Redis를 사용하여 3계층 애플리케이션을 배포합니다.
작업자
worker 애플리케이션은 NodeJS로 작성되며 수신되는 POST HTTP 요청을 리슨하고, 요청에 대해 해싱 작업을 실행하고, PREFIX
라는 환경 변수가 정의된 경우 해시에 해당 값을 추가합니다. 해시가 계산되면 애플리케이션은 지정된 Redis 서버의 채널 'calculation
'에 결과를 전송합니다.
나중에 PREFIX
환경 변수를 사용하여 멀티클러스터 기능을 보여줍니다.
참고: 다음은 애플리케이션에서 사용하는 패키지입니다.
body-parser:
HTTP 요청을 파싱할 수 있습니다.cors:
교차 출처 리소스 공유 사용을 허용합니다.dotenv:
환경 변수의 간편한 파싱express:
간편한 웹사이트 호스팅ioredis:
Redis 데이터베이스와 통신하는 클라이언트 라이브러리morgan:
깔끔하게 구조화된 로그를 제공합니다.
프런트엔드
프런트엔드는 express를 사용하여 웹페이지를 호스팅하는 NodeJS 애플리케이션이기도 합니다. 사용자 입력 빈도를 사용하여 해당 비율로 worker
애플리케이션에 요청을 전송합니다. 이 애플리케이션은 'calculation
'라는 Redis 채널의 메시지도 구독하고 결과를 웹페이지에 표시합니다.
애플리케이션은 다음 종속 항목을 사용합니다.
body-parser:
HTTP 요청을 파싱할 수 있습니다.dotenv:
환경 변수의 간편한 파싱express:
간편한 웹사이트 호스팅ioredis:
Redis 데이터베이스와 통신하는 클라이언트 라이브러리morgan:
깔끔하게 구조화된 로그를 제공합니다.request:
HTTP 요청을 허용합니다.socket.io:
웹페이지에서 서버로의 양방향 통신을 허용합니다.
이 웹페이지는 스타일 지정을 위해 부트스트랩을 사용하며 실행하면 다음과 같이 표시됩니다.
아키텍처 다이어그램
배포 다이어그램
만든 두 클러스터에 최종 애플리케이션을 배포합니다. primary
클러스터에는 모든 구성요소 (frontend
, worker
, Redis)가 배포되지만 burst
클러스터에는 worker
애플리케이션만 배포됩니다.
다음은 두 클러스터를 설명하는 다이어그램입니다. 빨간색으로 윤곽선이 표시된 상자는 Kubernetes 서비스이고 파란색 상자는 Kubernetes 배포입니다. 노란색 상자는 Istio가 설치되었음을 나타냅니다.
클러스터에 Redis용 배포가 없더라도 burst
클러스터에 Redis용 서비스가 배포된 것을 볼 수 있습니다. Kubernetes DNS가 요청을 확인할 수 있도록 클러스터에 이 서비스가 있어야 하지만 요청이 실제로 이루어지면 Istio 프록시가 요청을 primary
클러스터의 Redis 배포로 다시 라우트합니다.
최종 애플리케이션에는 primary
클러스터에서 istiowatcher.
라는 이름의 추가 배포가 실행됩니다. 이를 통해 트래픽이 특정 임곗값을 초과하면 트래픽을 burst
로 자동으로 동적으로 다시 라우트할 수 있습니다.
9. 애플리케이션 배포 파일 만들기
애플리케이션을 배포하려면 Kubernetes 매니페스트 세트를 만들어야 합니다.
프로젝트의 루트 디렉터리로 이동하여 kubernetes
라는 새 폴더를 만듭니다.
mkdir ${proj}/kubernetes && cd ${proj}/kubernetes
frontend.yaml 작성
이렇게 하면 프런트엔드 이미지에 액세스할 Kubernetes 배포 및 서비스가 모두 생성됩니다.
frontend.yaml
에 다음을 삽입합니다.
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: frontend-deployment
labels:
app: frontend
spec:
replicas: 1
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: gcr.io/istio-burst-workshop/frontend
ports:
- containerPort: 8080
readinessProbe:
initialDelaySeconds: 10
httpGet:
path: "/_healthz"
port: 8080
httpHeaders:
- name: "Cookie"
value: "istio_session-id=x-readiness-probe"
livenessProbe:
initialDelaySeconds: 10
httpGet:
path: "/"
port: 8080
httpHeaders:
- name: "Cookie"
value: "istio_session-id=x-liveness-probe"
env:
- name: PORT
value: "8080"
- name: PROCESSOR_URL
value: "http://worker-service"
- name: REDIS_URL
value: "redis-cache-service:6379"
---
apiVersion: v1
kind: Service
metadata:
name: frontend-service
spec:
type: ClusterIP
selector:
app: frontend
ports:
- name: http
port: 80
targetPort: 8080
Deployment
에서 주목해야 할 주요 사항
- 애플리케이션이 실행될 포트를
8080
로 지정했습니다. - 작업자의 주소를 '
http://worker-service
'로 설정하고 Kubernetes 내장 DNS 기능을 사용하여 결과 서비스를 확인합니다. REDIS_URL
의 주소를 'redis-cache-service:6379
'로 설정했으며 Kubernetes 내장 DNS 기능을 사용하여 결과 IP 주소를 확인합니다.- 또한 컨테이너가 실행 중일 때 Kubernetes에 알릴 수 있도록
liveness
및readiness
프로브를 컨테이너에 설정했습니다.
worker-service.yaml 작성
이 서비스를 여러 클러스터에서 재사용하지만 클러스터마다 다른 배포를 작성할 예정이므로 Kubernetes 서비스 정의를 배포 정의와 별도의 파일에 작성합니다.
worker-service.yaml
에 다음을 삽입합니다.
apiVersion: v1
kind: Service
metadata:
name: worker-service
spec:
type: ClusterIP
selector:
app: worker
ports:
- name: http
port: 80
targetPort: 8081
worker-primary.yaml 작성
이는 기본 클러스터에 푸시할 worker
의 배포입니다.
worker-primary.yaml
에 다음을 삽입합니다.
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: worker-deployment
labels:
app: worker
spec:
replicas: 1
selector:
matchLabels:
app: worker
template:
metadata:
labels:
app: worker
cluster-type: primary-cluster
spec:
containers:
- name: worker
image: gcr.io/istio-burst-workshop/worker
imagePullPolicy: Always
ports:
- containerPort: 8081
readinessProbe:
initialDelaySeconds: 10
httpGet:
path: "/_healthz"
port: 8081
httpHeaders:
- name: "Cookie"
value: "istio_session-id=x-readiness-probe"
livenessProbe:
initialDelaySeconds: 10
httpGet:
path: "/"
port: 8081
httpHeaders:
- name: "Cookie"
value: "istio_session-id=x-liveness-probe"
env:
- name: PORT
value: "8081"
- name: REDIS_URL
value: "redis-cache-service:6379"
여기서 liveness
및 readiness
프로브를 제공하고 애플리케이션에서 사용할 PORT
및 REDIS_URL
환경 변수를 지정하는 동일한 패턴을 따르고 있습니다.
이 배포에서 주목해야 할 또 다른 점은 PREFIX
환경 변수가 없다는 것입니다. 즉, 계산 결과는 접두사가 없는 원시 해시가 됩니다.
이 배포의 마지막 핵심 사항은 cluster-type: primary-cluster
라벨입니다. 나중에 Istio 멀티클러스터에서 트래픽 라우팅을 할 때 사용합니다.
redis.yaml 작성
작업자에서 프런트엔드로의 통신은 Redis 채널을 통해 이루어지므로 클러스터에 Redis 애플리케이션을 배포해야 합니다.
다음을 redis.yaml
에 삽입합니다.
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: redis-cache
spec:
template:
metadata:
labels:
app: redis-cache
spec:
containers:
- name: redis
image: redis:alpine
ports:
- containerPort: 6379
readinessProbe:
periodSeconds: 5
tcpSocket:
port: 6379
livenessProbe:
periodSeconds: 5
tcpSocket:
port: 6379
volumeMounts:
- mountPath: /data
name: redis-data
resources:
limits:
memory: 256Mi
cpu: 125m
requests:
cpu: 70m
memory: 200Mi
volumes:
- name: redis-data
emptyDir: {}
Redis 애플리케이션의 준표준 배포입니다. redis:alpine
이미지를 기반으로 컨테이너를 설정하고 적절한 포트를 노출하며 적절한 리소스 한도를 설정합니다.
redis-service.yaml 작성
Redis 애플리케이션과 통신하려면 Kubernetes 서비스가 필요합니다.
다음을 redis-service.yaml
에 삽입합니다.
apiVersion: v1
kind: Service
metadata:
name: redis-cache-service
spec:
type: ClusterIP
selector:
app: redis-cache
ports:
- port: 6379
targetPort: 6379
이렇게 하면 Redis 배포에 액세스하는 redis-cache-service
라는 서비스가 제공됩니다.
10. 애플리케이션 배포
이미지가 GCR에 푸시되고 Kubernetes 매니페스트가 작성되었으므로 이제 애플리케이션을 배포하고 작동 방식을 확인해 보겠습니다.
다음 명령어를 실행하여 애플리케이션을 배포합니다.
- 올바른 클러스터에 있는지 확인
kubectx primary
- Redis 캐시 배포
kubectl apply -f redis.yaml
- Redis 서비스 배포
kubectl apply -f redis-service.yaml
- 프런트엔드 배포
kubectl apply -f frontend.yaml
- 작업자 배포
kubectl apply -f worker-primary.yaml
- 작업자 서비스 배포
kubectl apply -f worker-service.yaml
애플리케이션을 GKE에 배포했습니다. 축하합니다.
테스트
포드가 온라인 상태가 될 때까지 기다립니다.
kubectl get pods -w
모든 포드가 '실행 중'이면 Ctrl + C를 누릅니다.
NAME READY STATUS RESTARTS AGE frontend-deployment-695d95fbf7-76sd8 1/1 Running 0 2m redis-cache-7475999bf5-nxj8x 1/1 Running 0 2m worker-deployment-5b9cf9956d-g975p 1/1 Running 0 2m
LoadBalancer를 통해 프런트엔드를 노출하지 않았습니다. 나중에 Istio를 통해 애플리케이션에 액세스할 것이기 때문입니다. 모든 것이 제대로 작동하는지 테스트하려면 kubectl port-forward.
다음 명령어를 실행하여 로컬 (또는 Cloud Shell) 머신의 포트 8080을 frontend
배포를 실행하는 포트 8080으로 전달합니다.
kubectl port-forward \
$(kubectl get pods -l app=frontend -o jsonpath='{.items[0].metadata.name}') \
8080:8080
로컬에서 실행하는 경우: 웹브라우저를 열고 http://localhost:8080으로 이동합니다.
Cloud Shell에서 실행하는 경우: '웹 미리보기' 버튼을 클릭하고 '포트 8080에서 미리보기'를 선택합니다.
프런트엔드가 표시됩니다. '빈도' 상자에 숫자를 입력하면 해시가 표시됩니다.
축하합니다. 모든 설정이 완료되었습니다.
Ctrl+C
를 눌러 포트 전달을 중지합니다.
11. 배포된 애플리케이션 정리
클러스터에 Istio를 적용한 후 애플리케이션을 다시 배포할 예정이므로 먼저 현재 애플리케이션을 정리하겠습니다.
다음 명령어를 실행하여 방금 만든 모든 배포 및 서비스를 삭제합니다.
redis-cache-service
삭제
kubectl delete -f redis-service.yaml
redis
삭제
kubectl delete -f redis.yaml
frontend
삭제
kubectl delete -f frontend.yaml
worker
삭제
kubectl delete -f worker-primary.yaml
worker-service
삭제
kubectl delete -f worker-service.yaml
12. 기본 클러스터에 Istio 설치
Istio 다운로드
Istio의 출시 버전은 GitHub에 호스팅됩니다. 다음 명령어를 실행하면 istio의 1.0.0 버전이 다운로드되고 압축이 풀립니다.
- 프로젝트의 루트로 변경
cd ${proj}
- 보관 파일 다운로드
curl -LO https://github.com/istio/istio/releases/download/1.0.0/istio-1.0.0-linux.tar.gz
- 아카이브 추출 및 삭제
tar xzf istio-1.0.0-linux.tar.gz && rm istio-1.0.0-linux.tar.gz
Istio 템플릿 만들기
다음 Helm 명령어를 실행하면 클러스터에 Istio를 설치하는 템플릿이 생성됩니다.
helm template istio-1.0.0/install/kubernetes/helm/istio \ --name istio --namespace istio-system \ --set prometheus.enabled=true \ --set servicegraph.enabled=true > istio-primary.yaml
이렇게 하면 Istio를 배포하고 실행하는 데 필요한 모든 정의와 사양이 포함된 istio-primary.yaml
라는 파일이 현재 디렉터리에 생성됩니다.
--set
매개변수 2개를 확인합니다. 이를 통해 Istio 시스템에 Prometheus 및 ServiceGraph 지원이 추가됩니다. 실습 후반부에서 Prometheus 서비스를 사용합니다.
Istio 배포
Istio를 배포하려면 먼저 Istio 배포 및 서비스가 실행될 수 있는 istio-system
라는 네임스페이스를 만들어야 합니다.
kubectl create namespace istio-system
마지막으로 Helm으로 만든 istio-primary.yaml
파일을 적용합니다.
kubectl apply -f istio-primary.yaml
기본 네임스페이스 라벨 지정
Istio는 각 배포에 사이드카 프록시 서비스를 삽입하여 작동합니다. 이는 선택사항으로 제공되므로 Istio에서 사이드카를 자동으로 삽입할 수 있도록 default
네임스페이스에 istio-injection=enabled
라벨을 지정해야 합니다.
kubectl label namespace default istio-injection=enabled
축하합니다. 이제 Istio를 사용하여 클러스터를 실행하고 애플리케이션을 배포할 준비가 되었습니다.
13. Istio 트래픽 관리로 애플리케이션 배포
Istio 트래픽 관리 구성 파일 만들기
Istio는 구성에 YAML 파일을 사용하므로 Kubernetes와 유사하게 작동합니다. 따라서 Istio에 트래픽을 노출하고 라우팅하는 방법을 알려주는 파일 세트를 만들어야 합니다.
istio-manifests
라는 디렉터리를 만들고 이 디렉터리로 이동합니다.
mkdir ${proj}/istio-manifests && cd ${proj}/istio-manifests
frontend-gateway.yaml 작성
이 파일은 GKE LoadBalancer와 유사한 방식으로 Kubernetes 클러스터를 노출하고 들어오는 모든 트래픽을 프런트엔드 서비스로 라우팅합니다.
frontend-gateway.yaml
라는 파일을 만들고 다음을 삽입합니다.
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: frontend-gateway
spec:
selector:
istio: ingressgateway # use Istio default gateway implementation
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: frontend-ingress-virtual-service
spec:
hosts:
- "*"
gateways:
- frontend-gateway
http:
- route:
- destination:
host: frontend-service
port:
number: 80
redis-virtualservice.yaml 작성
redis-virtualservice.yaml
라는 파일을 만들고 다음을 삽입합니다.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: redis-virtual-service
spec:
hosts:
- redis-cache-service
gateways:
- mesh
tcp:
- route:
- destination:
host: redis-cache-service.default.svc.cluster.local
worker-virtualservice.yaml 작성
worker-virtualservice.yaml
라는 파일을 만들고 다음을 삽입합니다.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: worker-virtual-service
spec:
hosts:
- worker-service
gateways:
- mesh
http:
- route:
- destination:
host: worker-service.default.svc.cluster.local
port:
number: 80
Istio 트래픽 관리 정책 배포
Istio 정책은 kubectl apply
를 사용하여 다른 Kubernetes 리소스와 동일한 방식으로 배포됩니다.
- 게이트웨이 적용
kubectl apply -f frontend-gateway.yaml
- Redis VirtualService 적용
kubectl apply -f redis-virtualservice.yaml
- Worker VirtualService 적용
kubectl apply -f worker-virtualservice.yaml
애플리케이션 배포
kubernetes
디렉터리로 다시 변경
cd ${proj}/kubernetes
- Redis 캐시 배포
kubectl apply -f redis.yaml
- Redis 서비스 배포
kubectl apply -f redis-service.yaml
- 프런트엔드 배포
kubectl apply -f frontend.yaml
- 작업자 배포
kubectl apply -f worker-primary.yaml
- 작업자 서비스 배포
kubectl apply -f worker-service.yaml
확인
이제 Istio 및 트래픽 관리 정책이 있는 클러스터에 애플리케이션을 다시 배포했습니다.
모든 워크로드가 온라인 상태가 될 때까지 기다리겠습니다.
모두 온라인 상태가 되면 frontend-ingressgateway.yaml
에서 구성한 IngressGateway를 가져옵니다.
$ kubectl -n istio-system get svc istio-ingressgateway NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE istio-ingressgateway LoadBalancer 10.36.3.112 35.199.158.10 80:31380/TCP,
<EXTERNAL-IP> 주소로 이동하거나 cURL을 실행하면 프런트엔드가 표시됩니다.
$ curl 35.199.158.10 <!doctype html> <html> <head> <title>String Hashr</title> <!-- Bootstrap --> ...
14. '버스트' 클러스터에 Istio 설치
primary
클러스터를 설정하고 배포하는 데 많은 시간을 보냈지만 배포할 또 다른 클러스터가 있습니다.
이 섹션에서는 두 클러스터에서 구성 변수를 가져와야 하므로 각 명령어에서 어떤 클러스터가 가리키는지 주의 깊게 살펴보세요.
Istio 원격 매니페스트 만들기
primary
클러스터에 Istio를 배포할 때와 마찬가지로 Helm을 사용하여 burst
클러스터에 Istio 원격 배포를 템플릿화합니다. 하지만 그렇게 하기 전에 primary
클러스터에 관한 몇 가지 정보를 가져와야 합니다.
기본 클러스터 정보 수집
primary
클러스터로 변경
kubectx primary
다음 명령어는 기본 클러스터의 다양한 포드의 IP 주소를 가져옵니다. Istio 원격에서 기본 클러스터와 다시 통신하는 데 사용됩니다.
export PILOT_POD_IP=$(kubectl -n istio-system get pod -l istio=pilot -o jsonpath='{.items[0].status.podIP}')
export POLICY_POD_IP=$(kubectl -n istio-system get pod -l istio-mixer-type=policy -o jsonpath='{.items[0].status.podIP}')
export STATSD_POD_IP=$(kubectl -n istio-system get pod -l istio=statsd-prom-bridge -o jsonpath='{.items[0].status.podIP}')
export TELEMETRY_POD_IP=$(kubectl -n istio-system get pod -l istio-mixer-type=telemetry -o jsonpath='{.items[0].status.podIP}')
export ZIPKIN_POD_IP=$(kubectl -n istio-system get pod -l app=jaeger -o jsonpath='{range .items[*]}{.status.podIP}{end}')
원격 템플릿 만들기
이제 helm
를 사용하여 istio-remote-burst.yaml
라는 파일을 만들고 burst
클러스터에 배포합니다.
프로젝트 루트로 변경
cd $proj
helm template istio-1.0.0/install/kubernetes/helm/istio-remote --namespace istio-system \ --name istio-remote \ --set global.remotePilotAddress=${PILOT_POD_IP} \ --set global.remotePolicyAddress=${POLICY_POD_IP} \ --set global.remoteTelemetryAddress=${TELEMETRY_POD_IP} \ --set global.proxy.envoyStatsd.enabled=true \ --set global.proxy.envoyStatsd.host=${STATSD_POD_IP} \ --set global.remoteZipkinAddress=${ZIPKIN_POD_IP} > istio-remote-burst.yaml
버스트 클러스터에 Istio 원격 설치
burst
클러스터에 Istio를 설치하려면 primary
클러스터에 설치할 때와 동일한 단계를 따라야 하지만 istio-remote-burst.yaml
파일을 대신 사용해야 합니다.
kubecontext를 burst로 변경
kubectx burst
istio-system 네임스페이스 만들기
kubectl create ns istio-system
istio-burst.yaml 적용
kubectl apply -f istio-remote-burst.yaml
라벨 기본 네임스페이스
프록시가 자동으로 삽입될 수 있도록 다시 한번 default
네임스페이스에 라벨을 지정해야 합니다.
kubectl label namespace default istio-injection=enabled
축하합니다. 이제 burst
클러스터에 Istio 원격을 설정했습니다. 하지만 이 시점에서는 클러스터가 여전히 통신할 수 없습니다. primary
클러스터에 배포하여 클러스터를 서로 연결할 수 있는 burst
클러스터의 kubeconfig 파일을 생성해야 합니다.
'버스트' 클러스터의 kubeconfig 만들기
버스트 클러스터로 변경
kubectx burst
환경 설정
클러스터의 kubeconfig
파일을 만들려면 클러스터에 관한 몇 가지 정보를 수집해야 합니다.
- 클러스터 이름 가져오기
CLUSTER_NAME=$(kubectl config view --minify=true -o "jsonpath={.clusters[].name}")
- 클러스터 서버 이름 가져오기
SERVER=$(kubectl config view --minify=true -o "jsonpath={.clusters[].cluster.server}")
istio-multi
서비스 계정 인증 기관의 보안 비밀 이름 가져오기
SECRET_NAME=$(kubectl get sa istio-multi -n istio-system -o jsonpath='{.secrets[].name}')
- 이전 비밀에 저장된 인증 기관 데이터 가져오기
CA_DATA=$(kubectl get secret ${SECRET_NAME} -n istio-system -o "jsonpath={.data['ca\.crt']}")
- 이전 보안 비밀에 저장된 토큰 가져오기
TOKEN=$(kubectl get secret ${SECRET_NAME} -n istio-system -o "jsonpath={.data['token']}" | base64 --decode)
kubeconfig 파일 만들기
모든 환경 변수를 설정했으므로 이제 kubeconfig 파일을 만들어야 합니다.
cat <<EOF > burst-kubeconfig apiVersion: v1 clusters: - cluster: certificate-authority-data: ${CA_DATA} server: ${SERVER} name: ${CLUSTER_NAME} contexts: - context: cluster: ${CLUSTER_NAME} user: ${CLUSTER_NAME} name: ${CLUSTER_NAME} current-context: ${CLUSTER_NAME} kind: Config preferences: {} users: - name: ${CLUSTER_NAME} user: token: ${TOKEN} EOF
이렇게 하면 현재 디렉터리에 burst-kubeconfig
라는 새 파일이 생성되며, 이 파일은 primary
클러스터에서 burst
클러스터를 인증하고 관리하는 데 사용할 수 있습니다.
기본 클러스터로 다시 변경하기
kubectx primary
보안 비밀을 만들고 라벨을 지정하여 '버스트'의 kubeconfig 적용
kubectl create secret generic burst-kubeconfig --from-file burst-kubeconfig -n istio-system
Istio에서 멀티 클러스터 인증에 이 보안 비밀을 사용하도록 라벨 지정
kubectl label secret burst-kubeconfig istio/multiCluster=true -n istio-system
축하합니다. 두 클러스터가 모두 인증되었으며 Istio 멀티 클러스터를 통해 서로 통신합니다. 애플리케이션을 클러스터 간 배포해 보겠습니다.
15. 교차 클러스터 애플리케이션 배포
배포 만들기
kubernetes
디렉터리로 변경
cd ${proj}/kubernetes
'버스트' 클러스터의 작업자 배포 만들기: worker-burst.yaml
worker-burst.yaml
라는 파일을 만들고 다음을 삽입합니다.
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: worker-deployment
labels:
app: worker
spec:
replicas: 1
selector:
matchLabels:
app: worker
template:
metadata:
labels:
app: worker
cluster-type: burst-cluster
spec:
containers:
- name: worker
image: gcr.io/istio-burst-workshop/worker
imagePullPolicy: Always
ports:
- containerPort: 8081
readinessProbe:
initialDelaySeconds: 10
httpGet:
path: "/_healthz"
port: 8081
httpHeaders:
- name: "Cookie"
value: "istio_session-id=x-readiness-probe"
livenessProbe:
initialDelaySeconds: 10
httpGet:
path: "/"
port: 8081
httpHeaders:
- name: "Cookie"
value: "istio_session-id=x-liveness-probe"
env:
- name: PORT
value: "8081"
- name: REDIS_URL
value: "redis-cache-service:6379"
- name: PREFIX
value: "bursty-"
이 파일은 앞에서 만든 worker-primary.yaml과 거의 동일합니다. 두 가지 주요 차이점이 있습니다.
첫 번째 주요 차이점은 값이 'bursty-
'인 PREFIX
환경 변수를 추가했다는 점입니다.
env:
- name: PORT
value: "8081"
- name: REDIS_URL
value: "redis-cache-service:6379"
- name: PREFIX
value: "bursty-"
즉, burst
클러스터의 작업자는 전송하는 모든 해시의 접두사로 'bursty-
'를 사용합니다. 이를 통해 애플리케이션이 실제로 교차 클러스터임을 알 수 있습니다.
두 번째 주요 차이점은 이 배포의 cluster-type
라벨을 primary-cluster
에서 burst-cluster
로 변경했다는 점입니다.
labels:
app: worker
cluster-type: burst-cluster
나중에 VirtualService를 업데이트할 때 이 라벨을 사용합니다.
Istio 서비스 수정
현재 Istio 서비스는 두 배포 환경을 모두 활용하지 못하고 있습니다. 트래픽의 100% 가 '기본' 클러스터로 라우팅됩니다. 변경해 보겠습니다.
istio-manifests
디렉터리로 변경
cd ${proj}/istio-manifests
worker-virtualservice.yaml을 수정하여 DestinationRules 포함
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: worker-virtual-service
spec:
hosts:
- worker-service
gateways:
- mesh
http:
- route:
- destination:
host: worker-service.default.svc.cluster.local
subset: primary
port:
number: 80
weight: 50
- destination:
host: worker-service.default.svc.cluster.local
subset: burst
port:
number: 80
weight: 50
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: worker-destination-rule
spec:
host: worker-service
trafficPolicy:
loadBalancer:
simple: RANDOM
subsets:
- name: primary
labels:
cluster-type: primary-cluster
- name: burst
labels:
cluster-type: burst-cluster
VirtualService에 두 번째 연결 대상이 추가된 것을 확인할 수 있습니다. 여전히 동일한 호스트 (worker-service.default.svc.cluster.local)
)를 참조하지만 트래픽의 50% 는 primary
하위 집합으로 라우팅되고 나머지 50% 는 burst
하위 집합으로 라우팅됩니다.
primary
하위 집합은 cluster-type: primary-cluster
라벨이 있는 배포로, burst
하위 집합은 cluster-type: burst-cluster
라벨이 있는 배포로 정의했습니다.
이렇게 하면 두 클러스터 간에 트래픽이 50/50으로 분할됩니다.
클러스터에 배포
redis-service.yaml을 버스트 클러스터에 배포
burst
kubeconfig로 변경
kubectx burst
프로젝트 루트로 변경
cd ${proj}
그런 다음 배포
버스트 클러스터에 redis-service.yaml 배포
kubectl apply -f kubernetes/redis-service.yaml
버스트 클러스터에 worker-burst.yaml 배포
kubectl apply -f kubernetes/worker-burst.yaml
버스트 클러스터에 worker-service.yaml 배포
kubectl apply -f kubernetes/worker-service.yaml
Istio VirtualServices 적용
primary
kubeconfig로 변경
kubectx primary
그런 다음 배포
kubectl apply -f istio-manifests/worker-virtualservice.yaml
작동 여부 확인
작동하는지 확인하려면 Istio 인그레스 포인트로 이동하여 해시의 약 50% 에 'burst-'가 접두사로 추가된 것을 확인합니다.
이는 클러스터 간에 성공적으로 통신하고 있음을 의미합니다. 여러 서비스의 가중치를 변경하고 worker-virtualservice.yaml
파일을 적용해 보세요. 이는 클러스터 간의 트래픽 균형을 유지하는 좋은 방법이지만 자동으로 할 수 있다면 어떨까요?
16. Prometheus 측정항목 활용
Prometheus 소개
Prometheus는 원래 SoundCloud에서 빌드한 오픈소스 시스템 모니터링 및 알림 도구입니다. 측정항목 이름 및 키-값 쌍으로 식별되는 시계열 데이터가 포함된 다차원 데이터 모델을 유지합니다.
참고로 다음은 Prometheus 아키텍처 다이어그램입니다.
Prometheus와 함께 배포된 Istio는 다양한 측정항목을 Prometheus 서버에 자동으로 보고합니다. 이러한 측정항목을 사용하여 클러스터를 즉시 관리할 수 있습니다.
Prometheus 측정항목 살펴보기
시작하려면 Prometheus 배포를 노출해야 합니다.
GKE의 워크로드 탭으로 이동하여 'prometheus' 워크로드로 드릴다운합니다.
배포 세부정보가 표시되면 작업 -> 노출로 이동합니다.
포트 9090
로 전달하도록 선택하고 '부하 분산기'를 입력합니다.
'노출'을 선택합니다.
이렇게 하면 Prometheus 측정항목을 탐색하는 데 사용할 수 있는 공개적으로 액세스할 수 있는 IP 주소에 서비스가 생성됩니다.
엔드포인트가 작동할 때까지 기다린 후 '외부 엔드포인트' 옆의 IP 주소를 클릭합니다.
이제 Prometheus UI가 표시됩니다.
Prometheus는 자체 워크샵으로 사용할 수 있을 만큼 충분한 측정항목을 제공합니다. 하지만 지금은 istio_requests_total
측정항목부터 살펴보겠습니다.
이 쿼리를 실행하면 많은 데이터가 반환됩니다. Istio 서비스 메시를 통과하는 모든 요청에 대한 측정항목으로, 그 수가 상당합니다. 실제로 관심 있는 항목으로 필터링하도록 표현식을 변경합니다.
대상 서비스가 worker-service.default.svc.cluster.local
이고 소스가 frontend-deployment
인 요청으로, 지난 15초로 제한됨
쿼리는 다음과 같습니다.
istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s]
또한 훨씬 더 관리하기 쉬운 데이터 세트를 제공합니다.
하지만 여전히 약간 빽빽합니다. 모든 요청이 아니라 초당 요청 수를 알고 싶습니다.
이를 위해 내장 rate
함수를 사용할 수 있습니다.
rate(istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s])
이제 답에 가까워졌지만 이러한 측정항목을 논리적 그룹으로 더 줄여야 합니다.
이렇게 하려면 sum
및 by
키워드를 사용하여 결과를 그룹화하고 합산하면 됩니다.
sum(rate(istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s])) by (source_workload,
source_app, destination_service)
그렇다면 Prometheus에서 필요한 정확한 측정항목을 가져올 수 있습니다.
최종 Prometheus 쿼리
지금까지 배운 내용을 바탕으로 Prometheus에 던져야 할 최종 쿼리는 다음과 같습니다.
sum(rate(istio_requests_total{reporter="destination",
destination_service="worker-service.default.svc.cluster.local",
source_workload="frontend-deployment"}[15s])) by (source_workload,
source_app, destination_service)
이제 HTTP API를 사용하여 측정항목을 가져올 수 있습니다.
다음과 같이 HTTP GET 요청을 실행하여 쿼리로 API를 쿼리할 수 있습니다. <prometheus-ip-here>를 바꿉니다.
curl http://<prometheus-ip-here>/api/v1/query?query=sum\(rate\(istio_requests_total%7Breporter%3D%22destination%22%2C%0Adestination_service%3D%22worker-service.default.svc.cluster.local%22%2C%0Asource_workload%3D%22frontend-deployment%22%7D%5B15s%5D\)\)%20by%20\(source_workload%2C%0Asource_app%2C%20destination_service\)
응답 예시는 다음과 같습니다.
{
"status": "success",
"data": {
"resultType": "vector",
"result": [
{
"metric": {
"destination_service": "worker-service.default.svc.cluster.local",
"source_app": "frontend",
"source_workload": "frontend-deployment"
},
"value": [
1544404907.503,
"18.892886390062788"
]
}
]
}
}
이제 JSON에서 측정항목 값을 추출할 수 있습니다.
삭제하기
Prometheus를 노출하는 데 사용한 서비스를 삭제해야 합니다. Google Cloud 콘솔에서 방금 만든 서비스 상단으로 이동하여 '삭제'를 클릭합니다.
다음 단계:
트래픽이 클러스터를 통해 이동하는 방식과 속도를 파악하는 방법을 찾은 다음에는 prometheus를 주기적으로 쿼리하는 소형 바이너리를 작성하고 worker
에 대한 초당 요청 수가 특정 임곗값을 초과하면 작업자 가상 서비스에 서로 다른 대상 가중치를 적용하여 모든 트래픽을 burst
클러스터로 전송합니다. 초당 요청 수가 하한 임곗값 미만이 되면 모든 트래픽을 primary
로 다시 전송합니다.
17. 교차 클러스터 버스트 만들기
설정
워커 서비스의 모든 트래픽을 기본 클러스터로 설정하기
worker-service
를 대상으로 하며 primary
클러스터로 라우팅되는 모든 트래픽은 애플리케이션의 '기본' 상태로 간주됩니다.
$proj/istio-manifests/worker-virtualservice.yaml
를 다음과 같이 수정합니다.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: worker-virtual-service
spec:
hosts:
- worker-service
gateways:
- mesh
http:
- route:
- destination:
host: worker-service.default.svc.cluster.local
subset: primary
port:
number: 80
weight: 100
- destination:
host: worker-service.default.svc.cluster.local
subset: burst
port:
number: 80
weight: 0
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: worker-destination-rule
spec:
host: worker-service
trafficPolicy:
loadBalancer:
simple: RANDOM
subsets:
- name: primary
labels:
cluster-type: primary-cluster
- name: burst
labels:
cluster-type: burst-cluster
primary
클러스터에 연결되어 있는지 확인
kubectx primary
istio-manifests/worker-virtualservice.yaml 적용
kubectl apply -f istio-manifests/worker-virtualservice.yaml
istiowatcher 데몬 작성
속도와 휴대성을 위해 Go를 사용하여 이 서비스를 작성합니다. 애플리케이션의 전반적인 흐름은 시작하고 1초마다 prometheus를 쿼리하는 것입니다.
src에 istiowatcher라는 새 디렉터리를 만듭니다.
mkdir -p ${proj}/src/istiowatcher && cd ${proj}/src/istiowatcher
클러스터 내에서 Istio 컨트롤 플레인을 조작하기 위해 컨테이너 내에서 istioctl
를 호출합니다.
istiowatcher.go 작성
해당 디렉터리에 istiowatcher.go
라는 파일을 만들고 다음을 삽입합니다.
package main
import (
"github.com/tidwall/gjson"
"io/ioutil"
"log"
"net/http"
"os/exec"
"time"
)
func main() {
//These are in requests per second
var targetLow float64 = 10
var targetHigh float64 = 15
// This is for the ticker in milliseconds
ticker := time.NewTicker(1000 * time.Millisecond)
isBurst := false
// Our prometheus query
reqQuery := `/api/v1/query?query=sum(rate(istio_requests_total{reporter="destination",destination_service="worker-service.default.svc.cluster.local",source_workload="frontend-deployment"}[15s]))by(source_workload,source_app,destination_service)`
for t := range ticker.C {
log.Printf("Checking Prometheus at %v", t)
// Check prometheus
// Note that b/c we are querying over the past 5 minutes, we are getting a very SLOW ramp of our reqs/second
// If we wanted this to be a little "snappier" we can scale it down to say 30s
resp, err := http.Get("http://prometheus.istio-system.svc.cluster.local:9090" + reqQuery)
if err != nil {
log.Printf("Error: %v", err)
continue
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
val := gjson.Get(string(body), "data.result.0.value.1")
log.Printf("Value: %v", val)
currentReqPerSecond := val.Float()
log.Printf("Reqs per second %f", currentReqPerSecond)
if currentReqPerSecond > targetHigh && !isBurst {
applyIstio("burst.yaml")
log.Println("Entering burst mode")
isBurst = true
} else if currentReqPerSecond < targetLow && isBurst {
applyIstio("natural.yaml")
log.Println("Returning to natural state.")
isBurst = false
}
}
}
func applyIstio(filename string) {
cmd := exec.Command("istioctl", "replace", "-f", filename)
if err := cmd.Run(); err != nil {
log.Printf("Error hit applying istio manifests: %v", err)
}
}
Dockerfile 작성
Dockerfile
라는 새 파일을 만들고 다음을 삽입합니다.
FROM golang:1.11.2-stretch as base
FROM base as builder
WORKDIR /workdir
RUN curl -LO https://github.com/istio/istio/releases/download/1.0.0/istio-1.0.0-linux.tar.gz
RUN tar xzf istio-1.0.0-linux.tar.gz
RUN cp istio-1.0.0/bin/istioctl ./istioctl
FROM base
WORKDIR /go/src/istiowatcher
COPY . .
COPY --from=builder /workdir/istioctl /usr/local/bin/istioctl
RUN go get -d -v ./...
RUN go install -v ./...
CMD ["istiowatcher"]
이 다단계 Dockerfile은 첫 번째 단계에서 Istio 1.0.0 출시를 다운로드하고 추출합니다. 두 번째 단계는 디렉터리의 모든 항목을 이미지로 복사한 다음 빌드 단계에서 istioctl
를 /usr/local/bin
로 복사하여 애플리케이션에서 호출할 수 있도록 하고 종속 항목을 가져오고 코드를 컴파일하고 CMD
를 'istiowatcher
'로 설정합니다.
burst.yaml 작성
frontend
에서 worker
에 대한 초당 요청 수가 15를 초과할 때 istiowatcher
가 적용하는 파일입니다.
burst.yaml
라는 새 파일을 만들고 다음을 삽입합니다.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: worker-virtual-service
spec:
hosts:
- worker-service
gateways:
- mesh
http:
- route:
- destination:
host: worker-service.default.svc.cluster.local
subset: primary
port:
number: 80
weight: 0
- destination:
host: worker-service.default.svc.cluster.local
subset: burst
port:
number: 80
weight: 100
natural.yaml 작성
frontend
에서 worker
의 요청/초가 10 미만으로 떨어지면 '자연스러운' 상태로 돌아간 것으로 간주됩니다. 이 상태에서는 트래픽의 100% 가 primary
클러스터로 라우팅됩니다.
natural.yaml
라는 새 파일을 만들고 다음을 삽입합니다.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: worker-virtual-service
spec:
hosts:
- worker-service
gateways:
- mesh
http:
- route:
- destination:
host: worker-service.default.svc.cluster.local
subset: primary
port:
number: 80
weight: 100
- destination:
host: worker-service.default.svc.cluster.local
subset: burst
port:
number: 80
weight: 0
istiowatcher 빌드 및 푸시
다음을 실행하여 현재 디렉터리를 Google Cloud Build (GCB)로 전송합니다. 그러면 GCR에서 이미지가 빌드되고 태그가 지정됩니다.
gcloud builds submit -t gcr.io/${GCLOUD_PROJECT}/istiowatcher
istiowatcher 배포
kubernetes
디렉터리로 변경
cd ${proj}/kubernetes/
배포 파일(istiowatcher.yaml) 작성
istiowatcher.yaml이라는 파일을 만들고 다음을 삽입합니다(<your-project-id>는 프로젝트 ID로 대체).
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: istiowatcher-deployment
labels:
app: istiowatcher
spec:
replicas: 1
selector:
matchLabels:
app: istiowatcher
template:
metadata:
labels:
app: istiowatcher
spec:
serviceAccountName: istio-pilot-service-account
automountServiceAccountToken: true
containers:
- name: istiowatcher
image: gcr.io/<your-project-id>/istiowatcher
imagePullPolicy: Always
배포
기본 클러스터에서 실행 중인지 확인
kubectx primary
istio-system
네임스페이스에 istiowatcher.yaml
배포
kubectl apply -n istio-system -f istiowatcher.yaml
yaml의 serviceAccountName
및 automountServiceAccountToken
디렉티브에 유의해야 합니다. 이렇게 하면 클러스터 내에서 istioctl
를 실행하는 데 필요한 사용자 인증 정보가 제공됩니다.
또한 istio-pilot-service-account
의 사용자 인증 정보가 있는지 확인하기 위해 istio-system
네임스페이스 내에 이를 배포해야 합니다. default
네임스페이스에 존재하지 않습니다.
트래픽이 자동으로 전환되는 것을 확인하세요.
이제 마법 같은 순간입니다. 프런트엔드로 이동하여 req/초를 20으로 높이겠습니다.
몇 초 정도 걸리지만 속도가 점점 빨라지고 모든 해시에 'bursty-' 접두사가 추가됩니다.
15s
범위에서 Prometheus를 샘플링하기 때문에 응답 시간이 약간 지연됩니다. 훨씬 더 좁은 범위를 원한다면 prometheus 쿼리를 5s.
로 변경할 수 있습니다.
18. 다음 단계
삭제하기
이 워크숍에 제공된 임시 계정을 사용하는 경우 정리할 필요가 없습니다.
GCR에서 Kubernetes 클러스터, 방화벽 규칙, 이미지를 삭제할 수 있습니다.
gcloud container clusters delete primary --zone=us-west1-a
gcloud container clusters delete burst --zone=us-west1-a
gcloud compute firewall-rules delete istio-multicluster-test-pods
gcloud container images delete gcr.io/$GCLOUD_PROJECT/istiowatcher
향후 계획
- Istio Talks에 참여하세요.
- 인증서 취득: Kubernetes + Istio로 다음 앱 빌드하기
- 키노트: Kubernetes, Istio, Knative: 새로운 개방형 클라우드 스택 - 아파르나 신하, Google Kubernetes 그룹 제품 관리자
- 튜토리얼: Istio 사용 - Lee Calcote 및 Girish Ranganathan, SolarWinds
- Istio - 패킷 관점 - 맷 터너, Tetrate
- Istio는 지금까지 만들어진 가장 차세대 차세대 방화벽인가요? - 존 모렐로, Twistlock
- Istio 문서 읽기
- Istio 워킹 그룹에 참여하세요.
- 트위터에서 @IstioMesh 팔로우