kopf를 버린 이유

호근·2024년 9월 4일
0

개요

클라우드 리소스 자동화를 위해
crossplane을 사용하여 리소스들을 매니징하고있음.
동시에, kopf를 통하여 이벤트를 모니터링함.

이슈상황

  • VPC리소스를 생성 시 crossplane과 kopf가 충돌없이 동작함.
  • EC2 Instance 생성 시 여러 하위 리소스들을 동시에 생성하며,
    하위 리소스들의 준비상태를 기다리며, Instance리소스의 생성이 지연되는 상황이 발생함.
    (리소스 status.atProvider가 갱신되지 않는 현상이 발생함. 이 부분에서 crossplane과 kopf의 충돌을 의심함)

해당시점에 ec2 Provider pod에서 대강 아래와 같은 Warning을 발생시킴.

,"error":"cannot update status of the resource ec2.aws.upbound.io/v1beta1, Kind=SecurityGroup/securitygroup-bvf6s3 after an async create: Operation cannot be fulfilled on securitygroups.ec2.aws.upbound.io \"securitygroup-bvf6s3\": the object has been modified; please apply your changes to the latest version and try again

처음 이 문제를 마주하였을 때, k8s API가 kopf와 crossplane에 의해 변경된 resource의 Version정보를 타게팅하지 못해서 발생하는 이슈이거나 하위리소스들이 정상적인 상태를 가지지 못하여 발생하는 문제로 생각했으나, 생성시간이 짧은 리소스들은 문제없이 동작한다는 부분이 설명되지 못했음..


예상되는 문제점은

  1. crossplane에 의해 리소스와 리소스 버전이 갱신된 후
    kopf가 리소스 관리목적으로 변경된 상태정보로 annotation 필드를 갱신하여 다시 한 번 리소스 버전이 업데이트되면 K8s API는 Crossplane과 kopf에 의해 업데이트 된 리소스버전을 기억해야하지만, 생성지연으로 인해 리소스버전이 유휴상태에 돌입하여 리소스 버전을 명확히 타겟팅하지 못하는 현상.

  2. crossplane의 finalizer와 kopf의 finalizer 충돌
    동일한 리소스에 대하여 두개의 트리거가 동작하여 충돌할 우려가 있음.

K8s watch stream

1번은 kopf의 피어링 설정으로 annotations과 finalizer를 부여하지 않도록 하면 되었으나, crossplane과 kopf의 트리거가 충돌하여 이마저도 불가해짐 ㅠㅠ 서로 관리해야할 필드를 분리해서 책임을 분산시키거나 읽기전용으로 kopf를 실행시켜볼까 생각도 했는데, 배보다 배꼽이 더 커지는 상황인것같아서 둘 중 하나는 포기해야하는 상황..

당연히 모니터링만을 위해 도입한 kopf를 버렸고, 모니터링 시스템을 k8s 네이티브하게 개발해야했음.

k8s API 가 제공하는 event watch stream으로 개별리소스를 스트림으로 동기적으로 연결하여 실시간으로 이벤트를 수령하도록 구현함.
(고객사가 관리하는 securityGroup만 수만 건.. 거기에 딸려있는 association들을 합치면 모니터링해야하는 리소스의 수는 수십만건 정도될듯)

kopf가 제공하는 강력한 기능인 diff를 사용하지 못하게되면서,

리소스의 이전 상태를 어딘가에 저장해둘 필요가 있었음.
(전역으로 관리하기엔 언젠가 분리해야할것같다는 걱정이 있어서 Redis도입하기로 함)

리소스의 상태는 매우 자주 바뀌기 땜시
Redis 서버에 리소스 만큼의 객체를 만들고, 그 안에 4칸짜리 dequeue를 만들어서 리소스 상태를 관리하기로 함.


구현 결과.
Instance 리소스를 생성하며 생성시간이 지연되어도, atProvider가 정상적으로 갱신되며 모든 crossplane의 프로비저닝 작업이 정상적으로 동작하는 것을 확인하였음.

더 이상 ec2 Provider pod에서 warning로그도 출력되지 않음

결론

당장의 이슈는 해결하였으나..

Kopf와 Crossplane을 동시에 사용할 수 있는 방법도 분명히 있을 것 같아서,
추후에 Kopf와 Crossplane의 이벤트 트리거가 동작하는 방식의 차이를 제대로 알아보고,

  • 읽기 전용으로 kopf 실행
  • finalizer 충돌 관리
    - kopf에서만 finalizer 제거

를 적용해보아야겠따..

조금 더 범용적으로 설계하려면 그냥 k8s 네이티브하게 개발하는게 나을지두?
고민고민

이슈를 기술적으로 우회해서 처리하기보다는 애초에 이슈가 안생기게끔 설계부터 잘하는게 좋을것같다.

profile
22.11.28 ~

0개의 댓글