Crossplane의 아키텍처, Provider와 Managed Resource, XRD와 Composition을 활용한 인프라 추상화, GitOps 통합, Terraform과의 비교를 다룹니다.
7장까지 Kubernetes 내부의 워크로드와 노드 관리를 다루었습니다. 하지만 실제 서비스 운영에서는 Kubernetes 외부의 클라우드 인프라도 관리해야 합니다. RDS 데이터베이스, S3 버킷, VPC 네트워크, IAM 역할 등을 누가, 어떻게 프로비저닝하고 관리할 것인가의 문제입니다. 이번 장에서는 이 문제를 Kubernetes 네이티브 방식으로 해결하는 Crossplane을 다루겠습니다.
Crossplane은 Kubernetes API를 확장하여 클라우드 인프라를 선언적으로 관리하는 CNCF 프로젝트입니다. 5장에서 배운 컨트롤러 패턴과 CRD를 활용하여, Kubernetes의 kubectl apply만으로 AWS RDS, GCP Cloud SQL, Azure Database 같은 클라우드 리소스를 프로비저닝할 수 있습니다.
기존 방식:
개발자 → "DB 필요" → 인프라 팀 티켓 → Terraform 실행 → 며칠 후 제공
Crossplane 방식:
개발자 → kubectl apply database.yaml → 수 분 내 프로비저닝
Crossplane의 핵심 가치는 인프라 셀프서비스입니다. 플랫폼 팀이 안전한 추상화 계층을 제공하고, 개발팀이 직접 필요한 인프라를 프로비저닝하는 모델을 가능하게 합니다.
Provider: 클라우드 API와 통신하는 컨트롤러입니다. AWS, GCP, Azure 등 각 클라우드에 대한 Provider가 존재합니다.
Managed Resource (MR): 클라우드 리소스 하나에 대응하는 CRD입니다. 예를 들어 RDSInstance는 AWS RDS 인스턴스에 대응합니다.
Composite Resource Definition (XRD): 여러 Managed Resource를 묶어 새로운 추상화를 정의하는 스키마입니다.
Composition: XRD에 정의된 추상화를 실제 Managed Resource로 매핑하는 규칙입니다.
Claim (XRC): 개발자가 사용하는 네임스페이스 스코프의 리소스 요청입니다.
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws-rds
spec:
package: xpkg.upbound.io/upbound/provider-aws-rds:v1.14.0
runtimeConfigRef:
name: default
---
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws-s3
spec:
package: xpkg.upbound.io/upbound/provider-aws-s3:v1.14.0apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
credentials:
source: IRSA # EKS IRSA (IAM Roles for Service Accounts)Crossplane Provider에 부여되는 IAM 권한은 최소 권한 원칙을 반드시 따라야 합니다. Provider가 생성/관리할 리소스에 대한 권한만 부여하십시오. 예를 들어 RDS Provider에는 RDS 관련 권한만, S3 Provider에는 S3 관련 권한만 부여합니다.
apiVersion: rds.aws.upbound.io/v1beta2
kind: Instance
metadata:
name: production-postgres
spec:
forProvider:
region: ap-northeast-2
instanceClass: db.r6g.large
engine: postgres
engineVersion: "16.3"
allocatedStorage: 100
storageType: gp3
storageEncrypted: true
multiAz: true
dbName: appdb
masterUsername: admin
masterPasswordSecretRef:
name: rds-master-password
namespace: crossplane-system
key: password
vpcSecurityGroupIdRefs:
- name: rds-security-group
dbSubnetGroupNameRef:
name: rds-subnet-group
backupRetentionPeriod: 7
deletionProtection: true
tags:
managed-by: crossplane
environment: production
providerConfigRef:
name: default
writeConnectionSecretToRef:
name: rds-connection
namespace: production위 YAML을 kubectl apply하면 Crossplane의 AWS Provider가 실제 RDS 인스턴스를 프로비저닝하고, 접속 정보를 Kubernetes Secret으로 자동 생성합니다.
Managed Resource를 직접 사용하면 클라우드 세부사항이 노출됩니다. XRD와 Composition을 활용하면 개발자에게 단순한 인터페이스를 제공하면서, 플랫폼 팀이 내부 구현을 제어할 수 있습니다.
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.platform.example.com
spec:
group: platform.example.com
names:
kind: XDatabase
plural: xdatabases
claimNames:
kind: Database
plural: databases
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
required: [size, engine]
properties:
size:
type: string
enum: [small, medium, large]
description: "데이터베이스 크기"
engine:
type: string
enum: [postgres, mysql]
description: "데이터베이스 엔진"
version:
type: string
default: "16.3"
description: "엔진 버전"
highAvailability:
type: boolean
default: false
description: "Multi-AZ 활성화"
status:
type: object
properties:
endpoint:
type: string
port:
type: integer
status:
type: stringapiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: database-aws
labels:
provider: aws
crossplane.io/xrd: xdatabases.platform.example.com
spec:
compositeTypeRef:
apiVersion: platform.example.com/v1alpha1
kind: XDatabase
resources:
- name: rds-instance
base:
apiVersion: rds.aws.upbound.io/v1beta2
kind: Instance
spec:
forProvider:
region: ap-northeast-2
storageType: gp3
storageEncrypted: true
backupRetentionPeriod: 7
deletionProtection: true
providerConfigRef:
name: default
patches:
# size → instanceClass 매핑
- type: FromCompositeFieldPath
fromFieldPath: spec.size
toFieldPath: spec.forProvider.instanceClass
transforms:
- type: map
map:
small: db.t4g.medium
medium: db.r6g.large
large: db.r6g.xlarge
# size → allocatedStorage 매핑
- type: FromCompositeFieldPath
fromFieldPath: spec.size
toFieldPath: spec.forProvider.allocatedStorage
transforms:
- type: map
map:
small: "50"
medium: "100"
large: "500"
- type: convert
convert:
toType: int64
# engine 매핑
- type: FromCompositeFieldPath
fromFieldPath: spec.engine
toFieldPath: spec.forProvider.engine
# version 매핑
- type: FromCompositeFieldPath
fromFieldPath: spec.version
toFieldPath: spec.forProvider.engineVersion
# HA 매핑
- type: FromCompositeFieldPath
fromFieldPath: spec.highAvailability
toFieldPath: spec.forProvider.multiAz
# 상태 역전파
- type: ToCompositeFieldPath
fromFieldPath: status.atProvider.endpoint
toFieldPath: status.endpoint
connectionDetails:
- name: host
fromFieldPath: status.atProvider.endpoint
- name: port
fromFieldPath: status.atProvider.port
type: FromFieldPath
- name: username
fromFieldPath: spec.forProvider.masterUsername
type: FromFieldPath
- name: security-group
base:
apiVersion: ec2.aws.upbound.io/v1beta1
kind: SecurityGroup
spec:
forProvider:
region: ap-northeast-2
description: "Database security group managed by Crossplane"
vpcIdRef:
name: main-vpc
patches:
- type: FromCompositeFieldPath
fromFieldPath: metadata.name
toFieldPath: spec.forProvider.name
transforms:
- type: string
string:
fmt: "%s-db-sg"개발자는 복잡한 AWS 세부사항 없이 단순한 Claim만 작성합니다.
apiVersion: platform.example.com/v1alpha1
kind: Database
metadata:
name: payment-db
namespace: payment
spec:
size: medium
engine: postgres
version: "16.3"
highAvailability: true이 단순한 Claim 하나로 RDS 인스턴스, 보안 그룹, 서브넷 그룹이 자동으로 생성되고, 접속 정보가 Kubernetes Secret으로 주입됩니다. 개발자는 AWS 콘솔에 접근하지 않고도 필요한 데이터베이스를 확보할 수 있습니다.
Crossplane 리소스는 모두 Kubernetes CRD이므로 ArgoCD나 Flux로 자연스럽게 관리됩니다.
infrastructure/
crossplane/
providers/
provider-aws-rds.yaml
provider-aws-s3.yaml
provider-aws-ec2.yaml
provider-config.yaml
platform-api/
xrd-database.yaml
composition-database-aws.yaml
xrd-cache.yaml
composition-cache-aws.yaml
claims/
production/
payment-db.yaml
session-cache.yaml
staging/
payment-db.yaml
session-cache.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: crossplane-platform
namespace: argocd
spec:
project: infrastructure
source:
repoURL: https://github.com/org/infra-manifests.git
targetRevision: main
path: infrastructure/crossplane
destination:
server: https://kubernetes.default.svc
namespace: crossplane-system
syncPolicy:
automated:
prune: false # 인프라 리소스는 자동 삭제 비활성화
selfHeal: true인프라 리소스를 관리하는 ArgoCD Application에서는 prune: false를 설정하는 것을 강력히 권장합니다. Git에서 실수로 파일을 삭제했을 때 실제 클라우드 리소스(데이터베이스, 네트워크 등)가 함께 삭제되는 사고를 방지합니다.
Crossplane과 Terraform은 모두 인프라를 코드로 관리하지만, 근본적인 접근 방식이 다릅니다.
| 기준 | Crossplane | Terraform |
|---|---|---|
| 실행 모델 | 지속적 조정 (컨트롤러) | 일회성 실행 (apply) |
| 상태 관리 | Kubernetes etcd | tfstate 파일 |
| 드리프트 감지 | 자동 (실시간) | 수동 (terraform plan) |
| API | Kubernetes CRD | HCL / Provider |
| 추상화 | XRD + Composition | Module |
| 셀프서비스 | Claim으로 자연스럽게 지원 | Terraform Cloud/Atlantis 필요 |
| 생태계 | 성장 중 (AWS, GCP, Azure 주요 리소스) | 매우 성숙 (거의 모든 리소스) |
Crossplane이 적합한 경우:
Terraform이 적합한 경우:
두 도구를 배타적으로 선택할 필요는 없습니다. 네트워크, DNS 같은 기반 인프라는 Terraform으로 관리하고, 애플리케이션 수준의 인프라(데이터베이스, 캐시, 큐)는 Crossplane으로 관리하는 하이브리드 전략이 실무에서 효과적입니다.
Crossplane은 Kubernetes API를 통해 클라우드 인프라를 선언적으로 관리하는 강력한 도구입니다. XRD와 Composition을 활용한 추상화 계층은 플랫폼 엔지니어링의 핵심 패턴이며, GitOps와의 자연스러운 통합은 인프라 관리의 일관성을 크게 향상시킵니다. 5장에서 배운 컨트롤러 패턴이 인프라 관리 영역까지 확장된 것으로 이해할 수 있습니다.
다음 장에서는 Kubernetes 운영의 또 다른 중요한 축인 보안 강화와 정책 관리를 살펴보겠습니다. OPA/Gatekeeper, Kyverno, 시크릿 관리, 이미지 서명 등 프로덕션 환경에 필수적인 보안 요소를 다룹니다.
이 글이 도움이 되셨나요?
Kubernetes 리소스 requests/limits 모범 사례, VPA/HPA 전략, Goldilocks, Kubecost/OpenCost, 스팟 인스턴스, 네임스페이스 쿼터, FinOps 실천법을 다룹니다.
OPA/Gatekeeper, Kyverno, Pod Security Standards, RBAC 모범 사례, External Secrets Operator, 공급망 보안(SLSA, Sigstore), 이미지 서명을 다룹니다.
Karpenter의 아키텍처, Cluster Autoscaler와의 비교, NodePool/EC2NodeClass CRD, 통합과 중단 관리, 스팟 인스턴스 전략, GPU 노드 프로비저닝을 다룹니다.