Kubernetes Crossplane 基礎架構編排

Kubernetes Crossplane Infrastructure Orchestration

前言

在現代雲端原生架構中,基礎架構即程式碼(Infrastructure as Code, IaC)已成為不可或缺的實踐。Crossplane 作為 CNCF 的孵化專案,提供了一種創新的方式來管理雲端基礎架構 — 透過 Kubernetes API 來編排和管理外部資源。本文將深入探討 Crossplane 的核心概念、安裝配置,以及如何利用它實現多雲資源管理。


1. Crossplane 概述與架構

什麼是 Crossplane?

Crossplane 是一個開源的 Kubernetes 擴展,它將 Kubernetes 轉變為一個通用的控制平面,用於管理雲端基礎架構和服務。透過 Crossplane,你可以使用 Kubernetes 的聲明式 API 來建立、配置和管理來自不同雲端供應商的資源。

核心概念

Crossplane 的架構由以下幾個核心元件組成:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
┌─────────────────────────────────────────────────────────────┐
│                    Kubernetes Cluster                        │
│  ┌─────────────────────────────────────────────────────────┐│
│  │                   Crossplane Core                        ││
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐  ││
│  │  │   Providers  │  │ Compositions │  │    Claims    │  ││
│  │  └──────────────┘  └──────────────┘  └──────────────┘  ││
│  └─────────────────────────────────────────────────────────┘│
│                              │                               │
│                              ▼                               │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │
│  │     AWS     │  │    Azure    │  │     GCP     │         │
│  │  Provider   │  │  Provider   │  │  Provider   │         │
│  └─────────────┘  └─────────────┘  └─────────────┘         │
└─────────────────────────────────────────────────────────────┘
              │               │               │
              ▼               ▼               ▼
         ┌─────────┐    ┌─────────┐    ┌─────────┐
         │   AWS   │    │  Azure  │    │   GCP   │
         │  Cloud  │    │  Cloud  │    │  Cloud  │
         └─────────┘    └─────────┘    └─────────┘

主要元件說明

元件說明
Providers負責與特定雲端服務互動的外掛程式
Managed Resources代表雲端中實際資源的 Kubernetes 物件
Composite Resources (XR)由多個 Managed Resources 組成的自訂資源
Compositions定義如何將 Composite Resources 映射到 Managed Resources
Claims (XRC)供應用程式團隊使用的抽象化介面

為什麼選擇 Crossplane?

  1. 統一的控制平面:使用熟悉的 Kubernetes API 管理所有基礎架構
  2. 聲明式管理:透過 YAML 定義期望狀態,Crossplane 自動調和
  3. GitOps 友善:完美整合 ArgoCD、Flux 等 GitOps 工具
  4. 多雲支援:單一介面管理 AWS、Azure、GCP 等多個雲端
  5. 自助式服務:透過抽象層讓開發團隊自主建立基礎架構

2. 安裝與 Provider 設定

前置需求

  • Kubernetes 叢集(v1.16+)
  • kubectl 已配置
  • Helm v3(可選,用於安裝)

使用 Helm 安裝 Crossplane

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 新增 Crossplane Helm 儲存庫
helm repo add crossplane-stable https://charts.crossplane.io/stable
helm repo update

# 建立命名空間
kubectl create namespace crossplane-system

# 安裝 Crossplane
helm install crossplane \
  --namespace crossplane-system \
  crossplane-stable/crossplane \
  --version 1.14.0

# 驗證安裝
kubectl get pods -n crossplane-system

預期輸出:

1
2
3
NAME                                       READY   STATUS    RESTARTS   AGE
crossplane-7c88c45998-xxxxx               1/1     Running   0          1m
crossplane-rbac-manager-8466dfb7c7-xxxxx  1/1     Running   0          1m

安裝 Crossplane CLI

1
2
3
4
5
6
7
8
# 安裝 crossplane CLI
curl -sL "https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh" | sh

# 移動到 PATH
sudo mv crossplane /usr/local/bin/

# 驗證安裝
crossplane --version

安裝 AWS Provider

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# provider-aws.yaml
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
  name: provider-aws
spec:
  package: xpkg.upbound.io/upbound/provider-aws-ec2:v1.1.0
  controllerConfigRef:
    name: aws-config
---
apiVersion: pkg.crossplane.io/v1alpha1
kind: ControllerConfig
metadata:
  name: aws-config
spec:
  resources:
    limits:
      memory: 512Mi
    requests:
      cpu: 100m
      memory: 256Mi
1
2
3
4
5
6
7
8
# 套用 Provider
kubectl apply -f provider-aws.yaml

# 等待 Provider 就緒
kubectl wait --for=condition=healthy provider.pkg.crossplane.io/provider-aws --timeout=300s

# 檢查 Provider 狀態
kubectl get providers

配置 AWS 憑證

1
2
3
4
# 建立 AWS 憑證 Secret
kubectl create secret generic aws-creds \
  -n crossplane-system \
  --from-file=credentials=./aws-credentials.txt

aws-credentials.txt 檔案格式:

1
2
3
[default]
aws_access_key_id = YOUR_ACCESS_KEY_ID
aws_secret_access_key = YOUR_SECRET_ACCESS_KEY

建立 ProviderConfig

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# provider-config.yaml
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
  name: default
spec:
  credentials:
    source: Secret
    secretRef:
      namespace: crossplane-system
      name: aws-creds
      key: credentials
1
kubectl apply -f provider-config.yaml

安裝其他 Providers

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# providers.yaml
---
# Azure Provider
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
  name: provider-azure
spec:
  package: xpkg.upbound.io/upbound/provider-azure-network:v0.42.0
---
# GCP Provider
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
  name: provider-gcp
spec:
  package: xpkg.upbound.io/upbound/provider-gcp-compute:v0.41.0

3. Managed Resources 使用

Managed Resources 是 Crossplane 中最基本的資源類型,直接對應到雲端服務中的具體資源。

建立 AWS VPC

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# vpc.yaml
apiVersion: ec2.aws.upbound.io/v1beta1
kind: VPC
metadata:
  name: my-crossplane-vpc
spec:
  forProvider:
    region: ap-northeast-1
    cidrBlock: 10.0.0.0/16
    enableDnsHostnames: true
    enableDnsSupport: true
    tags:
      Name: my-crossplane-vpc
      Environment: production
      ManagedBy: crossplane
  providerConfigRef:
    name: default
1
2
3
4
5
6
# 套用 VPC 配置
kubectl apply -f vpc.yaml

# 檢查資源狀態
kubectl get vpc
kubectl describe vpc my-crossplane-vpc

建立 Subnet

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# subnet.yaml
apiVersion: ec2.aws.upbound.io/v1beta1
kind: Subnet
metadata:
  name: my-public-subnet-1a
spec:
  forProvider:
    region: ap-northeast-1
    availabilityZone: ap-northeast-1a
    vpcIdRef:
      name: my-crossplane-vpc
    cidrBlock: 10.0.1.0/24
    mapPublicIpOnLaunch: true
    tags:
      Name: my-public-subnet-1a
      Type: public
  providerConfigRef:
    name: default
---
apiVersion: ec2.aws.upbound.io/v1beta1
kind: Subnet
metadata:
  name: my-private-subnet-1a
spec:
  forProvider:
    region: ap-northeast-1
    availabilityZone: ap-northeast-1a
    vpcIdRef:
      name: my-crossplane-vpc
    cidrBlock: 10.0.10.0/24
    mapPublicIpOnLaunch: false
    tags:
      Name: my-private-subnet-1a
      Type: private
  providerConfigRef:
    name: default

建立 RDS 資料庫

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# rds.yaml
apiVersion: rds.aws.upbound.io/v1beta1
kind: Instance
metadata:
  name: my-postgres-db
spec:
  forProvider:
    region: ap-northeast-1
    allocatedStorage: 20
    engine: postgres
    engineVersion: "15.4"
    instanceClass: db.t3.micro
    dbName: myappdb
    username: admin
    passwordSecretRef:
      name: db-password
      namespace: crossplane-system
      key: password
    skipFinalSnapshot: true
    publiclyAccessible: false
    vpcSecurityGroupIdRefs:
      - name: db-security-group
    dbSubnetGroupNameRef:
      name: my-db-subnet-group
    tags:
      Environment: production
  providerConfigRef:
    name: default
  writeConnectionSecretToRef:
    name: db-connection-secret
    namespace: default

資源狀態監控

1
2
3
4
5
6
7
8
9
# 列出所有 Managed Resources
kubectl get managed

# 檢查特定資源的詳細狀態
kubectl get vpc -o wide
kubectl describe vpc my-crossplane-vpc

# 查看事件
kubectl get events --field-selector involvedObject.name=my-crossplane-vpc

資源刪除

1
2
3
4
5
# 刪除單一資源
kubectl delete vpc my-crossplane-vpc

# 刪除所有特定類型的資源
kubectl delete vpc --all

4. Composite Resources(XR)

Composite Resources(XR)允許你將多個 Managed Resources 組合成一個更高階的自訂資源,實現基礎架構的模組化和重用。

定義 CompositeResourceDefinition(XRD)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# xrd-network.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
  name: xnetworks.infrastructure.example.com
spec:
  group: infrastructure.example.com
  names:
    kind: XNetwork
    plural: xnetworks
  claimNames:
    kind: Network
    plural: networks
  versions:
    - name: v1alpha1
      served: true
      referenceable: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                region:
                  type: string
                  description: "AWS Region"
                  default: "ap-northeast-1"
                vpcCidr:
                  type: string
                  description: "VPC CIDR block"
                  default: "10.0.0.0/16"
                publicSubnetCidrs:
                  type: array
                  items:
                    type: string
                  description: "Public subnet CIDR blocks"
                privateSubnetCidrs:
                  type: array
                  items:
                    type: string
                  description: "Private subnet CIDR blocks"
                environment:
                  type: string
                  enum:
                    - development
                    - staging
                    - production
                  default: "development"
              required:
                - region
            status:
              type: object
              properties:
                vpcId:
                  type: string
                subnetIds:
                  type: array
                  items:
                    type: string

建立 XR 實例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# network-xr.yaml
apiVersion: infrastructure.example.com/v1alpha1
kind: XNetwork
metadata:
  name: production-network
spec:
  region: ap-northeast-1
  vpcCidr: "10.0.0.0/16"
  publicSubnetCidrs:
    - "10.0.1.0/24"
    - "10.0.2.0/24"
  privateSubnetCidrs:
    - "10.0.10.0/24"
    - "10.0.11.0/24"
  environment: production

資料庫 XRD 範例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# xrd-database.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
  name: xdatabases.infrastructure.example.com
spec:
  group: infrastructure.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
              properties:
                engine:
                  type: string
                  enum:
                    - postgres
                    - mysql
                  default: postgres
                size:
                  type: string
                  enum:
                    - small
                    - medium
                    - large
                  default: small
                version:
                  type: string
                  default: "15.4"
                region:
                  type: string
                  default: "ap-northeast-1"
              required:
                - engine
                - size
            status:
              type: object
              properties:
                endpoint:
                  type: string
                port:
                  type: integer
  connectionSecretKeys:
    - username
    - password
    - endpoint
    - port

5. Compositions 定義

Composition 定義了如何將 Composite Resource 的規格映射到具體的 Managed Resources。

網路 Composition

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# composition-network.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
  name: network-aws
  labels:
    provider: aws
    infrastructure: network
spec:
  compositeTypeRef:
    apiVersion: infrastructure.example.com/v1alpha1
    kind: XNetwork
  patchSets:
    - name: common-parameters
      patches:
        - type: FromCompositeFieldPath
          fromFieldPath: spec.region
          toFieldPath: spec.forProvider.region
        - type: FromCompositeFieldPath
          fromFieldPath: spec.environment
          toFieldPath: spec.forProvider.tags.Environment
  resources:
    # VPC
    - name: vpc
      base:
        apiVersion: ec2.aws.upbound.io/v1beta1
        kind: VPC
        spec:
          forProvider:
            enableDnsHostnames: true
            enableDnsSupport: true
            tags:
              ManagedBy: crossplane
      patches:
        - type: PatchSet
          patchSetName: common-parameters
        - type: FromCompositeFieldPath
          fromFieldPath: spec.vpcCidr
          toFieldPath: spec.forProvider.cidrBlock
        - type: ToCompositeFieldPath
          fromFieldPath: status.atProvider.id
          toFieldPath: status.vpcId

    # Internet Gateway
    - name: internet-gateway
      base:
        apiVersion: ec2.aws.upbound.io/v1beta1
        kind: InternetGateway
        spec:
          forProvider:
            vpcIdSelector:
              matchControllerRef: true
            tags:
              Name: main-igw
      patches:
        - type: PatchSet
          patchSetName: common-parameters

    # Public Subnets
    - name: public-subnet-1
      base:
        apiVersion: ec2.aws.upbound.io/v1beta1
        kind: Subnet
        metadata:
          labels:
            type: public
            zone: a
        spec:
          forProvider:
            vpcIdSelector:
              matchControllerRef: true
            mapPublicIpOnLaunch: true
            availabilityZone: ap-northeast-1a
            tags:
              Type: public
      patches:
        - type: PatchSet
          patchSetName: common-parameters
        - type: FromCompositeFieldPath
          fromFieldPath: spec.publicSubnetCidrs[0]
          toFieldPath: spec.forProvider.cidrBlock

    - name: public-subnet-2
      base:
        apiVersion: ec2.aws.upbound.io/v1beta1
        kind: Subnet
        metadata:
          labels:
            type: public
            zone: c
        spec:
          forProvider:
            vpcIdSelector:
              matchControllerRef: true
            mapPublicIpOnLaunch: true
            availabilityZone: ap-northeast-1c
            tags:
              Type: public
      patches:
        - type: PatchSet
          patchSetName: common-parameters
        - type: FromCompositeFieldPath
          fromFieldPath: spec.publicSubnetCidrs[1]
          toFieldPath: spec.forProvider.cidrBlock

    # Private Subnets
    - name: private-subnet-1
      base:
        apiVersion: ec2.aws.upbound.io/v1beta1
        kind: Subnet
        metadata:
          labels:
            type: private
            zone: a
        spec:
          forProvider:
            vpcIdSelector:
              matchControllerRef: true
            mapPublicIpOnLaunch: false
            availabilityZone: ap-northeast-1a
            tags:
              Type: private
      patches:
        - type: PatchSet
          patchSetName: common-parameters
        - type: FromCompositeFieldPath
          fromFieldPath: spec.privateSubnetCidrs[0]
          toFieldPath: spec.forProvider.cidrBlock

    - name: private-subnet-2
      base:
        apiVersion: ec2.aws.upbound.io/v1beta1
        kind: Subnet
        metadata:
          labels:
            type: private
            zone: c
        spec:
          forProvider:
            vpcIdSelector:
              matchControllerRef: true
            mapPublicIpOnLaunch: false
            availabilityZone: ap-northeast-1c
            tags:
              Type: private
      patches:
        - type: PatchSet
          patchSetName: common-parameters
        - type: FromCompositeFieldPath
          fromFieldPath: spec.privateSubnetCidrs[1]
          toFieldPath: spec.forProvider.cidrBlock

    # Route Table for Public Subnets
    - name: public-route-table
      base:
        apiVersion: ec2.aws.upbound.io/v1beta1
        kind: RouteTable
        spec:
          forProvider:
            vpcIdSelector:
              matchControllerRef: true
            tags:
              Name: public-rt
      patches:
        - type: PatchSet
          patchSetName: common-parameters

    # Route to Internet Gateway
    - name: public-route
      base:
        apiVersion: ec2.aws.upbound.io/v1beta1
        kind: Route
        spec:
          forProvider:
            routeTableIdSelector:
              matchControllerRef: true
              matchLabels:
                crossplane.io/composite: ""
            destinationCidrBlock: "0.0.0.0/0"
            gatewayIdSelector:
              matchControllerRef: true
      patches:
        - type: PatchSet
          patchSetName: common-parameters

資料庫 Composition

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# composition-database.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
  name: database-postgres-aws
  labels:
    provider: aws
    engine: postgres
spec:
  compositeTypeRef:
    apiVersion: infrastructure.example.com/v1alpha1
    kind: XDatabase
  patchSets:
    - name: common-parameters
      patches:
        - type: FromCompositeFieldPath
          fromFieldPath: spec.region
          toFieldPath: spec.forProvider.region
  resources:
    # DB Subnet Group
    - name: db-subnet-group
      base:
        apiVersion: rds.aws.upbound.io/v1beta1
        kind: SubnetGroup
        spec:
          forProvider:
            description: "Crossplane managed DB subnet group"
            subnetIdSelector:
              matchLabels:
                type: private
            tags:
              ManagedBy: crossplane
      patches:
        - type: PatchSet
          patchSetName: common-parameters

    # Security Group for DB
    - name: db-security-group
      base:
        apiVersion: ec2.aws.upbound.io/v1beta1
        kind: SecurityGroup
        spec:
          forProvider:
            description: "Security group for RDS database"
            vpcIdSelector:
              matchControllerRef: true
            tags:
              Name: db-security-group
      patches:
        - type: PatchSet
          patchSetName: common-parameters

    # Security Group Rule
    - name: db-sg-rule
      base:
        apiVersion: ec2.aws.upbound.io/v1beta1
        kind: SecurityGroupRule
        spec:
          forProvider:
            type: ingress
            fromPort: 5432
            toPort: 5432
            protocol: tcp
            cidrBlocks:
              - "10.0.0.0/16"
            securityGroupIdSelector:
              matchControllerRef: true
      patches:
        - type: PatchSet
          patchSetName: common-parameters

    # RDS Instance
    - name: rds-instance
      base:
        apiVersion: rds.aws.upbound.io/v1beta1
        kind: Instance
        spec:
          forProvider:
            engine: postgres
            publiclyAccessible: false
            skipFinalSnapshot: true
            storageType: gp3
            autoMinorVersionUpgrade: true
            tags:
              ManagedBy: crossplane
          writeConnectionSecretToRef:
            namespace: crossplane-system
      patches:
        - type: PatchSet
          patchSetName: common-parameters
        - type: FromCompositeFieldPath
          fromFieldPath: spec.version
          toFieldPath: spec.forProvider.engineVersion
        - type: FromCompositeFieldPath
          fromFieldPath: spec.size
          toFieldPath: spec.forProvider.instanceClass
          transforms:
            - type: map
              map:
                small: db.t3.micro
                medium: db.t3.small
                large: db.t3.medium
        - type: FromCompositeFieldPath
          fromFieldPath: spec.size
          toFieldPath: spec.forProvider.allocatedStorage
          transforms:
            - type: map
              map:
                small: 20
                medium: 50
                large: 100
        - type: ToCompositeFieldPath
          fromFieldPath: status.atProvider.endpoint
          toFieldPath: status.endpoint
        - type: ToCompositeFieldPath
          fromFieldPath: status.atProvider.port
          toFieldPath: status.port
        - type: CombineFromComposite
          combine:
            variables:
              - fromFieldPath: metadata.name
            strategy: string
            string:
              fmt: "%s-db-secret"
          toFieldPath: spec.writeConnectionSecretToRef.name

Composition Functions(進階)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# composition-with-functions.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
  name: advanced-network
spec:
  compositeTypeRef:
    apiVersion: infrastructure.example.com/v1alpha1
    kind: XNetwork
  mode: Pipeline
  pipeline:
    - step: patch-and-transform
      functionRef:
        name: function-patch-and-transform
      input:
        apiVersion: pt.fn.crossplane.io/v1beta1
        kind: Resources
        resources:
          - name: vpc
            base:
              apiVersion: ec2.aws.upbound.io/v1beta1
              kind: VPC
              spec:
                forProvider:
                  enableDnsHostnames: true
                  enableDnsSupport: true
            patches:
              - type: FromCompositeFieldPath
                fromFieldPath: spec.vpcCidr
                toFieldPath: spec.forProvider.cidrBlock
    - step: auto-ready
      functionRef:
        name: function-auto-ready

6. Claims 與抽象化

Claims(XRC)提供了一個命名空間級別的介面,讓應用程式團隊可以在不了解底層實作細節的情況下請求基礎架構資源。

使用 Network Claim

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# network-claim.yaml
apiVersion: infrastructure.example.com/v1alpha1
kind: Network
metadata:
  name: my-app-network
  namespace: development
spec:
  region: ap-northeast-1
  vpcCidr: "10.1.0.0/16"
  publicSubnetCidrs:
    - "10.1.1.0/24"
    - "10.1.2.0/24"
  privateSubnetCidrs:
    - "10.1.10.0/24"
    - "10.1.11.0/24"
  environment: development
  compositionSelector:
    matchLabels:
      provider: aws

使用 Database Claim

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# database-claim.yaml
apiVersion: infrastructure.example.com/v1alpha1
kind: Database
metadata:
  name: my-app-database
  namespace: development
spec:
  engine: postgres
  size: small
  version: "15.4"
  region: ap-northeast-1
  compositionSelector:
    matchLabels:
      provider: aws
      engine: postgres
  writeConnectionSecretToRef:
    name: my-app-db-credentials

Claim 與應用程式整合

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# deployment-with-db.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-application
  namespace: development
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-application
  template:
    metadata:
      labels:
        app: my-application
    spec:
      containers:
        - name: app
          image: my-app:latest
          env:
            - name: DATABASE_HOST
              valueFrom:
                secretKeyRef:
                  name: my-app-db-credentials
                  key: endpoint
            - name: DATABASE_PORT
              valueFrom:
                secretKeyRef:
                  name: my-app-db-credentials
                  key: port
            - name: DATABASE_USER
              valueFrom:
                secretKeyRef:
                  name: my-app-db-credentials
                  key: username
            - name: DATABASE_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: my-app-db-credentials
                  key: password

管理 Claims

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 列出所有 Claims
kubectl get networks -A
kubectl get databases -A

# 檢查 Claim 狀態
kubectl describe network my-app-network -n development

# 查看關聯的 Composite Resource
kubectl get xnetwork -l crossplane.io/claim-name=my-app-network

# 刪除 Claim(會自動清除相關資源)
kubectl delete network my-app-network -n development

7. 多雲資源管理

Crossplane 的一大優勢是能夠透過統一的 API 管理多個雲端供應商的資源。

多雲 ProviderConfig 設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# multi-cloud-providers.yaml
---
# AWS Provider Config
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
  name: aws-production
spec:
  credentials:
    source: Secret
    secretRef:
      namespace: crossplane-system
      name: aws-production-creds
      key: credentials
---
# Azure Provider Config
apiVersion: azure.upbound.io/v1beta1
kind: ProviderConfig
metadata:
  name: azure-production
spec:
  credentials:
    source: Secret
    secretRef:
      namespace: crossplane-system
      name: azure-production-creds
      key: credentials
---
# GCP Provider Config
apiVersion: gcp.upbound.io/v1beta1
kind: ProviderConfig
metadata:
  name: gcp-production
spec:
  credentials:
    source: Secret
    secretRef:
      namespace: crossplane-system
      name: gcp-production-creds
      key: credentials
  projectID: my-gcp-project

多雲 Composition

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# composition-multicloud-storage.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
  name: xstorages.infrastructure.example.com
spec:
  group: infrastructure.example.com
  names:
    kind: XStorage
    plural: xstorages
  claimNames:
    kind: Storage
    plural: storages
  versions:
    - name: v1alpha1
      served: true
      referenceable: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                provider:
                  type: string
                  enum:
                    - aws
                    - azure
                    - gcp
                name:
                  type: string
                region:
                  type: string
              required:
                - provider
                - name
---
# AWS S3 Composition
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
  name: storage-aws-s3
  labels:
    provider: aws
spec:
  compositeTypeRef:
    apiVersion: infrastructure.example.com/v1alpha1
    kind: XStorage
  resources:
    - name: s3-bucket
      base:
        apiVersion: s3.aws.upbound.io/v1beta1
        kind: Bucket
        spec:
          forProvider:
            tags:
              ManagedBy: crossplane
      patches:
        - type: FromCompositeFieldPath
          fromFieldPath: spec.region
          toFieldPath: spec.forProvider.region
        - type: FromCompositeFieldPath
          fromFieldPath: spec.name
          toFieldPath: metadata.annotations[crossplane.io/external-name]
---
# Azure Blob Composition
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
  name: storage-azure-blob
  labels:
    provider: azure
spec:
  compositeTypeRef:
    apiVersion: infrastructure.example.com/v1alpha1
    kind: XStorage
  resources:
    - name: storage-account
      base:
        apiVersion: storage.azure.upbound.io/v1beta1
        kind: Account
        spec:
          forProvider:
            accountTier: Standard
            accountReplicationType: LRS
            tags:
              ManagedBy: crossplane
      patches:
        - type: FromCompositeFieldPath
          fromFieldPath: spec.region
          toFieldPath: spec.forProvider.location
    - name: blob-container
      base:
        apiVersion: storage.azure.upbound.io/v1beta1
        kind: Container
        spec:
          forProvider:
            containerAccessType: private
            storageAccountNameSelector:
              matchControllerRef: true
---
# GCP Storage Composition
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
  name: storage-gcp-gcs
  labels:
    provider: gcp
spec:
  compositeTypeRef:
    apiVersion: infrastructure.example.com/v1alpha1
    kind: XStorage
  resources:
    - name: gcs-bucket
      base:
        apiVersion: storage.gcp.upbound.io/v1beta1
        kind: Bucket
        spec:
          forProvider:
            storageClass: STANDARD
            labels:
              managed-by: crossplane
      patches:
        - type: FromCompositeFieldPath
          fromFieldPath: spec.region
          toFieldPath: spec.forProvider.location
        - type: FromCompositeFieldPath
          fromFieldPath: spec.name
          toFieldPath: metadata.annotations[crossplane.io/external-name]

使用多雲儲存

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# storage-claims.yaml
---
# AWS S3
apiVersion: infrastructure.example.com/v1alpha1
kind: Storage
metadata:
  name: logs-aws
  namespace: production
spec:
  provider: aws
  name: my-company-logs-aws
  region: ap-northeast-1
  compositionSelector:
    matchLabels:
      provider: aws
---
# Azure Blob
apiVersion: infrastructure.example.com/v1alpha1
kind: Storage
metadata:
  name: backups-azure
  namespace: production
spec:
  provider: azure
  name: mycompanybackups
  region: japaneast
  compositionSelector:
    matchLabels:
      provider: azure
---
# GCP GCS
apiVersion: infrastructure.example.com/v1alpha1
kind: Storage
metadata:
  name: analytics-gcp
  namespace: production
spec:
  provider: gcp
  name: my-company-analytics-gcp
  region: asia-northeast1
  compositionSelector:
    matchLabels:
      provider: gcp

8. 與 ArgoCD/Flux 整合

Crossplane 與 GitOps 工具的整合讓基礎架構管理更加自動化和可追蹤。

ArgoCD 整合

安裝 ArgoCD

1
2
3
4
5
6
7
8
# 建立命名空間
kubectl create namespace argocd

# 安裝 ArgoCD
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

# 等待 ArgoCD 就緒
kubectl wait --for=condition=available deployment/argocd-server -n argocd --timeout=300s

ArgoCD Application 設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# argocd-crossplane-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: crossplane-infrastructure
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/your-org/infrastructure-repo.git
    targetRevision: main
    path: crossplane/
    directory:
      recurse: true
  destination:
    server: https://kubernetes.default.svc
    namespace: crossplane-system
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
      - PrunePropagationPolicy=foreground
    retry:
      limit: 5
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m

ArgoCD ApplicationSet(多環境)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# argocd-applicationset.yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: crossplane-environments
  namespace: argocd
spec:
  generators:
    - list:
        elements:
          - env: development
            cluster: dev-cluster
            region: ap-northeast-1
          - env: staging
            cluster: staging-cluster
            region: ap-northeast-1
          - env: production
            cluster: prod-cluster
            region: ap-northeast-1
  template:
    metadata:
      name: 'infra-{{env}}'
    spec:
      project: default
      source:
        repoURL: https://github.com/your-org/infrastructure-repo.git
        targetRevision: main
        path: 'environments/{{env}}'
      destination:
        server: '{{cluster}}'
        namespace: crossplane-system
      syncPolicy:
        automated:
          prune: true
          selfHeal: true

Flux 整合

安裝 Flux

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 安裝 Flux CLI
curl -s https://fluxcd.io/install.sh | sudo bash

# 初始化 Flux
flux bootstrap github \
  --owner=your-org \
  --repository=flux-infrastructure \
  --branch=main \
  --path=clusters/production \
  --personal

Flux Kustomization 設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# flux-crossplane-sync.yaml
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
  name: infrastructure
  namespace: flux-system
spec:
  interval: 1m
  url: https://github.com/your-org/infrastructure-repo.git
  ref:
    branch: main
  secretRef:
    name: github-credentials
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: crossplane-providers
  namespace: flux-system
spec:
  interval: 10m
  sourceRef:
    kind: GitRepository
    name: infrastructure
  path: ./crossplane/providers
  prune: true
  healthChecks:
    - apiVersion: pkg.crossplane.io/v1
      kind: Provider
      name: provider-aws
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: crossplane-compositions
  namespace: flux-system
spec:
  interval: 10m
  dependsOn:
    - name: crossplane-providers
  sourceRef:
    kind: GitRepository
    name: infrastructure
  path: ./crossplane/compositions
  prune: true
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: crossplane-claims
  namespace: flux-system
spec:
  interval: 5m
  dependsOn:
    - name: crossplane-compositions
  sourceRef:
    kind: GitRepository
    name: infrastructure
  path: ./crossplane/claims
  prune: true
  healthChecks:
    - apiVersion: infrastructure.example.com/v1alpha1
      kind: Network
      name: production-network
      namespace: production

Git Repository 結構

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
infrastructure-repo/
├── crossplane/
│   ├── providers/
│   │   ├── provider-aws.yaml
│   │   ├── provider-azure.yaml
│   │   └── provider-gcp.yaml
│   ├── provider-configs/
│   │   ├── aws-config.yaml
│   │   ├── azure-config.yaml
│   │   └── gcp-config.yaml
│   ├── xrds/
│   │   ├── network-xrd.yaml
│   │   ├── database-xrd.yaml
│   │   └── storage-xrd.yaml
│   ├── compositions/
│   │   ├── network-aws.yaml
│   │   ├── database-aws.yaml
│   │   └── storage-multicloud.yaml
│   └── claims/
│       └── production/
│           ├── network.yaml
│           └── database.yaml
├── environments/
│   ├── development/
│   │   └── kustomization.yaml
│   ├── staging/
│   │   └── kustomization.yaml
│   └── production/
│       └── kustomization.yaml
└── clusters/
    └── production/
        ├── flux-system/
        └── crossplane-sync.yaml

監控與故障排除

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# 檢查 ArgoCD 同步狀態
argocd app get crossplane-infrastructure

# 檢查 Flux 同步狀態
flux get kustomizations

# 查看 Crossplane 資源狀態
kubectl get managed
kubectl get composite
kubectl get claim -A

# 檢查 Provider 健康狀態
kubectl get providers
kubectl describe provider provider-aws

# 查看 Crossplane 日誌
kubectl logs -n crossplane-system -l app=crossplane --tail=100

# 檢查特定資源的事件
kubectl get events --field-selector reason=CannotCreateExternalResource

最佳實踐

1. 資源命名規範

1
2
3
4
5
6
7
8
9
# 使用一致的命名慣例
metadata:
  name: ${environment}-${application}-${resource-type}
  labels:
    app.kubernetes.io/name: ${application}
    app.kubernetes.io/instance: ${environment}-${application}
    app.kubernetes.io/component: ${component}
    app.kubernetes.io/managed-by: crossplane
    environment: ${environment}

2. 敏感資訊管理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 使用 External Secrets Operator 整合
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: aws-credentials
  namespace: crossplane-system
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: vault-backend
    kind: ClusterSecretStore
  target:
    name: aws-creds
  data:
    - secretKey: credentials
      remoteRef:
        key: secret/crossplane/aws
        property: credentials

3. 資源清理策略

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 設定刪除策略
apiVersion: ec2.aws.upbound.io/v1beta1
kind: VPC
metadata:
  name: my-vpc
  annotations:
    # 刪除 VPC 時保留雲端資源
    crossplane.io/external-name: vpc-12345678
spec:
  deletionPolicy: Orphan  # Delete | Orphan
  forProvider:
    region: ap-northeast-1
    cidrBlock: 10.0.0.0/16

4. 健康檢查與告警

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# Prometheus ServiceMonitor
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: crossplane-metrics
  namespace: crossplane-system
spec:
  selector:
    matchLabels:
      app: crossplane
  endpoints:
    - port: metrics
      interval: 30s

總結

Crossplane 為 Kubernetes 原生的基礎架構管理帶來了革命性的改變。透過本文的介紹,我們了解了:

  1. Crossplane 核心架構:Providers、Managed Resources、Compositions 和 Claims 的運作方式
  2. 安裝與配置:如何安裝 Crossplane 並配置不同雲端供應商的 Providers
  3. 資源抽象化:使用 XRD 和 Compositions 建立可重用的基礎架構模組
  4. 多雲管理:透過統一的 API 管理 AWS、Azure、GCP 等多個雲端的資源
  5. GitOps 整合:與 ArgoCD 和 Flux 的整合實現完整的 GitOps 工作流程

Crossplane 的聲明式模型讓團隊可以使用熟悉的 Kubernetes 工具和實踐來管理雲端基礎架構,大幅降低了多雲環境的管理複雜度,同時提供了更好的可追蹤性和自助式服務能力。


參考資源

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy