前言
在現代雲端原生架構中,基礎架構即程式碼(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?
- 統一的控制平面:使用熟悉的 Kubernetes API 管理所有基礎架構
- 聲明式管理:透過 YAML 定義期望狀態,Crossplane 自動調和
- GitOps 友善:完美整合 ArgoCD、Flux 等 GitOps 工具
- 多雲支援:單一介面管理 AWS、Azure、GCP 等多個雲端
- 自助式服務:透過抽象層讓開發團隊自主建立基礎架構
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 原生的基礎架構管理帶來了革命性的改變。透過本文的介紹,我們了解了:
- Crossplane 核心架構:Providers、Managed Resources、Compositions 和 Claims 的運作方式
- 安裝與配置:如何安裝 Crossplane 並配置不同雲端供應商的 Providers
- 資源抽象化:使用 XRD 和 Compositions 建立可重用的基礎架構模組
- 多雲管理:透過統一的 API 管理 AWS、Azure、GCP 等多個雲端的資源
- GitOps 整合:與 ArgoCD 和 Flux 的整合實現完整的 GitOps 工作流程
Crossplane 的聲明式模型讓團隊可以使用熟悉的 Kubernetes 工具和實踐來管理雲端基礎架構,大幅降低了多雲環境的管理複雜度,同時提供了更好的可追蹤性和自助式服務能力。
參考資源