diff --git a/content/master/getting-started/app-compositions.md b/content/master/getting-started/app-compositions.md new file mode 100644 index 000000000..b121791bc --- /dev/null +++ b/content/master/getting-started/app-compositions.md @@ -0,0 +1,545 @@ +--- +title: App Compositions Quickstart +weight: 200 +--- + +In the previous quickstarts, you learn how to build and access a custom API with Crossplane geared for Cloud infrastructure (such as a _bucket_). Crossplane's composition engine is equally suitable for composing resources on a Kubernetes app cluster. In this guide, you'll learn to create a Composite Resource API that deploys multiple resources together onto a Kubernetes cluster. + +## Prerequisites + +* A Kubernetes cluster with Crossplane installed. +* `kubectl` installed. + +## Create a custom application API + +Use the [composition]({{}}) feature of Crossplane to define a new Kubernetes API for deploying an application composed of a `Deployment`, a `Service`, and an `Ingress`. The custom API is a Kubernetes object. Below is an example of the API we'll create. + +```yaml {label="exAPI"} +apiVersion: application.example.com/v1alpha1 +kind: Application +metadata: + name: my-application +spec: + image: "nginx" + ingress: + enabled: false +``` + +### Apply the API + +Apply this XRD to create the custom application API in your Kubernetes cluster. + +```yaml {label="xrd",copy-lines="all"} +cat <}} +For more details on the fields and options of Composite Resource Definitions +read the +[XRD documentation]({{}}). +{{< /hint >}} + +View the installed XRD with `kubectl get xrd`. + +```shell {copy-lines="1"} +kubectl get xrd +NAME ESTABLISHED OFFERED AGE +xapplications.application.example.com True True 2s +``` + +View the new custom API endpoints with `kubectl api-resources | grep application` + +```shell {copy-lines="1",label="apiRes"} +kubectl api-resources | grep application +applications application.example.com/v1alpha1 true Application +xapplications application.example.com/v1alpha1 false XApplication +``` + +## Create a deployment template + +Define a [composition]({{}}) that takes the API inputs and templates the underlying Kubernetes resources. + +This template creates a `Deployment`, `Service`, and an `Ingress`. + +This Composition takes the user's container image input and optionally configures an ingress in the cluster. + +Crossplane's composition engine is flexible and supports a growing list of modules, called _composition functions_ to drive the templatization of resources. You can use: + +- [Patch and Transform](https://marketplace.upbound.io/functions/crossplane-contrib/function-patch-and-transform) +- [Go Templating](https://marketplace.upbound.io/functions/crossplane-contrib/function-go-templating) +- [KCL](https://marketplace.upbound.io/functions/crossplane-contrib/function-kcl/) +- [CUE](https://marketplace.upbound.io/functions/crossplane-contrib/function-cue) + +and more. You can find composition functions built by the community on the [Upbound Marketplace](https://marketplace.upbound.io/functions). The snippet below demonstrates two of these implementations. Pick whichever you prefer and apply the Composition to your cluster. + +{{< tabs >}} +{{< tab "Patch and Transform" >}} + +```yaml {label="comp",copy-lines="all"} +cat <}} +Read the [Composition documentation]({{}}) for +more information on configuring Compositions and all the available options. + +Read the +[Patch and Transform function documentation]({{}}) +for more information on how it uses patches to map user inputs to Composition +resource templates. +{{< /hint >}} + +{{< /tab >}} + +{{< tab "KCL" >}} + +Save the following to a file called `composition-kcl.yaml` locally, then apply it to your cluster: + +```yaml {label="comp",copy-lines="all"} +apiVersion: apiextensions.crossplane.io/v1 +kind: Composition +metadata: + name: app-composition +spec: + mode: Pipeline + pipeline: + - step: compose-kcl + functionRef: + name: function-kcl + input: + apiVersion: krm.kcl.dev/v1alpha1 + kind: KCLInput + metadata: + name: basic + spec: + target: Resources + source: | + oxr = option("params").oxr + deployment = { + apiVersion: "kubernetes.crossplane.io/v1alpha2" + kind: "Object" + metadata.name = "app-deployment" + spec.forProvider.manifest = { + apiVersion: "apps/v1" + kind: "Deployment" + metadata.namespace: "default" + metadata.annotations: { + "krm.kcl.dev/composition-resource-name" = "deployment" + } + spec = { + replicas: 3 + selector.matchLabels.app: oxr?.metadata?.name + template = { + metadata.labels.app: oxr?.metadata?.name + spec = { + containers = [{ + name: oxr?.metadata?.name + image: oxr?.spec?.image + ports = [{ + containerPort: 80 + }] + }] + } + } + } + } + } + service = { + apiVersion: "kubernetes.crossplane.io/v1alpha2" + kind: "Object" + metadata.name = "app-service" + metadata.annotations: { + "krm.kcl.dev/composition-resource-name" = "service" + } + spec.forProvider.manifest = { + apiVersion: "v1" + kind: "Service" + metadata.name: '${oxr.metadata.name}-service' + metadata.namespace: "default" + spec = { + selector.app: oxr?.metadata?.name + ports: [{ + protocol: "TCP" + port: 80 + targetPort: 80 + }] + } + } + } + ingress = [{ + apiVersion: "kubernetes.crossplane.io/v1alpha2" + kind: "Object" + metadata.name = "app-ingress" + metadata.annotations: { + "krm.kcl.dev/composition-resource-name" = "ingress" + } + spec.forProvider.manifest = { + apiVersion: "networking.k8s.io/v1" + kind: "Ingress" + metadata.name: '${oxr.metadata.name}-ingress' + metadata.namespace: "default" + annotations = { + "kubernetes.io/ingress.class": "alb" + "alb.ingress.kubernetes.io/scheme": "internet-facing" + "alb.ingress.kubernetes.io/target-type": "ip" + "alb.ingress.kubernetes.io/healthcheck-path": "/health" + "alb.ingress.kubernetes.io/listen-ports": '[{"HTTP": 80}]' + "alb.ingress.kubernetes.io/target-group-attributes": "stickiness.enabled=true,stickiness.lb_cookie.duration_seconds=60" + } + spec.rules = [{ + http.paths = [{ + path: "/" + pathType: "Prefix" + backend.service = { + name: oxr?.metadata?.name + port.number: 80 + } + }] + }] + } + }] if oxr?.spec.ingress.enabled else [] + _items = [deployment, service] + _items += ingress + items = _items + compositeTypeRef: + apiVersion: application.example.com/v1alpha1 + kind: XApplication +``` + +Apply it to your cluster: +```shell +kubectl apply -f composition-kcl.yaml +``` + +Apply this Function to install `function-kcl`: + +```yaml {label="install"} +cat <}} +Read the [Composition documentation]({{}}) for +more information on configuring Compositions and all the available options. +{{< /hint >}} + +{{< /tab >}} +{{< /tabs >}} + +View the Composition with `kubectl get composition` + +```shell {copy-lines="1"} +kubectl get composition +NAME XR-KIND XR-APIVERSION AGE +app-composition XApplication application.example.com/v1alpha1 5s +``` + +### Install and configure provider-kubernetes + +This guide uses _provider-kubernetes_ to compose resources running in the same cluster where Crossplane is installed. Install the provider in your cluster: + +```shell +cat <}} +Crossplane compositions natively compose Crossplane Managed Resources and _provider-kubernetes_ is crucial for enabling Crossplane to compose other types of Kubernetes resource. In the [Crossplane V2 proposal](https://blog.crossplane.io/announcing-crossplane-v2-proposal/), Crossplane compositions will natively support _any_ Kubernetes resource, not just Managed Resources. +{{< /hint >}} + +Read the provider-kubernetes [documentation](https://github.com/crossplane-contrib/provider-kubernetes) on GitHub to learn about advanced configuration options. + +## Access the custom API + +With the custom API (XRD) installed and associated to a resource template +(Composition) users can access the API to create resources. + +Create an {{}}Application{{}} object to create the +cloud resources. + +```yaml {copy-lines="all",label="xr"} +cat <}}) * [AWS Quickstart]({{}}) * [GCP Quickstart]({{}}) +* [App Compositions Quickstart]({{}}) diff --git a/content/master/getting-started/provider-aws-part-2.md b/content/master/getting-started/provider-aws-part-2.md index 48545b9db..3b57c9be0 100644 --- a/content/master/getting-started/provider-aws-part-2.md +++ b/content/master/getting-started/provider-aws-part-2.md @@ -601,3 +601,5 @@ No resources found Crossplane users and contributors. * Read more about the [Crossplane concepts]({{}}) to find out what else you can do with Crossplane. +* Learn how to use Crossplane to compose Kubernetes app resources. Read the [App Compositions Quickstart]({{}}). + diff --git a/content/master/getting-started/provider-azure-part-2.md b/content/master/getting-started/provider-azure-part-2.md index b2a083081..1376d1a5c 100644 --- a/content/master/getting-started/provider-azure-part-2.md +++ b/content/master/getting-started/provider-azure-part-2.md @@ -699,3 +699,4 @@ No resources found Crossplane users and contributors. * Read more about the [Crossplane concepts]({{}}) to find out what else you can do with Crossplane. +* Learn how to use Crossplane to compose Kubernetes app resources. Read the [App Compositions Quickstart]({{}}). diff --git a/content/master/getting-started/provider-gcp-part-2.md b/content/master/getting-started/provider-gcp-part-2.md index 6f0a1ddd4..09cb067de 100644 --- a/content/master/getting-started/provider-gcp-part-2.md +++ b/content/master/getting-started/provider-gcp-part-2.md @@ -605,4 +605,5 @@ No resources found * Join the [Crossplane Slack](https://slack.crossplane.io/) and connect with Crossplane users and contributors. * Read more about the [Crossplane concepts]({{}}) to find out what else you can do - with Crossplane. \ No newline at end of file + with Crossplane. +* Learn how to use Crossplane to compose Kubernetes app resources. Read the [App Compositions Quickstart]({{}}).