이 페이지에서는 Kubernetes용 CI/CD GitOps 파이프라인을 계획하고 설계하는 데 도움이 되는 시작점을 제공합니다. GitOps는 구성 동기화와 같은 도구와 함께 향상된 코드 안정성, 더 나은 가독성, 자동화와 같은 이점을 제공합니다.
GitOps는 Kubernetes 구성을 대규모로 관리하기 위한 빠르게 성장하는 접근 방식입니다. CI/CD 파이프라인의 요구사항에 따라 애플리케이션 및 구성 코드를 설계하고 구성하는 방법에는 여러 가지 옵션이 있습니다. GitOps 권장사항을 숙지하면 안정적이고 잘 정리된 안전한 아키텍처를 만들 수 있습니다.
이 페이지는 환경에 GitOps를 구현하려는 관리자, 설계자, 운영자를 위해 작성되었습니다. Google Cloud 콘텐츠에서 참조하는 일반적인 역할 및 예시 태스크에 대해 자세히 알아보려면 일반 GKE Enterprise 사용자 역할 및 태스크를 참조하세요.
저장소 정리
GitOps 아키텍처를 설정할 때는 각 저장소에 저장된 구성 파일의 유형에 따라 저장소를 구분합니다. 대략적으로 4개 이상의 저장소 유형을 고려할 수 있습니다.
- 관련 구성 그룹의 패키지 저장소
- 클러스터 및 네임스페이스의 Fleet 차원 구성을 위한 플랫폼 저장소
- 애플리케이션 구성 저장소
- 애플리케이션 코드 저장소
다음은 이러한 저장소의 레이아웃을 보여주는 다이어그램입니다.
그림 2:
- 개발팀이 애플리케이션 및 애플리케이션 구성을 위한 코드를 저장소에 푸시합니다.
- 앱과 구성을 위한 코드가 같은 위치에 저장되고 애플리케이션팀이 이러한 저장소를 제어할 수 있습니다.
- 애플리케이션팀이 코드를 빌드에 푸시합니다.
중앙 집중식 비공개 패키지 저장소 사용
공개 또는 내부 패키지(예: Helm 차트)에 중앙 저장소를 사용하면 팀이 패키지를 찾는 데 도움이 됩니다. 예를 들어 저장소가 논리적으로 구성되어 있거나 readme
가 포함된 경우 중앙 집중식 비공개 패키지 저장소를 사용하면 팀에서 정보를 빠르게 찾을 수 있습니다. Artifact Registry 또는 Git 저장소와 같은 서비스를 사용하여 중앙 저장소를 구성할 수 있습니다.
예를 들어 조직의 플랫폼팀은 애플리케이션팀이 중앙 저장소에서만 패키지를 사용할 수 있는 정책을 구현할 수 있습니다.
저장소에 대한 쓰기 권한을 소수의 엔지니어로만 제한할 수 있습니다. 조직 내 다른 부서는 읽기 액세스 권한을 가질 수 있습니다. 패키지를 중앙 저장소로 승격하고 업데이트를 브로드캐스팅하는 프로세스를 구현하는 것이 좋습니다.
중앙 저장소를 관리하면 누군가 중앙 저장소를 유지보수해야 하므로 오버헤드가 추가되고 애플리케이션팀에 프로세스가 추가되지만 이 접근 방식에는 많은 이점이 있습니다.
- 중앙팀은 정의된 케이던스에 따라 공개 패키지를 추가할 수 있습니다. 이렇게 하면 연결 또는 업스트림 손실로 인한 손상을 방지할 수 있습니다.
- 자동 검토와 검토자를 함께 사용하면 패키지를 널리 제공하기 전에 패키지에 문제가 있는지 확인할 수 있습니다.
- 중앙 저장소는 팀이 사용 중인 항목과 지원되는 항목을 찾을 수 있는 방법을 제공합니다. 예를 들어 팀은 중앙 저장소에 저장된 표준 Redis 배포를 찾을 수 있습니다.
- 업스트림 패키지 변경사항을 자동화하여 기본값, 라벨 추가, 컨테이너 이미지 저장소와 같은 내부 표준을 충족할 수 있습니다.
WET 저장소 만들기
WET는 'Write Everything Twice'(모든 것을 두 번 쓰기)의 약자입니다. 'Don't Repeat Yourself'(반복 금지)의 약자인 DRY와는 대조적입니다. 이러한 접근 방식은 두 가지 유형의 구성 파일을 나타냅니다.
- DRY 구성: 단일 구성 파일이 변환 작업을 거쳐 필드에 각각 다른 환경에 다른 값을 채웁니다. 예를 들어 서로 다른 환경에 서로 다른 리전 또는 보안 설정으로 채워지는 공유 클러스터 구성을 가질 수 있습니다.
- WET(또는 '완전히 하이드레이션된') 구성: 각 구성 파일이 최종 상태를 나타냅니다.
WET 저장소는 일부 구성 파일이 반복될 수 있지만 GitOps 워크플로에는 다음과 같은 이점이 있습니다.
- 팀원들이 변경사항을 더 쉽게 검토할 수 있습니다.
- 구성 파일의 의도된 상태를 확인하는 데 별도의 처리가 필요하지 않습니다.
구성 검증 시 더 일찍 테스트
문제 확인을 위해 구성 동기화가 동기화를 시작할 때까지 기다리면 불필요한 Git 커밋과 장시간 피드백 루프가 발생할 수 있습니다. kpt
검사기 함수를 사용하면 구성을 클러스터에 적용하기 전에 많은 문제를 발견할 수 있습니다.
커밋 프로세스에 도구와 로직을 추가해야 하지만 구성을 적용하기 전에 테스트하면 다음과 같은 이점이 있습니다.
- 변경 요청 시 구성 변경사항을 표시하면 저장소에서 오류가 발생하지 않도록 방지할 수 있습니다.
- 공유 구성에 미치는 문제의 영향이 줄어듭니다.
브랜치 대신 폴더 사용
구성 파일의 변형에 브랜치 대신 폴더를 사용합니다. 폴더에서 tree
명령어를 사용하여 변형을 볼 수 있습니다. 브랜치를 사용하면 프로덕션 브랜치와 개발 브랜치 간의 델타가 예정된 구성 변경인지 아니면 prod
및 dev
환경 간의 차이가 영구적인지 알 수 없습니다.
이 접근 방식의 주요 단점은 폴더를 사용하면 동일한 파일에 대한 변경 요청을 사용하여 구성 변경사항을 승격할 수 없다는 것입니다. 하지만 브랜치 대신 폴더를 사용하면 다음과 같은 이점이 있습니다.
- 폴더 탐색이 브랜치 탐색보다 더 쉽습니다.
- Git 제공업체 외부에서 브랜치 diff를 수행하는 것은 일반적이지 않지만, 많은 CLI 및 GUI 도구로 폴더에 대한 diff를 수행할 수 있습니다.
- 폴더에서는 영구적인 차이와 승격되지 않은 차이를 쉽게 구분할 수 있습니다.
- 하나의 변경 요청으로 여러 클러스터 및 네임스페이스에 변경사항을 배포할 수 있지만 브랜치의 경우 브랜치별로 서로 다른 변경 요청이 필요합니다.
ClusterSelectors
사용 최소화
ClusterSelectors
를 사용하면 구성의 특정 부분을 클러스터의 하위 집합에 적용할 수 있습니다. RootSync
또는 RepoSync
객체를 구성하는 대신 적용 중인 리소스를 수정하거나 클러스터에 라벨을 추가할 수 있습니다. 이는 클러스터에 특성을 추가하는 경량화된 방법이지만 시간이 지남에 따라 ClusterSelectors
의 수가 증가하면 클러스터의 최종 상태를 이해하기가 복잡해질 수 있습니다.
구성 동기화를 사용하면 여러 개의 RootSync
및 RepoSync
객체를 한 번에 동기화할 수 있으므로 관련 구성을 별도의 저장소에 추가한 후 원하는 클러스터에 동기화할 수 있습니다. 이렇게 하면 클러스터의 최종 상태를 더 쉽게 파악할 수 있으며 클러스터에 이러한 구성 결정을 직접 적용하는 대신 클러스터의 구성을 폴더로 조합할 수 있습니다.
구성 동기화로 작업 관리 방지
대부분의 경우 작업 및 기타 상황별 태스크는 수명 주기 관리를 처리하는 서비스에서 관리해야 합니다. 그러면 작업 자체 대신 구성 동기화로 해당 서비스를 관리할 수 있습니다.
구성 동기화가 작업을 자동으로 적용할 수 있지만 다음과 같은 이유로 작업이 GitOps 배포에 적합하지 않습니다.
변경할 수 없는 필드: 많은 작업 필드는 변경할 수 없습니다. 변경 불가능한 필드를 변경하려면 객체를 삭제하고 다시 만들어야 합니다. 하지만 소스에서 객체를 삭제하지 않는 한 구성 동기화는 객체를 삭제하지 않습니다.
의도하지 않은 작업 실행: 구성 동기화로 작업을 동기화한 후 해당 작업이 클러스터에서 삭제되면 구성 동기화는 선택한 상태에서 드리프트를 고려하여 작업을 다시 만듭니다. 작업 TTL(수명)을 지정하면 구성 동기화는 사용자가 정보 소스에서 작업을 삭제할 때까지 작업을 자동으로 삭제하고 자동으로 다시 만들고 다시 시작합니다.
조정 문제: 구성 동기화는 일반적으로 객체가 적용된 후 조정될 때까지 기다립니다. 하지만 작업은 실행이 시작되면 조정된 것으로 간주됩니다. 즉, 구성 동기화는 작업이 완료될 때까지 기다리지 않고 다른 객체를 계속 적용합니다. 그러나 나중에 작업이 실패하면 조정 실패로 간주됩니다. 경우에 따라 이로 인해 다른 리소스가 동기화되지 않으며 해결될 때까지 오류가 발생할 수 있습니다. 일부 경우에는 동기화가 성공하고 조정만 실패할 수 있습니다.
이러한 이유로 구성 동기화로 작업을 동기화하지 않는 것이 좋습니다.
구조화되지 않은 저장소 사용
구성 동기화는 저장소 구성을 위해 구조화되지 않은 형식과 계층 구조 형식의 두 가지 구조를 지원합니다.
구조화되지 않은 형식을 사용하면 가장 편리한 방식으로 저장소를 구성할 수 있으므로 권장됩니다.
반면에 계층적 저장소는 cluster
디렉터리에 커스텀 리소스 정의(CRD)와 같은 특정 구조를 적용합니다.
이로 인해 구성을 공유해야 할 때 문제가 발생할 수 있습니다. 예를 들어 한 팀에서 CRD가 포함된 패키지를 게시하면 해당 패키지를 사용해야 하는 다른 팀은 CRD를 cluster
디렉터리로 이동해야 하므로 프로세스에 더 많은 오버헤드가 추가됩니다.
구조화되지 않은 저장소를 사용하면 구성 패키지를 훨씬 더 쉽게 공유하고 재사용할 수 있습니다. 하지만 저장소를 구성하기 위한 정의된 프로세스나 가이드라인이 없으면 저장소 구조가 팀마다 다를 수 있으므로 Fleet 차원의 도구를 구현하기가 더 어려워질 수 있습니다.
계층적 저장소를 변환하는 방법은 계층적 저장소를 구조화되지 않은 저장소로 변환을 참조하세요.
별도의 코드 및 구성 저장소
모노 저장소를 확장할 때는 각 폴더별 빌드가 필요합니다. 코드 작업자와 클러스터 구성 작업자의 권한과 우려사항은 일반적으로 다릅니다.
코드 저장소 및 구성 저장소를 분리하면 다음과 같은 이점이 있습니다.
- 커밋이 '루프'에 빠지는 것을 방지합니다. 예를 들어 코드 저장소에 커밋할 경우 CI 요청을 트리거하여 이미지를 생성한 후에 코드 커밋이 필요할 수 있습니다.
- 필요한 커밋 수가 많으면 참여하는 팀원에게 부담이 될 수 있습니다.
- 애플리케이션 코드 및 클러스터 구성 작업자에 대해 서로 다른 권한을 사용할 수 있습니다.
코드 저장소와 구성 저장소를 분리하면 다음과 같은 단점이 있습니다.
- 애플리케이션 코드와 동일한 저장소에 있지 않으므로 애플리케이션 구성 검색이 줄어듭니다.
- 많은 저장소를 관리하려면 시간이 오래 걸릴 수 있습니다.
별도의 저장소를 사용하여 변경사항 보호
모노 저장소를 확장할 때는 폴더마다 다른 권한이 필요합니다. 이로 인해 저장소를 분리하면 보안, 플랫폼, 애플리케이션 구성 간에 보안 경계를 허용할 수 있습니다. 또한 프로덕션 저장소와 비프로덕션 저장소를 구분하는 것이 좋습니다.
여러 저장소를 관리하는 것은 그 자체로 큰 작업일 수 있지만, 여러 저장소에서 서로 다른 유형의 구성을 격리하면 다음과 같은 이점이 있습니다.
- 플랫폼, 보안, 애플리케이션팀이 있는 조직에서 변경 및 권한 주기는 서로 다릅니다.
- 권한은 저장소 수준으로 유지됩니다.
CODEOWNERS
파일을 사용하면 조직에서 쓰기 권한을 제한하면서 읽기 권한은 계속 허용할 수 있습니다. - 구성 동기화는 네임스페이스당 여러 동기화를 지원하므로 여러 저장소에서 파일을 가져오는 것과 유사한 효과를 얻을 수 있습니다.
패키지 버전 고정
Helm 또는 Git의 사용 여부에 관계없이 명시적 출시 없이 실수로 이동하지 않은 버전으로 구성 패키지 버전을 고정해야 합니다.
이렇게 하면 공유 구성이 업데이트될 때 출시에 추가 검사가 추가되지만 공유 업데이트가 의도한 것보다 더 큰 영향을 미칠 위험이 줄어듭니다.
GKE용 워크로드 아이덴티티 제휴 사용
GKE 클러스터에서 GKE용 워크로드 아이덴티티 제휴를 사용 설정하면 Kubernetes 워크로드가 안전하고 관리 가능한 방식으로 Google 서비스에 액세스할 수 있습니다.
GitHub 및 GitLab과 같은 일부 Google Cloud 외부 서비스는 GKE용 워크로드 아이덴티티 제휴를 지원하지 않지만, 보안이 강화되고 보안 비밀 및 비밀번호 관리의 복잡성이 줄어들므로 가능하면 항상 GKE용 워크로드 아이덴티티 제휴를 사용해야 합니다.