ICA模擬試験A
한국어 원문으로 표시합니다.
ICA 모의고사 A 입니다. 제한 시간 120분, 과제 17개, 합격선 68% 입니다. 부분 점수제이므로 막히는 과제는 건너뛰고 나중에 돌아오는 편이 낫습니다.
모의고사이므로 힌트와 정답을 보지 말고 먼저 끝까지 풀어 보십시오. 시간이 모자라 못 푼 것과 몰라서 못 푼 것은 다른 문제이고, 그 둘을 구분해야 다음에 무엇을 공부할지가 정해집니다. 다 풀고 채점한 뒤에 펼치십시오.
실제 시험 환경
시험 중에 istio.io/docs, istio.io/blog, kubernetes.io/docs 를 볼 수 있습니다.
istio.io/search/ 로 문서 사이트 안에서 검색하는 것은 허용되지만 외부 검색
결과를 클릭하면 안 됩니다. k 별칭과 bash 자동완성, 그리고 istioctl
자동완성이 이미 설정되어 있습니다. 과제마다 지정된 호스트로 ssh 해서
작업하며 중첩 ssh 는 지원되지 않습니다. 터미널 복사는 Ctrl+Shift+C,
붙여넣기는 Ctrl+Shift+V 입니다.
이 모의고사 환경
파드 안의 1인용 클러스터에서 바로 작업합니다(ssh 는 필요 없습니다). kube-apiserver 는 진짜라서 잘못된 매니페스트는 실제로 거부되지만, 사이드카는 뜨지 않고 트래픽도 흐르지 않습니다. 채점은 여러분이 클러스터에 남긴 설정을 다시 읽어서 합니다.
1번 과제가 나머지 대부분의 전제입니다. Istio 리소스 종류가 등록되기 전에는
kubectl apply 가 VirtualService 를 받아 주지 않습니다. 먼저 끝내십시오.
1. 기본 프로파일의 Istio 설치 매니페스트를 만들어 /root/ica/install/manifest.yaml
에 저장하십시오. 그리고 그 매니페스트 안의 CustomResourceDefinition 만 골라
클러스터에 등록하십시오. 이 환경에서는 istiod 파드가 뜨지 않으므로 필요한 것은
API 타입뿐입니다.
2. 네임스페이스 세 개를 만들고 사이드카 주입 라벨을 붙이십시오.
ica-shop에istio-injection=enabledica-legacy에istio-injection=disabledica-rev에istio.io/rev=1-24. 이 네임스페이스에는istio-injection라벨을 남기지 마십시오.
3. 파드 수준에서 네임스페이스의 결정을 뒤집으십시오. 두 디플로이먼트 모두
레플리카 1, 이미지 nginx:1.27-alpine 입니다.
ica-shop의batch-runner: 파드 템플릿 라벨sidecar.istio.io/inject: "false"ica-legacy의legacy-api: 파드 템플릿 라벨app: legacy-api와sidecar.istio.io/inject: "true"
4. ica-shop 에 리뷰 서비스를 세 버전으로 올리고 subset 을 정의하십시오.
- 디플로이먼트
reviews-v1·reviews-v2·reviews-v3, 각 1 레플리카. 파드 라벨은app=reviews와version=v1/v2/v3. 이미지nginx:1.27-alpine, 컨테이너 포트 9080. - 서비스
reviews: 포트 9080, 포트 이름http. selector 는app=reviews하나만 둡니다. - DestinationRule
reviews:spec.host는reviews.ica-shop.svc.cluster.local. subsetv1·v2·v3를 각각의version라벨로 정의하고,trafficPolicy.loadBalancer.simple을LEAST_REQUEST로 둡니다.
5. ica-shop 에 VirtualService reviews 를 만드십시오. 호스트는
reviews.ica-shop.svc.cluster.local 이고, 조건 없는 규칙 하나로 subset v1 에
80, subset v2 에 20 을 나눕니다.
6. 5번의 VirtualService reviews 앞에 규칙 두 개를 더해 모두 세 개로
만드십시오. 순서가 채점 대상입니다.
- 헤더
end-user가 정확히tester이면 subsetv3 uri접두사가/api/v2이면서 동시에 메서드가GET이면 subsetv2- 5번의 가중치 규칙이 조건 없는 마지막 규칙으로 남습니다
7. 같은 VirtualService reviews 의 마지막(조건 없는) 규칙에 회복력 설정을
붙이십시오. 전체 타임아웃 2s, 재시도 3회, 시도당 타임아웃 500ms, 재시도
조건은 5xx·reset·connect-failure 입니다.
8. DestinationRule reviews 의 trafficPolicy 에 상한과 이상치 감지를
더하십시오.
connectionPool.tcp.maxConnections는 100connectionPool.http.http1MaxPendingRequests는 10connectionPool.http.maxRequestsPerConnection은 1outlierDetection은consecutive5xxErrors5,interval10s,baseEjectionTime30s,maxEjectionPercent50
9. ica-shop 에 인그레스를 세우십시오.
- Gateway
shop-gateway: selector 는istio: ingressgateway. 80 포트(이름http, 프로토콜 HTTP)는 호스트shop.example.com을 받아 HTTPS 로 넘깁니다. 443 포트(이름https, 프로토콜 HTTPS)는 같은 호스트를SIMPLE모드로 종료하며 인증서 시크릿 이름은shop-cert입니다. - VirtualService
shop-edge: 호스트shop.example.com, 게이트웨이shop-gateway에 묶고,uri접두사/reviews를reviews.ica-shop.svc.cluster.local의 9080 포트로 보냅니다.
10. mTLS 를 메시 전역으로 강제하되 낡은 네임스페이스만 예외로 두십시오.
istio-system네임스페이스를 만들고 그 안에 PeerAuthenticationdefault를STRICT로 둡니다. selector 는 붙이지 마십시오.ica-legacy에 PeerAuthenticationdefault를PERMISSIVE로 둡니다. 여기에도 selector 는 붙이지 마십시오.
11. ica-legacy 의 legacy-api 워크로드만 STRICT 로 올리되 8080 포트는
예외로 두십시오. PeerAuthentication 이름은 legacy-api, selector 는
app: legacy-api, mtls.mode 는 STRICT, portLevelMtls 의 8080 은
DISABLE 입니다.
12. ica-shop 에 인가 정책 두 개를 만드십시오. 둘 다 selector 는
app: reviews 입니다.
reviews-allow:ALLOW. 출처 principal 은cluster.local/ns/ica-shop/sa/productpage, 허용 동작은 메서드GET과 경로/reviews*입니다.reviews-deny-admin:DENY. 경로/admin*을 막습니다.
13. ica-shop 의 app: reviews 워크로드에 JWT 검증을 붙이십시오.
- RequestAuthentication
shop-jwt: issuer 는https://auth.shop.example.com, jwksUri 는https://auth.shop.example.com/.well-known/jwks.json - AuthorizationPolicy
require-jwt:ALLOW. requestPrincipals 는https://auth.shop.example.com/*
14. 어떤 팀이 ica-fix 네임스페이스에 쓰겠다며 아래 VirtualService 하나만
넘겨 주었습니다. 이대로는 istioctl analyze 가 오류를 냅니다. 무엇이 빠졌는지
진단해 채워 넣고, istioctl analyze -n ica-fix 가 Error 를 하나도 내지 않게
만드십시오.
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: payments
namespace: ica-fix
spec:
hosts:
- payments.ica-fix.svc.cluster.local
http:
- route:
- destination:
host: payments.ica-fix.svc.cluster.local
subset: stable
채워 넣을 것의 규격은 이렇습니다. 디플로이먼트 payments 는 파드 라벨
app=payments 와 version=v1, 서비스 payments 는 포트 9090 에 포트 이름
http, DestinationRule payments 는 위와 같은 FQDN 을 host 로 두고 subset
stable 을 version: v1 로 정의합니다. 이 네임스페이스에 과제와 무관한
리소스를 남기지 마십시오. 남으면 analyze 가 그것까지 잡습니다.
15. ica-triage 네임스페이스에 아래 VirtualService 를 적용했더니
x-beta: true 헤더를 붙여도 언제나 stable 로 갑니다. 원인을 진단해 고친 것을
적용하십시오. 규칙은 두 개 그대로 둡니다.
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: checkout
namespace: ica-triage
spec:
hosts:
- checkout.ica-triage.svc.cluster.local
http:
- route:
- destination:
host: checkout.ica-triage.svc.cluster.local
subset: stable
- match:
- headers:
x-beta:
exact: "true"
route:
- destination:
host: checkout.ica-triage.svc.cluster.local
subset: beta
16. 아래 정책을 넣은 뒤 ica-triage 의 payments 워크로드가 모든 요청을
거부합니다. 원인을 진단하고, cluster.local/ns/ica-triage/sa/frontend 가
POST 로 /pay* 에 접근하는 것만 허용하도록 고치십시오.
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: payments-allow
namespace: ica-triage
spec:
selector:
matchLabels:
app: payments
action: ALLOW
rules: []
17. ica-triage 에 아래 두 리소스를 두었더니 orders 를 호출하는 쪽이 전부
실패합니다. 서버 쪽 요구는 그대로 두고 클라이언트 쪽을 고치십시오.
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: default
namespace: ica-triage
spec:
mtls:
mode: STRICT
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: orders
namespace: ica-triage
spec:
host: orders.ica-triage.svc.cluster.local
trafficPolicy:
tls:
mode: DISABLE
15번부터 17번까지의 ica-triage 에는 워크로드를 만들 필요가 없습니다. 고쳐야
할 것은 설정입니다.
메시 API 타입을 클러스터에 등록하기
istioctl manifest generate 는 차트를 바이너리 안에 품고 있어 인터넷 없이도 동작합니다. 그 결과에는 istiod 와 서비스까지 들어 있는데, 이 환경에서 필요한 것은 CRD 뿐이니 kind 로 걸러 내십시오. 적용할 때는 --server-side 를 쓰십시오. Istio CRD 는 어노테이션이 커서 일반 apply 의 last-applied-configuration 한도(262144바이트)를 넘깁니다.
네임스페이스별 사이드카 주입 라벨 걸기
리비전 라벨과 istio-injection 라벨이 한 네임스페이스에 함께 있으면 istio-injection 이 이깁니다. 그래서 리비전으로 옮기는 중에 예전 라벨을 지우지 않으면 새 리비전이 조용히 무시됩니다. 지울 때는 라벨 이름 뒤에 빼기 기호를 붙입니다.
파드 수준에서 주입 여부 뒤집기
sidecar.istio.io/inject 는 파드 템플릿의 라벨에 붙습니다. 디플로이먼트 자체의 라벨이나 어노테이션이 아닙니다. 값은 반드시 따옴표로 감싼 문자열이어야 합니다. 쿠버네티스 라벨 값은 문자열만 받으므로 따옴표 없이 쓰면 apiserver 가 거부합니다.
버전별 워크로드와 subset 만들기
서비스의 selector 에 version 을 넣으면 한 버전만 잡혀서 가중치 분배가 아예 불가능해집니다. 버전을 가르는 일은 DestinationRule 의 subset 이 합니다. subset 의 labels 는 subset 이름이 아니라 파드 라벨과 글자 그대로 같아야 하고, spec.host 는 짧은 이름 대신 FQDN 으로 적으십시오. 서비스 포트 이름은 Istio 가 프로토콜을 판별하는 근거입니다.
가중치로 80 대 20 나누기
가중치는 route 배열의 각 destination 에 붙고 합이 100 이어야 합니다. 이 규칙에는 match 를 두지 마십시오. 뒤 과제에서 조건이 붙은 규칙들이 이 앞에 들어오고, 조건 없는 규칙은 언제나 맨 뒤에 있어야 합니다.
구체적인 규칙을 catch-all 앞에 두기
규칙은 위에서 아래로 평가되고 첫 매치가 이깁니다. 조건 없는 규칙이 맨 앞에 있으면 뒤 규칙은 영영 평가되지 않습니다. 그리고 조건 두 개를 AND 로 묶으려면 같은 match 블록 안에 나란히 적어야 합니다. 블록을 둘로 나누면 OR 이 됩니다.
타임아웃과 재시도의 관계 맞추기
timeout 은 재시도를 포함한 전체 데드라인입니다. perTryTimeout 곱하기 시도 횟수가 timeout 을 넘으면 마지막 시도는 시작도 못 하고 잘립니다. 여기서는 500ms 곱하기 3 이 1.5초라 2초 안에 들어갑니다. retryOn 은 쉼표로 이은 문자열이며 비워 두면 어떤 실패에 재시도할지 정해지지 않습니다.
커넥션 풀 상한과 이상치 감지 걸기
둘은 같은 trafficPolicy 안에 있지만 하는 일이 다릅니다. connectionPool 은 이쪽에서 나가는 부하를 막고, outlierDetection 은 상대 인스턴스가 계속 5xx 를 내면 잠시 빼 버립니다. maxEjectionPercent 를 적지 않으면 필드가 아예 저장되지 않으니 값을 명시하십시오. 앞 과제에서 만든 loadBalancer 를 지우지 않도록 조심하십시오.
인그레스 게이트웨이 세우기
Gateway 는 포트를 열 뿐이고 라우팅은 하지 않습니다. VirtualService 의 spec.gateways 에 이름을 적어 붙이지 않으면 그 규칙은 메시 내부에만 적용되고 외부 요청은 404 를 받습니다. httpsRedirect 는 80 포트 server 의 tls 아래에 둡니다. 인증서는 게이트웨이 파드의 네임스페이스에서 credentialName 으로 찾습니다.
메시 전역 STRICT 와 네임스페이스 예외
PeerAuthentication 은 세 층으로 걸립니다. selector 가 없고 루트 네임스페이스(istio-system)에 있으면 메시 전역이고, selector 없이 다른 네임스페이스에 있으면 그 네임스페이스 전체이며, selector 가 있으면 워크로드입니다. 좁은 범위가 넓은 범위를 이깁니다. 전역 정책에 selector 를 붙이는 순간 그것은 더 이상 전역이 아닙니다.
워크로드 STRICT 에 포트 예외 두기
portLevelMtls 는 selector 가 있는 워크로드 정책에서만 동작합니다. selector 없이 쓰면 apiserver 가 거부합니다. 그리고 여기 적는 포트 번호는 서비스 포트가 아니라 파드의 컨테이너 포트입니다. 서비스 포트를 적으면 예외가 아무 데도 걸리지 않고, 그 사실은 오류 없이 조용히 지나갑니다.
ALLOW 와 DENY 정책 나눠 쓰기
DENY 는 ALLOW 보다 먼저 평가되고, 하나라도 걸리면 거기서 끝납니다. 평가 순서는 CUSTOM, DENY, ALLOW 입니다. principal 은 서비스 계정의 SPIFFE 신원이며 형식은 cluster.local/ns/<네임스페이스>/sa/<서비스계정> 입니다. 경로 끝의 별표는 접두사 매칭입니다.
JWT 검증과 토큰 요구를 함께 걸기
RequestAuthentication 은 토큰이 있으면 검증할 뿐이고, 토큰이 없는 요청은 그냥 통과시킵니다. 토큰을 요구하려면 requestPrincipals 를 쓰는 AuthorizationPolicy 를 함께 걸어야 합니다. requestPrincipals 의 형식은 issuer 와 subject 를 슬래시로 이은 것이고, 발급자만 제한하려면 뒤를 별표로 둡니다.
analyze 가 잡아 주는 것을 채워 넣기
istioctl analyze -n ica-fix 를 먼저 돌려 무엇을 못 찾는다고 하는지 읽으십시오. IST0101 은 참조한 host 나 host 와 subset 의 짝을 찾지 못했다는 뜻입니다. 서비스가 없어도, DestinationRule 에 그 subset 이 없어도 같은 코드가 나옵니다. 하나씩 채우고 다시 돌리면 남은 것이 줄어드는 것을 볼 수 있습니다.
도달하지 못하는 규칙 살려 내기
규칙은 위에서 아래로 평가되고 첫 매치가 이깁니다. 조건이 없는 규칙은 모든 요청에 매치되므로, 그것이 맨 앞에 있으면 뒤의 규칙은 어떤 요청으로도 평가되지 않습니다. 아무 오류도 나지 않고 설정은 유효한 채로 남기 때문에 눈으로 찾는 수밖에 없습니다.
모든 요청을 막는 빈 ALLOW 정책 고치기
AuthorizationPolicy 가 어떤 워크로드에 하나라도 걸리면 그 워크로드는 기본 거부로 바뀝니다. 그 상태에서 ALLOW 규칙이 비어 있으면 아무 요청도 규칙에 걸리지 못해 전부 거부됩니다. 정책이 없는 것과 빈 정책이 있는 것은 정반대의 결과를 냅니다.
서버 요구와 어긋난 클라이언트 TLS 고치기
PeerAuthentication 은 서버가 무엇을 받아 줄지를 정하고, DestinationRule 의 trafficPolicy.tls 는 클라이언트가 어떻게 붙을지를 정합니다. 서버가 STRICT 인데 클라이언트가 DISABLE 이면 평문으로 붙었다가 끊깁니다. 둘 다 유효한 설정이라 어느 쪽도 오류를 내지 않는다는 점이 이 장애를 어렵게 만듭니다. 사이드카가 대신 인증서를 다뤄 주는 모드를 고르십시오.