KnativeCon 2022 NA - Taming Thousands of Knative Services for Thousands of Users
KnativeCon North America 2022: Taming Thousands of Knative Services for...
View more about this event at KnativeCon North America 2022
knativeconna22.sched.com
IBM Cloud의 Code-Engine product 구조는 위와 같다.
- Knative 기반
- Running your containers in the cloud easily
- batch experience
- tekton 사용한 code deploy
UI로 Container Image / Source Code 입력값 구분.
- ibmcloud cli로 클라우드 관련 정보를 전혀 몰라도 배포 가능.
knative v0.11 때부터 시작해서 서비스 꽤 오래 했음. 이 과정에서 겪은 노하우 크게 두 가지를 공유하려 한다.
- Securing a multi-tenant knative installation
- Scaling a multi-tenant knative installation
Securing a multi-tenant knative installation
Sharing one Cluster with a lot of users
- avoiding the interference each other
- not see the other person's services and data.
Encryption
- service to service (or activator) 에서 이루어지는 트래픽에는 istio의 mTLS 사용
- project 단위로 Certificate가 달라야 하는 요구사항에 부합하는 knative-supported service mesh라서 istio를 선택하긴 했음
- project마다 lets encrypt를 사용한 certificate를 gateway configuration에 정의했다.
Lesson
- Multi-Certificate requirements를 충족하는 service mesh product가 너무 적다.
- 정황상 knative와 호환되는 service mesh중에서 이 요구사항을 어떻게든 구현할 수 있는 게 istio 하나뿐이라는 것 같음
- gateway configuration을 생성할 때마다 중복되는 정보들
- TLS의 Cipher Suites와 같은 값들. service가 많아질수록 이 값이 커질 거고, etcd가 저장할 수 있는 entry size를 넘어설 수 있다.
- istio 1.15 버전에서는 envoy에서 중복된 정보를 처리할 수 있게 되어 etcd에 저장해둬야 하는 데이터 양이 줄어들었다고 함.
Personal Note
정확히 무슨 업데이트가 이 역할을 해낸 건지 확인해봐야겠다
Network
k8s의 networkPolicy를 사용한 namespace isolation이 불가능함.
- knative service 간 통신을 담당하는 knative-local-gateway 컴포넌트 때문.
- customers' VPC에서만 접근할 수 있는 private access application 관점에서는 이런 방식의 연결이 있어선 안 됨.
knative나 istio에서 해결해줄 수 있는 성격의 것이 아니었으므로 Envoy에 custom filter 추가해서 해결함.
- 내부 DNS를 destination으로 한 outbound traffic이 발생할 경우 request header에 secret을 추가함.
- inbound traffic을 받을 경우, request header에 포함된 secret이 fit namespace인지 확인하는 식으로 구현
Lesson
- k8s의 network policy로는 cross-namespace traffic을 통제할 수 없다.
Resources
한 명의 customer가 entire cluster resource를 가져갈 수는 없어야 함. 그래서 서비스에 위와 같은 리소스 제한을 부여했음.
- limit the number of apps / revisions.
- revision도 결국 클러스터 내부의 ip address 리소스이므로 한계가 있다.
운영 관점에서 보안 / 속도 생각하면 클러스터 내부에 캐시된 이미지만 쓰도록 할 수 있으나
- 공용 클러스터이므로 사용자가 image path를 유추해서 Pull 시도할 경우... 클러스터 내에서 authentication 처리할 수가 없음. 그래서 image pull policy는 always.
- image pull이 always라고 해서 성능이 느려지거나 하진 않음. pull 과정에 authentication 추가한 거라 보면 됨
Lesson
- ifNotPresent는 공용클러스터에서 사용 시 security 이슈가 있으므로 always를 사용함
- knative에서 제공하는 기능으로 pod allow / disallow control이 가능했음
Scaling a multi-tenant Knative installation
knative의 어떤 configuration을 어느 정도로 변경해서 클러스터당 몇 천 대의 knative services를 운영하고 있는지.
Performance
istio를 사용한다는 건 cold start에 추가적인 overhead가 들어간다는 것. 이 값을 최대한 줄이기 위한 시도.
크게 두 가지.
- prepull sidecar image out of band
- sidecar image를 별도의 bandwidth로 미리 노드에 pull받아 둔다.
- 노드의 scale이 발생할 때, istio-proxy나 queue-proxy를 미리 받아둠으로써 pre-warm 상태를 만드는 것.
- 드라마틱한 성능 향상이 있진 않음. overhead가 큰 건 두 번째인 mesh tuning
- mesh tuning
- istio가 붙은 상황에서 scaling을 진행할 때... 새로 뜨는 pod에 service mesh configuration (service information)을 부여하는 작업이 가장 오래 걸림. 특히 scale 0 to 1으로 넘어갈 때.
- 이건 강연 끝자락에 따로 설명할 예정
- "push in the discovery information for the services to the activator & to the service endpoint" 속도를 최대한 빠르게 해야 한다.
- istio로 할 수 있는 여러 experiment를 진행해봤는데,
- configuring IP table as a network layer
- performance test on istio cni plugin...
- cold start에 영향을 주는 건 mesh tuning 프로세스였다. 다른 부분을 변경한다 해도 유의미한 차이는 없었음.
- istio가 붙은 상황에서 scaling을 진행할 때... 새로 뜨는 pod에 service mesh configuration (service information)을 부여하는 작업이 가장 오래 걸림. 특히 scale 0 to 1으로 넘어갈 때.
Lesson
- istio sidecar와 queue-proxy injection은 minor overhead
- CNI plugin이나 IP table configuration을 init container 등으로 최적화하는 건 cold start 속도 향상에 도움이 되지 않는다.
- istio state synchronization 속도 향상이 cold start 단축의 핵심
- activator / knative service가 필요한 정보를 istio control plain이 확인하고 전달하는 과정.
Knative Component의 scaling 관점
- activator에는 HPA 비활성화.
- HPA가 활성화되면, activator instance가 동작할 때마다 service가 변경됨 + all services in the cluster will be changed.
- 즉 istio가 변경된 activator 정보를 업데이트하고, 다시 모든 proxy에 전다해야 하는 상황이 됨
- activator는 최대한 static configuration으로 관리... limit scaling / changing service as much as possible
- proxy mode 적용 (no serve mode)
- proxy mode: 모든 트래픽이 반드시 activator를 통하도록 설정.
- target-burst-capacity 옵션은 -1로 설정. request buffering / queue 기능을 해제해서 특정 revision으로 트래픽이 바로 전달되도록 세팅했다.
- 장점: lower latency
- 단점: revision에 할당된 리소스가 부족할 경우 performance 하락.
- target-burst-capacity 옵션은 -1로 설정. request buffering / queue 기능을 해제해서 특정 revision으로 트래픽이 바로 전달되도록 세팅했다.
- serve mode는 istio의 dynamic configuration Push에 더 영향을 주기 때문.
- istio가 '변경된 정보만' Push해주는 게 아니라 '서비스에서 접근할 수 있는 모든 정보'를 push하기 때문.
- 예컨대 하나의 서비스 정보가 바뀌면, 해당 서비스에 접근할 수 있는 모든 서비스에 변경사항이 전달되어야 한다.
- serve mode는 pod에 직접 요청을 보내므로, pod가 바뀔 때마다 istio configuration이 수정되어야 함.
- proxy mode: 모든 트래픽이 반드시 activator를 통하도록 설정.
- HA setup (pod anti-affinity) 설정으로 knative application이 여러 region / zone에 배포될 수 있도록 설정.
- queue sidecar size 세팅하기. (knative default 세팅 변경)
- 사용자마다 resource quota가 다르고 사용자가 직접 quota 변경이 가능할 경우
- pin it to specific / make it tied to the size of the service itself.
- k8s API를 호출하는 controller 커스텀
- QPS와 burst 값 수정하기. default 설정값은 너무 작으므로, 서비스에 맞게 적절히 수정.
- 'get more worker thread': 지금은 knative에서 지원하지 않는 기능이라 issue 열어둔 상태
- 지금은 controller가 resync 진행할 때 Big Queue가 생성됨... service provisioning time / revision creation time에 병목을 유발함.
클러스터 단위의 autoscaler + provisioning feature
- workload demand 예상치에 맞게 node 생성 + pre-warm 수행
Lesson 결론
- activator instance가 변경될 때마다 발생하는 state sync는 최소화한다.
- k8s API Limit값을 수정한다
- Future: API 호출 최적화. knative가 호출하는 API가 엄첨 많은데, 불필요한 것들이 몇 있다고 생각함.
- issue: https://github.com/knative/serving/issues/13204
- 예컨대 resync 수행할 때 knative는 클러스터의 모든 deployment를 대상으로 함. resync 대상으로 '변경할 필요가 없는 것'까지 포함하고 있음
- cold start time / provisioning time 증가의 원인
istio를 붙여서 쓴다.
- traffic management를 istio가 관리하도록 Mesh mode로 사용함 (knative가 pod에 직접 접근하고 clusterIP주소를 받는 등의 작업은 resync overhead가 발생함)
- proxy mode로 항상 activator를 통해 트래픽이 전달되도록 설정. 마찬가지로 resycn overhead 감소
- if not present, 즉 트래픽이 상황에 따라 actual pod / activator로 Routing되는 경우;
- activator로 트래픽이 다시 들어오면, activator는 이 트래픽을 전달할 service information이 필요함
- 만약 이 service information이 없다면 switch endpoint 시도.
- 이 때, istio가 switch하려는 endpoint 정보 동기화가 아직 안 된 상태라면 사용자에게 503 에러가 발생함.
- if not present, 즉 트래픽이 상황에 따라 actual pod / activator로 Routing되는 경우;
Personal Note
"activator in path" 가 반복적으로 등장하는데, 단순히 proxy mode를 의미하는 건지 아니면 따로 설정을 준 건지는 좀더 학습이 필요함.
knative로 새 애플리케이션을 생성하면 service Configuration / Routes / Revision이 생성된다.
- 이 중 Revision은 public / private 두 개가 생성되며, revision 내부 설정을 커스텀하는 기능은 없음.
- 여러 개의 revision을 만들다 보면, route가 트래픽을 전달하지 않는 non-active revision도 만들어진다.
- knative는 non-active artifacts 정보도 가지고 있다. (deployment, autoscaler, sks 등등)
- istio sends these informations with every push.
istio mesh sync가 수행될 때 cpu 리소스 사용 + 서비스 delay 유발.
- knative GC 활용해서, 하나의 knative service 애플리케이션의 max non-active revision 값을 1로 설정.
- 문제 생겼을 때 롤백할 수 있는 최소한의 선택지 + istio sync에 들어갈 불필요한 configuration 리소스 정리.
- istio의 mesh debounce 옵션 수정
- how often istio pushes / how to aggregate pushes.
- receiver 부하 조절하는 것이 목적
- istio control plane은 모든 proxy에 정보를 push하는 역할만 함. 실제로 옵션을 적용하는 건 receiver
Lesson
- knative에 istio를 붙여 사용할 때, non-active revision이 istio에 어떤 부하를 얼마나 주는지 확인해야 함.
- istio의 debounce option 확인. 필요 시 최적화.
- debounce_after: every push will be delayed by that amount of time.
- Direct impact on provisioning time on revision creation.
- debounce_max: how long to keep aggregating pushes until you finally send it out.
- debounce_after: every push will be delayed by that amount of time.
envoy에서 이미 제공하는 기능인 delta pushes를 istio에서도 도입하기 위한 논의가 진행 중.
- unnecessary information도 전부 push하는 로직 개선
IBM Cloud Engine outlook
- custom domain 기능을 knative 활용하도록 개선 예정
- proxy protocol support for enhanced auditabiltiy
- istio가 delta xDS push 지원하게 되면 도입할 예정
- 기타 scalability improvement
Q&A
Q. Max Number of services you can deploy on a single cluster? 예컨대 cluster의 iptable은 유한한데, 클러스터에 더 이상 쓰이지 않는 knative service들도 ip 리소스를 잡아먹으니까..
- hard number가 있진 않다.
- DB side to store 고민을 하게 된다면, 원인이 될 가장 유력한 컴포넌트로 Gateway를 꼽고 있다.
- 데이터 저장도 그렇고, marshal & unmarshal 로직이 cpu / memory intensive한데 default 옵션으로는 충분하지 않다.
Q. 클러스터에 수천 개의 애플리케이션이 돌고 있는 상황에서 istio 버전 rollout upgrade는 어떻게 했나?
- in-flight 업데이트.
Q. xDS fine-grain tuning을 시도했는데, sidecar injection 방식 말고 ambient mesh를 적용하면 성능이 더 향상될 수 있을지?
- ambient mesh 유심히 보고 있긴 한데, sync 목적보다는 resource 절약 차원에서 생각중임. 모든 클러스터에 sidecar 배포하는 것보다 리소스 절약이 확실하니까
- ambient mesh 도입과 별개로, delta xDS 적용을 안 하면 istio control plane은 여전히 send all information. 따라서 도입만으로 sync가 해결되진 않을 거라 생각함
Q. 상당 부분이 reducing what istio is pushing out에 집중되어 있는데, 혹시 trade-off가 있었는지.
- trade off가 되는 영역은
- cold start / provisioning time과
- creating new revision / updating services.
- 데이터 보고 적절한 밸런스를 찾아야 함
- how many services you have in your cluster
- what rate of changes / how many services are provisioned per minute(second)
- how many cold starts you have.
여기에 질문자 누가 답변에 첨언함
- xDS Sync 문제 해결을 위해 autoscaling 관련 옵션을 상당 부분 비활성화한 상태.
- activator의 autoscaling, activator out of path (정황상 proxy mode로 고정한 걸 말하는 듯)
- 즉, 많은 트래픽이 특정 앱에 집중되더라도 반드시 activator를 거쳐가야 하는 방식.
- 따라서 resource efficiency를 일부 희생했다고보 돌 수 있다.
marshalling / unmarshalling에 드는 리소스 절약을 위해 이 부분을 희생한 셈.
Q. 이 정도 규모의 서비스를 생각하고 있는 사람들에게 조언을 부탁한다. One single large cluster with all the customers in one Region? / Sharding & having multiple clusters?
- 우리는 sharding 적용한 multl-cluster 구성.
- 멀티 클러스터 구조로 가려면 control plane에서 수행할 sorting overhead / management component 고려까지도 필요함.
- 따라서 Clusters 자체를 최대한 잘 쓰는 게 먼저인 거 같고, 우리는 adapt growth & customer number를 위해 sharding 적용함.
'학습일지 > Knative' 카테고리의 다른 글
Knative의 Eventing Prometheus 고쳐서 동작하게 만들었던 히스토리 (0) | 2024.03.19 |
---|---|
knative eventing github 코드 분석 (0) | 2023.04.21 |
Serverless Practitioners Summit 2019 - How Knative Uses Concurrency and RPS (0) | 2023.03.26 |
KnativeCon 2022 - How Fast is FaaS? Reducing Cold Start Times in Knative (0) | 2023.03.12 |
KubeDay 2022 - Distributed Tracing Integration with OpenTelemetry and Knative (0) | 2023.03.01 |