├── .gitignore ├── README.md ├── apps.yaml ├── cluster.yaml ├── config-cluster-aws.sh ├── crossplane-compositions ├── cluster-aws.yaml ├── cluster-civo.yaml └── definition.yaml ├── crossplane-configs ├── aws-creds.yaml ├── civo-creds.yaml └── providers.yaml ├── crossplane-providers └── providers.yaml ├── k3d.yaml ├── kind.yaml ├── orig ├── argo-cd.yaml ├── civo-creds.yaml ├── cluster-civo.yaml ├── cluster-claim.yaml ├── cluster.yaml ├── gke.yaml ├── my-app.yaml ├── team-a-infra.yaml ├── team-app-reqs.yaml └── team-apps.yaml ├── production ├── crossplane.yaml ├── sealed-secrets.yaml └── team-a-infra.yaml ├── project.yaml ├── sealed-secrets └── controller.yaml ├── team-a-infra └── dummy └── team-app-reqs └── kubevela.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | /*creds* 2 | kubeconfig.yaml 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Combining Argo CD (GitOps), Crossplane (Control Plane), And KubeVela (OAM)](https://youtu.be/eEcgn_gU3SM) 2 | -------------------------------------------------------------------------------- /apps.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | apiVersion: argoproj.io/v1alpha1 4 | kind: Application 5 | metadata: 6 | name: production 7 | namespace: argocd 8 | finalizers: 9 | - resources-finalizer.argocd.argoproj.io 10 | spec: 11 | project: production 12 | source: 13 | repoURL: https://github.com/vfarcic/crossplane-kubevela-argocd-demo 14 | targetRevision: HEAD 15 | path: production 16 | destination: 17 | server: https://kubernetes.default.svc 18 | namespace: production 19 | syncPolicy: 20 | automated: 21 | selfHeal: true 22 | prune: true 23 | allowEmpty: true 24 | -------------------------------------------------------------------------------- /cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: devopstoolkitseries.com/v1alpha1 2 | kind: CompositeCluster 3 | metadata: 4 | name: team-a 5 | labels: 6 | cluster-owner: vfarcic 7 | spec: 8 | compositionRef: 9 | name: cluster-aws 10 | parameters: 11 | # Possible values small, medium, large 12 | nodeSize: small 13 | # version: "1.20" 14 | # minNodeCount: 2 15 | writeConnectionSecretToRef: 16 | namespace: team-a 17 | name: cluster 18 | -------------------------------------------------------------------------------- /config-cluster-aws.sh: -------------------------------------------------------------------------------- 1 | export TEAM_NAME=$1 2 | 3 | export CLUSTER_NAME=$(\ 4 | kubectl get clusters \ 5 | --selector crossplane.io/composite=$TEAM_NAME \ 6 | --output jsonpath="{.items[0].metadata.name}") 7 | 8 | export KUBECONFIG=$PWD/kubeconfig.yaml 9 | 10 | mkdir -p $TEAM_NAME-apps 11 | 12 | touch $TEAM_NAME-apps/dummy 13 | 14 | cp -R team-app-reqs $TEAM_NAME-app-reqs 15 | 16 | aws eks --region us-east-1 \ 17 | update-kubeconfig \ 18 | --name $CLUSTER_NAME 19 | 20 | kubectl create namespace production 21 | 22 | argocd cluster add \ 23 | $(kubectl config current-context) \ 24 | --name $TEAM_NAME 25 | 26 | export SERVER_URL=$(kubectl config view \ 27 | --minify \ 28 | --output jsonpath="{.clusters[0].cluster.server}") 29 | 30 | cat orig/team-app-reqs.yaml \ 31 | | sed -e "s@server: .*@server: $SERVER_URL@g" \ 32 | | tee production/$TEAM_NAME-app-reqs.yaml 33 | 34 | cat orig/team-apps.yaml \ 35 | | sed -e "s@server: .*@server: $SERVER_URL@g" \ 36 | | tee production/$TEAM_NAME-apps.yaml 37 | 38 | git add . 39 | 40 | git commit -m "Team A apps" 41 | 42 | git push 43 | 44 | -------------------------------------------------------------------------------- /crossplane-compositions/cluster-aws.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: cluster-aws 5 | labels: 6 | provider: aws 7 | cluster: eks 8 | spec: 9 | compositeTypeRef: 10 | apiVersion: devopstoolkitseries.com/v1alpha1 11 | kind: CompositeCluster 12 | writeConnectionSecretsToNamespace: crossplane-system 13 | patchSets: 14 | - name: metadata 15 | patches: 16 | - fromFieldPath: metadata.labels 17 | resources: 18 | - name: ekscluster 19 | base: 20 | apiVersion: eks.aws.crossplane.io/v1beta1 21 | kind: Cluster 22 | spec: 23 | forProvider: 24 | region: us-east-1 25 | version: "1.21" 26 | roleArnSelector: 27 | matchControllerRef: true 28 | matchLabels: 29 | role: controlplane 30 | resourcesVpcConfig: 31 | endpointPrivateAccess: true 32 | endpointPublicAccess: true 33 | subnetIdSelector: 34 | matchControllerRef: true 35 | patches: 36 | - fromFieldPath: spec.id 37 | toFieldPath: metadata.name 38 | - fromFieldPath: spec.parameters.version 39 | toFieldPath: spec.forProvider.version 40 | - fromFieldPath: metadata.uid 41 | toFieldPath: spec.writeConnectionSecretToRef.name 42 | transforms: 43 | - type: string 44 | string: 45 | fmt: "%s-ekscluster" 46 | - type: ToCompositeFieldPath 47 | fromFieldPath: spec.id 48 | toFieldPath: status.clusterName 49 | - type: ToCompositeFieldPath 50 | fromFieldPath: status.atProvider.status 51 | toFieldPath: status.controlPlaneStatus 52 | - fromFieldPath: spec.writeConnectionSecretToRef.namespace 53 | toFieldPath: spec.writeConnectionSecretToRef.namespace 54 | readinessChecks: 55 | - type: MatchString 56 | fieldPath: status.atProvider.status 57 | matchString: ACTIVE 58 | connectionDetails: 59 | - fromConnectionSecretKey: kubeconfig 60 | - name: eksnodegroup 61 | base: 62 | apiVersion: eks.aws.crossplane.io/v1alpha1 63 | kind: NodeGroup 64 | spec: 65 | forProvider: 66 | region: us-east-1 67 | clusterNameSelector: 68 | matchControllerRef: true 69 | nodeRoleSelector: 70 | matchControllerRef: true 71 | matchLabels: 72 | role: nodegroup 73 | subnetSelector: 74 | matchLabels: 75 | access: public 76 | scalingConfig: 77 | minSize: 1 78 | maxSize: 10 79 | desiredSize: 1 80 | instanceTypes: 81 | - t3.small 82 | patches: 83 | - fromFieldPath: spec.id 84 | toFieldPath: metadata.name 85 | - fromFieldPath: spec.parameters.nodeSize 86 | toFieldPath: spec.forProvider.instanceTypes[0] 87 | transforms: 88 | - type: map 89 | map: 90 | small: t3.small 91 | medium: t3.medium 92 | large: t3.large 93 | - fromFieldPath: spec.parameters.minNodeCount 94 | toFieldPath: spec.forProvider.scalingConfig.minSize 95 | - fromFieldPath: spec.parameters.minNodeCount 96 | toFieldPath: spec.forProvider.scalingConfig.desiredSize 97 | - type: ToCompositeFieldPath 98 | fromFieldPath: status.atProvider.status 99 | toFieldPath: status.nodePoolStatus 100 | readinessChecks: 101 | - type: MatchString 102 | fieldPath: status.atProvider.status 103 | matchString: ACTIVE 104 | - name: iamrole-controlplane 105 | base: 106 | apiVersion: identity.aws.crossplane.io/v1beta1 107 | kind: IAMRole 108 | metadata: 109 | labels: 110 | role: controlplane 111 | spec: 112 | forProvider: 113 | assumeRolePolicyDocument: | 114 | { 115 | "Version": "2012-10-17", 116 | "Statement": [ 117 | { 118 | "Effect": "Allow", 119 | "Principal": { 120 | "Service": [ 121 | "eks.amazonaws.com" 122 | ] 123 | }, 124 | "Action": [ 125 | "sts:AssumeRole" 126 | ] 127 | } 128 | ] 129 | } 130 | patches: 131 | - fromFieldPath: spec.id 132 | toFieldPath: metadata.name 133 | transforms: 134 | - type: string 135 | string: 136 | fmt: "%s-controlplane" 137 | - name: iamrole-nodegroup 138 | base: 139 | apiVersion: identity.aws.crossplane.io/v1beta1 140 | kind: IAMRole 141 | metadata: 142 | labels: 143 | role: nodegroup 144 | spec: 145 | forProvider: 146 | assumeRolePolicyDocument: | 147 | { 148 | "Version": "2012-10-17", 149 | "Statement": [ 150 | { 151 | "Effect": "Allow", 152 | "Principal": { 153 | "Service": [ 154 | "ec2.amazonaws.com" 155 | ] 156 | }, 157 | "Action": [ 158 | "sts:AssumeRole" 159 | ] 160 | } 161 | ] 162 | } 163 | patches: 164 | - fromFieldPath: spec.id 165 | toFieldPath: metadata.name 166 | transforms: 167 | - type: string 168 | string: 169 | fmt: "%s-nodegroup" 170 | - name: iamattachment-controlplane 171 | base: 172 | apiVersion: identity.aws.crossplane.io/v1beta1 173 | kind: IAMRolePolicyAttachment 174 | spec: 175 | forProvider: 176 | policyArn: arn:aws:iam::aws:policy/AmazonEKSClusterPolicy 177 | roleNameSelector: 178 | matchControllerRef: true 179 | matchLabels: 180 | role: controlplane 181 | patches: 182 | - fromFieldPath: spec.id 183 | toFieldPath: metadata.name 184 | transforms: 185 | - type: string 186 | string: 187 | fmt: "%s-controlplane" 188 | - name: iamattachment-service 189 | base: 190 | apiVersion: identity.aws.crossplane.io/v1beta1 191 | kind: IAMRolePolicyAttachment 192 | spec: 193 | forProvider: 194 | policyArn: arn:aws:iam::aws:policy/AmazonEKSServicePolicy 195 | roleNameSelector: 196 | matchControllerRef: true 197 | matchLabels: 198 | role: controlplane 199 | patches: 200 | - fromFieldPath: spec.id 201 | toFieldPath: metadata.name 202 | transforms: 203 | - type: string 204 | string: 205 | fmt: "%s-service" 206 | - name: iamattachment-worker 207 | base: 208 | apiVersion: identity.aws.crossplane.io/v1beta1 209 | kind: IAMRolePolicyAttachment 210 | spec: 211 | forProvider: 212 | policyArn: arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy 213 | roleNameSelector: 214 | matchControllerRef: true 215 | matchLabels: 216 | role: nodegroup 217 | patches: 218 | - fromFieldPath: spec.id 219 | toFieldPath: metadata.name 220 | transforms: 221 | - type: string 222 | string: 223 | fmt: "%s-worker" 224 | - name: iamattachment-cni 225 | base: 226 | apiVersion: identity.aws.crossplane.io/v1beta1 227 | kind: IAMRolePolicyAttachment 228 | spec: 229 | forProvider: 230 | policyArn: arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy 231 | roleNameSelector: 232 | matchControllerRef: true 233 | matchLabels: 234 | role: nodegroup 235 | patches: 236 | - fromFieldPath: spec.id 237 | toFieldPath: metadata.name 238 | transforms: 239 | - type: string 240 | string: 241 | fmt: "%s-cni" 242 | - name: iamattachment-registry 243 | base: 244 | apiVersion: identity.aws.crossplane.io/v1beta1 245 | kind: IAMRolePolicyAttachment 246 | spec: 247 | forProvider: 248 | policyArn: arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly 249 | roleNameSelector: 250 | matchControllerRef: true 251 | matchLabels: 252 | role: nodegroup 253 | patches: 254 | - fromFieldPath: spec.id 255 | toFieldPath: metadata.name 256 | transforms: 257 | - type: string 258 | string: 259 | fmt: "%s-registry" 260 | - name: vpc-nodepool 261 | base: 262 | apiVersion: ec2.aws.crossplane.io/v1beta1 263 | kind: VPC 264 | spec: 265 | forProvider: 266 | region: us-east-1 267 | cidrBlock: 10.0.0.0/16 268 | enableDnsSupport: true 269 | patches: 270 | - fromFieldPath: spec.id 271 | toFieldPath: metadata.name 272 | - name: sc-nodepool 273 | base: 274 | apiVersion: ec2.aws.crossplane.io/v1beta1 275 | kind: SecurityGroup 276 | spec: 277 | forProvider: 278 | description: Cluster communication with worker nodes 279 | groupName: devops-catalog 280 | region: us-east-1 281 | vpcIdSelector: 282 | matchControllerRef: true 283 | egress: 284 | - fromPort: 0 285 | toPort: 0 286 | ipProtocol: "-1" 287 | ipRanges: 288 | - cidrIp: "0.0.0.0/0" 289 | patches: 290 | - fromFieldPath: spec.id 291 | toFieldPath: metadata.name 292 | - name: subnet-nodepool-1a 293 | base: 294 | apiVersion: ec2.aws.crossplane.io/v1beta1 295 | kind: Subnet 296 | metadata: 297 | labels: 298 | zone: us-east-1a 299 | access: public 300 | spec: 301 | forProvider: 302 | region: us-east-1 303 | availabilityZone: us-east-1a 304 | cidrBlock: 10.0.0.0/24 305 | vpcIdSelector: 306 | matchControllerRef: true 307 | mapPublicIPOnLaunch: true 308 | tags: 309 | - key: kubernetes.io/role/elb 310 | value: "1" 311 | patches: 312 | - fromFieldPath: spec.id 313 | toFieldPath: metadata.name 314 | transforms: 315 | - type: string 316 | string: 317 | fmt: "%s-1a" 318 | - name: subnet-nodepool-1b 319 | base: 320 | apiVersion: ec2.aws.crossplane.io/v1beta1 321 | kind: Subnet 322 | metadata: 323 | labels: 324 | zone: us-east-1b 325 | access: public 326 | spec: 327 | forProvider: 328 | region: us-east-1 329 | availabilityZone: us-east-1b 330 | cidrBlock: 10.0.1.0/24 331 | vpcIdSelector: 332 | matchControllerRef: true 333 | mapPublicIPOnLaunch: true 334 | tags: 335 | - key: kubernetes.io/role/elb 336 | value: "1" 337 | patches: 338 | - fromFieldPath: spec.id 339 | toFieldPath: metadata.name 340 | transforms: 341 | - type: string 342 | string: 343 | fmt: "%s-1b" 344 | - name: subnet-nodepool-1c 345 | base: 346 | apiVersion: ec2.aws.crossplane.io/v1beta1 347 | kind: Subnet 348 | metadata: 349 | labels: 350 | zone: us-east-1c 351 | access: public 352 | spec: 353 | forProvider: 354 | region: us-east-1 355 | availabilityZone: us-east-1c 356 | cidrBlock: 10.0.2.0/24 357 | vpcIdSelector: 358 | matchControllerRef: true 359 | mapPublicIPOnLaunch: true 360 | tags: 361 | - key: kubernetes.io/role/elb 362 | value: "1" 363 | patches: 364 | - fromFieldPath: spec.id 365 | toFieldPath: metadata.name 366 | transforms: 367 | - type: string 368 | string: 369 | fmt: "%s-1c" 370 | - name: gateway 371 | base: 372 | apiVersion: ec2.aws.crossplane.io/v1beta1 373 | kind: InternetGateway 374 | spec: 375 | forProvider: 376 | region: us-east-1 377 | vpcIdSelector: 378 | matchControllerRef: true 379 | patches: 380 | - fromFieldPath: spec.id 381 | toFieldPath: metadata.name 382 | - name: routetable 383 | base: 384 | apiVersion: ec2.aws.crossplane.io/v1beta1 385 | kind: RouteTable 386 | spec: 387 | forProvider: 388 | region: us-east-1 389 | vpcIdSelector: 390 | matchControllerRef: true 391 | routes: 392 | - destinationCidrBlock: 0.0.0.0/0 393 | gatewayIdSelector: 394 | matchControllerRef: true 395 | associations: 396 | - subnetIdSelector: 397 | matchControllerRef: true 398 | matchLabels: 399 | zone: us-east-1a 400 | access: public 401 | - subnetIdSelector: 402 | matchControllerRef: true 403 | matchLabels: 404 | zone: us-east-1b 405 | access: public 406 | - subnetIdSelector: 407 | matchControllerRef: true 408 | matchLabels: 409 | zone: us-east-1c 410 | access: public 411 | patches: 412 | - fromFieldPath: spec.id 413 | toFieldPath: metadata.name 414 | - name: helm 415 | base: 416 | apiVersion: helm.crossplane.io/v1beta1 417 | kind: ProviderConfig 418 | spec: 419 | credentials: 420 | source: Secret 421 | secretRef: 422 | key: kubeconfig 423 | patches: 424 | - fromFieldPath: spec.id 425 | toFieldPath: metadata.name 426 | - fromFieldPath: spec.writeConnectionSecretToRef.namespace 427 | toFieldPath: spec.credentials.secretRef.namespace 428 | - fromFieldPath: metadata.uid 429 | toFieldPath: spec.credentials.secretRef.name 430 | transforms: 431 | - type: string 432 | string: 433 | fmt: "%s-ekscluster" 434 | readinessChecks: 435 | - type: None 436 | - name: kubevela 437 | base: 438 | apiVersion: helm.crossplane.io/v1beta1 439 | kind: Release 440 | spec: 441 | rollbackLimit: 3 442 | forProvider: 443 | namespace: vela-system 444 | chart: 445 | name: vela-core 446 | repository: https://charts.kubevela.net/core 447 | version: "1.0.7" 448 | patches: 449 | - fromFieldPath: spec.id 450 | toFieldPath: metadata.name 451 | - fromFieldPath: spec.id 452 | toFieldPath: spec.providerConfigRef.name 453 | -------------------------------------------------------------------------------- /crossplane-compositions/cluster-civo.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: Composition 3 | metadata: 4 | name: cluster-civo 5 | labels: 6 | provider: civo 7 | cluster: ck 8 | spec: 9 | compositeTypeRef: 10 | apiVersion: devopstoolkitseries.com/v1alpha1 11 | kind: CompositeCluster 12 | writeConnectionSecretsToNamespace: crossplane-system 13 | patchSets: 14 | - name: metadata 15 | patches: 16 | - fromFieldPath: metadata.labels 17 | resources: 18 | - name: civocluster 19 | base: 20 | apiVersion: cluster.civo.crossplane.io/v1alpha1 21 | kind: CivoKubernetes 22 | spec: 23 | instances: 1 24 | size: g3.k3s.small 25 | connectionDetails: 26 | connectionSecretNamePrefix: cluster-civo 27 | connectionSecretNamespace: crossplane-system 28 | providerConfigRef: 29 | name: provider-civo 30 | patches: 31 | - fromFieldPath: spec.id 32 | toFieldPath: metadata.name 33 | - fromFieldPath: spec.id 34 | toFieldPath: spec.name 35 | - fromFieldPath: spec.parameters.minNodeCount 36 | toFieldPath: spec.instanced 37 | - fromFieldPath: spec.parameters.nodeSize 38 | toFieldPath: spec.size 39 | transforms: 40 | - type: map 41 | map: 42 | small: g3.k3s.small 43 | medium: g3.k3s.medium 44 | large: g3.k3s.xlarge 45 | -------------------------------------------------------------------------------- /crossplane-compositions/definition.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.crossplane.io/v1 2 | kind: CompositeResourceDefinition 3 | metadata: 4 | name: compositeclusters.devopstoolkitseries.com 5 | spec: 6 | connectionSecretKeys: 7 | - kubeconfig 8 | defaultCompositionRef: 9 | name: cluster-google 10 | group: devopstoolkitseries.com 11 | names: 12 | kind: CompositeCluster 13 | plural: compositeclusters 14 | claimNames: 15 | kind: ClusterClaim 16 | plural: clusterclaims 17 | versions: 18 | - name: v1alpha1 19 | served: true 20 | referenceable: true 21 | schema: 22 | openAPIV3Schema: 23 | type: object 24 | properties: 25 | spec: 26 | type: object 27 | properties: 28 | id: 29 | type: string 30 | description: ID of this Cluster that other objects will use to refer to it. 31 | parameters: 32 | type: object 33 | properties: 34 | version: 35 | description: The Kubernetes version for the cluster. 36 | type: string 37 | nodeSize: 38 | description: The size of the nodes; small, medium, large 39 | type: string 40 | minNodeCount: 41 | description: The minimum number of nodes 42 | type: integer 43 | default: 1 44 | required: 45 | - nodeSize 46 | required: 47 | - id 48 | - parameters 49 | status: 50 | type: object 51 | properties: 52 | clusterName: 53 | description: The name of the cluster 54 | type: string 55 | controlPlaneStatus: 56 | description: The status of the control plane 57 | type: string 58 | nodePoolStatus: 59 | description: The status of the node pool 60 | type: string 61 | additionalPrinterColumns: 62 | - name: clusterName 63 | type: string 64 | jsonPath: ".status.clusterName" 65 | - name: controlPlane 66 | type: string 67 | jsonPath: ".status.controlPlaneStatus" 68 | - name: nodePool 69 | type: string 70 | jsonPath: ".status.nodePoolStatus" 71 | -------------------------------------------------------------------------------- /crossplane-configs/aws-creds.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: bitnami.com/v1alpha1 2 | kind: SealedSecret 3 | metadata: 4 | creationTimestamp: null 5 | name: aws-creds 6 | namespace: crossplane-system 7 | spec: 8 | encryptedData: 9 | creds: AgDD7wFaXXmiW+RfgmShmBgK1grNIOrT61l97yk+4vrHBeV5Lae/WzTMHBwZA91omQ+plTe7fFX0Do+AYxGE0YSvSKgyjc9qy/gxewmqTlJpoLalRFg3ezJrcQQMGZVTKt81Fe3LcIFAywQBBz+T+KCUddzhdxabJIzGS5K6kgL8r1UcnkT1IFhzLKkx71tCw3saBgJiW9+JTBDq9HWR489Kxd/7fMOEEBT8zEyfFthzbQpyXyMZHpw2bfqcPEkaMyJN0PMULM/vdOCpiQCYZLwZFtGf6aOVDYeiVHpVqPh00QzB4hqIRAmoSXjRnBKpZcPkdgwYsU84y35+zZwcS9X1cnpNPPS3u6SZBAh9Fmxe5keClF6r6LCrZzfk6NWL5DPN2slw3Eu+7dwRnOXLxYtKPEit4abC6FkZb/iRMrxpsm/+kklGTj0sr9LYYSiwVkgeKVS+QxWd98EXysg5VjAMJbWDnOckcgR6Mj8Awm4KE5C9E1PcP6ASMkUT8ZF/rUWrhDeRovKX0RMC1Ckxq0goeQwwHkeem3EWj8IIaGtOIO+fV7RYEEytdzBLLif/nGrj1iS/5LD61sdhUWJx9xnnyP4ZYLBXH2ryj5WZViAVjNNY39AW6cDf4XCr2pmZlc34ni43lcTf6Tw2mfZo4fCoKhJHFIJXcIgFFR5LxLrYsFsMiacBNG/2Y+b4h7+1+JLm9M5NuZ0XdZMQsqpjNqdRF7EnvB8lNS1CeCFK1TFuloeq4r5EkuQjC5GK2IgyfBzNhoR9zwmgsIiZkSok0EJZzk5WjhpBViSqTMzJ9yRQfzxaM9O0TUDY7jEXNE7KLM07FbpaAUzpfyNtHRzQWahHXNqLCFQ= 10 | template: 11 | data: null 12 | metadata: 13 | creationTimestamp: null 14 | name: aws-creds 15 | namespace: crossplane-system 16 | 17 | -------------------------------------------------------------------------------- /crossplane-configs/civo-creds.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: bitnami.com/v1alpha1 2 | kind: SealedSecret 3 | metadata: 4 | creationTimestamp: null 5 | name: civo-creds 6 | namespace: crossplane-system 7 | spec: 8 | encryptedData: 9 | credentials: AgCHKoE65GEwImz0wp27w6+1Q2tCAn61aYOUZxjWR9ccXupdQ9S1owQUWgC2YidNCOD8W0sBLXL0D+mH4/CmfYQn0U64ticCZxWVRxm3YoZlOMnT/ISHC9e7UFHkVpEL6b2kuBBh2kg+cgi29eVoyxIVbuT+68NXgNzvgLPmIZ+4gcpUS5L8sEotiyvin99ir0dwMM7HqGjoidU0rAKV3aDwW0sN6PMHu1te/XgJ+b32FDf2MsxVJDfpGPFk8Q2odkG8OJHa+tXKS3ce+0JMzhQ2i0DZkWCGijmBdvx/Enrd1B1iC904/Huy+1fjAM6N6hxCGdsv2F8fTM824uJm5g3yp58X0nspePhywO2vu6egkJFlsB2gRbxxROY2pVQyfhqlijlMQ5gcpFIe9BbOl72cWedulsJGnELh8cgt7NuzKMXNMr2YxGLUKWU42LUhCdthyqMf6iXe0xU2T6Gmw/aH26IisJy2EFjur5bBITBUYti5tHgNBn4CRhpg3Jz84Aw74qn2cBKHe3XCcIsOOMIW3kkeuyxoVhGPYfJZPMO5zkV2UASLt0iRc0m2Y2NxIJB87zHO96H1PusvCmNB+xHzcnTevB18j2eFBbRESIyeSgzclC+VPsKdykAoT6usS6+RrZzQ1xq48Vntpi0Fl+OoOqwFR7oL9CVn+O81MeLd8dwAgM5pYeI0FCGdkV2ASFK0m4fq3QVSneV1wrDdaOQnPmA3ttoZqk1Nebad8rImiI7P6VmDvHyFBONb92s4hH1dsto= 10 | template: 11 | data: null 12 | metadata: 13 | creationTimestamp: null 14 | name: civo-creds 15 | namespace: crossplane-system 16 | type: Opaque 17 | 18 | -------------------------------------------------------------------------------- /crossplane-configs/providers.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | apiVersion: aws.crossplane.io/v1beta1 4 | kind: ProviderConfig 5 | metadata: 6 | name: default 7 | spec: 8 | credentials: 9 | source: Secret 10 | secretRef: 11 | namespace: crossplane-system 12 | name: aws-creds 13 | key: creds 14 | 15 | --- 16 | 17 | apiVersion: civo.crossplane.io/v1alpha1 18 | kind: ProviderConfig 19 | metadata: 20 | name: provider-civo 21 | spec: 22 | region: nyc1 23 | credentials: 24 | source: Secret 25 | secretRef: 26 | namespace: crossplane-system 27 | name: civo-creds 28 | key: credentials 29 | -------------------------------------------------------------------------------- /crossplane-providers/providers.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | apiVersion: pkg.crossplane.io/v1 4 | kind: Provider 5 | metadata: 6 | name: provider-aws 7 | spec: 8 | package: crossplane/provider-aws:v0.19.0 9 | 10 | --- 11 | 12 | apiVersion: pkg.crossplane.io/v1 13 | kind: Provider 14 | metadata: 15 | name: provider-helm 16 | spec: 17 | package: crossplane/provider-helm:v0.5.0 18 | 19 | --- 20 | 21 | apiVersion: pkg.crossplane.io/v1 22 | kind: Provider 23 | metadata: 24 | name: provider-civo 25 | spec: 26 | package: crossplane/provider-civo:main 27 | -------------------------------------------------------------------------------- /k3d.yaml: -------------------------------------------------------------------------------- 1 | kind: Simple 2 | apiVersion: k3d.io/v1alpha2 3 | name: devops-toolkit 4 | image: rancher/k3s:v1.20.4-k3s1 5 | ports: 6 | - port: 80:80 7 | nodeFilters: 8 | - loadbalancer 9 | -------------------------------------------------------------------------------- /kind.yaml: -------------------------------------------------------------------------------- 1 | kind: Cluster 2 | apiVersion: kind.x-k8s.io/v1alpha4 3 | nodes: 4 | - kubeadmConfigPatches: 5 | - | 6 | kind: InitConfiguration 7 | nodeRegistration: 8 | kubeletExtraArgs: 9 | node-labels: "ingress-ready=true" 10 | extraPortMappings: 11 | - containerPort: 80 12 | hostPort: 80 13 | protocol: TCP 14 | - containerPort: 443 15 | hostPort: 443 16 | protocol: TCP 17 | -------------------------------------------------------------------------------- /orig/argo-cd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: argoproj.io/v1alpha1 2 | kind: Application 3 | metadata: 4 | name: argo-cd 5 | namespace: argocd 6 | finalizers: 7 | - resources-finalizer.argocd.argoproj.io 8 | spec: 9 | project: production 10 | source: 11 | path: argo-cd/overlays/production 12 | repoURL: https://github.com/vfarcic/crossplane-kubevela-argocd-demo 13 | targetRevision: HEAD 14 | destination: 15 | server: https://kubernetes.default.svc 16 | syncPolicy: 17 | automated: 18 | selfHeal: true 19 | prune: true 20 | allowEmpty: true 21 | 22 | -------------------------------------------------------------------------------- /orig/civo-creds.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | namespace: crossplane-system 5 | name: civo-creds 6 | type: Opaque 7 | data: 8 | credentials: MY_CREDS 9 | -------------------------------------------------------------------------------- /orig/cluster-civo.yaml: -------------------------------------------------------------------------------- 1 | 2 | apiVersion: cluster.civo.crossplane.io/v1alpha1 3 | kind: CivoKubernetes 4 | metadata: 5 | name: devops-toolkit 6 | spec: 7 | name: devops-toolkit 8 | instances: 1 9 | size: g3.k3s.small 10 | applications: 11 | - prometheus-operator 12 | - argo-cd 13 | connectionDetails: 14 | connectionSecretNamePrefix: cluster-civo 15 | connectionSecretNamespace: crossplane-system 16 | providerConfigRef: 17 | name: provider-civo 18 | -------------------------------------------------------------------------------- /orig/cluster-claim.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: devopstoolkitseries.com/v1alpha1 2 | kind: ClusterClaim 3 | metadata: 4 | name: team-a 5 | labels: 6 | cluster-owner: vfarcic 7 | spec: 8 | id: team-a 9 | compositionSelector: 10 | matchLabels: 11 | provider: aws 12 | cluster: eks 13 | parameters: 14 | # Possible values small, medium, large 15 | nodeSize: small 16 | # version: "1.20" 17 | # minNodeCount: 1 18 | -------------------------------------------------------------------------------- /orig/cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: devopstoolkitseries.com/v1alpha1 2 | kind: CompositeCluster 3 | metadata: 4 | name: team-a 5 | labels: 6 | cluster-owner: vfarcic 7 | spec: 8 | id: team-a 9 | compositionRef: 10 | name: cluster-aws 11 | parameters: 12 | # Possible values small, medium, large 13 | nodeSize: small 14 | # version: "1.20" 15 | # minNodeCount: 1 16 | -------------------------------------------------------------------------------- /orig/gke.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: container.gcp.crossplane.io/v1beta1 2 | kind: GKECluster 3 | metadata: 4 | name: devops-toolkit 5 | spec: 6 | forProvider: 7 | location: us-east1 8 | initialClusterVersion: latest 9 | 10 | --- 11 | 12 | apiVersion: container.gcp.crossplane.io/v1alpha1 13 | kind: NodePool 14 | metadata: 15 | name: devops-toolkit 16 | spec: 17 | forProvider: 18 | locations: 19 | - us-east1-b 20 | clusterRef: 21 | name: devops-toolkit 22 | initialNodeCount: 1 23 | config: 24 | preemptible: true 25 | machineType: e2-standard-2 26 | oauthScopes: 27 | - https://www.googleapis.com/auth/cloud-platform 28 | autoscaling: 29 | enabled: true 30 | minNodeCount: 1 31 | maxNodeCount: 2 32 | management: 33 | autoUpgrade: false 34 | -------------------------------------------------------------------------------- /orig/my-app.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: core.oam.dev/v1beta1 2 | kind: Application 3 | metadata: 4 | name: devops-toolkit 5 | spec: 6 | components: 7 | - name: backend 8 | type: backend 9 | properties: 10 | image: alpine 11 | cmd: 12 | - sleep 13 | - "1000000" 14 | - name: frontend 15 | type: frontend 16 | properties: 17 | name: frontend 18 | image: vfarcic/devops-toolkit-series 19 | traits: 20 | - type: autoscaler 21 | properties: 22 | min: 3 23 | - type: ingress 24 | properties: 25 | domain: localhost 26 | http: 27 | "/": 80 28 | -------------------------------------------------------------------------------- /orig/team-a-infra.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: argoproj.io/v1alpha1 2 | kind: Application 3 | metadata: 4 | name: team-a-infra 5 | namespace: argocd 6 | finalizers: 7 | - resources-finalizer.argocd.argoproj.io 8 | spec: 9 | project: production 10 | source: 11 | path: team-a-infra 12 | repoURL: https://github.com/vfarcic/crossplane-kubevela-argocd-demo 13 | targetRevision: HEAD 14 | destination: 15 | server: https://kubernetes.default.svc 16 | syncPolicy: 17 | automated: 18 | selfHeal: true 19 | prune: true 20 | 21 | -------------------------------------------------------------------------------- /orig/team-app-reqs.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: argoproj.io/v1alpha1 2 | kind: Application 3 | metadata: 4 | name: team-a-apps-reqs 5 | namespace: argocd 6 | finalizers: 7 | - resources-finalizer.argocd.argoproj.io 8 | spec: 9 | project: production 10 | source: 11 | path: team-app-reqs 12 | repoURL: https://github.com/vfarcic/crossplane-kubevela-argocd-demo 13 | targetRevision: HEAD 14 | destination: 15 | server: team-a 16 | namespace: production 17 | syncPolicy: 18 | automated: 19 | selfHeal: true 20 | prune: true 21 | allowEmpty: true 22 | -------------------------------------------------------------------------------- /orig/team-apps.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: argoproj.io/v1alpha1 2 | kind: Application 3 | metadata: 4 | name: team-a-apps 5 | namespace: argocd 6 | finalizers: 7 | - resources-finalizer.argocd.argoproj.io 8 | spec: 9 | project: production 10 | source: 11 | path: team-a-apps 12 | repoURL: https://github.com/vfarcic/crossplane-kubevela-argocd-demo 13 | targetRevision: HEAD 14 | destination: 15 | server: team-a 16 | namespace: production 17 | syncPolicy: 18 | automated: 19 | selfHeal: true 20 | prune: true 21 | allowEmpty: true 22 | syncOptions: 23 | - CreateNamespace=true 24 | -------------------------------------------------------------------------------- /production/crossplane.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | apiVersion: argoproj.io/v1alpha1 4 | kind: Application 5 | metadata: 6 | name: crossplane 7 | namespace: argocd 8 | finalizers: 9 | - resources-finalizer.argocd.argoproj.io 10 | spec: 11 | project: production 12 | source: 13 | chart: crossplane 14 | repoURL: https://charts.crossplane.io/stable 15 | targetRevision: "1.3.0" 16 | destination: 17 | namespace: crossplane-system 18 | server: https://kubernetes.default.svc 19 | syncPolicy: 20 | automated: 21 | selfHeal: true 22 | prune: true 23 | allowEmpty: true 24 | syncOptions: 25 | - CreateNamespace=true 26 | 27 | --- 28 | 29 | apiVersion: argoproj.io/v1alpha1 30 | kind: Application 31 | metadata: 32 | name: crossplane-providers 33 | namespace: argocd 34 | finalizers: 35 | - resources-finalizer.argocd.argoproj.io 36 | spec: 37 | project: production 38 | source: 39 | path: crossplane-providers 40 | repoURL: https://github.com/vfarcic/crossplane-kubevela-argocd-demo 41 | targetRevision: HEAD 42 | destination: 43 | server: https://kubernetes.default.svc 44 | syncPolicy: 45 | automated: 46 | selfHeal: true 47 | prune: true 48 | allowEmpty: true 49 | 50 | --- 51 | 52 | apiVersion: argoproj.io/v1alpha1 53 | kind: Application 54 | metadata: 55 | name: crossplane-configs 56 | namespace: argocd 57 | finalizers: 58 | - resources-finalizer.argocd.argoproj.io 59 | spec: 60 | project: production 61 | source: 62 | path: crossplane-configs 63 | repoURL: https://github.com/vfarcic/crossplane-kubevela-argocd-demo 64 | targetRevision: HEAD 65 | destination: 66 | server: https://kubernetes.default.svc 67 | syncPolicy: 68 | automated: 69 | selfHeal: true 70 | prune: true 71 | allowEmpty: true 72 | 73 | --- 74 | 75 | apiVersion: argoproj.io/v1alpha1 76 | kind: Application 77 | metadata: 78 | name: crossplane-compositions 79 | namespace: argocd 80 | finalizers: 81 | - resources-finalizer.argocd.argoproj.io 82 | spec: 83 | project: production 84 | source: 85 | path: crossplane-compositions 86 | repoURL: https://github.com/vfarcic/crossplane-kubevela-argocd-demo 87 | targetRevision: HEAD 88 | destination: 89 | server: https://kubernetes.default.svc 90 | syncPolicy: 91 | automated: 92 | selfHeal: true 93 | prune: true 94 | allowEmpty: true 95 | 96 | -------------------------------------------------------------------------------- /production/sealed-secrets.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: argoproj.io/v1alpha1 2 | kind: Application 3 | metadata: 4 | name: sealed-secrets 5 | namespace: argocd 6 | finalizers: 7 | - resources-finalizer.argocd.argoproj.io 8 | spec: 9 | project: production 10 | source: 11 | path: sealed-secrets 12 | repoURL: https://github.com/vfarcic/crossplane-kubevela-argocd-demo 13 | targetRevision: HEAD 14 | destination: 15 | server: https://kubernetes.default.svc 16 | syncPolicy: 17 | automated: 18 | selfHeal: true 19 | prune: true 20 | allowEmpty: true 21 | 22 | -------------------------------------------------------------------------------- /production/team-a-infra.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: argoproj.io/v1alpha1 2 | kind: Application 3 | metadata: 4 | name: team-a-infra 5 | namespace: argocd 6 | finalizers: 7 | - resources-finalizer.argocd.argoproj.io 8 | spec: 9 | project: production 10 | source: 11 | path: team-a-infra 12 | repoURL: https://github.com/vfarcic/crossplane-kubevela-argocd-demo 13 | targetRevision: HEAD 14 | destination: 15 | server: https://kubernetes.default.svc 16 | syncPolicy: 17 | automated: 18 | selfHeal: true 19 | prune: true 20 | allowEmpty: true 21 | 22 | -------------------------------------------------------------------------------- /project.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | apiVersion: argoproj.io/v1alpha1 4 | kind: AppProject 5 | metadata: 6 | name: production 7 | namespace: argocd 8 | finalizers: 9 | - resources-finalizer.argocd.argoproj.io 10 | spec: 11 | description: Production project 12 | sourceRepos: 13 | - '*' 14 | destinations: 15 | - namespace: '*' 16 | server: '*' 17 | clusterResourceWhitelist: 18 | - group: '*' 19 | kind: '*' 20 | namespaceResourceWhitelist: 21 | - group: '*' 22 | kind: '*' 23 | -------------------------------------------------------------------------------- /sealed-secrets/controller.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1beta1 3 | kind: Role 4 | metadata: 5 | annotations: {} 6 | labels: 7 | name: sealed-secrets-key-admin 8 | name: sealed-secrets-key-admin 9 | namespace: kube-system 10 | rules: 11 | - apiGroups: 12 | - "" 13 | resources: 14 | - secrets 15 | verbs: 16 | - create 17 | - list 18 | --- 19 | apiVersion: rbac.authorization.k8s.io/v1beta1 20 | kind: ClusterRoleBinding 21 | metadata: 22 | annotations: {} 23 | labels: 24 | name: sealed-secrets-controller 25 | name: sealed-secrets-controller 26 | roleRef: 27 | apiGroup: rbac.authorization.k8s.io 28 | kind: ClusterRole 29 | name: secrets-unsealer 30 | subjects: 31 | - kind: ServiceAccount 32 | name: sealed-secrets-controller 33 | namespace: kube-system 34 | --- 35 | apiVersion: rbac.authorization.k8s.io/v1beta1 36 | kind: ClusterRole 37 | metadata: 38 | annotations: {} 39 | labels: 40 | name: secrets-unsealer 41 | name: secrets-unsealer 42 | rules: 43 | - apiGroups: 44 | - bitnami.com 45 | resources: 46 | - sealedsecrets 47 | verbs: 48 | - get 49 | - list 50 | - watch 51 | - apiGroups: 52 | - bitnami.com 53 | resources: 54 | - sealedsecrets/status 55 | verbs: 56 | - update 57 | - apiGroups: 58 | - "" 59 | resources: 60 | - secrets 61 | verbs: 62 | - get 63 | - create 64 | - update 65 | - delete 66 | - apiGroups: 67 | - "" 68 | resources: 69 | - events 70 | verbs: 71 | - create 72 | - patch 73 | --- 74 | apiVersion: v1 75 | kind: Service 76 | metadata: 77 | annotations: {} 78 | labels: 79 | name: sealed-secrets-controller 80 | name: sealed-secrets-controller 81 | namespace: kube-system 82 | spec: 83 | ports: 84 | - port: 8080 85 | targetPort: 8080 86 | selector: 87 | name: sealed-secrets-controller 88 | type: ClusterIP 89 | --- 90 | apiVersion: rbac.authorization.k8s.io/v1beta1 91 | kind: RoleBinding 92 | metadata: 93 | annotations: {} 94 | labels: 95 | name: sealed-secrets-service-proxier 96 | name: sealed-secrets-service-proxier 97 | namespace: kube-system 98 | roleRef: 99 | apiGroup: rbac.authorization.k8s.io 100 | kind: Role 101 | name: sealed-secrets-service-proxier 102 | subjects: 103 | - apiGroup: rbac.authorization.k8s.io 104 | kind: Group 105 | name: system:authenticated 106 | --- 107 | apiVersion: rbac.authorization.k8s.io/v1beta1 108 | kind: Role 109 | metadata: 110 | annotations: {} 111 | labels: 112 | name: sealed-secrets-service-proxier 113 | name: sealed-secrets-service-proxier 114 | namespace: kube-system 115 | rules: 116 | - apiGroups: 117 | - "" 118 | resourceNames: 119 | - 'http:sealed-secrets-controller:' 120 | - sealed-secrets-controller 121 | resources: 122 | - services/proxy 123 | verbs: 124 | - create 125 | - get 126 | --- 127 | apiVersion: rbac.authorization.k8s.io/v1beta1 128 | kind: RoleBinding 129 | metadata: 130 | annotations: {} 131 | labels: 132 | name: sealed-secrets-controller 133 | name: sealed-secrets-controller 134 | namespace: kube-system 135 | roleRef: 136 | apiGroup: rbac.authorization.k8s.io 137 | kind: Role 138 | name: sealed-secrets-key-admin 139 | subjects: 140 | - kind: ServiceAccount 141 | name: sealed-secrets-controller 142 | namespace: kube-system 143 | --- 144 | apiVersion: v1 145 | kind: ServiceAccount 146 | metadata: 147 | annotations: {} 148 | labels: 149 | name: sealed-secrets-controller 150 | name: sealed-secrets-controller 151 | namespace: kube-system 152 | --- 153 | apiVersion: apps/v1 154 | kind: Deployment 155 | metadata: 156 | annotations: {} 157 | labels: 158 | name: sealed-secrets-controller 159 | name: sealed-secrets-controller 160 | namespace: kube-system 161 | spec: 162 | minReadySeconds: 30 163 | replicas: 1 164 | revisionHistoryLimit: 10 165 | selector: 166 | matchLabels: 167 | name: sealed-secrets-controller 168 | strategy: 169 | rollingUpdate: 170 | maxSurge: 25% 171 | maxUnavailable: 25% 172 | type: RollingUpdate 173 | template: 174 | metadata: 175 | annotations: {} 176 | labels: 177 | name: sealed-secrets-controller 178 | spec: 179 | containers: 180 | - args: [] 181 | command: 182 | - controller 183 | env: [] 184 | image: quay.io/bitnami/sealed-secrets-controller:v0.13.1 185 | imagePullPolicy: Always 186 | livenessProbe: 187 | httpGet: 188 | path: /healthz 189 | port: http 190 | name: sealed-secrets-controller 191 | ports: 192 | - containerPort: 8080 193 | name: http 194 | readinessProbe: 195 | httpGet: 196 | path: /healthz 197 | port: http 198 | securityContext: 199 | readOnlyRootFilesystem: true 200 | runAsNonRoot: true 201 | runAsUser: 1001 202 | stdin: false 203 | tty: false 204 | volumeMounts: 205 | - mountPath: /tmp 206 | name: tmp 207 | imagePullSecrets: [] 208 | initContainers: [] 209 | securityContext: 210 | fsGroup: 65534 211 | serviceAccountName: sealed-secrets-controller 212 | terminationGracePeriodSeconds: 30 213 | volumes: 214 | - emptyDir: {} 215 | name: tmp 216 | --- 217 | apiVersion: apiextensions.k8s.io/v1beta1 218 | kind: CustomResourceDefinition 219 | metadata: 220 | name: sealedsecrets.bitnami.com 221 | spec: 222 | group: bitnami.com 223 | names: 224 | kind: SealedSecret 225 | listKind: SealedSecretList 226 | plural: sealedsecrets 227 | singular: sealedsecret 228 | scope: Namespaced 229 | subresources: 230 | status: {} 231 | version: v1alpha1 232 | 233 | -------------------------------------------------------------------------------- /team-a-infra/dummy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vfarcic/crossplane-kubevela-argocd-demo/3f0d80c4dbc34c6efe44d449b06d8574fa7e23ab/team-a-infra/dummy -------------------------------------------------------------------------------- /team-app-reqs/kubevela.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: core.oam.dev/v1beta1 2 | kind: ComponentDefinition 3 | metadata: 4 | name: backend 5 | annotations: 6 | definition.oam.dev/description: "It's backend and I'm too lazy to write descriptions" 7 | spec: 8 | workload: 9 | definition: 10 | apiVersion: apps/v1 11 | kind: Deployment 12 | schematic: 13 | cue: 14 | template: | 15 | output: { 16 | apiVersion: "apps/v1" 17 | kind: "Deployment" 18 | spec: { 19 | selector: matchLabels: { 20 | "app.oam.dev/component": context.name 21 | } 22 | template: { 23 | metadata: labels: { 24 | "app.oam.dev/component": context.name 25 | } 26 | spec: { 27 | containers: [{ 28 | name: context.name 29 | image: parameter.image 30 | 31 | if parameter["cmd"] != _|_ { 32 | command: parameter.cmd 33 | } 34 | }] 35 | } 36 | } 37 | } 38 | } 39 | parameter: { 40 | image: string 41 | cmd?: [...string] 42 | } 43 | 44 | --- 45 | 46 | apiVersion: core.oam.dev/v1beta1 47 | kind: ComponentDefinition 48 | metadata: 49 | name: frontend 50 | annotations: 51 | definition.oam.dev/description: "It's frontend and I'm too lazy to write descriptions" 52 | spec: 53 | workload: 54 | definition: 55 | apiVersion: apps/v1 56 | kind: Deployment 57 | schematic: 58 | kube: 59 | template: 60 | apiVersion: apps/v1 61 | kind: Deployment 62 | spec: 63 | selector: 64 | matchLabels: 65 | app.oam.dev/component: frontend 66 | template: 67 | metadata: 68 | labels: 69 | app.oam.dev/component: frontend 70 | spec: 71 | containers: 72 | - name: frontend 73 | ports: 74 | - containerPort: 80 75 | livenessProbe: 76 | httpGet: 77 | path: / 78 | port: 80 79 | readinessProbe: 80 | httpGet: 81 | path: / 82 | port: 80 83 | parameters: 84 | - name: name 85 | required: true 86 | type: string 87 | fieldPaths: 88 | - metadata.name 89 | - metadata.labels.app 90 | - spec.selector.matchLabels.app 91 | - spec.template.metadata.labels.app 92 | - name: image 93 | required: true 94 | type: string 95 | fieldPaths: 96 | - spec.template.spec.containers[0].image 97 | - name: port 98 | required: false 99 | type: number 100 | fieldPaths: 101 | - spec.template.spec.containers[0].ports[0].containerPort 102 | - spec.template.spec.containers[0].livenessProbe.httpGet.port 103 | - spec.template.spec.containers[0].readinessProbe.httpGet.port 104 | 105 | --- 106 | 107 | apiVersion: core.oam.dev/v1beta1 108 | kind: TraitDefinition 109 | metadata: 110 | annotations: 111 | definition.oam.dev/description: "configure k8s HPA for Deployment" 112 | name: autoscaler 113 | spec: 114 | appliesToWorkloads: 115 | - frontend 116 | schematic: 117 | cue: 118 | template: | 119 | outputs: hpa: { 120 | apiVersion: "autoscaling/v2beta2" 121 | kind: "HorizontalPodAutoscaler" 122 | metadata: name: context.name 123 | spec: { 124 | scaleTargetRef: { 125 | apiVersion: "apps/v1" 126 | kind: "Deployment" 127 | name: context.name 128 | } 129 | minReplicas: parameter.min 130 | maxReplicas: parameter.max 131 | metrics: [{ 132 | type: "Resource" 133 | resource: { 134 | name: "cpu" 135 | target: { 136 | type: "Utilization" 137 | averageUtilization: parameter.cpuUtil 138 | } 139 | } 140 | }] 141 | } 142 | } 143 | parameter: { 144 | min: *2 | int 145 | max: *6 | int 146 | cpuUtil: *80 | int 147 | } 148 | --------------------------------------------------------------------------------