create v1.13 docs set

Signed-off-by: Pete Lumbis <pete@upbound.io>
This commit is contained in:
Pete Lumbis 2023-07-27 10:44:35 -04:00
parent 7f443f319d
commit f474acf16b
28 changed files with 17766 additions and 0 deletions

49
content/v1.13/_index.md Normal file
View File

@ -0,0 +1,49 @@
---
title: "Overview"
weight: -1
cascade:
version: "master"
---
{{< img src="/media/banner.png" alt="Crossplane Popsicle Truck" size="large" >}}
<br />
Crossplane is an open source Kubernetes extension that transforms your Kubernetes
cluster into a **universal control plane**.
Crossplane lets you manage anything, anywhere, all through standard Kubernetes
APIs. Crossplane can even let you
[order a pizza](https://blog.crossplane.io/providers-101-ordering-pizza-with-kubernetes-and-crossplane/)
directly from Kubernetes. If it has an API, Crossplane can connect to it.
With Crossplane, platform teams can create new abstractions and custom
APIs with the full power of Kubernetes policies, namespaces, role-based access
controls and more. Crossplane brings all your non-Kubernetes resources under
one roof.
Custom APIs, created by platform teams, allow security and compliance
enforcement across resources or clouds, without exposing any complexity to the
developers. A single API call can create multiple resources, in multiple clouds
and use Kubernetes as the control plane for everything.
{{< hint "tip" >}}
**What's a control plane?**
Control planes create and manage the lifecycle of resources. Control planes
constantly _check_ that the intended resources exist, _report_ when the intended
state doesn't match reality and _act_ to make things right.
Crossplane extends the Kubernetes control plane to be a **universal control
plane** to check, report and act on any resource, anywhere.
{{< /hint >}}
# Get Started
* [Install Crossplane]({{<ref "software/install">}}) in your Kubernetes cluster
* Learn more about how Crossplane works in the
[Crossplane introduction]({{<ref "getting-started/introduction" >}})
* Join the [Crossplane Slack](https://slack.crossplane.io/) and start a
conversation with a community of over 7,000 operators.
Crossplane is a [Cloud Native Compute Foundation](https://www.cncf.io/) project.

View File

@ -0,0 +1,56 @@
---
title: Concepts
weight: 100
description: Understand Crossplane's core components
---
Crossplane introduces multiple building blocks that enable you to provision,
compose, and consume infrastructure using the Kubernetes API. These individual
concepts work together to allow for powerful separation of concern between
different personas in an organization, meaning that each member of a team
interacts with Crossplane at an appropriate level of abstraction.
## Packages
[Packages] allow Crossplane to be extended to include new functionality. This
typically looks like bundling a set of Kubernetes [CRDs] and [controllers] that
represent and manage external infrastructure (i.e. a provider), then installing
them into a cluster where Crossplane is running. Crossplane handles making sure
any new CRDs do not conflict with existing ones, as well as manages the RBAC and
security of new packages. Packages are not strictly required to be providers,
but it is the most common use-case for packages at this time.
## Providers
Providers are packages that enable Crossplane to provision infrastructure on an
external service. They bring CRDs (i.e. managed resources) that map one-to-one
to external infrastructure resources, as well as controllers to manage the
life-cycle of those resources. You can read more about providers, including how
to install and configure them, in the [providers documentation].
## Managed Resources
Managed resources are Kubernetes custom resources that represent infrastructure
primitives. Managed resources with an API version of `v1beta1` or higher support
every field that the cloud provider does for the given resource. You can find
the Managed Resources and their API specifications for each provider on
the [Upbound Marketplace] and learn more in the [managed resources documentation].
## Composite Resources
A composite resource (XR) is a special kind of custom resource that is defined
by a `CompositeResourceDefinition`. It composes one or more managed resources
into a higher level infrastructure unit. Composite resources are infrastructure
operator facing, but may optionally offer an application developer facing
composite resource claim that acts as a proxy for a composite resource. You can
learn more about all of these concepts in the [composition documentation].
<!-- Named Links -->
[Packages]: {{<ref "packages" >}}
[CRDs]: https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/
[controllers]: https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#custom-controllers
[providers documentation]: {{<ref "providers" >}}
[Upbound Marketplace]: https://marketplace.upbound.io
[managed resources documentation]: {{<ref "managed-resources" >}}
[composition documentation]: {{<ref "./compositions" >}}

View File

@ -0,0 +1,208 @@
---
title: Claims
weight: 60
description: "Claims are a way to consume Crossplane resources with namespace scoping"
---
Claims represents a set of managed resources as a single
Kubernetes object, inside a namespace.
Users create claims when they access the
custom API, defined in the CompositeResourceDefinition.
{{< hint "tip" >}}
Claims are like [composite resources]({{<ref "./composite-resources">}}). The
difference between Claims and composite resources is Crossplane can create
Claims in a namespace, while composite resources are cluster scoped.
{{< /hint >}}
{{<expand "Confused about Compositions, XRDs, XRs and Claims?" >}}
Crossplane has four core components that users commonly mix up:
* [Compositions]({{<ref "./compositions">}}) - A template to define how to create resources.
* [Composite Resource Definition]({{<ref "./composite-resource-definitions">}})
(`XRD`) - A custom API specification.
* [Composite Resources]({{<ref "./composite-resources">}}) (`XR`) - Created by
using the custom API defined in a Composite Resource Definition. XRs use the
Composition template to create new managed resources.
* Claims (`XRC`) - This page. Like a Composite Resource, but
with namespace scoping.
{{</expand >}}
## Creating a Claim
Creating a Claim requires a
[Composition]({{<ref "./compositions">}}) and a
[CompositeResourceDefinition]({{<ref "./composite-resource-definitions">}})
(`XRD`) already installed.
{{<hint "note" >}}
The XRD must
[enable Claims]({{<ref "./composite-resource-definitions#enable-claims">}}).
{{< /hint >}}
The Composition defines the set of resources to create.
The XRD defines the custom API users call to request the set of resources.
![Diagram of the relationship of Crossplane components](/media/composition-how-it-works.svg)
For example,
this {{<hover label="xrd1" line="2">}}CompositeResourceDefinition{{</hover>}}
creates a composite resource API endpoint
{{<hover label="xrd1" line="4">}}xmydatabases.example.org{{</hover>}} and
enables a Claim API endpoint
{{<hover label="xrd1" line="11">}}database.example.org{{</hover>}}
```yaml {label="xrd1",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xmydatabases.example.org
spec:
group: example.org
names:
kind: XMyDatabase
plural: xmydatabases
claimNames:
kind: Database
plural: databases
# Removed for brevity
```
The Claim uses the XRD's
{{<hover label="xrd1" line="11">}}kind{{</hover>}} API endpoint to request
resources.
The Claim's {{<hover label="xrd1" line="1">}}apiVersion{{</hover>}} matches
the XRD {{<hover label="xrd1" line="6">}}group{{</hover>}} and the
{{<hover label="claim1" line="2">}}kind{{</hover>}} matches the XRD
{{<hover label="xrd1" line="11">}}claimNames.kind{{</hover>}}
```yaml {label="claim1",copy-lines="none"}
apiVersion: example.org/v1alpha1
kind: database
metadata:
name: my-claimed-database
spec:
# Removed for brevity
```
When a user creates a Claim in a namespace Crossplane also creates a composite
resource.
Use {{<hover label="claimcomp" line="1">}}kubectl describe{{</hover>}} on the
Claim to view the related composite resource.
The {{<hover label="claimcomp" line="6">}}Resource Ref{{</hover>}} is the
composite resource Crossplane created for this Claim.
```shell {label="claimcomp",copy-lines="1"}
kubectl describe database.example.org/my-claimed-database
Name: my-claimed-database
API Version: example.org/v1alpha1
Kind: database
Spec:
Resource Ref:
API Version: example.org/v1alpha1
Kind: XMyDatabase
Name: my-claimed-database-rr4ll
# Removed for brevity.
```
Use {{<hover label="getcomp" line="1">}}kubectl describe{{</hover>}} on the
composite resource to view the
{{<hover label="getcomp" line="6">}}Claim Ref{{</hover>}} linking the
composite resource to the original Claim.
```shell {label="getcomp",copy-lines="1"}
kubectl describe xmydatabase.example.org/my-claimed-database-rr4ll
Name: my-claimed-database-rr4ll
API Version: example.org/v1alpha1
Kind: XMyDatabase
Spec:
Claim Ref:
API Version: example.org/v1alpha1
Kind: database
Name: my-claimed-database
Namespace: default
```
{{<hint "note" >}}
Crossplane supports directly creating composite resources. Claims allow
namespace scoping and isolation for users consuming the custom APIs.
If you don't use namespaces in your Kubernetes deployment Claims aren't necessary.
{{< /hint >}}
### Claiming existing composite resources
By default, creating a Claim creates a new composite resource. Claims can also
link to existing composite resources.
A use case for claiming existing composite resources may be slow to provision
resources. Composite resources can be pre-provisioned and a Claim can
use those resources without waiting for their creation.
Set the Claim's {{<hover label="resourceref" line="6">}}resourceRef{{</hover>}}
and match the pre-existing composite resource
{{<hover label="resourceref" line="9">}}name{{</hover>}}.
```yaml {label="resourceref",copy-lines="none"}
apiVersion: example.org/v1alpha1
kind: database
metadata:
name: my-claimed-database
spec:
resourceRef:
apiVersion: example.org/v1alpha1
kind: XMyDatabase
name: my-pre-created-xr
```
If a Claim specifies a
{{<hover label="resourceref" line="6">}}resourceRef{{</hover>}} that doesn't
exist, Crossplane doesn't create a composite resource.
{{<hint "note" >}}
All Claims have a
{{<hover label="resourceref" line="6">}}resourceRef{{</hover>}}. Manually
defining the
{{<hover label="resourceref" line="6">}}resourceRef{{</hover>}}
isn't required. Crossplane fills in the
{{<hover label="resourceref" line="6">}}resourceRef{{</hover>}}
with the information from the composite resource created for the Claim.
{{< /hint >}}
## Claim connection secrets
If a Claim expects connection secrets the Claim must define a
{{<hover label="claimSec" line="6">}}writeConnectionSecretToRef{{</hover>}}
object.
The
{{<hover label="claimSec" line="6">}}writeConnectionSecretToRef{{</hover>}}
object defines the name of the Kubernetes secret object where Crossplane saves
the connection details.
{{<hint "note" >}}
The Crossplane creates the secret object in the same namespace as the Claim.
{{< /hint >}}
For example, to a new secret object named
{{<hover label="claimSec" line="7">}}my-claim-secret{{</hover>}} use
{{<hover label="claimSec" line="6">}}writeConnectionSecretToRef{{</hover>}} with
the
{{<hover label="claimSec" line="7">}}name: my-claim-secret{{</hover>}}.
```yaml {label="claimSec"}
apiVersion: example.org/v1alpha1
kind: database
metadata:
name: my-claimed-database
spec:
writeConnectionSecretToRef:
name: my-claim-secret
```
For more information on connection secrets read the [Connection Secrets
knowledge base article]({{<ref "/knowledge-base/guides/connection-details">}}).

View File

@ -0,0 +1,841 @@
---
title: Composite Resource Definitions
weight: 40
description: "Composite Resource Definitions or XRDs define custom API schemas"
---
Composite resource definitions (`XRDs`) define the schema for a custom API.
Users create composite resources (`XRs`) and Claims (`XCs`) using the API
schema defined by an `XRD`.
{{< hint "note" >}}
Read the [composite resources]({{<ref "./composite-resources">}}) page for more
information about composite resources.
Read the [Claims]({{<ref "./claims">}}) page for more
information about Claims.
{{</hint >}}
{{<expand "Confused about Compositions, XRDs, XRs and Claims?" >}}
Crossplane has four core components that users commonly mix up:
* [Compositions]({{<ref "./compositions" >}}) - A template to define how to create resources.
* Composite Resource Definition (`XRD`) - This page. A custom API specification.
* [Composite Resource]({{<ref "./composite-resources">}}) (`XR`) - Created by
using the custom API defined in a Composite Resource Definition. XRs use the
Composition template to create new managed resources.
* [Claims]({{<ref "./claims" >}}) (`XRC`) - Like a Composite Resource, but
with namespace scoping.
{{</expand >}}
Crossplane XRDs are like
[Kubernetes custom resource definitions](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/).
XRDs require fewer fields and add options related to Crossplane, like Claims and
connection secrets.
## Creating a CompositeResourceDefinition
Creating a CompositeResourceDefinition consists of:
* [Defining a custom API group](#xrd-groups).
* [Defining a custom API name](#xrd-names).
* [Defining a custom API schema and version](#xrd-versions).
Optionally, CompositeResourceDefinitions also support:
* [Offering a Claim](#enable-claims).
* [Defining connection secrets](#manage-connection-secrets).
* [Setting composite resource defaults](#set-composite-resource-defaults).
Composite resource definitions (`XRDs`) create new API endpoints inside a
Kubernetes cluster.
Creating a new API requires defining an API
{{<hover label="xrd1" line="6">}}group{{</hover>}},
{{<hover label="xrd1" line="7">}}name{{</hover>}} and
{{<hover label="xrd1" line="10">}}version{{</hover>}}.
```yaml {label="xrd1",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xmydatabases.example.org
spec:
group: example.org
names:
kind: XMyDatabase
plural: xmydatabases
versions:
- name: v1alpha1
# Removed for brevity
```
After applying an XRD, Crossplane creates a new Kubernetes custom resource
definition matching the defined API.
For example, the XRD
{{<hover label="xrd1" line="4">}}xmydatabases.example.org{{</hover >}}
creates a custom resource definition
{{<hover label="kubeapi" line="2">}}xmydatabases.example.org{{</hover >}}.
```shell {label="kubeapi",copy-lines="3"}
kubectl api-resources
NAME SHORTNAMES APIVERSION NAMESPACED KIND
xmydatabases.example.org v1alpha1 false xmydatabases
# Removed for brevity
```
{{<hint "warning">}}
You can't change the XRD
{{<hover label="xrd1" line="6">}}group{{</hover>}} or
{{<hover label="xrd1" line="7">}}names{{</hover>}}.
You must delete and
recreate the XRD to change the
{{<hover label="xrd1" line="6">}}group{{</hover>}} or
{{<hover label="xrd1" line="7">}}names{{</hover>}}.
{{</hint >}}
### XRD groups
Groups define a collection of related API endpoints. The `group` can be any
value, but common convention is to map to a fully qualified domain name.
<!-- vale write-good.Weasel = NO -->
Many XRDs may use the same `group` to create a logical collection of APIs.
<!-- vale write-good.Weasel = YES -->
For example a `database` group may have a `relational` and `nosql` kinds.
{{<hint "tip" >}}
Group names are cluster scoped. Choose group names that don't conflict with
Providers.
Avoid Provider names in the group.
{{< /hint >}}
### XRD names
The `names` field defines how to refer to this specific XRD.
The required name fields are:
* `kind` - the `kind` value to use when calling this API. The kind is
[UpperCamelCased](https://kubernetes.io/docs/contribute/style/style-guide/#use-upper-camel-case-for-api-objects).
Crossplane recommends starting XRD `kinds` with an `X` to show
it's a custom Crossplane API definition.
* `plural` - the plural name used for the API URL. The plural name must be
lowercase.
{{<hint "important" >}}
The XRD
{{<hover label="xrdName" line="4">}}metadata.name{{</hover>}} must be
{{<hover label="xrdName" line="9">}}plural{{</hover>}} name, `.` (dot character),
{{<hover label="xrdName" line="6">}}group{{</hover>}}.
For example, {{<hover label="xrdName"
line="4">}}xmydatabases.example.org{{</hover>}} matches the {{<hover
label="xrdName" line="9">}}plural{{</hover>}} name
{{<hover label="xrdName" line="9">}}xmydatabases{{</hover>}}, `.`
{{<hover label="xrdName" line="6">}}group{{</hover>}} name,
{{<hover label="xrdName" line="6">}}example.org{{</hover>}}.
```yaml {label="xrdName",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xmydatabases.example.org
spec:
group: example.org
names:
kind: XMyDatabase
plural: xmydatabases
# Removed for brevity
```
{{</hint >}}
### XRD versions
<!-- vale gitlab.SentenceLength = NO -->
The XRD `version` is like the
[API versioning used by Kubernetes](https://kubernetes.io/docs/reference/using-api/#api-versioning).
The version shows how mature or stable the API is and increments when changing,
adding or removing fields in the API.
<!-- vale gitlab.SentenceLength = YES -->
Crossplane doesn't require specific versions or a specific version naming
convention, but following
[Kubernetes API versioning guidelines](https://kubernetes.io/docs/reference/using-api/#api-versioning)
is strongly recommended.
* `v1alpha1` - A new API that may change at any time.
* `v1beta1` - An existing API that's considered stable. Breaking changes are
strongly discouraged.
* `v1` - A stable API that doesn't have breaking changes.
#### Define a schema
<!-- vale write-good.Passive = NO -->
<!-- vale write-good.TooWordy = NO -->
The `schema` defines the names
of the parameters, the data types of the parameters and which parameters are
required or optional.
<!-- vale write-good.Passive = YES -->
<!-- vale write-good.TooWordy = YES -->
{{<hint "note" >}}
All `schemas` follow the Kubernetes custom resource definition
[OpenAPIv3 structural schema](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#specifying-a-structural-schema).
{{< /hint >}}
Each
{{<hover label="schema" line="11">}}version{{</hover>}} of the API has a unique
{{<hover label="schema" line="12">}}schema{{</hover>}}.
All XRD {{<hover label="schema" line="12">}}schemas{{</hover>}} validate against
the {{<hover label="schema" line="13">}}openAPIV3Schema{{</hover>}}. The schema
is an OpenAPI
{{<hover label="schema" line="14">}}object{{</hover>}} with the
{{<hover label="schema" line="15">}}properties{{</hover>}} of a
{{<hover label="schema" line="16">}}spec{{</hover>}}
{{<hover label="schema" line="17">}}object{{</hover>}}.
Inside the {{<hover label="schema" line="18">}}spec.properties{{</hover>}} is the custom
API definition.
In this example, the key {{<hover label="schema" line="19">}}region{{</hover>}}
is a {{<hover label="schema" line="20">}}string{{</hover>}}.
```yaml {label="schema",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.custom-api.example.org
spec:
group: custom-api.example.org
names:
kind: xDatabase
plural: xdatabases
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
region:
type: string
# Removed for brevity
```
A composite resource using this API references the
{{<hover label="xr" line="1">}}group/version{{</hover>}} and
{{<hover label="xr" line="2">}}kind{{</hover>}}. The
{{<hover label="xr" line="5">}}spec{{</hover>}} has the
{{<hover label="xr" line="6">}}region{{</hover>}} key with a string value.
```yaml {label="xr"}
apiVersion: custom-api.example.org/v1alpha1
kind: xDatabase
metadata:
name: my-composite-resource
spec:
region: "US"
```
{{<hint "tip" >}}
The custom API defined inside the
{{<hover label="schema" line="18">}}spec.properties{{</hover>}} is an OpenAPIv3
specification. The
[data models page](https://swagger.io/docs/specification/data-models/) of
the Swagger documentation provides a list of examples using data types and input
restrictions.
The Kubernetes documentation lists
[the set of special restrictions](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#validation)
on what your OpenAPIv3 custom API can use.
{{< /hint >}}
{{<hint "important" >}}
Changing or expanding the XRD schema requires restarting the [Crossplane
pod]({{<ref "./pods#crossplane-pod">}}) to take effect.
{{< /hint >}}
##### Required fields
By default all fields in a schema are optional. Define a parameter as required
with the
{{< hover label="required" line="25">}}required{{</hover>}} attribute.
In this example the XRD requires
{{< hover label="required" line="19">}}region{{</hover>}} and
{{< hover label="required" line="21">}}size{{</hover>}} but
{{< hover label="required" line="23">}}name{{</hover>}} is optional.
```yaml {label="required",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.custom-api.example.org
spec:
group: custom-api.example.org
names:
kind: xDatabase
plural: xdatabases
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
region:
type: string
size:
type: string
name:
type: string
required:
- region
- size
# Removed for brevity
```
According to the OpenAPIv3 specification, the `required` field is per-object. If
a schema contains multiple objects the schema may need multiple `required`
fields.
This XRD defines two objects:
1. the top-level {{<hover label="required2" line="7">}}spec{{</hover>}} object
2. a second {{<hover label="required2" line="14">}}location{{</hover>}} object
The {{<hover label="required2" line="7">}}spec{{</hover>}} object
{{<hover label="required2" line="23">}}requires{{</hover>}} the
{{<hover label="required2" line="10">}}size{{</hover>}} and
{{<hover label="required2" line="14">}}location{{</hover>}} but
{{<hover label="required2" line="12">}}name{{</hover>}} is optional.
Inside the required {{<hover label="required2" line="14">}}location{{</hover>}}
object,
{{<hover label="required2" line="17">}}country{{</hover>}} is
{{<hover label="required2" line="21">}}required{{</hover>}} and
{{<hover label="required2" line="19">}}zone{{</hover>}} is optional.
```yaml {copy-lines="none",label="required2"}
# Removed for brevity
- name: v1alpha1
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
size:
type: string
name:
type: string
location:
type: object
properties:
country:
type: string
zone:
type: string
required:
- country
required:
- size
- location
```
The Swagger "[Describing
Parameters](https://swagger.io/docs/specification/describing-parameters/)"
documentation has more examples.
##### Crossplane reserved fields
Crossplane doesn't allow the following fields in a schema:
* `spec.resourceRef`
* `spec.resourceRefs`
* `spec.claimRef`
* `spec.writeConnectionSecretToRef`
* `status.conditions`
* `status.connectionDetails`
Crossplane ignores any fields matching the reserved fields.
#### Serve and reference a schema
To use a schema it must be
{{<hover label="served" line="12" >}}served: true{{</hover >}}
and
{{<hover label="served" line="13" >}}referenceable: true{{</hover>}}.
```yaml {label="served"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.custom-api.example.org
spec:
group: custom-api.example.org
names:
kind: xDatabase
plural: xdatabases
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
region:
type: string
```
Composite resources can use any schema version set as
{{<hover label="served" line="12" >}}served: true{{</hover >}}.
Kubernetes rejects any composite resource using a schema version set as `served:
false`.
{{< hint "tip" >}}
Setting a schema version as `served:false` causes errors for users using an older
schema. This can be an effective way to identify and upgrade users before
deleting the older schema version.
{{< /hint >}}
The {{<hover label="served" line="13" >}}referenceable: true{{</hover>}}
field indicates which version of the schema Compositions use. Only one
version can be `referenceable`.
{{< hint "note" >}}
Changing which version is `referenceable:true` requires [updating the
`compositeTypeRef.apiVersion`]({{<ref "./compositions#enabling-composite-resources" >}})
of any Compositions referencing that XRD.
{{< /hint >}}
#### Multiple schema versions
{{<hint "warning" >}}
Crossplane supports defining multiple `versions`, but the schema of each version
can't change any existing fields, also called "making a breaking change."
Breaking schema changes between versions requires the use of [conversion
webhooks](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning/#webhook-conversion).
New versions may define new optional parameters, but new required fields are
a "breaking change."
<!-- vale Crossplane.Spelling = NO -->
<!-- ignore to allow for CRDs -->
<!-- don't add to the spelling exceptions to catch when it's used instead of XRD -->
Crossplane XRDs use Kubernetes custom resource definitions for versioning.
Read the Kubernetes documentation on
[versions in CustomResourceDefinitions](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning/)
for more background on versions and breaking changes.
<!-- vale Crossplane.Spelling = YES -->
Crossplane recommends implementing breaking schema changes as brand new XRDs.
{{< /hint >}}
For XRDs, to create a new version of an API add a new
{{<hover label="ver" line="21">}}name{{</hover>}} in the
{{<hover label="ver" line="10">}}versions{{</hover>}}
list.
For example, this XRD version
{{<hover label="ver" line="11">}}v1alpha1{{</hover>}} only has the field
{{<hover label="ver" line="19">}}region{{</hover>}}.
A second version,
{{<hover label="ver" line="21">}}v1{{</hover>}} expands the API to have both
{{<hover label="ver" line="29">}}region{{</hover>}} and
{{<hover label="ver" line="31">}}size{{</hover>}}.
```yaml {label="ver",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.custom-api.example.org
spec:
group: custom-api.example.org
names:
kind: xDatabase
plural: xdatabases
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
region:
type: string
- name: v1
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
region:
type: string
size:
type: string
```
{{<hint "important" >}}
Changing or expanding the XRD schema requires restarting the [Crossplane
pod]({{<ref "./pods#crossplane-pod">}}) to take effect.
{{< /hint >}}
### Enable Claims
Optionally, XRDs can allow Claims to use the XRD API.
{{<hint "note" >}}
Read the [Claims]({{<ref "./claims">}}) page for more
information about Claims.
{{</hint >}}
XRDs offer Claims with a
{{<hover label="claim" line="10">}}claimNames{{</hover >}} object.
The {{<hover label="claim" line="10">}}claimNames{{</hover >}} defines a
{{<hover label="claim" line="11">}}kind{{</hover >}} and
{{<hover label="claim" line="12">}}plural{{</hover >}} like the XRD
{{<hover label="claim" line="7">}}names{{</hover >}} object.
Also like XRD
{{<hover label="claim" line="7">}}names{{</hover >}}, use UpperCamelCase
for the
{{<hover label="claim" line="11">}}kind{{</hover >}} and lowercase for the
{{<hover label="claim" line="12">}}plural{{</hover >}}.
The Claim
{{<hover label="claim" line="11">}}kind{{</hover >}} and
{{<hover label="claim" line="12">}}plural{{</hover >}} must be unique. They
can't match any other Claim or other XRD
{{<hover label="claim" line="8">}}kind{{</hover >}}.
{{<hint "tip" >}}
Common Crossplane convention is to use
{{<hover label="claim" line="10">}}claimNames{{</hover >}} that match the XRD
{{<hover label="claim" line="7">}}names{{</hover >}}, but without the beginning
"x."
{{</hint >}}
```yaml {label="claim",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.custom-api.example.org
spec:
group: custom-api.example.org
names:
kind: xDatabase
plural: xdatabases
claimNames:
kind: Database
plural: databases
versions:
# Removed for brevity
```
{{<hint "important" >}}
You can't change the
{{<hover label="claim" line="10">}}claimNames{{</hover >}}
after they're defined. You must delete and
recreate the XRD to change the
{{<hover label="claim" line="10">}}claimNames{{</hover >}}.
{{</hint >}}
### Manage connection secrets
When a composite resource creates managed resources, Crossplane provides any
[connection secrets]({{<ref "./managed-resources#writeconnectionsecrettoref">}})
to the composite resource or Claim. This requires the creators of composite
resources and Claims to know the secrets provided by a managed resource.
In other cases, Crossplane administrators may not want to expose some or all the
generated connection secrets.
XRDs can define a list of
{{<hover label="key" line="10">}}connectionSecretKeys{{</hover>}}
to limit what's provided to a composite resource or Claim.
Crossplane only provides the keys listed in the
{{<hover label="key" line="10">}}connectionSecretKeys{{</hover>}}
to the composite resource or Claim using this XRD. Any other connection
secrets aren't passed to the composite resource or Claim.
{{<hint "important" >}}
The keys listed in the
{{<hover label="key" line="10">}}connectionSecretKeys{{</hover>}} must match the
key names listed in the Composition's `connectionDetails`.
An XRD ignores any keys listed that aren't created by a managed resource.
For more information read the
[Composition documentation]({{<ref "./compositions#storing-connection-details">}}).
{{< /hint >}}
For example, an XRD passes the keys
{{<hover label="key" line="11">}}username{{</hover>}},
{{<hover label="key" line="12">}}password{{</hover>}} and
{{<hover label="key" line="13">}}address{{</hover>}}.
Composite resources or Claims save these in the secret defined by their
`writeConnectionSecretToRef` field.
```yaml {label="key",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.custom-api.example.org
spec:
group: custom-api.example.org
names:
kind: xDatabase
plural: xdatabases
connectionSecretKeys:
- username
- password
- address
versions:
# Removed for brevity
```
{{<hint "warning">}}
You can't change the `connectionSecretKeys` of an XRD. You must delete and
recreate the XRD to change the `connectionSecretKeys`.
{{</hint >}}
For more information on connection secrets read the [Connection Secrets
knowledge base article]({{<ref "/knowledge-base/guides/connection-details">}}).
### Set composite resource defaults
XRDs can set default parameters for composite resources and Claims.
<!-- vale off -->
#### defaultCompositeDeletePolicy
<!-- vale on -->
The `defaultCompositeDeletePolicy` defines the deletion policy for composite
resources and claims.
Using a `defaultCompositeDeletePolicy: Background` policy deletes
the composite resource or Claim and relies on Kubernetes to delete the remaining
dependent objects, like managed resources or secrets.
Using `defaultCompositeDeletePolicy: Foreground` causes Kubernetes to attach a
`foregroundDeletion` finalizer to the composite resource or Claim. Kubernetes
deletes all the dependent objects before deleting the composite resource or
Claim.
The default value is `defaultCompositeDeletePolicy: Background`.
Set
{{<hover label="delete" line="6">}}defaultCompositeDeletePolicy: Foreground{{</hover>}}
to change the XRD deletion policy.
```yaml {label="delete",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.custom-api.example.org
spec:
defaultCompositeDeletePolicy: Foreground
group: custom-api.example.org
names:
# Removed for brevity
versions:
# Removed for brevity
```
<!-- vale off -->
#### defaultCompositionRef
<!-- vale on -->
It's possible for multiple [Compositions]({{<ref "./compositions">}}) to
reference the same XRD. If more than one Composition references the same XRD,
the composite resource or Claim must select which Composition to use.
An XRD can define the default Composition to use with the
`defaultCompositionRef` value.
Set a
{{<hover label="defaultComp" line="6">}}defaultCompositionRef{{</hover>}}
to set the default Composition.
```yaml {label="defaultComp",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.custom-api.example.org
spec:
defaultCompositionRef:
name: myComposition
group: custom-api.example.org
names:
# Removed for brevity
versions:
# Removed for brevity
```
<!-- vale off -->
#### defaultCompositionUpdatePolicy
<!-- vale on -->
Changes to a Composition generate a new Composition revision. By default all
composite resources and Claims use the updated Composition revision.
Set the XRD `defaultCompositionUpdatePolicy` to `Manual` to prevent composite
resources and Claims from automatically using the new revision.
The default value is `defaultCompositionUpdatePolicy: Automatic`.
Set {{<hover label="compRev" line="6">}}defaultCompositionUpdatePolicy: Manual{{</hover>}}
to set the default Composition update policy for composite resources and Claims
using this XRD.
```yaml {label="compRev",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.custom-api.example.org
spec:
defaultCompositionUpdatePolicy: Manual
group: custom-api.example.org
names:
# Removed for brevity
versions:
# Removed for brevity
```
<!-- vale off -->
#### enforcedCompositionRef
<!-- vale on -->
To require all composite resources or Claims to use a specific Composition use
the `enforcedCompositionRef` setting in the XRD.
For example, to require all composite resources and Claims using this XRD to use
the Composition
{{<hover label="enforceComp" line="6">}}myComposition{{</hover>}}
set
{{<hover label="enforceComp" line="6">}}enforcedCompositionRef.name: myComposition{{</hover>}}.
```yaml {label="defaultComp",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.custom-api.example.org
spec:
enforcedCompositionRef:
name: myComposition
group: custom-api.example.org
names:
# Removed for brevity
versions:
# Removed for brevity
```
## Verify a CompositeResourceDefinition
Verify an XRD with `kubectl get compositeresourcedefinition` or the short form,
{{<hover label="getxrd" line="1">}}kubectl get xrd{{</hover>}}.
```yaml {label="getxrd",copy-lines="1"}
kubectl get xrd
NAME ESTABLISHED OFFERED AGE
xdatabases.custom-api.example.org True True 22m
```
The `ESTABLISHED` field indicates Crossplane installed the Kubernetes custom
resource definition for this XRD.
The `OFFERED` field indicates this XRD offers a Claim and Crossplane installed
the Kubernetes custom resource definitions for the Claim.
### XRD conditions
Crossplane uses a standard set of `Conditions` for XRDs.
View the conditions of a XRD under their `Status` with
`kubectl describe xrd`.
```yaml {copy-lines="none"}
kubectl describe xrd
Name: xpostgresqlinstances.database.starter.org
API Version: apiextensions.crossplane.io/v1
Kind: CompositeResourceDefinition
# Removed for brevity
Status:
Conditions:
Reason: WatchingCompositeResource
Status: True
Type: Established
Reason: WatchingCompositeResourceClaim
Status: True
Type: Offered
# Removed for brevity
```
<!-- vale off -->
#### WatchingCompositeResource
<!-- vale on -->
`Reason: WatchingCompositeResource` indicates Crossplane defined the new
Kubernetes custom resource definitions related to the composite resource and is
watching for the creation of new composite resources.
```yaml
Type: Established
Status: True
Reason: WatchingCompositeResource
```
<!-- vale off -->
#### TerminatingCompositeResource
<!-- vale on -->
`Reason: TerminatingCompositeResource` indicates Crossplane is deleting the
custom resource definitions related to the composite resource and is
terminating the composite resource controller.
```yaml
Type: Established
Status: False
Reason: TerminatingCompositeResource
```
<!-- vale off -->
#### WatchingCompositeResourceClaim
<!-- vale on -->
`Reason: WatchingCompositeResourceClaim` indicates Crossplane defined the new
Kubernetes custom resource definitions related to the offered Claims and is
watching for the creation of new Claims.
```yaml
Type: Offered
Status: True
Reason: WatchingCompositeResourceClaim
```
<!-- vale off -->
#### TerminatingCompositeResourceClaim
<!-- vale on -->
`Reason: TerminatingCompositeResourceClaim` indicates Crossplane is deleting the
custom resource definitions related to the offered Claims and is
terminating the Claims controller.
```yaml
Type: Offered
Status: False
Reason: TerminatingCompositeResourceClaim
```

View File

@ -0,0 +1,472 @@
---
title: Composite Resources
weight: 50
description: "Composite resources, an XR or XRs, represent a collection of related cloud resources."
---
A composite resource represents a set of managed resources as a single
Kubernetes object. Crossplane creates composite resources when users access a
custom API, defined in the CompositeResourceDefinition.
{{<hint "tip" >}}
Composite resources are a _composite_ of managed resources.
A _Composition_ defines how to _compose_ the managed resources together.
{{< /hint >}}
{{<expand "Confused about Compositions, XRDs, XRs and Claims?" >}}
Crossplane has four core components that users commonly mix up:
* [Compositions]({{<ref "./compositions">}}) - A template to define how to create resources.
* [Composite Resource Definition]({{<ref "./composite-resource-definitions">}})
(`XRD`) - A custom API specification.
* Composite Resource (`XR`) - This page. Created by
using the custom API defined in a Composite Resource Definition. XRs use the
Composition template to create new managed resources.
* [Claims]({{<ref "./claims" >}}) (`XRC`) - Like a Composite Resource, but
with namespace scoping.
{{</expand >}}
## Creating composite resources
Creating composite resources requires a
[Composition]({{<ref "./compositions">}}) and a
[CompositeResourceDefinition]({{<ref "./composite-resource-definitions">}})
(`XRD`).
The Composition defines the set of resources to create.
The XRD defines the custom API users call to request the set of resources.
![Diagram of the relationship of Crossplane components](/media/composition-how-it-works.svg)
XRDs define the API used to create a composite resource.
For example,
this {{<hover label="xrd1" line="2">}}CompositeResourceDefinition{{</hover>}}
creates a custom API endpoint
{{<hover label="xrd1" line="4">}}xmydatabases.example.org{{</hover>}}.
```yaml {label="xrd1",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xmydatabases.example.org
spec:
group: example.org
names:
kind: xMyDatabase
plural: xmydatabases
# Removed for brevity
```
When a user calls the custom API,
{{<hover label="xrd1" line="4">}}xmydatabases.example.org{{</hover>}},
Crossplane chooses the Composition to use based on the Composition's
{{<hover label="typeref" line="6">}}compositeTypeRef{{</hover>}}
```yaml {label="typeref",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: my-composition
spec:
compositeTypeRef:
apiVersion: example.org/v1alpha1
kind: xMyDatabase
# Removed for brevity
```
The Composition
{{<hover label="typeref" line="6">}}compositeTypeRef{{</hover>}} matches the
XRD {{<hover label="xrd1" line="6">}}group{{</hover>}} and
{{<hover label="xrd1" line="9">}}kind{{</hover>}}.
Crossplane creates the resources defined in the matching Composition and
represents them as a single `composite` resource.
```shell{copy-lines="1"}
kubectl get composite
NAME SYNCED READY COMPOSITION AGE
my-composite-resource True True my-composition 4s
```
### Naming external resources
By default, managed resources created by a composite resource have the name of
the composite resource, followed by a random suffix.
<!-- vale Google.FirstPerson = NO -->
<!-- vale Crossplane.Spelling = NO -->
For example, a composite resource named "my-composite-resource" creates external
resources named "my-composite-resource-fqvkw."
<!-- vale Google.FirstPerson = YES -->
<!-- vale Crossplane.Spelling = YES -->
Resource names can be deterministic by applying an
{{<hover label="annotation" line="5">}}annotation{{</hover>}} to the composite
resource.
```yaml {label="annotation",copy-lines="none"}
apiVersion: example.org/v1alpha1
kind: xMyDatabase
metadata:
name: my-composite-resource
annotations:
crossplane.io/external-name: my-custom-name
# Removed for brevity
```
Inside the Composition, use a
{{<hover label="comp" line="10">}}patch{{</hover>}}
to apply the external-name to the resources.
The {{<hover label="comp" line="11">}}fromFieldPath{{</hover>}} patch copies the
{{<hover label="comp" line="11">}}metadata.annotations{{</hover>}} field from
the composite resource to the
{{<hover label="comp" line="12">}}metadata.annotations{{</hover>}} inside the
managed resource.
{{<hint "note" >}}
If a managed resource has the `crossplane.io/external-name` annotation
Crossplane uses the annotation value to name the external resource.
{{</hint >}}
```yaml {label="comp",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: my-composition
spec:
resources:
- name: database
base:
# Removed for brevity
patches:
- fromFieldPath: metadata.annotations
toFieldPath: metadata.annotations
```
For more information on patching resources refer to the [Patch and
Transform]({{<ref "./patch-and-transform">}}) documentation.
### Composition selection
Select a specific Composition for a composite resource to use with
{{<hover label="compref" line="6">}}compositionRef{{</hover>}}
{{<hint "important">}}
The selected Composition must allow the composite resource to use it with a
`compositeTypeRef`. Read more about the `compositeTypeRef` field in the
[Enabling Composite Resources]({{<ref "./compositions#enabling-composite-resources">}})
section of the Composition documentation.
{{< /hint >}}
```yaml {label="compref",copy-lines="none"}
apiVersion: example.org/v1alpha1
kind: xMyDatabase
metadata:
name: my-composite-resource
spec:
compositionRef:
name: my-other-composition
# Removed for brevity
```
A composite resource can also select a Composition based on labels instead of
the exact name with a
{{<hover label="complabel" line="6">}}compositionSelector{{</hover>}}.
Inside the {{<hover label="complabel" line="7">}}matchLabels{{</hover>}} section
provide one or more Composition labels to match.
```yaml {label="complabel",copy-lines="none"}
apiVersion: example.org/v1alpha1
kind: xMyDatabase
metadata:
name: my-composite-resource
spec:
compositionSelector:
matchLabels:
environment: production
# Removed for brevity
```
### Composition revision policy
Crossplane tracks changes to Compositions as
[Composition revisions]({{<ref "/knowledge-base/guides/composition-revisions">}}) .
A composite resource can use
a {{<hover label="comprev" line="6">}}compositionUpdatePolicy{{</hover>}} to
manually or automatically reference newer Composition revisions.
The default
{{<hover label="comprev" line="6">}}compositionUpdatePolicy{{</hover>}} is
"Automatic." Composite resources automatically use the latest Composition
revision.
Change the policy to
{{<hover label="comprev" line="6">}}Manual{{</hover>}} to prevent composite
resources from automatically upgrading.
```yaml {label="comprev",copy-lines="none"}
apiVersion: example.org/v1alpha1
kind: xMyDatabase
metadata:
name: my-composite-resource
spec:
compositionUpdatePolicy: Manual
# Removed for brevity
```
### Composition revision selection
Crossplane records changes to Compositions as
[Composition revisions]({{<ref "/knowledge-base/guides/composition-revisions">}}).
A composite resource can
select a specific Composition revision.
Use {{<hover label="comprevref" line="6">}}compositionRevisionRef{{</hover>}} to
select a specific Composition revision by name.
For example, to select a specific Composition revision use the name of the
desired Composition revision.
```yaml {label="comprevref",copy-lines="none"}
apiVersion: example.org/v1alpha1
kind: xMyDatabase
metadata:
name: my-composite-resource
spec:
compositionRevisionRef: my-composition-b5aa1eb
# Removed for brevity
```
{{<hint "note" >}}
Find the Composition revision name from
{{<hover label="getcomprev" line="1">}}kubectl get compositionrevision{{</hover>}}
```shell {label="getcomprev",copy-lines="1"}
kubectl get compositionrevision
NAME REVISION XR-KIND XR-APIVERSION AGE
my-composition-5c976ad 1 xmydatabases example.org/v1alpha1 65m
my-composition-b5aa1eb 2 xmydatabases example.org/v1alpha1 64m
```
{{< /hint >}}
A Composite resource can also select Composition revisions based on labels
instead of the exact name with a
{{<hover label="comprevsel" line="6">}}compositionRevisionSelector{{</hover>}}.
Inside the {{<hover label="comprevsel" line="7">}}matchLabels{{</hover>}}
section provide one or more Composition revision labels to match.
```yaml {label="comprevsel",copy-lines="none"}
apiVersion: example.org/v1alpha1
kind: xMyDatabase
metadata:
name: my-composite-resource
spec:
compositionRevisionSelector:
matchLabels:
channel: dev
# Removed for brevity
```
### Manage connection secrets
When a composite resource creates resources, Crossplane provides any
[connection secrets]({{<ref "./managed-resources#writeconnectionsecrettoref">}})
to the composite resource.
{{<hint "important" >}}
A resource may only access connection secrets allowed by the XRD. By
default XRDs provide access to all connection secrets generated by managed
resources.
Read more about [managing connection
secrets]({{<ref "./composite-resource-definitions#manage-connection-secrets">}})
in the XRD documentation.
{{< /hint >}}
Use
{{<hover label="writesecret" line="6">}}writeConnectionSecretToRef{{</hover>}}
to specify where the composite resource writes their connection secrets to.
For example, this composite resource saves the connection secrets in a
Kubernetes secret object named
{{<hover label="writesecret" line="7">}}my-secret{{</hover>}} in the namespace
{{<hover label="writesecret" line="8">}}crossplane-system{{</hover>}}.
```yaml {label="writesecret",copy-lines="none"}
apiVersion: example.org/v1alpha1
kind: xMyDatabase
metadata:
name: my-composite-resource
spec:
writeConnectionSecretToRef:
name: my-secret
namespace: crossplane-system
# Removed for brevity
```
Composite resources can write connection secrets to an
[external secret store]({{<ref "/knowledge-base/integrations/vault-as-secret-store">}}),
like HashiCorp Vault.
{{<hint "important" >}}
External secret stores are an alpha feature. Alpha features aren't enabled by
default.
{{< /hint >}}
Use the {{<hover label="publishsecret"
line="6">}}publishConnectionDetailsTo{{</hover>}} field to save connection
secrets to an external secrets store.
```yaml {label="publishsecret",copy-lines="none"}
apiVersion: example.org/v1alpha1
kind: xMyDatabase
metadata:
name: my-composite-resource
spec:
publishConnectionDetailsTo:
name: my-external-secret-store
# Removed for brevity
```
Read the [External Secrets Store]({{<ref "/knowledge-base/integrations/vault-as-secret-store">}}) documentation for more information on using
external secret stores.
For more information on connection secrets read the [Connection Secrets
knowledge base article]({{<ref "/knowledge-base/guides/connection-details">}}).
### Pausing composite resources
<!-- vale Google.WordList = NO -->
Crossplane supports pausing composite resources. A paused composite resource
doesn't check or make changes on its external resources.
<!-- vale Google.WordList = YES -->
To pause a composite resource apply the
{{<hover label="pause" line="4">}}crossplane.io/paused{{</hover>}} annotation.
```yaml {label="pause",copy-lines="none"}
apiVersion: example.org/v1alpha1
kind: xMyDatabase
metadata:
name: my-composite-resource
annotations:
crossplane.io/paused: "true"
spec:
# Removed for brevity
```
## Verify composite resources
Use
{{<hover label="getcomposite" line="1">}}kubectl get composite{{</hover>}}
to view all the composite resources Crossplane created.
```shell{copy-lines="1",label="getcomposite"}
kubectl get composite
NAME SYNCED READY COMPOSITION AGE
my-composite-resource True True my-composition 4s
```
Use `kubectl get` for the specific custom API endpoint to view
only those resources.
```shell {copy-lines="1"}
kubectl get xMyDatabase.example.org
NAME SYNCED READY COMPOSITION AGE
my-composite-resource True True my-composition 12m
```
Use
{{<hover label="desccomposite" line="1">}}kubectl describe composite{{</hover>}}
to view the linked
{{<hover label="desccomposite" line="16">}}Composition Ref{{</hover>}},
and unique managed resources created in the
{{<hover label="desccomposite" line="22">}}Resource Refs{{</hover>}}.
```yaml {copy-lines="1",label="desccomposite"}
kubectl describe composite my-composite-resource
Name: my-composite-resource
API Version: example.org/v1alpha1
Kind: xMyDatabase
Spec:
Composition Ref:
Name: my-composition
Composition Revision Ref:
Name: my-composition-cf2d3a7
Composition Update Policy: Automatic
Resource Refs:
API Version: s3.aws.upbound.io/v1beta1
Kind: Bucket
Name: my-composite-resource-fmrks
API Version: dynamodb.aws.upbound.io/v1beta1
Kind: Table
Name: my-composite-resource-wnr9t
# Removed for brevity
```
### Composite resource conditions
The conditions of composite resources match the conditions of their managed
resources.
Read the
[conditions section]({{<ref "./managed-resources#conditions">}}) of the
managed resources documentation for details.
## Composite resource labels
Crossplane adds labels to composite resources to show their relationship to
other Crossplane components.
### Composite label
Crossplane adds the
{{<hover label="complabel" line="4">}} crossplane.io/composite{{</hover>}} label
to all composite resources. The label matches the name of the composite.
Crossplane applies the composite label to any manged resource created by a
composite, creating a reference between the managed resource and owning
composite resource.
```shell {label="claimname",copy-lines="1"}
kubectl describe xmydatabase.example.org/my-claimed-database-x9rx9
Name: my-claimed-database2-x9rx9
Namespace:
Labels: crossplane.io/composite=my-claimed-database-x9rx9
```
### Claim name label
Crossplane adds the
{{<hover label="claimname" line="4">}}crossplane.io/claim-name{{</hover>}}
label to composite resources created from a Claim. The label indicates the name
of the Claim linked to this composite resource.
```shell {label="claimname",copy-lines="1"}
kubectl describe xmydatabase.example.org/my-claimed-database-x9rx9
Name: my-claimed-database2-x9rx9
Namespace:
Labels: crossplane.io/claim-name=my-claimed-database
```
Composite resources created directly, without using a Claim, don't have a
{{<hover label="claimname" line="4">}}crossplane.io/claim-name{{</hover>}}
label.
### Claim namespace label
Crossplane adds the
{{<hover label="claimname" line="4">}}crossplane.io/claim-namespace{{</hover>}}
label to composite resources created from a Claim. The label indicates the
namespace of the Claim linked to this composite resource.
```shell {label="claimname",copy-lines="1"}
kubectl describe xmydatabase.example.org/my-claimed-database-x9rx9
Name: my-claimed-database2-x9rx9
Namespace:
Labels: crossplane.io/claim-namespace=default
```
Composite resources created directly, without using a Claim, don't have a
{{<hover label="claimname" line="4">}}crossplane.io/claim-namespace{{</hover>}}
label.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,303 @@
---
title: Environment Configurations
weight: 90
state: alpha
alphaVersion: "1.11"
description: "Environment Configurations or EnvironmentConfigs are an in-memory datastore used in patching Compositions"
---
A Crossplane EnvironmentConfig is an in-memory data store. Composition
patches can read from and write to an environment.
Crossplane supports multiple EnvironmentConfigs, each acting as a unique
data store.
## Enable EnvironmentConfigs
EnvironmentConfigs are an alpha feature. Alpha features aren't enabled by
default.
Enable EnvironmentConfig support by
[changing the Crossplane pod setting]({{<ref "./pods#change-pod-settings">}})
and enabling
{{<hover label="deployment" line="12">}}--enable-environment-configs{{</hover>}}
argument.
```yaml {label="deployment",copy-lines="12"}
$ kubectl edit deployment crossplane --namespace crossplane-system
apiVersion: apps/v1
kind: Deployment
spec:
# Removed for brevity
template:
spec:
containers:
- args:
- core
- start
- --enable-environment-configs
```
{{<hint "tip" >}}
The [Crossplane install guide]({{<ref "../software/install#feature-flags">}})
describes enabling feature flags like
{{<hover label="deployment" line="12">}}--enable-environment-configs{{</hover>}}
with Helm.
{{< /hint >}}
<!-- vale Google.Headings = NO -->
## Create an EnvironmentConfig
<!-- vale Google.Headings = YES -->
An {{<hover label="env1" line="2">}}EnvironmentConfig{{</hover>}} has a single
object field,
{{<hover label="env1" line="5">}}data{{</hover>}}.
An EnvironmentConfig supports any data inside the
{{<hover label="env1" line="5">}}data{{</hover>}} field.
Here an example
{{<hover label="env1" line="2">}}EnvironmentConfig{{</hover>}}.
```yaml {label="env1"}
apiVersion: apiextensions.crossplane.io/v1alpha1
kind: EnvironmentConfig
metadata:
name: example-environment
data:
locations:
us: us-east-2
eu: eu-north-1
key1: value1
key2: value2
key3:
- item1
- item2
```
## Patching with EnvironmentConfigs
To patch data from or to an EnvironmentConfig, reference the EnvironmentConfig
inside a Composition's
{{<hover label="comp" line="6">}}environment{{</hover>}} field.
The {{<hover label="comp" line="7">}}environmentConfigs{{</hover>}} field is a
list of environments this Composition can use.
{{<hint "tip" >}}
Read about EnvironmentConfig patch types in the
[Patch and Transform]({{<ref "./patch-and-transform">}}) documentation.
{{< /hint >}}
Select an environment by
{{<hover label="comp" line="8">}}Reference{{</hover>}} or
by
{{<hover label="comp" line="11">}}Selector{{</hover>}}.
A
{{<hover label="comp" line="8">}}Reference{{</hover>}}
selects an environment by
{{<hover label="comp" line="10">}}name{{</hover>}}.
The
{{<hover label="comp" line="11">}}Selector{{</hover>}} selects an environment
based on the
{{<hover label="comp" line="13">}}Labels{{</hover>}} applied to the environment.
```yaml {label="comp",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: example-composition
spec:
environment:
environmentConfigs:
- type: Reference
ref:
name: example-environment
- type: Selector
selector:
matchLabels:
# Removed for brevity
```
If a Composition uses multiple
{{<hover label="comp" line="7">}}environmentConfigs{{</hover>}}
Crossplane merges them together in the order they're listed.
{{<hint "note" >}}
If multiple
{{<hover label="comp" line="7">}}environmentConfigs{{</hover>}}
use the same key, the Composition uses the value of the last environment listed.
{{</hint >}}
### Select by name
Select an environment by name with
{{<hover label="byName" line="8">}}type: Reference{{</hover>}}.
Define the
{{<hover label="byName" line="9">}}ref{{</hover>}} object and the
{{<hover label="byName" line="10">}}name{{</hover>}} matching the exact name of
the environment.
For example, select the
{{<hover label="byName" line="7">}}environmentConfig{{</hover>}}
named
{{<hover label="byName" line="10">}}example-environment{{</hover>}}
```yaml {label="byName",copy-lines="all"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: example-composition
spec:
environment:
environmentConfigs:
- type: Reference
ref:
name: example-environment
```
### Select by label
Select an environment by labels with a
{{<hover label="byLabel" line="8">}}type: Selector{{</hover>}}.
Define the {{<hover label="byLabel" line="9">}}selector{{</hover>}} object.
The
{{<hover label="byLabel" line="10">}}matchLabels{{</hover>}} object contains a
list of labels to match on.
Selecting a label requires matching both the label
{{<hover label="byLabel" line="11">}}key{{</hover>}}
and the value of key.
When matching the label's value, provide an exact value with a
{{<hover label="byLabel" line="12">}}type: Value{{</hover>}} and provide the value
to match in the
{{<hover label="byLabel" line="13">}}value{{</hover>}} field.
Crossplane can also match a label's value based on an input in the composite
resource. Use
{{<hover label="byLabel" line="15">}}type: FromCompositeFieldPath{{</hover>}}
and provide the field to match in the
{{<hover label="byLabel" line="16">}}valueFromFieldPath{{</hover>}} field.
```yaml {label="byLabel",copy-lines="all"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: example-composition
spec:
environment:
environmentConfigs:
- type: Selector
selector:
matchLabels:
- key: my-label-key
type: Value
value: my-label-value
- key: my-label-key
type: FromCompositeFieldPath
valueFromFieldPath: spec.parameters.deploy
resources:
# Removed for brevity
```
#### Manage selector results
Selecting environments by labels may return more than one environment.
The Composition sorts all the results by the name of the environments and
only uses the first environment in the sorted list.
Set the {{<hover label="selectResults" line="10">}}mode{{</hover>}} as
{{<hover label="selectResults" line="10">}}mode: Multiple{{</hover>}} to return
all matched environments. Use
{{<hover label="selectResults" line="19">}}mode: Single{{</hover>}} to
return a single environment.
{{<hint "note" >}}
Sorting and the selection
{{<hover label="selectResults" line="10">}}mode{{</hover>}}
only applies to a single
{{<hover label="selectResults" line="8">}}type: Selector{{</hover>}}.
This doesn't change how Compositions merge multiple
{{<hover label="selectResults" line="7">}}environmentConfigs{{</hover>}}.
{{< /hint >}}
```yaml {label="selectResults"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: example-composition
spec:
environment:
environmentConfigs:
- type: Selector
selector:
mode: Multiple
matchLabels:
- key: my-label-key
type: Value
value: my-label-value
- key: my-label-key
type: FromCompositeFieldPath
valueFromFieldPath: spec.parameters.deploy
- type: Selector
selector:
mode: Single
matchLabels:
- key: my-other-label-key
type: Value
value: my-other-label-value
- key: my-other-label-key
type: FromCompositeFieldPath
valueFromFieldPath: spec.parameters.deploy
```
When using
{{<hover label="maxMatch" line="10">}}mode: Multiple{{</hover>}} limit the
number of returned environments with
{{<hover label="maxMatch" line="11">}}maxMatch{{</hover>}} and define the
maximum number of environments returned.
The Composition sorts the returned environments alphabetically by name. Sort the
environments on a different field with
{{<hover label="maxMatch" line="12">}}sortByFieldPath{{</hover>}} and define
the field to sort by.
```yaml {label="maxMatch"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: example-composition
spec:
environment:
environmentConfigs:
- type: Selector
selector:
mode: Multiple
maxMatch: 4
sortByFieldPath: metadata.annotations[sort.by/weight]
matchLabels:
- key: my-label-key
type: Value
value: my-label-value
- key: my-label-key
type: FromCompositeFieldPath
valueFromFieldPath: spec.parameters.deploy
```
The environments selected by
{{<hover label="maxMatch" line="18">}}matchLabels{{</hover>}} are then merged
into any other environments listed in the
{{<hover label="maxMatch" line="7">}}environmentConfigs{{</hover>}}.
<!--
TODO: Add Policies
TODO: Add webhook validations
-->

View File

@ -0,0 +1,760 @@
---
title: Managed Resources
weight: 10
description: "Managed resources are the Crossplane representation of external provider resources"
---
A _managed resource_ (`MR`) represents an external service in a Provider. When
users create a new managed resource, the Provider reacts by creating an external
resource inside the Provider's environment. Every external service managed by
Crossplane maps to a managed resource.
{{< hint "note" >}}
Crossplane calls the object inside Kubernetes a _managed resource_ and the
external object inside the Provider an _external resource_.
{{< /hint >}}
Examples of managed resources include:
* Amazon AWS EC2 [`Instance`](https://marketplace.upbound.io/providers/upbound/provider-aws/latest/resources/ec2.aws.upbound.io/Instance/v1beta1)
* Google Cloud GKE [`Cluster`](https://marketplace.upbound.io/providers/upbound/provider-gcp/latest/resources/container.gcp.upbound.io/Cluster/v1beta1)
* Microsoft Azure PostgreSQL [`Database`](https://marketplace.upbound.io/providers/upbound/provider-azure/latest/resources/dbforpostgresql.azure.upbound.io/Database/v1beta1)
{{< hint "tip" >}}
You can create individual managed resources, but Crossplane recommends using
[Compositions]({{<ref "./compositions" >}}) and Claims to create
managed resources.
{{< /hint >}}
## Managed resource fields
The Provider defines the group, kind and version of a managed resource. The
Provider also define the available settings of a managed resource.
### Group, kind and version
Each managed resource is a unique API endpoint with their own
group, kind and version.
For example the [Upbound AWS
Provider](https://marketplace.upbound.io/providers/upbound/provider-aws/latest/)
defines the {{<hover label="gkv" line="2">}}Instance{{</hover>}} kind from the
group {{<hover label="gkv" line="1">}}ec2.aws.upbound.io{{</hover>}}
```yaml {label="gkv",copy-lines="none"}
apiVersion: ec2.aws.upbound.io/v1beta1
kind: Instance
```
<!-- vale off -->
### deletionPolicy
<!-- vale on -->
A managed resource's `deletionPolicy` tells the Provider what to do after
deleting the managed resource. If the `deletionPolicy` is `delete` the Provider
deletes the external resource as well. If the `deletionPolicy` is `orphan` the
Provider deletes the managed resource but doesn't delete the external resource.
#### Options
* `deletionPolicy: Delete` - **Default** - Delete the external resource when deleting the managed resource.
* `deletionPolicy: Orphan` - Leave the external resource when deleting the managed resource.
<!-- vale off -->
### forProvider
<!-- vale on -->
The {{<hover label="forProvider" line="4">}}spec.forProvider{{</hover>}} of a
managed resource maps to the parameters of the external resource.
For example, when creating an AWS EC2 instance, the Provider supports defining
the AWS {{<hover label="forProvider" line="5">}}region{{</hover>}} and the VM
size, called the
{{<hover label="forProvider" line="6">}}instanceType{{</hover>}}.
{{< hint "note" >}}
The Provider defines the settings and their valid values. Providers also define
required and optional values in the `forProvider` definition.
Refer to the documentation of your specific Provider for details.
{{< /hint >}}
```yaml {label="forProvider",copy-lines="none"}
apiVersion: ec2.aws.upbound.io/v1beta1
kind: Instance
# Removed for brevity
spec:
forProvider:
region: us-west-1
instanceType: t2.micro
```
{{< hint "important">}}
Crossplane considers the `forProvider` field of a managed resource
the "source of truth" for external resources. Crossplane overrides any changes
made to an external resource outside of Crossplane. If a user makes a change
inside a Provider's web console, Crossplane reverts that change back to what's
configured in the `forProvider` setting.
{{< /hint >}}
Providers add any settings not manually set to the `forProvider` field of the
created managed resource object.
Use `kubectl describe <managed_resource>` to view the applied values.
#### Referencing other resources
Some fields in a managed resource may depend on values from other managed
resources. For example a VM may need the name of a virtual network to use.
Managed resources can reference other managed resources by external name, name
reference or selector.
##### Matching by external name
When matching a resource by name Crossplane looks for the name of the external
resource in the Provider.
For example, a AWS VPC object named `my-test-vpc` has the external name
`vpc-01353cfe93950a8ff`.
```shell {copy-lines="1"
kubectl get vpc
NAME READY SYNCED EXTERNAL-NAME AGE
my-test-vpc True True vpc-01353cfe93950a8ff 49m
```
To match the VPC by name, use the external name. For example, creating a Subnet
managed resource attached to this VPC.
```yaml {copy-lines="none"}
apiVersion: ec2.aws.upbound.io/v1beta1
kind: Subnet
spec:
forProvider:
# Removed for brevity
vpcId: vpc-01353cfe93950a8ff
```
##### Matching by name reference
To match a resource based on the name of the managed resource and not the
external resource name inside the Provider, use a `nameRef`.
For example, a AWS VPC object named `my-test-vpc` has the external name
`vpc-01353cfe93950a8ff`.
```shell {copy-lines="1"}
kubectl get vpc
NAME READY SYNCED EXTERNAL-NAME AGE
my-test-vpc True True vpc-01353cfe93950a8ff 49m
```
To match the VPC by name reference, use the managed resource name. For example,
creating a Subnet managed resource attached to this VPC.
```yaml {copy-lines="none"}
apiVersion: ec2.aws.upbound.io/v1beta1
kind: Subnet
spec:
forProvider:
# Removed for brevity
vpcIdRef:
name: my-test-vpc
```
##### Matching by selector
Matching by selector is the most flexible matching method.
{{<hint "note" >}}
The [Compositions]({{<ref "./compositions">}}) section covers the
`matchControllerRef` selector.
{{</hint >}}
Use `matchLabels` to match the labels applied to a resource. For example, this
Subnet resource only matches VPC resources with the label
`my-label: label-value`.
```yaml {copy-lines="none"}
apiVersion: ec2.aws.upbound.io/v1beta1
kind: Subnet
spec:
forProvider:
# Removed for brevity
vpcIdSelector:
matchLabels:
my-label: label-value
```
#### Immutable fields
Some providers don't support changing the fields of some managed resources after
creation. For example, you can't change the `region` of an Amazon AWS
`RDSInstance`. These fields are _immutable fields_. Amazon requires you delete
and recreate the resource.
Crossplane allows you to edit the immutable field of a managed resource, but
doesn't apply the change. Crossplane never deletes a resource based on a
`forProvider` change.
{{<hint "note" >}}
<!-- vale write-good.Passive = NO -->
Crossplane behaves differently than other tools like Terraform. Terraform
deletes and recreates a resource to change an immutable field. Crossplane only
deletes an external resource if their corresponding managed
resource object is deleted from Kubernetes and the `deletionPolicy` is
`delete`.
<!-- vale write-good.Passive = YES -->
{{< /hint >}}
<!-- vale off -->
### managementPolicy
<!-- vale on -->
{{<hint "important" >}}
The managed resource `managementPolicy` option is an alpha feature.
Enable the `managementPolicy` in a provider with `--enable-management-policies`
in a
[ControllerConfig]({{<ref "./providers#controller-configuration" >}}).
{{< /hint >}}
A `managementPolicy` determines if Crossplane can make changes to managed
resources. The `ObserveOnly` policy imports existing external resources not
originally created by Crossplane.
This allows new managed resources to reference
the `ObserveOnly` resource, for example, a shared database or network.
The `ObserveOnly` policy can also place existing resources under the control of
Crossplane.
{{< hint "tip" >}}
Read the [Import Existing Resources]({{<ref "/knowledge-base/guides/import-existing-resources" >}})
guide for more
information on using the `managementPolicy` to import existing resources.
{{< /hint >}}
#### Options
* `managementPolicy: FullControl` - **Default** - Crossplane can create, change
and delete the managed resource.
* `managementPolicy: ObserveOnly` - Crossplane only imports the details of the
external resource, but doesn't make any changes to the managed resource.
<!-- vale off -->
### providerConfigRef
<!-- vale on -->
The `providerConfigRef` on a managed resource tells the Provider which
[ProviderConfig]({{<ref "./providers#provider-configuration">}}) to
use when creating the managed resource.
Use a ProviderConfig to define the authentication method to use when
communicating to the Provider.
{{< hint "important" >}}
If `providerConfigRef` isn't applied, Providers use the ProviderConfig named `default`.
{{< /hint >}}
For example, a managed resource references a ProviderConfig named
{{<hover label="pcref" line="6">}}user-keys{{</hover>}}.
This matches the {{<hover label="pc" line="4">}}name{{</hover>}} of a ProviderConfig.
```yaml {label="pcref",copy-lines="none"}}
apiVersion: ec2.aws.upbound.io/v1beta1
kind: Instance
spec:
forProvider:
# Removed for brevity
providerConfigRef: user-keys
```
```yaml {label="pc"}
apiVersion: aws.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: user-keys
# Removed for brevity
```
{{< hint "tip" >}}
Each managed resource can reference different ProviderConfigs. This allows
different managed resources to authenticate with different credentials to the
same Provider.
{{< /hint >}}
<!-- vale off -->
### providerRef
<!-- vale on -->
<!-- vale Crossplane.Spelling = NO -->
Crossplane deprecated the `providerRef` field in `crossplane-runtime`
[v0.10.0](https://github.com/crossplane/crossplane-runtime/releases/tag/v0.10.0).
Managed resources using `providerRef`must use [`providerConfigRef`](#providerconfigref).
<!-- vale Crossplane.Spelling = YES -->
<!-- vale off -->
### writeConnectionSecretToRef
<!-- vale on -->
When a Provider creates a managed resource it may generate resource-specific
details, like usernames, passwords or connection details like an IP address.
Crossplane stores these details in a Kubernetes Secret object specified by the
`writeConnectionSecretToRef` values.
For example, when creating an AWS RDS database instance with the Crossplane
[community AWS provider](https://marketplace.upbound.io/providers/crossplane-contrib/provider-aws/v0.40.0)
generates an endpoint, password, port and username data. The Provider saves
these variables in the Kubernetes secret
{{<hover label="secretname" line="9" >}}rds-secret{{</hover>}}, referenced by
the
{{<hover label="secretname" line="9" >}}writeConnectionSecretToRef{{</hover>}}
field.
```yaml {label="secretname",copy-lines="none"}
apiVersion: database.aws.crossplane.io/v1beta1
kind: RDSInstance
metadata:
name: my-rds-instance
spec:
forProvider:
# Removed for brevity
writeConnectionSecretToRef:
name: rds-secret
```
Viewing the Secret object shows the saved fields.
```yaml {copy-lines="1"}
kubectl describe secret rds-secret
Name: rds-secret
# Removed for brevity
Data
====
port: 4 bytes
username: 10 bytes
endpoint: 54 bytes
password: 27 bytes
```
{{<hint "important" >}}
The Provider determines the data written to the Secret object. Refer to the
specific Provider documentation for the generated Secret data.
{{< /hint >}}
<!-- vale off -->
### publishConnectionDetailsTo
<!-- vale on -->
The `publishConnectionDetailsTo` field expands on
[`writeConnectionSecretToRef`](#writeconnectionsecrettoref) supporting storing
managed resource information as a Kubernetes Secret object or in an external
secrets store like [HashiCorp Vault](https://www.vaultproject.io/).
Using `publishConnectionDetailsTo` requires enabling Crossplane
External Secrets Stores (ESS). Enable ESS inside a Provider with a
[ControllerConfig]({{<ref "providers#controller-configuration" >}}) and
in Crossplane with the `--enable-external-secret-stores` argument.
{{< hint "note" >}}
Not all Providers support `publishConnectionDetailsTo`. Check your Provider
documentation for details.
{{< /hint >}}
#### Publish secrets to Kubernetes
To publish the data generated by a managed resource as a Kubernetes Secret
object provide a
{{<hover label="k8secret" line="7">}}publishConnectionDetailsTo.name{{< /hover >}}
```yaml {label="k8secret",copy-lines="none"}
apiVersion: rds.aws.upbound.io/v1beta1
kind: Instance
spec:
forProvider:
# Removed for brevity
publishConnectionDetailsTo:
name: rds-kubernetes-secret
```
Crossplane can apply labels and annotations to the Kubernetes secret as well
using
{{<hover label="k8label" line="8">}}publishConnectionDetailsTo.metadata{{</hover>}}.
```yaml {label="k8label",copy-lines="none"}
apiVersion: rds.aws.upbound.io/v1beta1
kind: Instance
spec:
forProvider:
# Removed for brevity
publishConnectionDetailsTo:
name: rds-kubernetes-secret
metadata:
labels:
label-tag: label-value
annotations:
annotation-tag: annotation-value
```
#### Publish secrets to an external secrets store
Publishing secrets data to an external secret store like
[HashiCorp Vault](https://www.vaultproject.io/) relies on a
{{<hover label="configref" line="8">}}publishConnectionDetailsTo.configRef{{</hover>}}.
The
{{<hover label="configref" line="9">}}configRef.name{{</hover>}} references a
{{<hover label="storeconfig" line="4">}}StoreConfig{{</hover>}}
object.
```yaml {label="configref",copy-lines="none"}
apiVersion: rds.aws.upbound.io/v1beta1
kind: Instance
spec:
forProvider:
# Removed for brevity
publishConnectionDetailsTo:
name: rds-kubernetes-secret
configRef:
name: my-vault-storeconfig
```
```yaml {label="storeconfig",copy-lines="none"}
apiVersion: secrets.crossplane.io/v1alpha1
kind: StoreConfig
metadata:
name: my-vault-storeconfig
# Removed for brevity
```
{{<hint "tip" >}}
Read the
[Vault as an External Secrets Store]({{<ref "knowledge-base/integrations/vault-as-secret-store">}})
guide for details on using StoreConfig objects.
{{< /hint >}}
## Annotations
Crossplane applies a standard set of Kubernetes `annotations` to managed
resources.
{{<table "table table-sm">}}
| Annotation | Definition |
| --- | --- |
| `crossplane.io/external-name` | The name of the managed resource inside the Provider. |
| `crossplane.io/external-create-pending` | The timestamp of when Crossplane
began creating a new managed resource. |
| `crossplane.io/external-create-succeeded` | The timestamp of when the Provider successfully created the managed resource. |
| `crossplane.io/external-create-failed` | The timestamp of when the Provider failed to create the managed resource. |
| `crossplane.io/paused` | Indicates Crossplane isn't reconciling this resource. Read the [Pause Annotation](#paused) for more details. |
| `crossplane.io/composition-resource-name` | For managed resource created by a Composition, this is the Composition's `resources.name` value. |
{{</table >}}
### Naming external resources
By default Providers give external resources the same name as the Kubernetes
object.
For example, a managed resource named
{{<hover label="external-name" line="4">}}my-rds-instance{{</hover >}} has
the name `my-rds-instance` as an external resource inside the Provider's
environment.
```yaml {label="external-name",copy-lines="none"}
apiVersion: database.aws.crossplane.io/v1beta1
kind: RDSInstance
metadata:
name: my-rds-instance
```
```shell
kubectl get rdsinstance
NAME READY SYNCED EXTERNAL-NAME AGE
my-rds-instance True True my-rds-instance 11m
```
Managed resource created with a `crossplane.io/external-name`
annotation already provided use the annotation value as the external
resource name.
For example, the Provider creates managed resource named
{{< hover label="custom-name" line="6">}}my-rds-instance{{</hover>}} but uses
the name {{<hover label="custom-name" line="5">}}my-custom-name{{</hover >}}
for the external resource inside AWS.
```yaml {label="custom-name",copy-lines="none"}
apiVersion: database.aws.crossplane.io/v1beta1
kind: RDSInstance
metadata:
name: my-rds-instance
annotations:
crossplane.io/external-name: my-custom-namee
```
```shell {copy-lines="1"}
kubectl get rdsinstance
NAME READY SYNCED EXTERNAL-NAME AGE
my-rds-instance True True my-custom-name 11m
```
### Creation annotations
Providers create new managed resources with the
`crossplane.io/external-create-pending` annotation.
The Provider applies the `crossplane.io/external-create-succeeded` or
`crossplane.io/external-create-failed` annotation after making the external API
call and receiving a response.
{{<hint "note" >}}
If a Provider restarts before creating the `succeed` or `fail` annotations the
Provider can't reconcile the manged resource.
Read Crossplane [issue
#3037](https://github.com/crossplane/crossplane/issues/3037#issuecomment-1110142427)
for more details
{{< /hint >}}
### Paused
Manually applying the `crossplane.io/paused` annotation causes the Provider to
stop reconciling the managed resource.
Pausing a resource is useful when modifying Providers or preventing
race-conditions when editing Kubernetes objects.
Apply a {{<hover label="pause" line="6">}}crossplane.io/paused: "true"{{</hover>}}
annotation to a managed resource to pause reconciliation.
{{< hint "note" >}}
Only the value `"true"` pauses reconciliation.
{{< /hint >}}
```yaml {label="pause"}
apiVersion: ec2.aws.upbound.io/v1beta1
kind: Instance
metadata:
name: my-rds-instance
annotations:
crossplane.io/paused: "true"
spec:
forProvider:
region: us-west-1
instanceType: t2.micro
```
Remove the annotation to resume reconciliation.
## Finalizers
Crossplane applies a
[Finalizer](https://kubernetes.io/docs/concepts/overview/working-with-objects/finalizers/)
on managed resources to control their deletion.
{{< hint "note" >}}
Kubernetes can't delete objects with Finalizers.
{{</hint >}}
When Crossplane deletes a managed resource the Provider begins deleting the
external resource, but the managed resource remains until the external
resource is fully deleted.
When the external resource is fully deleted Crossplane removes the Finalizer and
deletes the managed resource object.
## Conditions
Crossplane has a standard set of `Conditions` for a managed
resource. View the `Conditions` of a managed resource with
`kubectl describe <managed_resource>`
{{<hint "note" >}}
Providers may define their own custom `Conditions`.
{{</hint >}}
### Available
`Reason: Available` indicates the Provider created the managed resource and it's
ready for use.
```yaml {copy-lines="none"}
Conditions:
Type: Ready
Status: True
Reason: Available
```
### Creating
`Reason: Creating` indicates the Provider is attempting to create the managed
resource.
```yaml {copy-lines="none"}
Conditions:
Type: Ready
Status: False
Reason: Creating
```
### Deleting
`Reason: Deleting` indicates the Provider is attempting to delete the managed
resource.
```yaml {copy-lines="none"}
Conditions:
Type: Ready
Status: False
Reason: Deleting
```
<!-- vale off -->
### ReconcilePaused
<!-- vale on -->
`Reason: ReconcilePaused` indicates the managed resource has a [Pause](#paused)
annotation
```yaml {copy-lines="none"}
Conditions:
Type: Synced
Status: False
Reason: ReconcilePaused
```
<!-- vale off -->
### ReconcileError
<!-- vale on -->
`Reason: ReconcileError` indicates Crossplane encountered an error while
reconciling the managed resource. The `Message:` value of the `Condition` helps
identify the Crossplane error.
```yaml {copy-lines="none"}
Conditions:
Type: Synced
Status: False
Reason: ReconcileError
```
<!-- vale off -->
### ReconcileSuccess
<!-- vale on -->
`Reason: ReconcileSuccess` indicates the Provider created and is monitoring the
managed resource.
```yaml {copy-lines="none"}
Conditions:
Type: Synced
Status: True
Reason: ReconcileSuccess
```
### Unavailable
`Reason: Unavailable` indicates Crossplane expects the managed resource to be
available, but the Provider reports the resource is unhealthy.
```yaml {copy-lines="none"}
Conditions:
Type: Ready
Status: False
Reason: Unavailable
```
### Unknown
`Reason: Unknown` indicates the Provider has an unexpected error with the
managed resource. The `conditions.message` provides more information on what
went wrong.
```yaml {copy-lines="none"}
Conditions:
Type: Unknown
Status: False
Reason: Unknown
```
### Upjet Provider conditions
[Upjet](https://github.com/upbound/upjet), the open source tool to generate
Crossplane Providers, also has a set of standard `Conditions`.
<!-- vale off -->
#### AsyncOperation
<!-- vale on -->
Some resources may take more than a minute to create. Upjet based providers can
complete their Kubernetes command before creating the managed resource by using
an asynchronous operation.
##### Finished
The `Reason: Finished` indicates the asynchronous operation completed
successfully.
```yaml {copy-lines="none"}
Conditions:
Type: AsyncOperation
Status: True
Reason: Finished
```
##### Ongoing
`Reason: Ongoing` indicates the managed resource operation is still in progress.
```yaml {copy-lines="none"}
Conditions:
Type: AsyncOperation
Status: True
Reason: Ongoing
```
<!-- vale off -->
#### LastAsyncOperation
<!-- vale on -->
The Upjet `Type: LastAsyncOperation` captures the previous asynchronous
operation status as either `Success` or a failure `Reason`.
<!-- vale off -->
##### ApplyFailure
<!-- vale on -->
`Reason: ApplyFailure` indicates the Provider failed to apply a setting to the
managed resource. The `conditions.message` provides more information on what
went wrong.
```yaml {copy-lines="none"}
Conditions:
Type: LastAsyncOperation
Status: False
Reason: ApplyFailure
```
<!-- vale off -->
##### DestroyFailure
<!-- vale on -->
`Reason: DestroyFailure` indicates the Provider failed to delete the managed
resource. The `conditions.message` provides more information on what
went wrong.
```yaml {copy-lines="none"}
Conditions:
Type: LastAsyncOperation
Status: False
Reason: DestroyFailure
```
##### Success
`Reason: Success` indicates the Provider successfully created the managed
resource asynchronously.
```yaml {copy-lines="none"}
Conditions:
Type: LastAsyncOperation
Status: True
Reason: Success
```

View File

@ -0,0 +1,513 @@
---
title: Crossplane Packages
weight: 104
description: "Packages combine multiple Crossplane resources into a single, portable, OCI image."
---
<!--
Install packages behind a proxy.
https://github.com/upbound/provider-azure/issues/475#issuecomment-1608390254 -->
Crossplane packages are opinionated [OCI images] that contain a stream of YAML
that can be parsed by the Crossplane package manager. Crossplane packages come
in two varieties: [Providers] and Configurations. Ultimately, the primary
purposes of Crossplane packages are as follows:
- **Convenient Distribution**: Crossplane packages can be pushed to or installed
from any OCI-compatible registry.
- **Version Upgrade**: Crossplane can update packages in-place, meaning that you
can pick up support for new resource types or controller bug-fixes without
modifying your existing infrastructure.
- **Permissions**: Crossplane allocates permissions to packaged controllers in a
manner that ensures they will not maliciously take over control of existing
resources owned by other packages. Installing CRDs via packages also allows
Crossplane itself to manage those resources, allowing for powerful
[composition] features to be enabled.
- **Dependency Management**: Crossplane resolves dependencies between packages,
automatically installing a package's dependencies if they are not present in
the cluster, and checking if dependency versions are valid if they are already
installed.
## Table of Contents
The following packaging operations are covered in detail below:
- [Table of Contents](#table-of-contents)
- [Building a Package](#building-a-package)
- [Provider Packages](#provider-packages)
- [Configuration Packages](#configuration-packages)
- [Pushing a Package](#pushing-a-package)
- [Installing a Package](#installing-a-package)
- [spec.package](#specpackage)
- [spec.packagePullPolicy](#specpackagepullpolicy)
- [spec.revisionActivationPolicy](#specrevisionactivationpolicy)
- [spec.revisionHistoryLimit](#specrevisionhistorylimit)
- [spec.packagePullSecrets](#specpackagepullsecrets)
- [spec.skipDependencyResolution](#specskipdependencyresolution)
- [spec.ignoreCrossplaneConstraints](#specignorecrossplaneconstraints)
- [spec.controllerConfigRef](#speccontrollerconfigref)
- [Upgrading a Package](#upgrading-a-package)
- [Package Upgrade Issues](#package-upgrade-issues)
- [The Package Cache](#the-package-cache)
- [Pre-Populating the Package Cache](#pre-populating-the-package-cache)
## Building a Package
As stated above, Crossplane packages are just opinionated OCI images, meaning
they can be constructed using any tool that outputs files that comply the the
OCI specification. However, constructing packages using the Crossplane CLI is a
more streamlined experience, as it will perform build-time checks on your
packages to ensure that they are compliant with the Crossplane [package format].
Providers and Configurations vary in the types of resources they may contain in
their packages. All packages must have a `crossplane.yaml` file in the root
directory with package contents. The `crossplane.yaml` contains the package's
metadata, which governs how Crossplane will install the package.
### Provider Packages
A Provider package contains a `crossplane.yaml` with the following format:
```yaml
apiVersion: meta.pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-gcp
spec:
crossplane:
version: ">=v1.0.0"
controller:
image: crossplane/provider-gcp-controller:v0.14.0
permissionRequests:
- apiGroups:
- apiextensions.crossplane.io
resources:
- compositions
verbs:
- get
- list
- create
- update
- patch
- watch
```
See all available fields in the [official documentation][provider-docs].
> Note: The `meta.pkg.crossplane.io` group does not contain custom resources
> that may be installed into the cluster. They are strictly used as metadata in
> a Crossplane package.
A Provider package may optionally contain one or more CRDs. These CRDs will be
installed prior to the creation of the Provider's `Deployment`. Crossplane will
not install _any_ CRDs for a package unless it can determine that _all_ CRDs can
be installed. This guards against multiple Providers attempting to reconcile the
same CRDs. Crossplane will also create a `ServiceAccount` with permissions to
reconcile these CRDs and it will be assigned to the controller `Deployment`.
The `spec.controller.image` fields specifies that the `Provider` desires for the
controller `Deployment` to be created with the provided image. It is important
to note that this image is separate from the package image itself. In the case
above, it is an image containing the `provider-gcp` controller binary.
The `spec.controller.permissionRequests` field allows a package author to
request additional RBAC for the packaged controller. The controller's
`ServiceAccount` will automatically give the controller permission to reconcile
all types that its package installs, as well as `Secrets`, `ConfigMaps`, and
`Events`. Any additional permissions must be explicitly requested.
> Note that the Crossplane RBAC manager can be configured to reject permissions
> for certain API groups. If a package requests permissions that Crossplane is
> configured to reject, the package will fail to be installed.
> Authorized permissions should be aggregated to the rbac manager clusterrole
> (the cluster role defined by the provider-clusterrole flag in the rbac manager)
> by using the label `rbac.crossplane.io/aggregate-to-allowed-provider-permissions: "true"`
The `spec.crossplane.version` field specifies the version constraints for core
Crossplane that the `Provider` is compatible with. It is advisable to use this
field if a package relies on specific features in a minimum version of
Crossplane.
> All version constraints used in packages follow the [specification] outlined
> in the `Masterminds/semver` repository.
For an example Provider package, see [provider-gcp].
To build a Provider package, navigate to the package root directory and execute
the following command:
```
kubectl crossplane build provider
```
If the Provider package is valid, you will see a file with the `.xpkg`
extension.
> Note that the Crossplane CLI will not follow symbolic links for files in the
> root package directory.
### Configuration Packages
A Configuration package contains a `crossplane.yaml` with the following format:
```yaml
apiVersion: meta.pkg.crossplane.io/v1
kind: Configuration
metadata:
name: my-org-infra
spec:
crossplane:
version: ">=v1.0.0"
dependsOn:
- provider: xpkg.upbound.io/crossplane-contrib/provider-gcp
version: ">=v0.14.0"
```
See all available fields in the [official documentation][configuration-docs].
A Configuration package may also specify one or more of
`CompositeResourceDefinition` and `Composition` types. These resources will be
installed and will be solely owned by the Configuration package. No other
package will be able to modify them.
The `spec.crossplane.version` field serves the same purpose that it does in a
`Provider` package.
The `spec.dependsOn` field specifies packages that this package depends on. When
installed, the package manager will ensure that all dependencies are present and
have a valid version given the constraint. If a dependency is not installed, the
package manager will install it at the latest version that fits within the
provided constraints.
> Dependency resolution is a `beta` feature and depends on the `v1beta1`
> [`Lock` API][lock-api].
For an example Configuration package, see [getting-started-with-gcp](https://github.com/crossplane/docs/tree/master/content/v1.10/snippets/package/gcp).
To build a Configuration package, navigate to the package root directory and
execute the following command:
```
kubectl crossplane build configuration
```
If the Provider package is valid, you will see a file with the `.xpkg`
extension.
## Pushing a Package
Crossplane packages can be pushed to any OCI-compatible registry. If a specific
registry is not specified they will be pushed to Docker Hub.
To push a Provider package, execute the following command:
```
kubectl crossplane push provider xpkg.upbound.io/crossplane-contrib/provider-gcp:v0.22.0
```
To push a Configuration package, execute the following command:
```
kubectl crossplane push configuration xpkg.upbound.io/crossplane-contrib/my-org-infra:v0.1.0
```
> Note: Both of the above commands assume a single `.xpkg` file exists in the
> directory. If multiple exist or you would like to specify a package in a
> different directory, you can supply the `-f` flag with the path to the
> package.
## Installing a Package
Packages can be installed into a Crossplane cluster using the Crossplane CLI.
To install a Provider package, execute the following command:
```
kubectl crossplane install provider xpkg.upbound.io/crossplane-contrib/provider-gcp:v0.22.0
```
To install a Configuration package, execute the following command:
```
kubectl crossplane install configuration xpkg.upbound.io/crossplane-contrib/my-org-infra:v0.1.0
```
Packages can also be installed manually by creating a `Provider` or
`Configuration` object directly. The preceding commands would result in the
creation of the following two resources, which could have been authored by hand:
```yaml
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-gcp
spec:
package: xpkg.upbound.io/crossplane-contrib/provider-gcp:v0.22.0
packagePullPolicy: IfNotPresent
revisionActivationPolicy: Automatic
revisionHistoryLimit: 1
```
```yaml
apiVersion: pkg.crossplane.io/v1
kind: Configuration
metadata:
name: my-org-infra
spec:
package: xpkg.upbound.io/crossplane-contrib/my-org-infra:v0.1.0
packagePullPolicy: IfNotPresent
revisionActivationPolicy: Automatic
revisionHistoryLimit: 1
```
> Note: These types differ from the `Provider` and `Configuration` types we saw
> earlier. They exist in the `pkg.crossplane.io` group rather than the
> `meta.pkg.crossplane.io` group and are actual custom resources created in the
> cluster.
The default fields specified above can be configured with different values to
modify the installation and upgrade behavior of a package. In addition, there
are multiple other fields which can further customize how the package manager
handles a specific revision.
### spec.package
This is the package image that we built, pushed, and are asking Crossplane to
install. The tag we specify here is important. Crossplane will periodically
check if the installed image matches the digest of the image in the remote
registry. If it does not, Crossplane will create a new _Revision_ (either
`ProviderRevision` or `ConfigurationRevision`). If you do not wish Crossplane to
ever update your packages without explicitly instructing it to do so, you should
consider specifying a tag which you know will not have the underlying contents
change unexpectedly (e.g. a specific semantic version, such as `v0.1.0`) or, for
an even stronger guarantee, providing the image with a `@sha256` extension
instead of a tag.
### spec.packagePullPolicy
Valid values: `IfNotPresent`, `Always`, or `Never` (default: `IfNotPresent`)
When a package is installed, Crossplane downloads the image contents into a
cache. Depending on the image identifier (tag or digest) and the
`packagePullPolicy`, the Crossplane package manager will decide if and when to
check and see if newer package contents are available. The following table
describes expected behavior based on the supplied fields:
| | `IfNotPresent` | `Always` | `Never` |
|---------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------|
| Semver Tag (e.g. `v1.3.0`) | Package is downloaded when initially installed, and as long as it is present in the cache, it will not be downloaded again. If the cache is lost and the a new version of the package image has been pushed for the same tag, package could inadvertently be upgraded. <br><br> **Upgrade Safety: Strong** | Package is downloaded when initially installed, but Crossplane will check every minute if new content is available. New content would have to be pushed for the same semver tag for upgrade to take place. <br><br> **Upgrade Safety: Weak** | Crossplane will never download content. Must manually load package image in cache. <br><br> **Upgrade Safety: Strongest** |
| Digest (e.g. `@sha256:28b6...`) | Package is downloaded when initially installed, and as long as it is present in the cache, it will not be downloaded again. If the cache is lost but an image with this digest is still available, it will be downloaded again. The package will never be upgraded without a user changing the digest. <br><br> **Upgrade Safety: Very Strong** | Package is downloaded when initially installed, but Crossplane will check every minute if new content is available. Because image digest is used, new content will never be downloaded. <br><br> **Upgrade Safety: Strong** | Crossplane will never download content. Must manually load package image in cache. <br><br> **Upgrade Safety: Strongest** |
| Channel Tag (e.g. `latest`) | Package is downloaded when initially installed, and as long as it is present in the cache, it will not be downloaded again. If the cache is lost, the latest version of this package image will be downloaded again, which will frequently have different contents. <br><br> **Upgrade Safety: Weak** | Package is downloaded when initially installed, but Crossplane will check every minute if new content is available. When the image content is new, Crossplane will download the new contents and create a new revision. <br><br> **Upgrade Safety: Very Weak** | Crossplane will never download content. Must manually load package image in cache. <br><br> **Upgrade Safety: Strongest** |
### spec.revisionActivationPolicy
Valid values: `Automatic` or `Manual` (default: `Automatic`)
When Crossplane downloads new contents for a package, regardless of whether it
was a manual upgrade (i.e. user updating package image tag), or an automatic one
(enabled by the `packagePullPolicy`), it will create a new package revision.
However, the new objects and / or controllers will not be installed until the
new revision is marked as `Active`. This activation process is configured by the
`revisionActivationPolicy` field.
An `Active` package revision attempts to become the _controller_ of all
resources it installs. There can only be one controller of a resource, so if two
`Active` revisions both install the same resource, one will fail to install
until the other cedes control.
An `Inactive` package revision attempts to become the _owner_ of all resources
it installs. There can be an arbitrary number of owners of a resource, so
multiple `Inactive` revisions and a single `Active` revision can exist for a
resource. Importantly, an `Inactive` package revision will not perform any
auxiliary actions (such as creating a `Deployment` in the case of a `Provider`),
meaning we will not encounter a situation where two revisions are fighting over
reconciling a resource.
With `revisionActivationPolicy: Automatic`, Crossplane will mark any new
revision as `Active` when it is created, as well as transition any old revisions
to `Inactive`. When `revisionActivationPolicy: Manual`, the user must manually
edit a new revision and mark it as `Active`. This can be useful if you are using
a `packagePullPolicy: Automatic` with a channel tag (e.g. `latest`) and you want
Crossplane to create new revisions when a new version is available, but you
don't want to automatically update to that newer revision.
It is recommended for most users to use semver tags or image digests and
manually update their packages, but use a `revisionActivationPolicy: Automatic`
to avoid having to manually activate new versions. However, each user should
consider their specific environment and choose a combination that makes sense
for them.
For security reasons, it's suggested using image digests instead or alongside
tags (`vx.y.z@sha256:...`), to ensure that the package content wasn't tampered
with.
### spec.revisionHistoryLimit
Valid values: any integer, disabled by explicitly setting to `0` (default `1`)
When a revision transitions from `Inactive` to `Active`, its revision number
gets set to one greater than the largest revision number of all revisions for
its package. Therefore, as the number of revisions increases, the least recently
`Active` revision will have the lowest revision number. Crossplane will garbage
collect old `Inactive` revisions if they fall outside the
`spec.revisionHistoryLimit`. For instance, if my revision history limit is `3`
and I currently have three old `Inactive` revisions and one `Active` revision,
when I upgrade the next time, the new revision will be given the highest
revision number when it becomes `Active`, the previously `Active` revision will
become `Inactive`, and the oldest `Inactive` revision will be garbage collected.
> Note: In the case that `spec.revisionActivationPolicy: Manual` and you upgrade
> enough times (but do not make `Active` the new revisions), it is possible that
> activating a newer revision could cause the previously `Active` revision to
> immediately be garbage collected if it is outside the
> `spec.revisionHistoryLimit`.
### spec.packagePullSecrets
Valid values: slice of `Secret` names (secrets must exist in `namespace`
Crossplane was installed in, typically `crossplane-system`)
This field allows a user to provide credentials required to pull a package from
a private repository on a registry. The credentials are passed along to a
packaged controller if the package is a `Provider`, but are not passed along to
any dependencies.
### spec.skipDependencyResolution
Valid values: `true` or `false` (default: `false`)
If `skipDependencyResolution: true`, the package manager will install a package
without considering its dependencies.
### spec.ignoreCrossplaneConstraints
Valid values: `true` or `false` (default: `false`)
If `ignoreCrossplaneConstraints: true`, the package manager will install a
package without considering the version of Crossplane that is installed.
### spec.controllerConfigRef
{{< hint "warning" >}}
The `ControllerConfig` API has been deprecated and will be removed in a future
release when a comparable alternative is available.
{{< /hint >}}
Valid values: name of a `ControllerConfig` object
Packaged `Provider` controllers are installed in the form of a `Deployment`.
Crossplane populates the `Deployment` with default values that may not be
appropriate for every use-case. In the event that a user wants to override some
of the defaults that Crossplane has set, they may create and reference a
`ControllerConfig`.
An example of when this may be useful is when a user is running Crossplane on
EKS and wants to take advantage of [IAM Roles for Service Accounts]. This
requires setting an `fsGroup` and annotating the `ServiceAccount` that
Crossplane creates for the controller. This could be accomplished with the
following `ControllerConfig` and `Provider`:
```yaml
apiVersion: pkg.crossplane.io/v1alpha1
kind: ControllerConfig
metadata:
name: aws-config
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::$AWS_ACCOUNT_ID\:role/$IAM_ROLE_NAME
spec:
podSecurityContext:
fsGroup: 2000
---
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws
spec:
package: xpkg.upbound.io/crossplane-contrib/provider-aws:v0.33.0
controllerConfigRef:
name: aws-config
```
You can find all configurable values in the [official `ControllerConfig`
documentation][controller-config-docs].
## Upgrading a Package
Upgrading a `Provider` or `Configuration` to a new version can be accomplished
by editing the existing manifest and applying it with a new version tag in
`spec.package`. Crossplane will observe the updated manifest and create a new
`ProviderRevision` or `ConfigurationRevision` for the specified version. The new
revision will be activated in accordance with `spec.revisionActivationPolicy`.
### Package Upgrade Issues
Upgrading a package can require manual intervention in the event that the
previous version of the package supported a version of a custom resource that
has been dropped and replaced by a new version in the new package revision.
Kubernetes does not allow for applying a `CustomResourceDefinition` (CRD) that
drops a version in the `spec` that is in the current `status.storedVersions`
list, meaning that a revision cannot update and become the _controller_ of all
of its resources.
This situation can be remedied by manually deleting the offending CRD and
letting the new revision re-create it. In the event that custom resources exist
for the given CRD, they must be deleted before the CRD can be removed.
## The Package Cache
When a package is installed into a cluster, Crossplane fetches the package image
and stores its contents in a dedicated package cache. By default, this cache is
backed by an [`emptyDir` Volume][emptyDir-volume], meaning that all cached data
is lost when a `Pod` restarts. Users who wish for cache contents to be persisted
between `Pod` restarts may opt to instead use a [`persistentVolumeClaim`
(PVC)][pvc] by setting the `packageCache.pvc` Helm chart parameter to the name
of the PVC.
### Pre-Populating the Package Cache
Because the package cache can be backed by any storage medium, users are able to
optionally to pre-populate the cache with images that are not present on an
external [OCI registry]. To utilize a package that has been manually stored in
the cache, users must specify the name of the package in `spec.package` and use
`packagePullPolicy: Never`. For instance, if a user built a `Configuration`
package named `mycoolpkg.xpkg` and loaded it into the volume that was to be used
for the package cache (i.e. copied the `.xpkg` file into the storage medium
backing the PVC), the package could be utilized with the following manifest:
```yaml
apiVersion: pkg.crossplane.io/v1
kind: Configuration
metadata:
name: my-cool-pkg
spec:
package: mycoolpkg
packagePullPolicy: Never
```
Importantly, as long as a package is being used as the `spec.package` of a
`Configuration` or `Provider`, it must remain in the cache. For this reason, it
is recommended that users opt for a durable storage medium when manually loading
packages into the cache.
In addition, if manually loading a `Provider` package into the cache, users must
ensure that the controller image that it references is able to be pulled by the
cluster nodes. This can be accomplished either by pushing it to a registry, or
by [pre-pulling images] onto nodes in the cluster.
<!-- Named Links -->
[OCI images]: https://github.com/opencontainers/image-spec
[Providers]: {{<ref "providers" >}}
[provider-docs]: https://doc.crds.dev/github.com/crossplane/crossplane/meta.pkg.crossplane.io/Provider/v1
[configuration-docs]: https://doc.crds.dev/github.com/crossplane/crossplane/meta.pkg.crossplane.io/Configuration/v1
[lock-api]: https://doc.crds.dev/github.com/crossplane/crossplane/pkg.crossplane.io/Lock/v1beta1
[specification]: https://github.com/Masterminds/semver#basic-comparisons
[composition]: {{<ref "compositions" >}}
[IAM Roles for Service Accounts]: https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html
[controller-config-docs]: https://doc.crds.dev/github.com/crossplane/crossplane/pkg.crossplane.io/ControllerConfig/v1alpha1
[package format]: https://github.com/crossplane/crossplane/blob/1aa83092172bdf0d2ed64754d33517c612ff7368/design/one-pager-package-format-v2.md
[provider-gcp]: https://doc.crds.dev/github.com/crossplane/crossplane/meta.pkg.crossplane.io/Provider/v1
[emptyDir-volume]: https://kubernetes.io/docs/concepts/storage/volumes/#emptydir
[pvc]: https://kubernetes.io/docs/concepts/storage/volumes/#persistentvolumeclaim
[OCI registry]: https://github.com/opencontainers/distribution-spec
[pre-pulling images]: https://kubernetes.io/docs/concepts/containers/images/#pre-pulled-images

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,381 @@
---
title: Crossplane Pods
weight: 1
description: Background on the components installed with Crossplane and their functions.
---
The base Crossplane installation consists of two pods, the `crossplane` pod and
the `crossplane-rbac-manager` pod. Both pods install in the `crossplane-system`
namespace by default.
## Crossplane pod
### Init container
Before starting the core Crossplane container an _init_ container runs. The init
container installs the core Crossplane
[Custom Resource Definitions](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#customresourcedefinitions)
(`CRDs`), configures Crossplane webhooks and installs any supplied Providers or
Configurations.
{{<hint "tip" >}}
The Kubernetes documentation contains more information about
[init containers](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/).
{{< /hint >}}
The settings the init container sets include installing Provider or Configuration
packages with Crossplane, customizing the namespace Crossplane installs in and
defining webhook configurations.
The core CRDs installed by the init container include:
* CompositeResourceDefinitions, Compositions, Configurations and Providers
* Locks to manage package dependencies
* ControllerConfigs to apply settings to installed Providers
* StoreConfigs for connecting external secret stores like
[HashiCorp Vault](https://www.vaultproject.io/)
{{< hint "note" >}}
The [Install Crossplane]({{< ref "../software/install" >}}) section has more
information about customizing the Crossplane install.
{{< /hint >}}
The status `Init` on the Crossplane pod is the init container running.
```shell
kubectl get pods -n crossplane-system
NAME READY STATUS RESTARTS AGE
crossplane-9f6d5cd7b-r9j8w 0/1 Init:0/1 0 6s
```
The init container completes and starts the Crossplane core container
automatically.
```shell
kubectl get pods -n crossplane-system
NAME READY STATUS RESTARTS AGE
crossplane-9f6d5cd7b-r9j8w 1/1 Running 0 15s
```
### Core container
The main Crossplane container, called the _core_ container, enforces
the desired state of Crossplane resources, manages leader elections and process
webhooks.
{{<hint "note" >}}
The Crossplane pod only reconciles core Crossplane components, including Claims
and composite resources. Providers are responsible for reconciling their managed
resources.
{{< /hint >}}
#### Reconcile loop
The core container operates on a _reconcile loop_, constantly checking the
status of deployed resources and correcting any "drift." After checking a
resource Crossplane waits some time and checks again.
Crossplane monitors resources through a Kubernetes
[_watch_](https://kubernetes.io/docs/reference/using-api/api-concepts/#efficient-detection-of-changes)
or through periodic polling. Some resources may be both watched and polled.
Crossplane requests that the API server notifies Crossplane of any changes on
objects. This notification tool is a _watch_.
Watched objects include Providers, managed resources and
CompositeResourceDefinitions.
For objects that Kubernetes can't provide a watch for, Crossplane
periodically poll the resource to find it's state. The default polling rate is
one minute. Change the polling rate with the `--poll-interval` pod argument.
Reducing the poll-interval value causes Crossplane to poll resources more
frequently. This increases the load of the Crossplane pod and
results in more frequent provider API calls.
<!-- vale write-good.TooWordy = NO -->
<!-- allow "maximum" -->
Increasing the poll-interval causes Crossplane to poll resources less
frequently. This increases the maximum time until Crossplane
discovers changes in the cloud provider that require updating.
<!-- vale write-good.TooWordy = YES -->
Managed resources use polling.
{{< hint "note" >}}
Managed resources watch for Kubernetes events like deletion or changes to
their `spec`. Managed resources rely on polling to detect changes in the
external system.
{{< /hint >}}
Crossplane double-checks all resources to
confirm they're in the desired state. Crossplane does this every one hour by
default. Use the `--sync-interval` Crossplane pod argument to change this
interval.
The `--max-reconcile-rate` rate defines the rate, in times per second,
Crossplane reconciles resources.
Reducing the `--max-reconcile-rate`, or making it smaller, reduces CPU
resources Crossplane uses, but increases the amount of time until changed
resources are fully synced.
Increasing the `--max-reconcile-rate`, or making it larger, increases the
CPU resources Crossplane uses but allows Crossplane to reconcile all resources
faster.
{{< hint "important" >}}
Most Providers use their own `--max-reconcile-rate`. This determines the
same settings for Providers and their managed resources. Applying the
`--max-reconcile-rate` to Crossplane only controls the rate for
core Crossplane resources.
{{< /hint >}}
##### Reconcile retry rate
The `--max-reconcile-rate` setting configures the number of times per second
Crossplane or a provider attempts to correct a resource. The default value is
10 times per second.
All core Crossplane components share the reconcile rate. Each Provider
implements their own max reconcile rate setting.
##### Number of reconcilers
The second value `--max-reconcile-rate` defines is the number of
resources that Crossplane can reconcile at once. If there are more resources than
the configured `--max-reconcile-rate` the remaining resources must wait until
Crossplane reconciles a an existing resource.
Read the [Change Pod Settings]({{<ref "#change-pod-settings">}}) section for
instructions on applying these settings.
<!-- vale Microsoft.HeadingAcronyms = NO -->
<!-- allow 'RBAC' since that's the name -->
## RBAC manager pod
<!-- vale Microsoft.HeadingAcronyms = YES -->
The Crossplane RBAC manager pod automates required Kubernetes RBAC permissions
for Crossplane and Crossplane Providers.
{{<hint "note" >}}
Crossplane installs and enables the RBAC manager by default.
Disabling the RBAC manager requires manual Kubernetes permissions definitions
for proper Crossplane operations.
The
[RBAC manager design document](https://github.com/crossplane/crossplane/blob/master/design/design-doc-rbac-manager.md)
provides more comprehensive details on the Crossplane RBAC requirements.
{{< /hint >}}
### Disable the RBAC manager
Disable the RBAC manager after installation by deleting the
`crossplane-rbac-manager` deployment from the `crossplane-system` namespace.
Disable the RBAC manager before installation by editing the Helm `values.yaml`
file, setting `rbacManager.deploy` to `false`.
{{< hint "note" >}}
Instructions for changing Crossplane pod settings during installation are in the
[Crossplane Install]({{<ref "../software/install">}}) section.
{{< /hint >}}
<!-- vale Microsoft.HeadingAcronyms = NO -->
<!-- allow 'RBAC' since that's the name -->
### RBAC init container
<!-- vale Microsoft.HeadingAcronyms = YES -->
The RBAC manager requires the `CompositeResourceDefinition` and
`ProviderRevision` resources to be available before starting.
The RBAC manager init container waits for these resources before starting the
main RBAC manager container.
### RBAC manager container
The RBAC manager container preforms the following tasks:
* creating and binding RBAC roles to Provider ServiceAccounts, allowing
them to control their managed resources
* allowing the `crossplane` ServiceAccount to create managed resources
* creating ClusterRoles to access Crossplane resources in all namespaces
* creating Roles to access Crossplane resources in specific namespaces
Use the [ClusterRoles]({{<ref "#crossplane-clusterroles">}}) to grant access to all Crossplane resources in the
cluster.
Use the [Roles]({{<ref "#crossplane-roles" >}}) to only grant access to Crossplane Claims.
#### Crossplane ClusterRoles
The RBAC manager creates four Kubernetes ClusterRoles. These Roles grant
permissions over cluster wide Crossplane resources.
<!-- vale Google.Headings = NO -->
<!-- disable heading checking for the role names -->
<!-- vale Google.WordList = NO -->
<!-- allow "admin" -->
##### crossplane-admin
<!-- vale Google.WordList = YES -->
<!-- vale Crossplane.Spelling = NO -->
The `crossplane-admin` ClusterRole has the following permissions:
* full access to all Crossplane types
* full access to all secrets and namespaces (even those unrelated to Crossplane)
* read-only access to all cluster RBAC roles, CustomResourceDefinitions and
events
* ability to bind RBAC roles to other entities.
<!-- vale Crossplane.Spelling = YES -->
View the full RBAC policy with
```shell
kubectl describe clusterrole crossplane:admin
```
##### crossplane-edit
The `crossplane-edit` ClusterRole has the following permissions:
* full access to all Crossplane types
* full access to all secrets (even those unrelated to Crossplane)
* read-only access to all namespaces and events (even those unrelated to Crossplane).
View the full RBAC policy with
```shell
kubectl describe clusterrole crossplane:edit
```
##### crossplane-view
The `crossplane-view` ClusterRole has the following permissions:
* read-only access to all Crossplane types
* read-only access to all namespaces and events (even those unrelated to Crossplane).
View the full RBAC policy with
```shell
kubectl describe clusterrole crossplane:view
```
##### crossplane-browse
The `crossplane-browse` ClusterRole has the following permissions:
* read-only access to all Crossplane types
* read-only access to all namespaces and events (even those unrelated to Crossplane).
View the full RBAC policy with
```shell
kubectl describe clusterrole crossplane:browse
```
#### Crossplane Roles
By default the RBAC manager creates three Roles in every namespace. These Roles
grant access to Claims in a specific namespace. The RBAC manager dynamically
updates the Roles to access the specific API endpoints in a Claim.
{{< hint "note" >}}
The specific details of the namespace Roles are beyond this guide. For more
information read the [Composite Resource ClusterRole
Mechanics](https://github.com/crossplane/crossplane/blob/master/design/design-doc-rbac-manager.md#composite-resource-clusterrole-mechanics)
section of the RBAC Manager design document.
{{< /hint >}}
You can disable these namespace specific roles by configuring the RBAC manager
with `--manage=Basic`.
{{< hint "note" >}}
Instructions for changing Crossplane pod settings during installation are in the
[Crossplane Install]({{<ref "../software/install">}}) section.
{{< /hint >}}
## Leader election
By default only a single Crossplane pod runs in a cluster. If more than one
Crossplane pod runs both pods try to manage Crossplane resources. To prevent
conflicts Crossplane uses a _leader election_ to have a single pod in control at
a time. Other Crossplane pods standby until the leader fails.
{{< hint "note" >}}
It's possible to run more than one Crossplane or RBAC manager pods for
redundancy.
Kubernetes restarts any failed Crossplane or RBAC manager pods.
Redundant pods aren't required in most deployments.
{{< /hint >}}
Both the Crossplane pod and the RBAC manager pods support leader elections.
Enable leader elections with the `--leader-election` pod argument.
{{< hint "warning" >}}
<!-- vale write-good.TooWordy = NO -->
<!-- "multiple" -->
<!-- vale write-good.Passive = NO -->
<!-- allow "is unsupported" -->
Running multiple Crossplane pods without leader election is unsupported.
<!-- vale write-good.Passive = YES -->
<!-- vale write-good.TooWordy = YES -->
{{< /hint >}}
## Change pod settings
Change Crossplane pod settings either before installing Crossplane by editing
the Helm `values.yml` file or after installation by editing the `Deployment`.
The full list of configuration options are available in the
[Crossplane Install]({{<ref "../software/install">}}) section.
{{< hint "note" >}}
Instructions for changing Crossplane pod settings during installation are in the
[Crossplane Install]({{<ref "../software/install">}}) section.
{{< /hint >}}
### Edit the deployment
{{< hint "note" >}}
These settings apply to both the `crossplane` and `rbac-manager` pods and
`Deployments`.
{{< /hint >}}
To change the settings of an installed Crossplane pod, edit the `crossplane`
deployment in the `crossplane-system` namespace with the command
`kubectl edit deployment crossplane --namespace crossplane-system`
{{< hint "warning" >}}
Updating the Crossplane deployment restarts the Crossplane pod.
{{< /hint >}}
Add Crossplane pod arguments to the
{{<hover label="args" line="9" >}}spec.template.spec.containers[].args{{< /hover >}}
section of the deployment.
For example, to change the `sync-interval` add
{{<hover label="args" line="12" >}}--sync-interval=30m{{< /hover >}}.
```yaml {label="args", copy-lines="1"}
kubectl edit deployment crossplane --namespace crossplane-system
apiVersion: apps/v1
kind: Deployment
spec:
# Removed for brevity
template:
spec:
containers:
- args:
- core
- start
- --sync-interval=30m
```
### Use environmental variables
The core Crossplane pod checks for configured environmental variables at startup
to change default settings.
The full list of configurable environmental variables are available in the
[Crossplane Install]({{<ref "../software/install">}}) section.

View File

@ -0,0 +1,438 @@
---
title: Providers
weight: 5
description: "Providers connect Crossplane to external APIs"
---
Providers enable Crossplane to provision infrastructure on an
external service. Providers create new Kubernetes APIs and map them to external
APIs.
Providers are responsible for all aspects of connecting to non-Kubernetes
resources. This includes authentication, making external API calls and
providing
[Kubernetes Controller](https://kubernetes.io/docs/concepts/architecture/controller/)
logic for any external resources.
Examples of providers include:
* [Provider AWS](https://github.com/upbound/provider-aws)
* [Provider Azure](https://github.com/upbound/provider-azure)
* [Provider GCP](https://github.com/upbound/provider-gcp)
* [Provider Kubernetes](https://github.com/crossplane-contrib/provider-kubernetes)
{{< hint "tip" >}}
Find more providers in the [Upbound Marketplace](https://marketplace.upbound.io).
{{< /hint >}}
<!-- vale write-good.Passive = NO -->
<!-- "are Managed" isn't passive in this context -->
Providers define every external resource they can create in Kubernetes as a
Kubernetes API endpoint. These endpoints are
[_Managed Resources_]({{<ref "managed-resources" >}}).
<!-- vale write-good.Passive = YES -->
{{< hint "note" >}}
Instructions on building your own Provider are outside of the scope of this
document. Read the Crossplane contributing [Provider Development
Guide](https://github.com/crossplane/crossplane/blob/master/contributing/guide-provider-development.md)
for more information.
{{< /hint >}}
## Install a Provider
Installing a provider creates a Provider pod that's responsible for installing
the Provider's APIs into the Kubernetes cluster. Providers constantly watch the
state of the desired managed resources and create any external resources that
are missing.
Install a Provider with a Crossplane
{{<hover label="install" line="2">}}Provider{{</hover >}} object setting the
{{<hover label="install" line="6">}}spec.package{{</hover >}} value to the
location of the provider package.
For example, to install the
[AWS Community Provider](https://github.com/crossplane-contrib/provider-aws),
```yaml {label="install"}
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws
spec:
package: xpkg.upbound.io/crossplane-contrib/provider-aws:v0.39.0
```
{{< hint "tip" >}}
Providers are Crossplane Packages. Read more about Packages in the
[Packages documentation]({{<ref "packages" >}}).
{{< /hint >}}
By default, the Provider pod installs in the same namespace as Crossplane
(`crossplane-system`).
### Install with Helm
Crossplane supports installing Providers during an initial Crossplane
installation with the Crossplane Helm chart.
Use the
{{<hover label="helm" line="5" >}}--set provider.packages{{</hover >}}
argument with `helm install`.
For example, to install the AWS Community Provider,
```shell {label="helm"}
helm install crossplane \
crossplane-stable/crossplane \
--namespace crossplane-system \
--create-namespace \
--set provider.packages={xpkg.upbound.io/crossplane-contrib/provider-aws:v0.39.0}
```
### Install from a private repository
Installing a Provider from a private package repository requires a
Kubernetes secret object. The Provider uses the secret with the
{{<hover label="pps" line="7" >}}packagePullSecrets{{</hover>}} option.
```yaml {label="pps"}
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: private-provider
spec:
package: private-repo.example.org/providers/my-provider
packagePullSecrets:
- name: my-secret
```
{{< hint "note" >}}
The Kubernetes secret object the Provider uses must be in the same namespace as
the Crossplane pod.
{{< /hint >}}
## Upgrade a Provider
To upgrade an existing Provider edit the installed Provider Package by either
applying a new Provider manifest or with `kubectl edit providers`.
Update the version number in the Provider's `spec.package` and apply the change.
Crossplane installs the new image and creates a new `ProviderRevision`.
## Remove a Provider
Remove a Provider by deleting the Provider object with `kubectl delete
provider`.
{{< hint "warning" >}}
Removing a Provider without first removing the Provider's managed resources
may abandon the resources. The external resources aren't deleted.
If you remove the Provider first, you must manually delete external resources
through your cloud provider. Managed resources must be manually deleted by
removing their finalizers.
For more information on deleting abandoned resources read the [Crossplane
troubleshooting guide]({{<ref "/knowledge-base/guides/troubleshoot#deleting-when-a-resource-hangs" >}}).
{{< /hint >}}
## Verify a Provider
Providers install their own APIs representing the managed resources they support.
Providers may also create Deployments, Service Accounts or RBAC configuration.
View the status of a Provider with
`kubectl get providers`
During the install a Provider report `INSTALLED` as `True` and `HEALTHY` as
`Unknown`.
```shell {copy-lines="1"}
kubectl get providers
NAME INSTALLED HEALTHY PACKAGE AGE
crossplane-contrib-provider-aws True Unknown xpkg.upbound.io/crossplane-contrib/provider-aws:v0.39.0 63s
```
After the Provider install completes and it's ready for use the `HEALTHY` status
reports `True`.
```shell {copy-lines="1"}
kubectl get providers
NAME INSTALLED HEALTHY PACKAGE AGE
crossplane-contrib-provider-aws True True xpkg.upbound.io/crossplane-contrib/provider-aws:v0.39.0 88s
```
{{<hint "important" >}}
Some Providers install hundreds of Kubernetes Custom Resource Definitions (`CRDs`).
This can create significant strain on undersized API Servers, impacting Provider
install times.
The Crossplane community has more
[details on scaling CRDs](https://github.com/crossplane/crossplane/blob/master/design/one-pager-crd-scaling.md).
{{< /hint >}}
### Provider conditions
Crossplane uses a standard set of `Conditions` for Providers.
View the conditions of a provider under their `Status` with
`kubectl describe provider`.
```yaml
kubectl describe provider
Name: my-provider
API Version: pkg.crossplane.io/v1
Kind: Provider
# Removed for brevity
Status:
Conditions:
Reason: HealthyPackageRevision
Status: True
Type: Healthy
Reason: ActivePackageRevision
Status: True
Type: Installed
# Removed for brevity
```
#### Types
Provider `Conditions` support two `Types`:
* `Type: Installed` - the Provider package installed but isn't ready for use.
* `Type: Healthy` - The Provider package is ready to use.
#### Reasons
Each `Reason` relates to a specific `Type` and `Status`. Crossplane uses the
following `Reasons` for Provider `Conditions`.
<!-- vale Google.Headings = NO -->
##### InactivePackageRevision
`Reason: InactivePackageRevision` indicates the Provider Package is using an
inactive Provider Package Revision.
<!-- vale Google.Headings = YES -->
```yaml
Type: Installed
Status: False
Reason: InactivePackageRevision
```
<!-- vale Google.Headings = NO -->
##### ActivePackageRevision
<!-- vale Google.Headings = YES -->
The Provider Package is the current Package Revision, but Crossplane hasn't
finished installing the Package Revision yet.
{{< hint "tip" >}}
Providers stuck in this state are because of a problem with Package Revisions.
Use `kubectl describe providerrevisions` for more details.
{{< /hint >}}
```yaml
Type: Installed
Status: True
Reason: ActivePackageRevision
```
<!-- vale Google.Headings = NO -->
##### HealthyPackageRevision
The Provider is fully installed and ready to use.
{{<hint "tip" >}}
`Reason: HealthyPackageRevision` is the normal state of a working Provider.
{{< /hint >}}
<!-- vale Google.Headings = YES -->
```yaml
Type: Healthy
Status: True
Reason: HealthyPackageRevision
```
<!-- vale Google.Headings = NO -->
##### UnhealthyPackageRevision
<!-- vale Google.Headings = YES -->
There was an error installing the Provider Package Revision, preventing
Crossplane from installing the Provider Package.
{{<hint "tip" >}}
Use `kubectl describe providerrevisions` for more details on why the Package
Revision failed.
{{< /hint >}}
```yaml
Type: Healthy
Status: False
Reason: UnhealthyPackageRevision
```
<!-- vale Google.Headings = NO -->
##### UnknownPackageRevisionHealth
<!-- vale Google.Headings = YES -->
The status of the Provider Package Revision is `Unknown`. The Provider Package
Revision may be installing or has an issue.
{{<hint "tip" >}}
Use `kubectl describe providerrevisions` for more details on why the Package
Revision failed.
{{< /hint >}}
```yaml
Type: Healthy
Status: Unknown
Reason: UnknownPackageRevisionHealth
```
## Configure a Provider
Providers have two different types of configurations:
* _Controller configurations_ that change the settings of the Provider pod
running inside the Kubernetes cluster. For example, Pod `toleration`.
* _Provider configurations_ that change settings used when communicating with
an external provider. For example, cloud provider authentication.
{{<hint "important" >}}
Apply `ControllerConfig` objects to Providers.
Apply `ProviderConfig` objects to managed resources.
{{< /hint >}}
### Controller configuration
{{< hint "important" >}}
The Crossplane community deprecated the `ControllerConfig` type in v1.11.
Applying a Controller configuration generates a deprecation warning.
Controller configurations are still supported until there is a replacement type
in a future Crossplane version.
{{< /hint >}}
Applying a Crossplane `ControllerConfig` to a Provider changes the settings of
the Provider's pod. The
[Crossplane ControllerConfig schema](https://doc.crds.dev/github.com/crossplane/crossplane/pkg.crossplane.io/ControllerConfig/v1alpha1)
defines the supported set of ControllerConfig settings.
The most common use case for ControllerConfigs are providing `args` to a
Provider's pod enabling optional services. For example, enabling
[external secret stores](https://docs.crossplane.io/knowledge-base/integrations/vault-as-secret-store/#enable-external-secret-stores-in-the-provider)
for a Provider.
Each Provider determines their supported set of `args`.
### Provider configuration
The `ProviderConfig` determines settings the Provider uses communicating to the
external provider. Each Provider determines available settings of their
`ProviderConfig`.
<!-- vale write-good.Weasel = NO -->
<!-- allow "usually" -->
Provider authentication is usually configured with a `ProviderConfig`. For
example, to use basic key-pair authentication with Provider AWS a
{{<hover label="providerconfig" line="2" >}}ProviderConfig{{</hover >}}
{{<hover label="providerconfig" line="5" >}}spec{{</hover >}}
defines the
{{<hover label="providerconfig" line="6" >}}credentials{{</hover >}} and that
the Provider pod should look in the Kubernetes
{{<hover label="providerconfig" line="7" >}}Secrets{{</hover >}} objects and use
the key named
{{<hover label="providerconfig" line="10" >}}aws-creds{{</hover >}}.
<!-- vale write-good.Weasel = YES -->
```yaml {label="providerconfig"}
apiVersion: aws.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: aws-provider
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: aws-creds
key: creds
```
{{< hint "important" >}}
Authentication configuration may be different across Providers.
Read the documentation on a specific Provider for instructions on configuring
authentication for that Provider.
{{< /hint >}}
<!-- vale write-good.TooWordy = NO -->
<!-- allow multiple -->
ProviderConfig objects apply to individual Managed Resources. A single
Provider can authenticate with multiple users or accounts through
ProviderConfigs.
<!-- vale write-good.TooWordy = YES -->
Each account's credentials tie to a unique ProviderConfig. When creating a
managed resource, attach the desired ProviderConfig.
For example, two AWS ProviderConfigs, named
{{<hover label="user" line="4">}}user-keys{{</hover >}} and
{{<hover label="admin" line="4">}}admin-keys{{</hover >}}
use different Kubernetes secrets.
```yaml {label="user"}
apiVersion: aws.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: user-keys
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: my-key
key: secret-key
```
```yaml {label="admin"}
apiVersion: aws.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: admin-keys
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: admin-key
key: admin-secret-key
```
Apply the ProviderConfig when creating a managed resource.
This creates an AWS {{<hover label="user-bucket" line="2" >}}Bucket{{< /hover >}}
resource using the
{{<hover label="user-bucket" line="9" >}}user-keys{{< /hover >}} ProviderConfig.
```yaml {label="user-bucket"}
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
name: user-bucket
spec:
forProvider:
region: us-east-2
providerConfigRef:
name: user-keys
```
This creates a second {{<hover label="admin-bucket" line="2" >}}Bucket{{< /hover >}}
resource using the
{{<hover label="admin-bucket" line="9" >}}admin-keys{{< /hover >}} ProviderConfig.
```yaml {label="admin-bucket"}
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
name: user-bucket
spec:
forProvider:
region: us-east-2
providerConfigRef:
name: admin-keys
```

View File

@ -0,0 +1,16 @@
---
title: Getting Started
weight: 4
description: An introduction to Crossplane and Crossplane quickstart guides.
---
{{<img src="/media/banner.png" alt="Crossplane Popsicle Truck" size="large" >}}
## Hands-On
Want a hands-on example? Follow a Crossplane Quickstart for your cloud provider.
* [AWS quickstart]({{<ref "provider-aws" >}})
* [Azure quickstart]({{<ref "provider-azure" >}})
* [GCP quickstart]({{<ref "provider-gcp" >}})
## Install
Ready to get started? [Install Crossplane]({{<ref "../software/install" >}}) in a Kubernetes cluster.

View File

@ -0,0 +1,488 @@
---
title: Crossplane Introduction
weight: 2
---
Crossplane connects your Kubernetes cluster to external,
non-Kubernetes resources, and allows platform teams to build custom Kubernetes
APIs to consume those resources.
<!-- vale gitlab.SentenceLength = NO -->
Crossplane creates Kubernetes
[Custom Resource Definitions](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/)
(`CRDs`) to represent the external resources as native
[Kubernetes objects](https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/).
As native Kubernetes objects, you can use standard commands like `kubectl create`
and `kubectl describe`. The full
[Kubernetes API](https://kubernetes.io/docs/reference/using-api/) is available
for every Crossplane resource.
<!-- vale gitlab.SentenceLength = YES -->
Crossplane also acts as a
[Kubernetes Controller](https://kubernetes.io/docs/concepts/architecture/controller/)
to watch the state of the external resources and provide state enforcement. If
something modifies or deletes a resource outside of Kubernetes, Crossplane reverses
the change or recreates the deleted resource.
{{<img src="/media/crossplane-intro-diagram.png" alt="Diagram showing a user communicating to Kubernetes. Crossplane connected to Kubernetes and Crossplane communicating with AWS, Azure and GCP" align="center">}}
With Crossplane installed in a Kubernetes cluster, users only communicate with
Kubernetes. Crossplane manages the communication to external resources like AWS,
Azure or Google Cloud.
Crossplane also allows the creation of custom Kubernetes APIs. Platform teams can
combine external resources and simplify or customize the APIs presented to the
platform consumers.
## Crossplane components overview
This table provides a summary of Crossplane components and their roles.
{{< table "table table-hover table-sm">}}
| Component | Abbreviation | Scope | Summary |
| --- | --- | --- | ---- |
| [Provider]({{<ref "#providers">}}) | | cluster | Creates new Kubernetes Custom Resource Definitions for an external service. |
| [ProviderConfig]({{<ref "#provider-configurations">}}) | `PC` | cluster | Applies settings for a _Provider_. |
| [Managed Resource]({{<ref "#managed-resources">}}) | `MR` | cluster | A Provider resource created and managed by Crossplane inside the Kubernetes cluster. |
| [Composition]({{<ref "#compositions">}}) | | cluster | A template for creating multiple _managed resources_ at once. |
| [Composite Resources]({{<ref "#composite-resources" >}}) | `XR` | cluster | Uses a _Composition_ template to create multiple _managed resources_ as a single Kubernetes object. |
| [CompositeResourceDefinitions]({{<ref "#composite-resource-definitions" >}}) | `XRD` | cluster | Defines the API schema for _Composite Resources_ and _Claims_ |
| [Claims]({{<ref "#claims" >}}) | `XC` | namespace | Like a _Composite Resource_, but namespace scoped. |
{{< /table >}}
## The Crossplane Pod
When installed in a Kubernetes cluster Crossplane creates an initial set of
Custom Resource Definitions (`CRDs`) of the core Crossplane components.
{{< expand "View the initial Crossplane CRDs" >}}
After installing Crossplane use `kubectl get crds` to view the Crossplane
installed CRDs.
```shell
kubectl get crds
NAME
compositeresourcedefinitions.apiextensions.crossplane.io
compositionrevisions.apiextensions.crossplane.io
compositions.apiextensions.crossplane.io
configurationrevisions.pkg.crossplane.io
configurations.pkg.crossplane.io
controllerconfigs.pkg.crossplane.io
locks.pkg.crossplane.io
providerrevisions.pkg.crossplane.io
providers.pkg.crossplane.io
storeconfigs.secrets.crossplane.io
```
{{< /expand >}}
The following sections describe the functions of some of these CRDs.
## Providers
A Crossplane _Provider_ creates a second set of CRDs that define how Crossplane
connects to a non-Kubernetes service. Each external service relies on its own
Provider. For example,
[AWS](https://marketplace.upbound.io/providers/upbound/provider-aws),
[Azure](https://marketplace.upbound.io/providers/upbound/provider-azure)
and [GCP](https://marketplace.upbound.io/providers/upbound/provider-gcp)
are different providers for each cloud service.
{{< hint "tip" >}}
Most Providers are for cloud services but Crossplane can use a Provider to
connect to any service with an API.
{{< /hint >}}
For example, an AWS Provider defines Kubernetes CRDs for AWS resources like EC2
compute instances or S3 storage buckets.
The Provider defines the Kubernetes API definition for the external resource.
For example, the
[Upbound Provider AWS](https://marketplace.upbound.io/providers/upbound/provider-aws/)
defines a
[`bucket`](https://marketplace.upbound.io/providers/upbound/provider-aws/v0.25.0/resources/s3.aws.upbound.io/Bucket/v1beta1)
resource for creating and managing AWS S3 storage buckets.
Within the `bucket` CRD is a
[`spec.forProvider.region`](https://marketplace.upbound.io/providers/upbound/provider-aws/v0.25.0/resources/s3.aws.upbound.io/Bucket/v1beta1#doc:spec-forProvider-region)
value that defines which AWS region to deploy the bucket in.
The Upbound Marketplace contains a large
[collection of Crossplane Providers](https://marketplace.upbound.io/providers).
More providers are available in the [Crossplane Contrib repository](https://github.com/crossplane-contrib/).
Providers are cluster scoped and available to all cluster namespaces.
View all installed Providers with the command `kubectl get providers`.
## Provider configurations
Providers have _ProviderConfigs_. _ProviderConfigs_ configure settings
related to the Provider like authentication or global defaults for the
Provider.
The API endpoints for ProviderConfigs are unique to each Provider.
_ProviderConfigs_ are cluster scoped and available to all cluster namespaces.
View all installed ProviderConfigs with the command `kubectl get providerconfig`.
## Managed resources
A Provider's CRDs map to individual _resources_ inside the provider. When
Crossplane creates and monitors a resource it's a _Managed Resource_.
Using a Provider's CRD creates a unique _Managed Resource_. For example,
using the Provider AWS's `bucket` CRD, Crossplane creates a `bucket` _Managed Resource_
inside the Kubernetes cluster that's connected to an AWS S3 storage bucket.
The Crossplane controller provides state enforcement for _Managed Resources_.
Crossplane enforces the settings and existence of _Managed Resources_. This
"Controller Pattern" is like how the Kubernetes
[kube-controller-manager](https://kubernetes.io/docs/reference/command-line-tools-reference/kube-controller-manager/)
enforces state for pods.
_Managed Resources_ are cluster scoped and available to all cluster namespaces.
Use `kubectl get managed` to view all _managed resources_.
{{<hint "warning" >}}
The `kubectl get managed` creates a lot of Kubernetes API queries.
Both the `kubectl` client and kube-apiserver throttle the API queries.
Depending on the size of the API server and number of managed resources, this
command may take minutes to return or may timeout.
For more information, read
[Kubernetes issue
#111880](https://github.com/kubernetes/kubernetes/issues/111880)
and
[Crossplane issue #3459](https://github.com/crossplane/crossplane/issues/3459).
{{< /hint >}}
## Compositions
A _Composition_ is a template for a collection of _managed resource_. _Compositions_
allow platform teams to define a set of _managed resources_ as a
single object.
For example, a compute _managed resource_ may require the creation of a storage
resource and a virtual network as well. A single _Composition_ can define all three
resources in a single _Composition_ object.
Using _Compositions_ simplifies the deployment of infrastructure made up of
multiple _managed resources_. _Compositions_ also enforce standards and settings
across deployments.
Platform teams can define fixed or default settings for each _managed resource_ inside a
_Composition_ or define fields and settings that users may change.
Using the previous example, the platform team may set a compute resource size
and virtual network settings. But the platform team allows users to define the
storage resource size.
Creating a _Composition_ Crossplane doesn't create any managed
resources. The _Composition_ is only a template for a collection of _managed
resources_ and their settings. A _Composite Resource_ creates the specific resources.
{{< hint "note" >}}
The [_Composite Resources_]({{<ref "#composite-resources">}})_ section discusses
_Composite Resources_.
{{< /hint >}}
_Compositions_ are cluster scoped and available to all cluster namespaces.
Use `kubectl get compositions` to view all _compositions_.
## Composite Resources
A _Composite Resource_ (`XR`) is a set of provisioned _managed resources_. A
_Composite Resource_ uses the template defined by a _Composition_ and applies
any user defined settings.
Multiple unique _Composite Resource_ objects can use the same _Composition_. For
example, a _Composition_ template can create a compute, storage and networking
set of _managed resources_. Crossplane uses the same _Composition_ template
every time a user requests this set of resources.
If a _Composition_ allows a user to define resource settings, users apply them
in a _Composite Resource_.
<!-- A _Composition_ defines which _Composite Resources_ can use the _Composition_
template with the _Composition_ `spec.compositeTypeRef` value. This defines the
{{<hover label="comp" line="7">}}apiVersion{{< /hover >}} and {{<hover
label="comp" line="8">}}kind{{< /hover >}} of _Composite Resources_ that can use the
_Composition_.
For example, in the _Composition_:
```yaml {label="comp"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: test.example.org
spec:
compositeTypeRef:
apiVersion: test.example.org/v1alpha1
kind: myComputeResource
# Removed for brevity
```
A _Composite Resource_ that can use this template must match this
{{<hover label="comp" line="7">}}apiVersion{{< /hover >}} and {{<hover
label="comp" line="8">}}kind{{< /hover >}}.
```yaml {label="xr"}
apiVersion: test.example.org/v1alpha1
kind: myComputeResource
metadata:
name: myResource
spec:
storage: "large"
```
The _Composite Resource_ {{<hover label="xr" line="1">}}apiVersion{{< /hover >}}
matches the and _Composition_
{{<hover label="comp" line="7">}}apiVersion{{</hover >}} and the
_Composite Resource_ {{<hover label="xr" line="2">}}kind{{< /hover >}}
matches the _Composition_ {{<hover label="comp" line="8">}}kind{{< /hover >}}.
In this example, the _Composite Resource_ also sets the
{{<hover label="xr" line="7">}}storage{{< /hover >}} setting. The
_Composition_ uses this value when creating the associated _managed resources_
owned by this _Composite Resource_. -->
{{< hint "tip" >}}
_Compositions_ are templates for a set of _managed resources_.
_Composite Resources_ fill out the template and create _managed resources_.
Deleting a _Composite Resource_ deletes all the _managed resources_ it created.
{{< /hint >}}
_Composite Resources_ are cluster scoped and available to all cluster namespaces.
Use `kubectl get composite` to view all _Composite Resources_.
## Composite Resource Definitions
_Composite Resource Definitions_ (`XRDs`) create custom Kubernetes APIs used by
_Claims_ and _Composite Resources_.
{{< hint "note" >}}
The [_Claims_]({{<ref "#claims">}}) section discusses
_Claims_.
{{< /hint >}}
Platform teams define the custom APIs.
These APIs can define specific values
like storage space in gigabytes, generic settings like `small` or `large`,
deployment options like `cloud` or `onprem`. Crossplane doesn't limit the API definitions.
The _Composite Resource Definition's_ `kind` is from Crossplane.
```yaml
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
```
The `spec` of a _Composite Resource Definition_ creates the `apiVersion`,
`kind` and `spec` of a _Composite Resource_.
{{< hint "tip" >}}
The _Composite Resource Definition_ defines the parameters for a _Composite
Resource_.
{{< /hint >}}
A _Composite Resource Definition_ has four main `spec` parameters:
* A {{<hover label="specGroup" line="3" >}}group{{< /hover >}}
to define the
{{< hover label="xr2" line="2" >}}apiVersion{{</hover >}}
in a _Composite Resource_ .
* The {{< hover label="specGroup" line="7" >}}versions.name{{</hover >}}
that defines the version used in a _Composite Resource_.
* A {{< hover label="specGroup" line="5" >}}names.kind{{</hover >}}
to define the _Composite Resource_
{{< hover label="xr2" line="3" >}}kind{{</hover>}}.
* A {{< hover label="specGroup" line="8" >}}versions.schema{{</hover>}} section
to define the _Composite Resource_ {{<hover label="xr2" line="6" >}}spec{{</hover >}}.
```yaml {label="specGroup"}
# Composite Resource Definition (XRD)
spec:
group: test.example.org
names:
kind: myComputeResource
versions:
- name: v1alpha1
schema:
# Removed for brevity
```
A _Composite Resource_ based on this _Composite Resource Definition_ looks like this:
```yaml {label="xr2"}
# Composite Resource (XR)
apiVersion: test.example.org/v1alpha1
kind: myComputeResource
metadata:
name: myResource
spec:
storage: "large"
```
A _Composite Resource Definition_ {{< hover label="specGroup" line="8" >}}schema{{</hover >}} defines the _Composite Resource_
{{<hover label="xr2" line="6" >}}spec{{</hover >}} parameters.
These parameters are the new, custom APIs, that developers can use.
For example, creating a compute _managed resource_ requires knowledge of a
cloud provider's compute class names like AWS's `m6in.large` or GCP's
`e2-standard-2`.
A _Composite Resource Definition_ can limit the choices to `small` or `large`.
A _Composite Resource_ uses those options and the _Composition_ maps them
to specific cloud provider settings.
The following _Composite Resource Definition_ defines a {{<hover label="specVersions" line="17" >}}storage{{< /hover >}}
parameter. The storage is a
{{<hover label="specVersions" line="18">}}string{{< /hover >}}
and the OpenAPI
{{<hover label="specVersions" line="19" >}}oneOf{{< /hover >}} requires the
options to be either {{<hover label="specVersions" line="20" >}}small{{< /hover >}}
or {{<hover label="specVersions" line="21" >}}large{{< /hover >}}.
```yaml {label="specVersions"}
# Composite Resource Definition (XRD)
spec:
group: test.example.org
names:
kind: myComputeResource
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
storage:
type: string
oneOf:
- pattern: '^small$'
- pattern: '^large$'
required:
- storage
```
A _Composite Resource Definition_ can define a wide variety of settings and options.
Creating a _Composite Resource Definition_ enables the creation of _Composite
Resources_ but can also create a _Claim_.
_Composite Resource Definitions_ with a `spec.claimNames` allow developers to
create _Claims_.
For example, the
{{< hover label="xrdClaim" line="6" >}}claimNames.kind{{</hover >}}
allows the creation of _Claims_ of `kind: computeClaim`.
```yaml {label="xrdClaim"}
# Composite Resource Definition (XRD)
spec:
group: test.example.org
names:
kind: myComputeResource
claimNames:
kind: computeClaim
# Removed for brevity
```
## Claims
_Claims_ are the primary way developers interact with Crossplane.
_Claims_ access the custom APIs defined by the platform team in a _Composite
Resource Definition_.
_Claims_ look like _Composite Resources_, but they're namespace scoped,
while _Composite Resources_ are cluster scoped.
{{< hint "note" >}}
**Why does namespace scope matter?**
Having namespace scoped _Claims_ allows multiple teams, using unique namespaces,
to create the same types of resources, independent of each other. The compute
resources of team A are unique to the compute resources of team B.
Directly creating _Composite Resources_ requires cluster-wide permissions,
shared with all teams.
_Claims_ create the same set of resources, but on a namespace level.
{{< /hint >}}
The previous _Composite Resource Definition_ allows the creation of _Claims_
of the kind
{{<hover label="xrdClaim2" line="7" >}}computeClaim{{</hover>}}.
Claims use the same
{{< hover label="xrdClaim2" line="3" >}}apiVersion{{< /hover >}}
defined in _Composite Resource Definition_ and also used by
_Composite Resources_.
```yaml {label="xrdClaim2"}
# Composite Resource Definition (XRD)
spec:
group: test.example.org
names:
kind: myComputeResource
claimNames:
kind: computeClaim
# Removed for brevity
```
In an example _Claim_ the
{{<hover label="claim" line="2">}}apiVersion{{< /hover >}}
matches the {{<hover label="xrdClaim2" line="3">}}group{{< /hover >}} in the
_Composite Resource Definition_.
The _Claim_ {{<hover label="claim" line="3">}}kind{{< /hover >}} matches the
_Composite Resource Definition_
{{<hover label="xrdClaim2" line="7">}}claimNames.kind{{< /hover >}}.
```yaml {label="claim"}
# Claim
apiVersion: test.example.org/v1alpha1
kind: computeClaim
metadata:
name: myClaim
namespace: devGroup
spec:
size: "large"
```
A _Claim_ can install in a {{<hover label="claim" line="6">}}namespace{{</hover >}}.
The _Composite Resource Definition_ defines the
{{<hover label="claim" line="7">}}spec{{< /hover >}} options the same way it
does for a _Composite Resource_
{{<hover label="xr-claim" line="6">}}spec{{< /hover >}}.
{{< hint "tip" >}}
_Composite Resources_ and _Claims_ are similar.
Only _Claims_ can be in
a {{<hover label="claim" line="6">}}namespace{{</hover >}}.
Also the _Composite Resource's_ {{<hover label="xr-claim"
line="3">}}kind{{</hover >}} may be different than the _Claim's_
{{<hover label="claim" line="3">}}kind{{< /hover >}}.
The _Composite Resource Definition_ defines the
{{<hover label="xrdClaim2" line="7">}}kind{{</hover >}} values.
{{< /hint >}}
```yaml {label="xr-claim"}
# Composite Resource (XR)
apiVersion: test.example.org/v1alpha1
kind: myComputeResource
metadata:
name: myResource
spec:
storage: "large"
```
_Claims_ are namespace scoped.
View all available Claims with the command `kubectl get claim`.
## Next steps
Build your own Crossplane platform using one of the quickstart guides.
* [Azure Quickstart]({{<ref "provider-azure" >}})
* [AWS Quickstart]({{<ref "provider-aws" >}})
* [GCP Quickstart]({{<ref "provider-gcp" >}})

View File

@ -0,0 +1,930 @@
---
title: AWS Quickstart Part 2
weight: 120
tocHidden: true
---
{{< hint "important" >}}
This guide is part 2 of a series. Follow [**part 1**]({{<ref "provider-aws" >}})**
to install Crossplane and connect your Kubernetes cluster to AWS.
[**Part 3**]({{<ref "provider-aws-part-3">}})** covers patching _composite resources_
and using Crossplane _packages_.
{{< /hint >}}
<!-- vale gitlab.SentenceLength = NO -->
This section creates a _[Composition](#create-a-composition)_,
_[Composite Resource Definition](#define-a-composite-resource)_ and a
_[Claim](#create-a-claim)_
to create a custom Kubernetes API to create AWS resources.
<!-- vale gitlab.SentenceLength = YES -->
## Prerequisites
* Complete [quickstart part 1]({{<ref "provider-aws" >}}) connecting Kubernetes
to AWS.
* an AWS account with permissions to create an AWS S3 storage bucket and a
DynamoDB instance
{{<expand "Skip part 1 and just get started" >}}
1. Add the Crossplane Helm repository and install Crossplane
```shell
helm repo add \
crossplane-stable https://charts.crossplane.io/stable
helm repo update
helm install crossplane \
crossplane-stable/crossplane \
--namespace crossplane-system \
--create-namespace
```
2. When the Crossplane pods finish installing and are ready, apply the AWS Provider
```yaml {label="provider",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: upbound-provider-aws
spec:
package: xpkg.upbound.io/upbound/provider-aws:v0.27.0
EOF
```
3. Create a file with your AWS keys
```ini
[default]
aws_access_key_id = <aws_access_key>
aws_secret_access_key = <aws_secret_key>
```
4. Create a Kubernetes secret from the AWS keys
```shell {label="kube-create-secret",copy-lines="all"}
kubectl create secret \
generic aws-secret \
-n crossplane-system \
--from-file=creds=./aws-credentials.txt
```
5. Create a _ProviderConfig_
```yaml {label="providerconfig",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: aws-secret
key: creds
EOF
```
{{</expand >}}
## Create a composition
[Part 1]({{<ref "provider-aws" >}}) created a single _managed resource_.
A _Composition_ is a template to create multiple _managed resources_ at the same time.
This sample _composition_ creates an DynamoDB instance and associated S3 storage
bucket.
{{< hint "note" >}}
This example comes from the AWS recommendation for
[storing large DynamoDB attributes in S3](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-use-s3-too.html#bp-use-s3-too-large-values).
{{< /hint >}}
To create a _composition_, first define each individual managed resource.
### Create an S3 bucket object
Define a `bucket` resource using the configuration from the previous section:
```yaml
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
name: crossplane-quickstart-bucket
spec:
forProvider:
region: "us-east-2"
providerConfigRef:
name: default
```
### Create a DynamoDB table resource
Next, define a DynamoDB `table` resource.
{{< hint "tip" >}}
The [Upbound Marketplace](https://marketplace.upbound.io/) provides
[schema documentation](https://marketplace.upbound.io/providers/upbound/provider-aws/v0.27.0/resources/dynamodb.aws.upbound.io/Table/v1beta1) for a `Table` resource.
{{< /hint >}}
The _AWS Provider_ defines the
{{<hover line="1" label="dynamoMR">}}apiVersion{{</hover>}}
and
{{<hover line="2" label="dynamoMR">}}kind{{</hover>}}.
DynamoDB instances require a
{{<hover line="7" label="dynamoMR">}}region{{</hover>}},
{{<hover line="8" label="dynamoMR">}}writeCapacity{{</hover>}}
and
{{<hover line="9" label="dynamoMR">}}readCapacity{{</hover>}}
parameters.
The {{<hover line="10" label="dynamoMR">}}attribute{{</hover>}} section creates
the database "Partition key" and "Hash key."
This example creates a single key named
{{<hover line="11" label="dynamoMR">}}S3ID{{</hover>}} of type
{{<hover line="12" label="dynamoMR">}}S{{</hover>}} for "string"
```yaml {label="dynamoMR"}
apiVersion: dynamodb.aws.upbound.io/v1beta1
kind: Table
metadata:
name: crossplane-quickstart-database
spec:
forProvider:
region: "us-east-2"
writeCapacity: 1
readCapacity: 1
attribute:
- name: S3ID
type: S
hashKey: S3ID
```
{{< hint "note" >}}
DynamoDB specifics are beyond the scope of this guide. Read the
[DynamoDB Developer Guide](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Introduction.html)
for more information.
{{</hint >}}
### Create the composition object
The _composition_ combines the two resource definitions.
A
{{<hover label="compName" line="2">}}Composition{{</ hover>}} comes from the
{{<hover label="compName" line="1">}}Crossplane{{</ hover>}}
API resources.
Create any {{<hover label="compName" line="4">}}name{{</ hover>}} for this _composition_.
```yaml {label="compName"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: dynamoDBWithS3
```
Add the resources to the
{{<hover label="specResources" line="5">}}spec.resources{{</ hover>}}
section of the _composition_.
Give each resource a
{{<hover label="specResources" line="7">}}name{{</ hover>}}
and put the resource definition under the
{{<hover label="specResources" line="8">}}base{{</ hover>}}
key.
```yaml {label="specResources"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: dynamoDBWithS3
spec:
resources:
- name: s3Bucket
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
name: crossplane-quickstart-bucket
spec:
forProvider:
region: "us-east-2"
providerConfigRef:
name: default
- name: dynamoDB
base:
apiVersion: dynamodb.aws.upbound.io/v1beta1
kind: Table
metadata:
name: crossplane-quickstart-database
spec:
forProvider:
region: "us-east-2"
writeCapacity: 1
readCapacity: 1
attribute:
- name: S3ID
type: S
hashKey: S3ID
```
Put the entire resource definition including the
{{<hover label="specResources" line="20">}}apiVersion{{</ hover>}} and resource
settings under the
{{<hover label="specResources" line="19">}}base{{</ hover>}}.
_Compositions_ are only a template for generating resources. A _composite
resource_ actually creates the resources.
A _composition_ defines what _composite resources_ can use this
template.
_Compositions_ do this with the
{{<hover label="compRef" line="6">}}spec.compositeTypeRef{{</ hover>}}
definition.
```yaml {label="compRef"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: dynamodb-with-bucket
spec:
compositeTypeRef:
apiVersion: custom-api.example.org/v1alpha1
kind: database
resources:
# Removed for Brevity
```
A _composite resource_ is actually a custom Kubernetes API type you define. The
platform team controls the kind, API endpoint and version.
<!-- vale gitlab.SentenceLength = NO -->
<!-- Lenght is because of shortcodes, ignore -->
With this {{<hover label="compRef" line="6">}}spec.compositeTypeRef{{</ hover>}}
Crossplane only allows _composite resources_ from the API group
{{<hover label="compRef" line="7">}}custom-api.example.org{{</ hover>}}
that are of
{{<hover label="compRef" line="8">}}kind: database{{</ hover>}}
to use this template to create resources.
<!-- vale gitlab.SentenceLength = YES -->
### Apply the composition
Apply the full _Composition_ to your Kubernetes cluster.
```yaml
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: dynamo-with-bucket
spec:
compositeTypeRef:
apiVersion: custom-api.example.org/v1alpha1
kind: database
resources:
- name: s3Bucket
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
name: crossplane-quickstart-bucket
spec:
forProvider:
region: us-east-2
providerConfigRef:
name: default
- name: dynamoDB
base:
apiVersion: dynamodb.aws.upbound.io/v1beta1
kind: Table
metadata:
name: crossplane-quickstart-database
spec:
forProvider:
region: "us-east-2"
writeCapacity: 1
readCapacity: 1
attribute:
- name: S3ID
type: S
hashKey: S3ID
EOF
```
Confirm the _composition_ exists with `kubectl get composition`
```shell {copy-lines="1"}
kubectl get composition
NAME AGE
dynamo-with-bucket 22s
```
## Define a composite resource
The _composition_ that was just created limited which _composite resources_ can
use that template.
A _composite resource_ is a custom API defined by the platform teams.
A _composite resource definition_ defines the schema for a _composite resource_.
A _composite resource definition_ installs the custom API type into Kubernetes
and defines what `spec` keys and values are valid when calling this new custom API.
Before creating a _composite resource_ Crossplane requires a _composite resource definition_.
{{< hint "tip" >}}
_Composite resource definitions_ are also called `XRDs` for short.
{{< /hint >}}
Just like a _composition_ the
{{<hover label="xrdName" line="2" >}}composite resource definition{{</hover>}}
is part of the
{{<hover label="xrdName" line="1" >}}Crossplane{{</hover>}}
API group.
The _XRD_ {{<hover label="xrdName" line="4" >}}name{{</hover>}} is the new
API endpoint.
```yaml {label="xrdName"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: databases.custom-api.example.org
```
The _XRD's_
{{<hover label="xrdGroup" line="5" >}}spec{{</hover>}} defines the new custom
API.
### Define the API endpoint and kind
First, define the new API
{{<hover label="xrdGroup" line="6" >}}group{{</hover>}}.
Next, create the API {{<hover label="xrdGroup" line="8" >}}kind{{</hover>}} and
{{<hover label="xrdGroup" line="9" >}}plural{{</hover>}}.
```yaml {label="xrdGroup"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: databases.custom-api.example.org
spec:
group: custom-api.example.org
names:
kind: database
plural: databases
```
{{<hint "note" >}}
The _XRD_ {{<hover label="xrdGroup" line="6" >}}group{{</hover>}} matches the _composition_ {{<hover label="noteComp"
line="5">}}apiVersion{{</hover>}} and the
_XRD_ {{<hover label="xrdGroup" line="8" >}}kind{{</hover>}} matches the _composition_
{{<hover label="noteComp" line="6">}}kind{{</hover>}} under the {{<hover label="noteComp" line="4">}}compositeTypeRef{{</hover>}}.
```yaml {label="noteComp"}
kind: Composition
# Removed for brevity
spec:
compositeTypeRef:
apiVersion: custom-api.example.org/v1alpha1
kind: database
```
{{< /hint >}}
### Set the API version
In Kubernetes, all API endpoints have a version to tell the stability of the API
and track revisions.
Apply a version to the _XRD_ with a
{{<hover label="xrdVersion" line="11">}}versions.name{{</hover>}}.
This matches the {{<hover label="noteComp"
line="5">}}apiVersion{{</hover>}} used in the _composition's_
{{<hover label="noteComp" line="4">}}compositeTypeRef{{</hover>}}.
_XRDs_ require both
{{<hover label="xrdVersion" line="12">}}versions.served{{</hover>}}
and
{{<hover label="xrdVersion" line="13">}}versions.referenceable{{</hover>}}.
```yaml {label="xrdVersion"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: custom-api-definition
spec:
group: custom-api.example.org
names:
kind: database
plural: databases
versions:
- name: v1alpha1
served: true
referenceable: true
```
{{<hint "note" >}}
For more information on defining versions in Kubernetes read the
[API versioning](https://kubernetes.io/docs/reference/using-api/#api-versioning) section of the Kubernetes documentation.
{{< /hint >}}
### Create the API schema
With an API endpoint named, now define the API schema, or what's allowed
inside the `spec` of the new Kubernetes object.
{{< hint "note" >}}
_XRDs_ follow the Kubernetes
[_custom resource definition_ rules for schemas](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#specifying-a-structural-schema).
{{</hint >}}
Place the API
{{< hover label="xrdSchema" line="8" >}}schema{{</hover>}}
under the
{{< hover label="xrdSchema" line="7" >}}version.name{{</hover>}}
The _XRD_ type defines the next lines. They're always the same.
<!-- vale write-good.TooWordy = NO -->
<!-- allow "validate" -->
{{< hover label="xrdSchema" line="9" >}}openAPIV3Schema{{</hover>}} specifies
how the schema gets validated.
<!-- vale write-good.TooWordy = YES -->
Next, the entire API is an
{{< hover label="xrdSchema" line="10" >}}object{{</hover>}}
with a
{{< hover label="xrdSchema" line="11" >}}property{{</hover>}} of
{{< hover label="xrdSchema" line="12" >}}spec{{</hover>}}.
The
{{< hover label="xrdSchema" line="12" >}}spec{{</hover>}} is also an
{{< hover label="xrdSchema" line="13" >}}object{{</hover>}} with
{{< hover label="xrdSchema" line="14" >}}properties{{</hover>}}.
```yaml {label="xrdSchema"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
# Removed for brevity
spec:
# Removed for brevity
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
```
{{< hint "tip" >}}
An _XRD_ is a Kubernetes _custom resource definition_.
For more information on the values allowed in the _XRD_ view the _XRD_ object with
`kubectl describe crd compositeresourcedefinitions`
{{< /hint >}}
Now, define the custom API. Your custom API continues under the last
{{<hover label="xrdSchema" line="14">}}properties{{</hover>}} definition in the
previous example.
This custom API has only one setting:
<!-- vale Google.We = NO -->
* {{<hover label="customAPI" line="4" >}}region{{</hover >}} - where to deploy
the resources, a choice of "EU" or "US"
Users can't change any other settings of the S3 bucket or DynamoDB instance.
The{{<hover label="customAPI" line="4" >}}region{{</hover >}}
is a {{<hover label="customAPI" line="5" >}}string{{</hover >}}
and can match the regular expression that's
{{<hover label="customAPI" line="6" >}}oneOf{{</hover >}}
{{<hover label="customAPI" line="7" >}}EU{{</hover >}}
or
{{<hover label="customAPI" line="8" >}}US{{</hover >}}.
This API requires the setting
{{<hover label="customAPI" line="10" >}}region{{</hover >}}.
```yaml {label="customAPI"}
# Removed for brevity
# schema.openAPIV3Schema.type.properties.spec
properties:
region:
type: string
oneOf:
- pattern: '^EU$'
- pattern: '^US$'
required:
- region
```
### Enable claims to the API
Allow a _claim_ to use this _XRD_ by defining the _claim_ API endpoint under the _XRD_
{{<hover label="XRDclaim" line="4">}}spec{{< /hover >}}.
```yaml {label="XRDclaim"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
# Removed for brevity
spec:
# Removed for brevity
claimNames:
kind: customDatabase
plural: customDatabases
```
{{<hint "note" >}}
The [Claims](#create-a-claim) section later in this guide discusses _claims_.
{{< /hint >}}
### Apply the composite resource definition
Apply the complete _XRD_ to your Kubernetes cluster.
```yaml
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: databases.custom-api.example.org
spec:
group: custom-api.example.org
names:
kind: database
plural: databases
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
region:
type: string
oneOf:
- pattern: '^EU$'
- pattern: '^US$'
required:
- region
claimNames:
kind: custom-database
plural: custom-databases
EOF
```
Verify Kubernetes created the XRD with `kubectl get xrd`
```shell {copy-lines="1",label="getXRD"}
kubectl get xrd
NAME ESTABLISHED OFFERED AGE
databases.custom-api.example.org True True 9s
```
## Create a composite resource
Creating an _XRD_ allows the creation _composite resources_.
_Composite resources_ are a convenient way to create multiple resources with a standard template.
A _composite resource_ uses the custom API created in the _XRD_.
Looking at part of the _XRD_:
```yaml {label="xrdSnip"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
# Removed for brevity
spec:
group: custom-api.example.org
names:
kind: database
# Removed for brevity
spec:
type: object
properties:
region:
type: string
oneOf:
- pattern: '^EU$'
- pattern: '^US$'
```
The _XRD_ {{<hover label="xrdSnip" line="5">}}group{{</hover>}}
becomes the _composite resource_
{{<hover label="xr" line="2">}}apiVersion{{</hover>}}.
The _XRD_ {{<hover label="xrdSnip" line="7">}}kind{{</hover>}}
is the _composite resource_
{{<hover label="xr" line="3">}}kind{{</hover>}}
The _XRD_ API {{<hover label="xrdSnip" line="9">}}spec{{</hover>}} defines the
_composite resource_ {{<hover label="xr" line="6">}}spec{{</hover>}}.
The _XRD_ {{<hover label="xrdSnip" line="11">}}properties{{</hover>}} section
defines the options for the _composite resource_
{{<hover label="xr" line="6">}}spec{{</hover>}}.
The one option is {{<hover label="xrdSnip" line="12">}}region{{</hover>}} and it
can be either {{<hover label="xrdSnip" line="15">}}EU{{</hover>}} or
{{<hover label="xrdSnip" line="16">}}US{{</hover>}}.
This _composite resource_ uses
{{<hover label="xr" line="7">}}region: US{{</hover>}}.
<!-- vale Google.We = YES -->
### Apply the composite resource
Apply the composite resource to the Kubernetes cluster.
```yaml {label="xr"}
cat <<EOF | kubectl apply -f -
apiVersion: custom-api.example.org/v1alpha1
kind: database
metadata:
name: my-composite-resource
spec:
region: "US"
EOF
```
### Verify the composite resource
Verify Crossplane created the _composite resource_ with `kubectl get composite`
```shell {copy-lines="1"}
kubectl get composite
NAME SYNCED READY COMPOSITION AGE
my-composite-resource True True dynamo-with-bucket 31s
```
The output mentions the _composite_ template that the _composite resource_ used.
Now look at the S3 `bucket` and DynmoDB `table` _managed resources_ with
`kubectl get bucket` and `kubectl get table`.
```shell {copy-lines="1"}
kubectl get bucket
NAME READY SYNCED EXTERNAL-NAME AGE
my-composite-resource-8b6tx True True my-composite-resource-8b6tx 56s
```
```shell {copy-lines="1"}
kubectl get table
NAME READY SYNCED EXTERNAL-NAME AGE
my-composite-resource-m6vk6 True True my-composite-resource-m6vk6 59s
```
The _composite resource_ automatically generated both _managed resources_.
Using `kubectl describe` on a _managed resource_ shows the `Owner References` is
the _composite resource_.
```yaml {copy-lines="1"}
kubectl describe bucket | grep "Owner References" -A5
Owner References:
API Version: custom-api.example.org/v1alpha1
Block Owner Deletion: true
Controller: true
Kind: database
Name: my-composite-resource
```
Each _composite resource_ creates and owns a unique set of _managed resources_.
If you create a second _composite resource_ Crossplane creates a new S3 `bucket`
and DynamoDB `table`.
```yaml {label="xr"}
cat <<EOF | kubectl apply -f -
apiVersion: custom-api.example.org/v1alpha1
kind: database
metadata:
name: my-second-composite-resource
spec:
region: "US"
EOF
```
Again, use `kubectl get composite` to view both _composite resources_.
```shell {copy-lines="1"}
kubectl get composite
NAME SYNCED READY COMPOSITION AGE
my-composite-resource True True dynamo-with-bucket 2m21s
my-second-composite-resource True True dynamo-with-bucket 42s
```
And see there are two `bucket` and two `table` _managed resources_.
```shell {copy-lines="1"}
kubectl get bucket
NAME READY SYNCED EXTERNAL-NAME AGE
my-composite-resource-8b6tx True True my-composite-resource-8b6tx 2m57s
my-second-composite-resource-z22lc True True my-second-composite-resource-z22lc 78s
```
```shell {copy-lines="1"}
kubectl get table
NAME READY SYNCED EXTERNAL-NAME AGE
my-composite-resource-m6vk6 True True my-composite-resource-m6vk6 3m
my-second-composite-resource-nsz6j True True my-second-composite-resource-nsz6j 81s
```
### Delete the composite resources
Because the _composite resource_ is the `Owner` of the _managed resources_, when
Crossplane deletes the _composite resource_, it also deletes the _managed resources_ automatically.
Delete the new _composite resource_ with `kubectl delete composite`.
```shell
kubectl delete composite my-second-composite-resource
```
{{<hint "note">}}
There may a delay in deleting the _managed resources_. Crossplane is making API
calls to AWS and waits for AWS to confirm they deleted the resources before
updating the state in Kubernetes.
{{</hint >}}
Now only one bucket and table exist.
```shell {copy-lines="1"}
kubectl get bucket
NAME READY SYNCED EXTERNAL-NAME AGE
my-composite-resource-8b6tx True True my-composite-resource-8b6tx 7m34s
```
```shell {copy-lines="1"}
kubectl get table
NAME READY SYNCED EXTERNAL-NAME AGE
my-composite-resource-m6vk6 True True my-composite-resource-m6vk6 7m37s
```
Delete the second _composite resource_ to remove the last `bucket` and `table`
_managed resources_.
```shell
kubectl delete composite my-composite-resource
```
_Composite resources_ are great for creating multiple related resources against
a template, but all _composite resources_ exist at the Kubernetes "cluster
level." There's no isolation between _composite resources_. Crossplane uses
_claims_ to create resources with namespace isolation.
## Create a claim
_Claims_, just like _composite resources_ use the custom API defined in the
_XRD_. Unlike a _composite resource_, Crossplane can create _claims_ in a
namespace.
### Create a new Kubernetes namespace
Create a new namespace with `kubectl create namespace`.
```shell
kubectl create namespace test
```
A _claim_ uses the same {{<hover label="XRDclaim2" line="7" >}}group{{</hover>}}
a _composite resource_ uses but a different
{{<hover label="XRDclaim2" line="8" >}}kind{{</hover>}}.
```yaml {label="XRDclaim2"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
# Removed for brevity
spec:
# Removed for brevity
group: custom-api.example.org
claimNames:
kind: custom-database
plural: custom-databases
```
Like the _composite resource_, create a new object with the
{{<hover label="claim" line="2" >}}custom-api.example.org{{</hover>}} API
endpoint.
The _XRD_
{{<hover label="XRDclaim2" line="8" >}}ClaimNames.kind{{</hover>}} defines the
{{<hover label="claim" line="3" >}}kind{{</hover>}}.
The {{<hover label="claim" line="7" >}}spec{{</hover>}} uses the same
API options as the _composite resource_.
### Apply the claim
Apply the _claim_ to your Kubernetes cluster.
```yaml {label="claim"}
cat <<EOF | kubectl apply -f -
apiVersion: custom-api.example.org/v1alpha1
kind: custom-database
metadata:
name: claimed-database
namespace: test
spec:
region: "US"
EOF
```
### Verify the claim
Verify Crossplane created the _claim_ with `kubectl get claim` in the `test`
namespace.
```shell {copy-lines="1"}
kubectl get claim -n test
NAME SYNCED READY CONNECTION-SECRET AGE
claimed-database True True 35s
```
When Crossplane creates a _claim_ a unique _composite resource_ is automatically
created too. View the new _composite resource_ with `kubectl get composite`.
```shell {copy-lines="1"}
kubectl get composite
NAME SYNCED READY COMPOSITION AGE
claimed-database-6xsgq True True dynamo-with-bucket 46s
```
The _composite resource_ exists at the "cluster scope" while the _claim_ exists
at the "namespace scope."
Create a second namespace and a second claim.
```shell
kubectl create namespace test2
cat <<EOF | kubectl apply -f -
apiVersion: custom-api.example.org/v1alpha1
kind: custom-database
metadata:
name: claimed-database
namespace: test2
spec:
region: "US"
EOF
```
View the _claims_ in all namespaces with `kubectl get claim -A`
```shell {copy-lines="1"}
kubectl get claim -A
NAMESPACE NAME SYNCED READY CONNECTION-SECRET AGE
test claimed-database True True 4m32s
test2 claimed-database True True 43s
```
Now look at the _composite resources_ at the cluster scope.
```shell
kubectl get composite
NAME SYNCED READY COMPOSITION AGE
claimed-database-6xsgq True True dynamo-with-bucket 8m37s
claimed-database-f54qv True True dynamo-with-bucket 4m47s
```
Crossplane created a second _composite resource_ for the second _claim_.
Looking at the S3 `bucket` and DynamoDB `table` shows two of each resource, one
for each claim.
```shell {copy-lines="1"}
kubectl get bucket
NAME READY SYNCED EXTERNAL-NAME AGE
claimed-database-6xsgq-l9d8z True True claimed-database-6xsgq-l9d8z 9m18s
claimed-database-f54qv-9542v True True claimed-database-f54qv-9542v 5m28s
```
```shell {copy-lines="1"}
kubectl get table
NAME READY SYNCED EXTERNAL-NAME AGE
claimed-database-6xsgq-nmxhs True True claimed-database-6xsgq-nmxhs 11m
claimed-database-f54qv-qrsdj True True claimed-database-f54qv-qrsdj 7m24s
```
### Delete the claims
Removing the _claims_ removes the _composite resources_ and the associated
_managed resources_.
```shell
kubectl delete claim claimed-database -n test
kubectl delete claim claimed-database -n test2
```
Verify Crossplane removed all the _managed resources_.
```shell
kubectl get bucket
kubectl get table
```
Claims are powerful tools to give users resources in their own isolated
namespace. But these examples haven't shown how the custom API can change
the settings defined in the _composition_. This _composition patching_ applies
the API settings when creating resources.
[Part 3]({{< ref "provider-aws-part-3">}}) of this guide covers _composition
patches_ and making all this configuration portable in Crossplane _packages_.
## Next steps
* [**Continue to part 3**]({{< ref "provider-aws-part-3">}}) to create a learn
about _patching_ resources and creating Crossplane _packages_.
* Explore AWS resources that Crossplane can configure in the [Provider CRD reference](https://marketplace.upbound.io/providers/upbound/provider-family-aws/).
* Join the [Crossplane Slack](https://slack.crossplane.io/) and connect with Crossplane users and contributors.

View File

@ -0,0 +1,652 @@
---
title: AWS Quickstart Part 3
weight: 120
tocHidden: true
---
{{< hint "important" >}}
This guide is part 3 of a series.
Follow [**part 1**]({{<ref "provider-aws" >}})
to install Crossplane and connect your Kubernetes cluster to AWS.
Follow [**part 2**]({{<ref "provider-aws-part-2" >}}) to create a _composition_,
_custom resource definition_ and a _claim_.
{{< /hint >}}
[Part 2]({{<ref "provider-aws-part-2" >}}) created a _composite resource
definition_ to define the schema of the custom API. Users create a _claim_ to
use the custom API and apply their options. Part 2 didn't show how the options
set in a _claim_ change or get applied the associated _composite resources_.
## Prerequisites
* Complete quickstart [part 1]({{<ref "provider-aws" >}}) and
[Part 2]({{<ref "provider-aws-part-2" >}}) to install Crossplane and the quickstart
configurations.
{{<expand "Skip parts 1 and 2 and just get started" >}}
1. Add the Crossplane Helm repository and install Crossplane
```shell
helm repo add \
crossplane-stable https://charts.crossplane.io/stable
helm repo update
helm install crossplane \
crossplane-stable/crossplane \
--namespace crossplane-system \
--create-namespace
```
2. When the Crossplane pods finish installing and are ready, apply the AWS Provider
```yaml {label="provider",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: upbound-provider-aws
spec:
package: xpkg.upbound.io/upbound/provider-aws:v0.27.0
EOF
```
3. Create a file with your AWS keys
```ini
[default]
aws_access_key_id = <aws_access_key>
aws_secret_access_key = <aws_secret_key>
```
4. Create a Kubernetes secret from the AWS keys
```shell {label="kube-create-secret",copy-lines="all"}
kubectl create secret \
generic aws-secret \
-n crossplane-system \
--from-file=creds=./aws-credentials.txt
```
5. Create a _ProviderConfig_
```yaml {label="providerconfig",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: aws-secret
key: creds
EOF
```
6. Create a _composition_
```yaml
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: dynamo-with-bucket
spec:
compositeTypeRef:
apiVersion: custom-api.example.org/v1alpha1
kind: database
resources:
- name: s3Bucket
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
name: crossplane-quickstart-bucket
spec:
forProvider:
region: "us-east-2"
- name: dynamoDB
base:
apiVersion: dynamodb.aws.upbound.io/v1beta1
kind: Table
metadata:
name: crossplane-quickstart-database
spec:
forProvider:
region: "us-east-2"
writeCapacity: 1
readCapacity: 1
attribute:
- name: S3ID
type: S
hashKey: S3ID
EOF
```
7. Create a _composite resource definition_
```yaml
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: databases.custom-api.example.org
spec:
group: custom-api.example.org
names:
kind: database
plural: databases
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
region:
type: string
oneOf:
- pattern: '^EU$'
- pattern: '^US$'
required:
- region
claimNames:
kind: custom-database
plural: custom-databases
EOF
```
8. Create a new namespace
```shell
kubectl create namespace test
```
{{</expand >}}
## Enable composition patches
In a _composition_ `patches` map fields in the custom API to fields inside the
_managed resources_.
The _composition_ has two _managed resources_, a
{{<hover label="compResources" line="8">}}bucket{{</hover>}} and a
{{<hover label="compResources" line="19">}}table{{</hover>}}.
```yaml {label="compResources"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for Brevity
resources:
- name: s3Bucket
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
name: crossplane-quickstart-bucket
spec:
forProvider:
region: "us-east-2"
- name: dynamoDB
base:
apiVersion: dynamodb.aws.upbound.io/v1beta1
kind: Table
metadata:
name: crossplane-quickstart-database
spec:
forProvider:
region: "us-east-2"
writeCapacity: 1
readCapacity: 1
attribute:
- name: S3ID
type: S
hashKey: S3ID
```
<!-- vale Google.We = NO -->
The custom API defined a single option,
{{<hover label="xrdSnip" line="12">}}region{{</hover>}}. A
{{<hover label="xrdSnip" line="12">}}region{{</hover>}} can be either
{{<hover label="xrdSnip" line="15">}}EU{{</hover>}} or
{{<hover label="xrdSnip" line="16">}}US{{</hover>}}.
<!-- vale Google.We = YES -->
```yaml {label="xrdSnip"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
# Removed for brevity
spec:
group: custom-api.example.org
names:
kind: database
# Removed for brevity
spec:
type: object
properties:
region:
type: string
oneOf:
- pattern: '^EU$'
- pattern: '^US$'
```
Creating a _composition_ `patch` allows Crossplane to update the settings of the
_composite resource_. Patches apply to the individual _managed resources_
inside the _composition_.
A {{<hover label="patch" line="12">}}patch{{</hover>}} has a
{{<hover label="patch" line="13">}}fromField{{</hover>}} and a
{{<hover label="patch" line="14">}}toField{{</hover>}} specifying which value
_from_ the custom API should apply _to_ the _managed resource_.
Patches can create a
{{<hover label="patch" line="15">}}transform{{</hover>}} to change the _from_
field before it's applied.
The transform
{{<hover label="patch" line="16">}}type{{</hover>}} is what kind of change to
make on the _from_ field. Types of changes could include appending a string,
preforming a math operation or mapping one value to another.
Applying a {{<hover label="patch" line="12">}}patch{{</hover>}} to the
{{<hover label="patch" line="8">}}Bucket{{</hover>}} uses the custom API
{{<hover label="patch" line="13">}}region{{</hover>}} to use as the _managed resource_
{{<hover label="patch" line="11">}}region{{</hover>}}.
<!-- vale Google.We = NO -->
The custom API value "EU" is
{{<hover label="patch" line="18">}}mapped{{</hover>}} to the value "eu-north-1"
and "US" is {{<hover label="patch" line="19">}}mapped{{</hover>}} to the value
"us-east-2."
<!-- vale Google.We = YES -->
```yaml {label="patch"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for Brevity
resources:
- name: s3Bucket
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
region: "us-east-2"
patches:
- fromFieldPath: "region"
toFieldPath: "spec.forProvider.region"
transforms:
- type: map
map:
EU: "eu-north-1"
US: "us-east-2"
```
<!-- vale Google.We = NO -->
Patching is a powerful tool enabling simpler or abstracted APIs. A developer
isn't required to know the specific AWS region identifier, only the abstracted
option of "EU" or "US."
<!-- vale Google.We = YES -->
### Apply the updated composition
Apply the same `patch` to the `Table` _managed resource_ and apply the updated
_composition_.
```yaml
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: dynamo-with-bucket
spec:
compositeTypeRef:
apiVersion: custom-api.example.org/v1alpha1
kind: database
resources:
- name: s3Bucket
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
name: crossplane-quickstart-bucket
spec:
forProvider:
name: default
region: "us-east-2"
patches:
- fromFieldPath: "spec.region"
toFieldPath: "spec.forProvider.region"
transforms:
- type: map
map:
EU: "eu-north-1"
US: "us-east-2"
- name: dynamoDB
base:
apiVersion: dynamodb.aws.upbound.io/v1beta1
kind: Table
metadata:
name: crossplane-quickstart-database
spec:
forProvider:
writeCapacity: 1
readCapacity: 1
attribute:
- name: S3ID
type: S
hashKey: S3ID
region: "us-east-2"
patches:
- fromFieldPath: "spec.region"
toFieldPath: "spec.forProvider.region"
transforms:
- type: map
map:
EU: "eu-north-1"
US: "us-east-2"
EOF
```
### Create a claim
Create a new _claim_ and set the
{{<hover label="claim" line="8" >}}region{{</hover >}} to "EU."
```yaml {label="claim"}
cat <<EOF | kubectl apply -f -
apiVersion: custom-api.example.org/v1alpha1
kind: custom-database
metadata:
name: claimed-eu-database
namespace: test
spec:
region: "EU"
EOF
```
View the _claim_ with `kubectl get claim`
```shell
kubectl get claim -n test
NAME SYNCED READY CONNECTION-SECRET AGE
claimed-eu-database True True 18m
```
The claim reports `SYNCED` and `READY` as `True` after Crossplane creates
all the _managed resources_.
Describe the `Table` resource to see the AWS region is `eu-north-1`.
```shell
kubectl describe table | grep arn:aws
Arn: arn:aws:dynamodb:eu-north-1:622343227358:table/claimed-eu-database-2sh9w-dhvw6
```
<!-- vale Google.We = NO -->
Using {{<hover label="claim" line="8" >}}region: "EU"{{</hover >}} patches the
_composite resource_, updating the AWS region from `us-east-2` to `eu-north-1`.
The developer creating the claim isn't required to know which specific AWS
region or the naming conventions. Using the abstract API options of "EU" or "US"
the developer places their resources in the desired location.
<!-- vale Google.We = YES -->
Deleting the claim removes the _managed resources_.
{{<hint "note" >}}
The _managed resources_ take up to 5 minutes to delete.
{{< /hint >}}
```shell
kubectl delete claim claimed-eu-database -n test
```
## Create a Crossplane configuration package
Crossplane _configuration packages_ allow users to combine their _custom
resource definition_ and _composition_ files into an OCI image.
{{< hint "note" >}}
The [Open Container Initiative](https://opencontainers.org/faq/)
defines the OCI image standard.
An OCI images is a standard way to package data.
{{< /hint >}}
You can host configuration packages in image registries like
[Docker Hub](https://hub.docker.com/) or the
[Upbound Marketplace](https://marketplace.upbound.io/).
Crossplane can download and install configuration packages into a Kubernetes
cluster.
Creating a configuration package makes your Crossplane custom APIs portable
and versioned.
Building and installing configuration packages requires an OCI image compatible
tool.
{{< hint "note" >}}
You can use any software that builds OCI images. This includes
[Docker](https://www.docker.com/) or
[Upbound's Up CLI)](https://github.com/upbound/up).
{{< /hint >}}
A configuration package includes three files:
* `crossplane.yaml` defines the metadata of the package.
* `definition.yaml` is the _composite resource definition_ for the package.
* `composition.yaml` is the _composition_ template for the package.
<!-- vale gitlab.Substitutions = NO -->
<!-- yaml is in the filename -->
### Create a crossplane.yaml file
<!-- vale gitlab.Substitutions = YES -->
Configuration packages describe their contents and requirements with a
`crossplane.yaml` file.
The `crossplane.yaml` file lists the required Crossplane _providers_ and their
compatible versions as well as the required Crossplane version.
The Crossplane
{{<hover label="xpyaml" line="1" >}}meta.pkg{{</hover>}} API defines the schema
for a
{{<hover label="xpyaml" line="2" >}}Configuration{{</hover>}}.
Inside the {{<hover label="xpyaml" line="5" >}}spec{{</hover>}} define the
required Crossplane
{{<hover label="xpyaml" line="7" >}}version{{</hover>}}.
The {{<hover label="xpyaml" line="8" >}}dependsOn{{</hover>}} section lists the
dependencies for a package.
This package lists the Upbound
{{<hover label="xpyaml" line="9" >}}provider-aws{{</hover>}}
version {{<hover label="xpyaml" line="10" >}}0.27.0{{</hover>}} or later as a
dependency.
{{<hint "tip" >}}
Crossplane automatically installs dependencies. Dependencies can include other
configuration packages.
{{< /hint >}}
```yaml {label="xpyaml"}
apiVersion: meta.pkg.crossplane.io/v1
kind: Configuration
metadata:
name: crossplane-aws-quickstart
spec:
crossplane:
version: ">=v1.11.0"
dependsOn:
- provider: xpkg.upbound.io/upbound/provider-aws
version: ">=v0.27.0"
```
Create a new directory and save the `crossplane.yaml` file.
```yaml
mkdir crossplane-aws-quickstart
cat <<EOF > crossplane-aws-quickstart/crossplane.yaml
apiVersion: meta.pkg.crossplane.io/v1
kind: Configuration
metadata:
name: crossplane-aws-quickstart
spec:
crossplane:
version: ">=v1.11.0"
dependsOn:
- provider: xpkg.upbound.io/upbound/provider-aws
version: ">=v0.27.0"
EOF
```
<!-- vale gitlab.Substitutions = NO -->
<!-- yaml is in the filename -->
### Create a definition.yaml file
<!-- vale gitlab.Substitutions = YES -->
A configuration package requires a _composite resource definition_ (XRD) to define the
custom API.
Save the _XRD_ as `definition.yaml` in the same directory as the
`crossplane.yaml` file.
```yaml
cat <<EOF > crossplane-aws-quickstart/definition.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: databases.custom-api.example.org
spec:
group: custom-api.example.org
names:
kind: database
plural: databases
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
region:
type: string
oneOf:
- pattern: '^EU$'
- pattern: '^US$'
required:
- region
claimNames:
kind: custom-database
plural: custom-databases
EOF
```
<!-- vale gitlab.Substitutions = NO -->
<!-- yaml is in the filename -->
### Create a composition.yaml file
<!-- vale gitlab.Substitutions = YES -->
The _composition_ template creates the _managed resources_ and allows _patches_
to customize the _managed resources_.
Copy the _composition_ into the `composition.yaml` file in the same directory as
`crossplane.yaml`.
```yaml
cat <<EOF > crossplane-aws-quickstart/composition.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: dynamo-with-bucket
spec:
compositeTypeRef:
apiVersion: custom-api.example.org/v1alpha1
kind: database
resources:
- name: s3Bucket
base:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
name: crossplane-quickstart-bucket
spec:
providerConfigRef:
name: default
patches:
- fromFieldPath: "spec.region"
toFieldPath: "spec.forProvider.region"
transforms:
- type: map
map:
EU: "eu-north-1"
US: "us-east-1"
- name: dynamoDB
base:
apiVersion: dynamodb.aws.upbound.io/v1beta1
kind: Table
metadata:
name: crossplane-quickstart-database
spec:
forProvider:
writeCapacity: 1
readCapacity: 1
attribute:
- name: S3ID
type: S
hashKey: S3ID
patches:
- fromFieldPath: "spec.region"
toFieldPath: "spec.forProvider.region"
transforms:
- type: map
map:
EU: "eu-north-1"
US: "us-east-1"
EOF
```
### Install the Crossplane command-line
To build a configuration package install the Crossplane Kubernetes command-line
extension.
```shell
curl "https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh"
./install.sh
sudo mv kubectl-crossplane /usr/bin
```
Verify the Crossplane command-line installed with `kubectl crossplane --help`
```shell
kubectl crossplane --help
Usage: kubectl crossplane <command>
A command line tool for interacting with Crossplane.
Flags:
-h, --help Show context-sensitive help.
-v, --version Print version and quit.
--verbose Print verbose logging statements.
# Ouptut removed for brevity
```
### Build a configuration package
Use the `kubectl crossplane` command to create an `.xpkg` file containing the
custom APIs and Crossplane configuration.
```shell
kubectl crossplane build configuration -f crossplane-aws-quickstart/ --name="crossplane-aws-quickstart"
```
Now an `.xpkg` OCI image is inside the `crossplane-aws-quickstart` directory.
```shell
ls crossplane-aws-quickstart/
composition.yaml crossplane-aws-quickstart.xpkg crossplane.yaml definition.yaml
```
## Next steps
* Explore AWS resources that Crossplane can configure in the [Provider CRD reference](https://marketplace.upbound.io/providers/upbound/provider-family-aws/).
* Join the [Crossplane Slack](https://slack.crossplane.io/) and connect with Crossplane users and contributors.
* Read more about [Crossplane concepts]({{<ref "../concepts" >}})

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,810 @@
---
title: Azure Quickstart Part 3
weight: 120
tocHidden: true
---
{{< hint "important" >}}
This guide is part 3 of a series.
Follow [**part 1**]({{<ref "provider-azure" >}})
to install Crossplane and connect your Kubernetes cluster to Azure.
Follow [**part 2**]({{<ref "provider-azure-part-2" >}}) to create a _composition_,
_custom resource definition_ and a _claim_.
{{< /hint >}}
[Part 2]({{<ref "provider-azure-part-2" >}}) created a
_CompositeResourceDefinition_ to define the schema of the custom API.
Users create a _Claim_ to use the custom API and apply their options.
Part 2 didn't show how the options set in a _Claim_ change or get
applied to the associated _composite resources_.
## Prerequisites
* Complete quickstart [part 1]({{<ref "provider-azure" >}}) and
[part 2]({{<ref "provider-azure-part-2" >}}) to install Crossplane and the quickstart
configurations.
{{<expand "Skip parts 1 and 2 and just get started" >}}
1. Add the Crossplane Helm repository and install Crossplane
```shell
helm repo add \
crossplane-stable https://charts.crossplane.io/stable
helm repo update
&&
helm install crossplane \
crossplane-stable/crossplane \
--namespace crossplane-system \
--create-namespace
```
1. When the Crossplane pods finish installing and are ready, apply the Azure
Provider
```yaml {label="provider",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: upbound-provider-azure
spec:
package: xpkg.upbound.io/upbound/provider-azure:v0.32.0
EOF
```
3. Use the Azure CLI to create a service principal and save the JSON output as
`azure-crednetials.json`
{{< editCode >}}
```console
az ad sp create-for-rbac \
--sdk-auth \
--role Owner \
--scopes /subscriptions/$$<subscription_id>$$
```
{{</ editCode >}}
4. Create a Kubernetes secret from the Azure JSON file.
```shell {label="kube-create-secret",copy-lines="all"}
kubectl create secret \
generic azure-secret \
-n crossplane-system \
--from-file=creds=./azure-credentials.json
```
5. Create a _ProviderConfig_
```yaml {label="providerconfig",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: azure.upbound.io/v1beta1
metadata:
name: default
kind: ProviderConfig
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: azure-secret
key: creds
EOF
```
6. Create a _composition_
{{< hint "tip" >}}
Apply your
{{<hover label="Composition" line="27">}}resourceGroupName{{</hover>}} to each resource.
{{< /hint >}}
{{< editCode >}}
```yaml {label="Composition"}
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: crossplane-quickstart-vm-with-network
spec:
compositeTypeRef:
apiVersion: custom-api.example.org/v1alpha1
kind: XVirtualMachine
resources:
- name: quickstart-vm
base:
apiVersion: compute.azure.upbound.io/v1beta1
kind: LinuxVirtualMachine
spec:
forProvider:
adminUsername: adminuser
adminSshKey:
- publicKey: ssh-rsa
AAAAB3NzaC1yc2EAAAADAQABAAABAQC+wWK73dCr+jgQOAxNsHAnNNNMEMWOHYEccp6wJm2gotpr9katuF/ZAdou5AaW1C61slRkHRkpRRX9FA9CYBiitZgvCCz+3nWNN7l/Up54Zps/pHWGZLHNJZRYyAB6j5yVLMVHIHriY49d/GZTZVNB8GoJv9Gakwc/fuEZYYl4YDFiGMBP///TzlI4jhiJzjKnEvqPFki5p2ZRJqcbCiF4pJrxUQR/RXqVFQdbRLZgYfJ8xGB878RENq3yQ39d8dVOkq4edbkzwcUmwwwkYVPIoDGsYLaRHnG+To7FvMeyO7xDVQkMKzopTQV8AuKpyvpqu0a9pWOMaiCyDytO7GGN
example@docs.crossplane.io
username: adminuser
location: "Central US"
osDisk:
- caching: ReadWrite
storageAccountType: Standard_LRS
resourceGroupName: $$<resource_group_name>$$
size: Standard_B1ms
sourceImageReference:
- offer: debian-11
publisher: Debian
sku: 11-backports-gen2
version: latest
networkInterfaceIdsSelector:
matchControllerRef: true
- name: quickstart-nic
base:
apiVersion: network.azure.upbound.io/v1beta1
kind: NetworkInterface
spec:
forProvider:
ipConfiguration:
- name: crossplane-quickstart-configuration
privateIpAddressAllocation: Dynamic
subnetIdSelector:
matchControllerRef: true
location: "Central US"
resourceGroupName: $$<resource_group_name>$$
- name: quickstart-subnet
base:
apiVersion: network.azure.upbound.io/v1beta1
kind: Subnet
spec:
forProvider:
addressPrefixes:
- 10.0.1.0/24
virtualNetworkNameSelector:
matchControllerRef: true
resourceGroupName: $$<resource_group_name>$$
- name: quickstart-network
base:
apiVersion: network.azure.upbound.io/v1beta1
kind: VirtualNetwork
spec:
forProvider:
addressSpace:
- 10.0.0.0/16
location: "Central US"
resourceGroupName: $$<resource_group_name>$$
EOF
```
{{< /editCode >}}
7. Create a _CompositeResourceDefinition_
```yaml
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xvirtualmachines.custom-api.example.org
spec:
group: custom-api.example.org
names:
kind: XVirtualMachine
plural: xvirtualmachines
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
region:
type: string
oneOf:
- pattern: '^EU$'
- pattern: '^US$'
required:
- region
claimNames:
kind: VirtualMachine
plural: virtualmachines
EOF
```
8. Create a new namespace
```shell
kubectl create namespace test
```
{{</expand >}}
## Enable composition patches
In a _Composition_ `patches` map fields in the custom API to fields inside the
_managed resources_.
The example _Composition_ has four _managed resources_. A {{<hover label="compResources" line="8" >}}LinuxVirtualMachine{{</hover>}},
{{<hover label="compResources" line="12" >}}NetworkInterface{{</hover>}},
{{<hover label="compResources" line="16" >}}Subnet{{</hover>}} and a
{{<hover label="compResources" line="20" >}}VirtualNetwork{{</hover>}}.
```yaml {label="compResources",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for Brevity
resources:
- name: quickstart-vm
base:
apiVersion: compute.azure.upbound.io/v1beta1
kind: LinuxVirtualMachine
- name: quickstart-nic
base:
apiVersion: network.azure.upbound.io/v1beta1
kind: NetworkInterface
- name: quickstart-subnet
base:
apiVersion: network.azure.upbound.io/v1beta1
kind: Subnet
- name: quickstart-network
base:
apiVersion: network.azure.upbound.io/v1beta1
kind: VirtualNetwork
```
<!-- vale Google.We = NO -->
The custom API defined a single option,
{{<hover label="xrdSnip" line="12">}}region{{</hover>}}. A
{{<hover label="xrdSnip" line="12">}}region{{</hover>}} can be either
{{<hover label="xrdSnip" line="15">}}EU{{</hover>}} or
{{<hover label="xrdSnip" line="16">}}US{{</hover>}}.
<!-- vale Google.We = YES -->
```yaml {label="xrdSnip",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
# Removed for brevity
spec:
group: custom-api.example.org
names:
kind: XVirtualMachine
# Removed for brevity
spec:
type: object
properties:
region:
type: string
oneOf:
- pattern: '^EU$'
- pattern: '^US$'
```
Creating a _composition_ `patch` allows Crossplane to update the settings of the
_composite resource_. Patches apply to the individual _managed resources_
inside the _Composition_.
A {{<hover label="patch" line="13">}}patch{{</hover>}} has a
{{<hover label="patch" line="14">}}fromField{{</hover>}} and a
{{<hover label="patch" line="15">}}toField{{</hover>}} specifying which value
_from_ the custom API should apply _to_ a field in the _managed resource_.
Patches can create a
{{<hover label="patch" line="16">}}transform{{</hover>}} to change the _from_
field before it's applied.
The transform
{{<hover label="patch" line="17">}}type{{</hover>}} is what kind of change to
make on the _from_ field. Types of changes could include appending a string,
preforming a math operation or mapping one value to another.
Applying a {{<hover label="patch" line="13">}}patch{{</hover>}} to the
{{<hover label="patch" line="8">}}LinuxVirtualMachine{{</hover>}} uses the
custom API
{{<hover label="patch" line="14">}}region{{</hover>}} to use as the
_managed resource_
{{<hover label="patch" line="15">}}location{{</hover>}}.
<!-- vale Google.We = NO -->
The custom API value "EU" is
{{<hover label="patch" line="19">}}mapped{{</hover>}} to the value
"Sweden Central"
and "US" is {{<hover label="patch" line="20">}}mapped{{</hover>}} to the value
"Central US."
<!-- vale Google.We = YES -->
```yaml {label="patch",copy-lines="none"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for Brevity
resources:
- name: quickstart-vm
base:
apiVersion: compute.azure.upbound.io/v1beta1
kind: LinuxVirtualMachine
spec:
forProvider:
location: "Central US"
# Removed for Brevity
patches:
- fromFieldPath: "spec.region"
toFieldPath: "spec.forProvider.location"
transforms:
- type: map
map:
EU: "Sweden Central"
US: "Central US"
```
<!-- vale Google.We = NO -->
Patching is a powerful tool enabling simpler or abstracted APIs. A developer
isn't required to know the specific Azure location names, only the abstracted
option of "EU" or "US."
<!-- vale Google.We = YES -->
### Apply the updated composition
Apply the same `patch` to all other _managed resource_
and apply the updated _Composition_.
{{< hint "tip" >}}
Update each `resourceGroupName` with your Azure Resource Group.
{{< /hint >}}
{{< editCode >}}
```yaml
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: crossplane-quickstart-vm-with-network
spec:
compositeTypeRef:
apiVersion: custom-api.example.org/v1alpha1
kind: XVirtualMachine
resources:
- name: quickstart-vm
base:
apiVersion: compute.azure.upbound.io/v1beta1
kind: LinuxVirtualMachine
spec:
forProvider:
adminUsername: adminuser
adminSshKey:
- publicKey: ssh-rsa
AAAAB3NzaC1yc2EAAAADAQABAAABAQC+wWK73dCr+jgQOAxNsHAnNNNMEMWOHYEccp6wJm2gotpr9katuF/ZAdou5AaW1C61slRkHRkpRRX9FA9CYBiitZgvCCz+3nWNN7l/Up54Zps/pHWGZLHNJZRYyAB6j5yVLMVHIHriY49d/GZTZVNB8GoJv9Gakwc/fuEZYYl4YDFiGMBP///TzlI4jhiJzjKnEvqPFki5p2ZRJqcbCiF4pJrxUQR/RXqVFQdbRLZgYfJ8xGB878RENq3yQ39d8dVOkq4edbkzwcUmwwwkYVPIoDGsYLaRHnG+To7FvMeyO7xDVQkMKzopTQV8AuKpyvpqu0a9pWOMaiCyDytO7GGN
example@docs.crossplane.io
username: adminuser
location: "Central US"
osDisk:
- caching: ReadWrite
storageAccountType: Standard_LRS
resourceGroupName: $$<resource_group_name>$$
size: Standard_B1ms
sourceImageReference:
- offer: debian-11
publisher: Debian
sku: 11-backports-gen2
version: latest
networkInterfaceIdsSelector:
matchControllerRef: true
patches:
- fromFieldPath: "spec.region"
toFieldPath: "spec.forProvider.location"
transforms:
- type: map
map:
EU: "Sweden Central"
US: "Central US"
- name: quickstart-nic
base:
apiVersion: network.azure.upbound.io/v1beta1
kind: NetworkInterface
spec:
forProvider:
ipConfiguration:
- name: crossplane-quickstart-configuration
privateIpAddressAllocation: Dynamic
subnetIdSelector:
matchControllerRef: true
location: "Central US"
resourceGroupName: $$<resource_group_name>$$
patches:
- fromFieldPath: "spec.region"
toFieldPath: "spec.forProvider.location"
transforms:
- type: map
map:
EU: "Sweden Central"
US: "Central US"
- name: quickstart-subnet
base:
apiVersion: network.azure.upbound.io/v1beta1
kind: Subnet
spec:
forProvider:
addressPrefixes:
- 10.0.1.0/24
virtualNetworkNameSelector:
matchControllerRef: true
resourceGroupName: $$<resource_group_name>$$
patches:
- fromFieldPath: "spec.region"
toFieldPath: "spec.forProvider.location"
transforms:
- type: map
map:
EU: "Sweden Central"
US: "Central US"
- name: quickstart-network
base:
apiVersion: network.azure.upbound.io/v1beta1
kind: VirtualNetwork
spec:
forProvider:
addressSpace:
- 10.0.0.0/16
location: "Sweden Central"
resourceGroupName: $$<resource_group_name>$$
patches:
- fromFieldPath: "spec.region"
toFieldPath: "spec.forProvider.location"
transforms:
- type: map
map:
EU: "Sweden Central"
US: "Central US"
EOF
```
{{< /editCode >}}
### Create a claim
Create a new _claim_ and set the
{{<hover label="claim" line="8" >}}region{{</hover >}} to "EU."
```yaml {label="claim"}
cat <<EOF | kubectl apply -f -
apiVersion: custom-api.example.org/v1alpha1
kind: VirtualMachine
metadata:
name: claimed-eu-virtualmachine
namespace: test
spec:
region: "EU"
EOF
```
View the _Claim_ with `kubectl get claim`
{{< hint "note" >}}
It may take up to 10 minutes for the Claim to be `READY`.
{{< /hint >}}
```shell {copy-lines="1"}
kubectl get claim -n test
NAME SYNCED READY CONNECTION-SECRET AGE
claimed-eu-virtualmachine True True 6m2s
```
The claim reports `SYNCED` and `READY` as `True` after Crossplane creates
all the _managed resources_.
Describe the `LinuxVirtualMachine` resource to see the Azure location is `Sweden
Central`.
```shell {copy-lines="1"}
kubectl describe linuxvirtualmachine | grep "At Provider\|Location"
Location: Sweden Central
At Provider:
Location: swedencentral
```
<!-- vale Google.We = NO -->
Using {{<hover label="claim" line="8" >}}region: "EU"{{</hover >}} patches the
_composite resource_, updating the Azure location from `Central US` to
`Sweden Central`.
The developer creating the claim isn't required to know which specific Azure
location or the location naming conventions. Using the abstract API options of
"EU" or "US" the developer places their resources in the desired location.
<!-- vale Google.We = YES -->
Deleting the claim removes the _managed resources_.
{{<hint "note" >}}
The _managed resources_ take up to 5 minutes to delete.
{{< /hint >}}
```shell
kubectl delete virtualmachine claimed-eu-virtualmachine -n test
```
## Create a Crossplane configuration package
Crossplane _configuration packages_ allow users to combine their
_Custom Resource Definition_ and _Composition_ files into a single OCI image.
{{< hint "note" >}}
The [Open Container Initiative](https://opencontainers.org/faq/)
defines the OCI image standard.
An OCI images is a standard way to package data.
{{< /hint >}}
You can host configuration packages in image registries like
[Docker Hub](https://hub.docker.com/) or the
[Upbound Marketplace](https://marketplace.upbound.io/).
Crossplane can download and install configuration packages into a Kubernetes
cluster.
Creating a configuration package makes your Crossplane custom APIs portable
and versioned.
Building and installing configuration packages requires an OCI image compatible
tool.
{{< hint "note" >}}
You can use any software that builds OCI images. This includes
[Docker](https://www.docker.com/) or
[Upbound's Up CLI](https://github.com/upbound/up).
{{< /hint >}}
A configuration package includes at least three files:
* `crossplane.yaml` defines the metadata of the package.
* `definition.yaml` is the _CompositeResourceDefinition_ for the package.
* `composition.yaml` is the _Composition_ template for the package.
<!-- vale gitlab.Substitutions = NO -->
<!-- yaml is in the filename -->
### Create a crossplane.yaml file
<!-- vale gitlab.Substitutions = YES -->
Configuration packages describe their contents and requirements with a
`crossplane.yaml` file.
The `crossplane.yaml` file lists the required Crossplane _Providers_ and their
compatible versions as well as the required Crossplane version.
The Crossplane
{{<hover label="xpyaml" line="3" >}}meta.pkg{{</hover>}} API defines the schema
for a
{{<hover label="xpyaml" line="4" >}}Configuration{{</hover>}}.
Inside the {{<hover label="xpyaml" line="7" >}}spec{{</hover>}} define the
required Crossplane
{{<hover label="xpyaml" line="9" >}}version{{</hover>}}.
The {{<hover label="xpyaml" line="10" >}}dependsOn{{</hover>}} section lists the
dependencies for a package.
This package lists the Upbound
{{<hover label="xpyaml" line="11" >}}provider-azure{{</hover>}}
version {{<hover label="xpyaml" line="12" >}}0.32.0{{</hover>}} or later as a
dependency.
{{<hint "tip" >}}
Crossplane automatically installs dependencies. Dependencies can include other
configuration packages.
{{< /hint >}}
Create a new directory and save the `crossplane.yaml` file.
```yaml {label="xpyaml"}
mkdir crossplane-azure-quickstart
cat <<EOF > crossplane-azure-quickstart/crossplane.yaml
apiVersion: meta.pkg.crossplane.io/v1
kind: Configuration
metadata:
name: crossplane-azure-quickstart
spec:
crossplane:
version: ">=v1.12.0"
dependsOn:
- provider: xpkg.upbound.io/upbound/provider-azure
version: ">=v0.32.0"
EOF
```
<!-- vale gitlab.Substitutions = NO -->
<!-- yaml is in the filename -->
### Create a definition.yaml file
<!-- vale gitlab.Substitutions = YES -->
A configuration package requires a _CompositeResourceDefinition_ (XRD) to
define the custom API.
Save the _XRD_ as `definition.yaml` in the same directory as the
`crossplane.yaml` file.
```yaml
cat <<EOF > crossplane-azure-quickstart/definition.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xvirtualmachines.custom-api.example.org
spec:
group: custom-api.example.org
names:
kind: XVirtualMachine
plural: xvirtualmachines
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
region:
type: string
oneOf:
- pattern: '^EU$'
- pattern: '^US$'
required:
- region
claimNames:
kind: VirtualMachine
plural: virtualmachines
EOF
```
<!-- vale gitlab.Substitutions = NO -->
<!-- yaml is in the filename -->
### Create a composition.yaml file
<!-- vale gitlab.Substitutions = YES -->
The _Composition_ template creates the _managed resources_ and allows _patches_
to customize the _managed resources_.
Copy the _Composition_ into the `composition.yaml` file in the same directory as
`crossplane.yaml`.
{{< hint "tip" >}}
Update each `resourceGroupName` with your Azure Resource Group.
{{< /hint >}}
{{< editCode >}}
```yaml
cat <<EOF > crossplane-azure-quickstart/composition.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: crossplane-quickstart-vm-with-network
spec:
compositeTypeRef:
apiVersion: custom-api.example.org/v1alpha1
kind: XVirtualMachine
resources:
- name: quickstart-vm
base:
apiVersion: compute.azure.upbound.io/v1beta1
kind: LinuxVirtualMachine
spec:
forProvider:
adminUsername: adminuser
adminSshKey:
- publicKey: ssh-rsa
AAAAB3NzaC1yc2EAAAADAQABAAABAQC+wWK73dCr+jgQOAxNsHAnNNNMEMWOHYEccp6wJm2gotpr9katuF/ZAdou5AaW1C61slRkHRkpRRX9FA9CYBiitZgvCCz+3nWNN7l/Up54Zps/pHWGZLHNJZRYyAB6j5yVLMVHIHriY49d/GZTZVNB8GoJv9Gakwc/fuEZYYl4YDFiGMBP///TzlI4jhiJzjKnEvqPFki5p2ZRJqcbCiF4pJrxUQR/RXqVFQdbRLZgYfJ8xGB878RENq3yQ39d8dVOkq4edbkzwcUmwwwkYVPIoDGsYLaRHnG+To7FvMeyO7xDVQkMKzopTQV8AuKpyvpqu0a9pWOMaiCyDytO7GGN
example@docs.crossplane.io
username: adminuser
location: "Central US"
osDisk:
- caching: ReadWrite
storageAccountType: Standard_LRS
resourceGroupName: $$<resource_group_name>$$
size: Standard_B1ms
sourceImageReference:
- offer: debian-11
publisher: Debian
sku: 11-backports-gen2
version: latest
networkInterfaceIdsSelector:
matchControllerRef: true
patches:
- fromFieldPath: "spec.region"
toFieldPath: "spec.forProvider.location"
transforms:
- type: map
map:
EU: "Sweden Central"
US: "Central US"
- name: quickstart-nic
base:
apiVersion: network.azure.upbound.io/v1beta1
kind: NetworkInterface
spec:
forProvider:
ipConfiguration:
- name: crossplane-quickstart-configuration
privateIpAddressAllocation: Dynamic
subnetIdSelector:
matchControllerRef: true
location: "Central US"
resourceGroupName: $$<resource_group_name>$$
patches:
- fromFieldPath: "spec.region"
toFieldPath: "spec.forProvider.location"
transforms:
- type: map
map:
EU: "Sweden Central"
US: "Central US"
- name: quickstart-subnet
base:
apiVersion: network.azure.upbound.io/v1beta1
kind: Subnet
spec:
forProvider:
addressPrefixes:
- 10.0.1.0/24
virtualNetworkNameSelector:
matchControllerRef: true
resourceGroupName: $$<resource_group_name>$$
patches:
- fromFieldPath: "spec.region"
toFieldPath: "spec.forProvider.location"
transforms:
- type: map
map:
EU: "Sweden Central"
US: "Central US"
- name: quickstart-network
base:
apiVersion: network.azure.upbound.io/v1beta1
kind: VirtualNetwork
spec:
forProvider:
addressSpace:
- 10.0.0.0/16
location: "Sweden Central"
resourceGroupName: $$<resource_group_name>$$
patches:
- fromFieldPath: "spec.region"
toFieldPath: "spec.forProvider.location"
transforms:
- type: map
map:
EU: "Sweden Central"
US: "Central US"
EOF
```
{{< /editCode >}}
### Install the Crossplane command-line
To build a configuration package install the Crossplane Kubernetes command-line
extension.
```shell
wget "https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh"
chmod +x install.sh
./install.sh
```
Follow the directions and move the `kubectl-crossplane` binary to the correct
directory.
Verify the Crossplane command-line installed with `kubectl crossplane --help`
```shell {copy-lines="1"}
kubectl crossplane --help
Usage: kubectl crossplane <command>
A command line tool for interacting with Crossplane.
Flags:
-h, --help Show context-sensitive help.
-v, --version Print version and quit.
--verbose Print verbose logging statements.
# Ouptut removed for brevity
```
### Build a configuration package
Use the `kubectl crossplane` command to create an `.xpkg` file containing the
custom APIs and Crossplane configuration.
```shell
kubectl crossplane build configuration -f crossplane-azure-quickstart/ --name="crossplane-azure-quickstart"
```
Now an `.xpkg` OCI image is inside the `crossplane-azure-quickstart` directory.
```shell {copy-lines="1"}
ls crossplane-azure-quickstart/
composition.yaml crossplane-azure-quickstart.xpkg crossplane.yaml definition.yaml
```
## Next steps
* Explore Azure resources that Crossplane can configure in the [Provider CRD reference](https://marketplace.upbound.io/providers/upbound/provider-family-azure/).
* Join the [Crossplane Slack](https://slack.crossplane.io/) and connect with Crossplane users and contributors.
* Read more about [Crossplane concepts]({{<ref "../concepts" >}})

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,967 @@
---
title: GCP Quickstart Part 2
weight: 120
tocHidden: true
---
{{< hint "important" >}}
This guide is part 2 of a series. Follow [**part 1**]({{<ref "provider-gcp" >}})
to install Crossplane and connect your Kubernetes cluster to GCP.
[**Part 3**]({{<ref "provider-gcp-part-3">}})** covers patching
_composite resources_ and using Crossplane _packages_.
{{< /hint >}}
This section creates a _[Composition](#create-a-composition)_,
_[Composite Resource Definition](#define-a-composite-resource)_ and a
_[Claim](#create-a-claim)_
to create a custom Kubernetes API to create GCP resources. This custom API is a
_Composite Resource_ (XR) API.
## Prerequisites
* Complete [quickstart part 1]({{<ref "provider-gcp" >}}) connecting Kubernetes
to GCP.
* a GCP account with permissions to create a GCP
[storage bucket](https://cloud.google.com/storage) and a
[Pub/Sub topic](https://cloud.google.com/pubsub).
{{<expand "Skip part 1 and just get started" >}}
1. Add the Crossplane Helm repository and install Crossplane.
```shell
helm repo add \
crossplane-stable https://charts.crossplane.io/stable
helm repo update
&&
helm install crossplane \
crossplane-stable/crossplane \
--namespace crossplane-system \
--create-namespace
```
2. When the Crossplane pods finish installing and are ready, apply the GCP Provider.
```yaml {label="provider",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: upbound-provider-gcp
spec:
package: xpkg.upbound.io/upbound/provider-gcp:v0.28.0
EOF
```
3. Create a file called `gcp-credentials.json` with your GCP service account
JSON file.
{{< hint type="tip" >}}
The
[GCP documentation](https://cloud.google.com/iam/docs/creating-managing-service-account-keys)
provides information on how to generate a service account JSON file.
{{< /hint >}}
4. Create a Kubernetes secret from the GCP JSON file
```shell {label="kube-create-secret",copy-lines="all"}
kubectl create secret \
generic gcp-secret \
-n crossplane-system \
--from-file=creds=./gcp-credentials.json
```
5. Create a _ProviderConfig_
Include your
{{< hover label="providerconfig" line="7" >}}GCP project ID{{< /hover >}} in the
_ProviderConfig_ settings.
{{< hint type="warning" >}}
Find your GCP project ID from the `project_id` field of the
`gcp-credentials.json` file.
{{< /hint >}}
{{< editCode >}}
```yaml {label="providerconfig",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: gcp.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
projectID: $@<PROJECT_ID>$@
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: gcp-secret
key: creds
EOF
```
{{< /editCode >}}
{{</expand >}}
## Create a composition
[Part 1]({{<ref "provider-gcp" >}}) created a single _managed resource_.
A _Composition_ is a template to create one or more _managed resources_ at the
same time.
This sample _composition_ creates a Pub/Sub instance and associated GCP storage
bucket.
{{< hint "note" >}}
This example comes from part of the GCP
[Stream messages from Pub/Sub by using Dataflow](https://cloud.google.com/pubsub/docs/stream-messages-dataflow)
guide.
{{< /hint >}}
To create a _composition_, first define each individual managed resource.
### Create a storage bucket object
Define a `bucket` resource using the configuration from the previous section:
{{< hint "note" >}}
Don't apply this configuration. This YAML is part of a larger
definition.
{{< /hint >}}
```yaml
apiVersion: storage.gcp.upbound.io/v1beta1
kind: Bucket
metadata:
name: crossplane-quickstart-bucket
spec:
forProvider:
location: US
providerConfigRef:
name: default
```
### Create a Pub/Sub topic resource
Next, define a Pub/Sub `topic` resource.
{{< hint "tip" >}}
The [Upbound Marketplace](https://marketplace.upbound.io/) provides
[schema documentation](https://marketplace.upbound.io/providers/upbound/provider-gcp/v0.28.0/resources/pubsub.gcp.upbound.io/Topic/v1beta1)
for a `topic` resource.
{{< /hint >}}
The _GCP Provider_ defines the
{{<hover line="1" label="topicMR">}}apiVersion{{</hover>}}
and
{{<hover line="2" label="topicMR">}}kind{{</hover>}}.
A Pub/Sub topic doesn't have requirements but using
{{<hover line="8" label="topicMR">}}messageStoragePolicy.allowedPersistenceRegions{{< /hover >}}
can keep messages stored in the same location as the storage bucket.
```yaml {label="topicMR"}
apiVersion: pubsub.gcp.upbound.io/v1beta1
kind: Topic
metadata:
name: crossplane-quickstart-topic
spec:
forProvider:
messageStoragePolicy:
- allowedPersistenceRegions:
- "us-central1"
```
{{< hint "note" >}}
Pub/Sub topic specifics are beyond the scope of this guide. Read the GCP
[Pub/Sub API reference](https://cloud.google.com/compute/docs/apis)
for more information.
{{</hint >}}
### Create the composition object
The _composition_ combines the two resource definitions.
A
{{<hover label="compName" line="2">}}Composition{{</ hover>}} comes from the
{{<hover label="compName" line="1">}}Crossplane{{</ hover>}}
API resources.
Create any {{<hover label="compName" line="4">}}name{{</ hover>}} for this _composition_.
```yaml {label="compName"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: topic-with-bucket
```
Add the resources to the
{{<hover label="specResources" line="5">}}spec.resources{{</ hover>}}
section of the _composition_.
Give each resource a
{{<hover label="specResources" line="7">}}name{{</ hover>}}
and put the resource definition under the
{{<hover label="specResources" line="8">}}base{{</ hover>}}
key.
{{< hint "note" >}}
Don't include resource `metadata` under the
{{<hover label="specResources" line="8">}}base{{</ hover>}} key.
{{< /hint >}}
```yaml {label="specResources"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: topic-with-bucket
spec:
resources:
- name: crossplane-quickstart-bucket
base:
apiVersion: storage.gcp.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
location: US
- name: crossplane-quickstart-topic
base:
apiVersion: pubsub.gcp.upbound.io/v1beta1
kind: Topic
spec:
forProvider:
messageStoragePolicy:
- allowedPersistenceRegions:
- "us-central1"
```
_Compositions_ are a template for generating resources. A
_composite resource_ actually creates the resources.
A _composition_ defines which _composite resources_ can use this
template.
_Compositions_ do this with the
{{<hover label="compRef" line="6">}}spec.compositeTypeRef{{</ hover>}}
definition.
{{< hint "tip" >}}
Crossplane recommends prefacing the `kind` with an `X` to show it's a
Composition.
{{< /hint >}}
```yaml {label="compRef"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: topic-with-bucket
spec:
compositeTypeRef:
apiVersion: custom-api.example.org/v1alpha1
kind: XTopicBucket
resources:
# Removed for Brevity
```
A _composite resource_ is actually a custom Kubernetes API type you define. The
platform team controls the kind, API endpoint and version.
<!-- vale gitlab.SentenceLength = NO -->
<!-- Length is because of shortcodes, ignore -->
With this {{<hover label="compRef" line="6">}}spec.compositeTypeRef{{</ hover>}}
Crossplane allows _composite resources_ from the API group
{{<hover label="compRef" line="7">}}custom-api.example.org{{</ hover>}}
that are of
{{<hover label="compRef" line="8">}}kind: XTopicBucket{{</ hover>}}
to use this template to create resources. No other API group or kind can use
this template.
<!-- vale gitlab.SentenceLength = YES -->
### Apply the composition
Apply the full _Composition_ to your Kubernetes cluster.
```yaml {copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: topic-with-bucket
spec:
compositeTypeRef:
apiVersion: custom-api.example.org/v1alpha1
kind: XTopicBucket
resources:
- name: crossplane-quickstart-bucket
base:
apiVersion: storage.gcp.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
location: US
- name: crossplane-quickstart-topic
base:
apiVersion: pubsub.gcp.upbound.io/v1beta1
kind: Topic
spec:
forProvider:
messageStoragePolicy:
- allowedPersistenceRegions:
- "us-central1"
EOF
```
Confirm the _composition_ exists with `kubectl get composition`
```shell {copy-lines="1"}
kubectl get composition
NAME AGE
topic-with-bucket 8s
```
## Define a composite resource
The _composition_ that was just created limited which _composite resources_ can
use that template.
A _composite resource_ is a custom API defined by the platform team.
A _composite resource definition_ defines the schema for a _composite resource_.
A _composite resource definition_ installs the custom API type into Kubernetes
and defines what `spec` keys and values are valid when calling this new custom API.
Before creating a _composite resource_ Crossplane requires a _composite resource definition_.
{{< hint "tip" >}}
_Composite resource definitions_ are also called `XRDs` for short.
{{< /hint >}}
Just like a _composition_ the
{{<hover label="xrdName" line="2" >}}composite resource definition{{</hover>}}
is part of the
{{<hover label="xrdName" line="1" >}}Crossplane{{</hover>}}
API group.
The _XRD_ {{<hover label="xrdName" line="4" >}}name{{</hover>}} is the new
API endpoint.
{{< hint "tip" >}}
Crossplane recommends using a plural name for the _XRD_
{{<hover label="xrdName" line="4" >}}name{{</hover>}}.
{{< /hint >}}
```yaml {label="xrdName"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xtopicbuckets.custom-api.example.org
```
The _XRD's_
{{<hover label="xrdGroup" line="5" >}}spec{{</hover>}} defines the new custom
API.
### Define the API endpoint and kind
First, define the new API
{{<hover label="xrdGroup" line="6" >}}group{{</hover>}}.
Next, create the API {{<hover label="xrdGroup" line="8" >}}kind{{</hover>}} and
{{<hover label="xrdGroup" line="9" >}}plural{{</hover>}}.
```yaml {label="xrdGroup"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xtopicbuckets.custom-api.example.org
spec:
group: custom-api.example.org
names:
kind: XTopicBucket
plural: xtopicbuckets
```
{{<hint "note" >}}
The _XRD_ {{<hover label="xrdGroup" line="6" >}}group{{</hover>}} matches the _composition_ {{<hover label="noteComp"
line="5">}}apiVersion{{</hover>}} and the
_XRD_ {{<hover label="xrdGroup" line="8" >}}kind{{</hover>}} matches the _composition_
{{<hover label="noteComp" line="6">}}compositeTypeRef.kind{{</hover>}}.
```yaml {label="noteComp"}
kind: Composition
# Removed for brevity
spec:
compositeTypeRef:
apiVersion: custom-api.example.org/v1alpha1
kind: XTopicBucket
```
{{< /hint >}}
### Set the API version
In Kubernetes, all API endpoints have a version to show the stability of the API
and track revisions.
Apply a version to the _XRD_ with a
{{<hover label="xrdVersion" line="11">}}versions.name{{</hover>}}.
This matches the
{{<hover label="noteComp"line="5">}}compositeTypeRef.apiVersion{{</hover>}}
_XRDs_ require both
{{<hover label="xrdVersion" line="12">}}versions.served{{</hover>}}
and
{{<hover label="xrdVersion" line="13">}}versions.referenceable{{</hover>}}.
```yaml {label="xrdVersion"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xtopicbuckets.custom-api.example.org
spec:
group: custom-api.example.org
names:
kind: XTopicBucket
plural: xtopicbuckets
versions:
- name: v1alpha1
served: true
referenceable: true
```
{{<hint "note" >}}
For more information on defining versions in Kubernetes read the
[API versioning](https://kubernetes.io/docs/reference/using-api/#api-versioning)
section of the Kubernetes documentation.
{{< /hint >}}
### Create the API schema
With an API endpoint named, now define the API schema, or what's allowed
inside the `spec` of the new Kubernetes object.
{{< hint "note" >}}
_XRDs_ follow the Kubernetes
[_custom resource definition_ rules for schemas](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#specifying-a-structural-schema).
{{</hint >}}
Place the API
{{< hover label="xrdSchema" line="8" >}}schema{{</hover>}}
under the
{{< hover label="xrdSchema" line="7" >}}version.name{{</hover>}}
The _XRD_ type defines the next lines. They're always the same.
<!-- vale write-good.TooWordy = NO -->
<!-- allow "validate" -->
{{< hover label="xrdSchema" line="9" >}}openAPIV3Schema{{</hover>}} specifies
how the schema gets validated.
<!-- vale write-good.TooWordy = YES -->
Next, the entire API is an
{{< hover label="xrdSchema" line="10" >}}object{{</hover>}}
with a
{{< hover label="xrdSchema" line="11" >}}property{{</hover>}} of
{{< hover label="xrdSchema" line="12" >}}spec{{</hover>}}.
The
{{< hover label="xrdSchema" line="12" >}}spec{{</hover>}} is also an
{{< hover label="xrdSchema" line="13" >}}object{{</hover>}} with
{{< hover label="xrdSchema" line="14" >}}properties{{</hover>}}.
```yaml {label="xrdSchema"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
# Removed for brevity
spec:
# Removed for brevity
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
```
{{< hint "tip" >}}
For more information on the values allowed in a _composite resource definition_ view its schema with
`kubectl explain xrd`
{{< /hint >}}
Now, define the custom API. Your custom API continues under the last
{{<hover label="xrdSchema" line="14">}}properties{{</hover>}} definition in the
previous example.
This custom API has one setting:
<!-- vale Google.We = NO -->
* {{<hover label="customAPI" line="4" >}}location{{</hover >}} - where to deploy
the resources, a choice of "EU" or "US."
Users can't change any other settings of the storage bucket or Pub/Sub topic.
The{{<hover label="customAPI" line="4" >}}location{{</hover >}}
is a {{<hover label="customAPI" line="5" >}}string{{</hover >}}
and matches the regular expression that's
{{<hover label="customAPI" line="6" >}}oneOf{{</hover >}}
{{<hover label="customAPI" line="7" >}}EU{{</hover >}}
or
{{<hover label="customAPI" line="8" >}}US{{</hover >}}.
This API requires the setting
{{<hover label="customAPI" line="10" >}}location{{</hover >}}.
```yaml {label="customAPI"}
# Removed for brevity
# schema.openAPIV3Schema.type.properties.spec
properties:
location:
type: string
oneOf:
- pattern: '^EU$'
- pattern: '^US$'
required:
- location
```
### Enable claims to the API
Tell this _XRD_ to offer a _claim_ by defining the _claim_ API endpoint under
the _XRD_ {{<hover label="XRDclaim" line="4">}}spec{{< /hover >}}.
{{< hint "tip" >}}
Crossplane recommends a _Claim_
{{<hover label="XRDclaim" line="10" >}}kind{{</hover>}} match the
_Composite Resource Definition_ (XRD)
{{<hover label="XRDclaim" line="7" >}}kind{{</ hover>}},
without the preceding `X`.
{{< /hint >}}
```yaml {label="XRDclaim"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
# Removed for brevity
spec:
# Removed for brevity
names:
kind: XTopicBucket
plural: xtopicbuckets
claimNames:
kind: TopicBucket
plural: topicbuckets
```
{{<hint "note" >}}
The [Claims](#create-a-claim) section later in this guide discusses _claims_.
{{< /hint >}}
### Apply the composite resource definition
Apply the complete _XRD_ to your Kubernetes cluster.
```yaml {copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xtopicbuckets.custom-api.example.org
spec:
group: custom-api.example.org
names:
kind: XTopicBucket
plural: xtopicbuckets
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
location:
type: string
oneOf:
- pattern: '^EU$'
- pattern: '^US$'
required:
- location
claimNames:
kind: TopicBucket
plural: topicbuckets
EOF
```
Verify Kubernetes created the XRD with `kubectl get xrd`
```shell {copy-lines="1",label="getXRD"}
kubectl get xrd
NAME ESTABLISHED OFFERED AGE
xtopicbuckets.custom-api.example.org True True 9s
```
## Create a composite resource
Creating an _XRD_ allows the creation _composite resources_.
A _composite resource_ uses the custom API created in the _XRD_.
The _XRD_ maps the _composite resource_ values to the _composition_ template and
creates new _managed resources_.
Looking at part of the _XRD_:
```yaml {label="xrdSnip"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
# Removed for brevity
spec:
group: custom-api.example.org
names:
kind: XTopicBucket
# Removed for brevity
spec:
type: object
properties:
location:
type: string
oneOf:
- pattern: '^EU$'
- pattern: '^US$'
```
The _XRD_ {{<hover label="xrdSnip" line="5">}}group{{</hover>}}
becomes the _composite resource_
{{<hover label="xr" line="2">}}apiVersion{{</hover>}}.
The _XRD_ {{<hover label="xrdSnip" line="7">}}kind{{</hover>}}
is the _composite resource_
{{<hover label="xr" line="3">}}kind{{</hover>}}
The _XRD_ API {{<hover label="xrdSnip" line="9">}}spec{{</hover>}} defines the
_composite resource_ {{<hover label="xr" line="6">}}spec{{</hover>}}.
The _XRD_ {{<hover label="xrdSnip" line="11">}}properties{{</hover>}} section
defines the options for the _composite resource_
{{<hover label="xr" line="6">}}spec{{</hover>}}.
The one option is {{<hover label="xrdSnip" line="12">}}location{{</hover>}}
and it can be either {{<hover label="xrdSnip" line="15">}}EU{{</hover>}} or
{{<hover label="xrdSnip" line="16">}}US{{</hover>}}.
This _composite resource_ uses
{{<hover label="xr" line="7">}}location: US{{</hover>}}.
<!-- vale Google.We = YES -->
### Apply the composite resource
Apply the composite resource to the Kubernetes cluster.
```yaml {label="xr", copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: custom-api.example.org/v1alpha1
kind: XTopicBucket
metadata:
name: my-composite-resource
spec:
location: "US"
EOF
```
### Verify the composite resource
Verify Crossplane created the _composite resource_ with `kubectl get xdatasetwithbucket`
{{<hint "tip" >}}
Use `kubectl get <composite resource kind>` to view a specific `kind` of _composite resource_.
View all _composite resources_ with `kubectl get composite`.
{{< /hint >}}
```shell {copy-lines="1"}
kubectl get XTopicBucket
NAME SYNCED READY COMPOSITION AGE
my-composite-resource True True topic-with-bucket 2m3s
```
Both `SYNCED` and `READY` are `True` when Crossplane created the GCP resources.
Now look at the GCP storage `bucket` and Pub/Sub `topic` _managed resources_
with `kubectl get bucket` and `kubectl get topic`.
```shell {copy-lines="1"}
kubectl get bucket
NAME READY SYNCED EXTERNAL-NAME AGE
my-composite-resource-m6lbx True True my-composite-resource-m6lbx 4m34s
```
```shell {copy-lines="1"}
kubectl get topics
NAME READY SYNCED EXTERNAL-NAME AGE
my-composite-resource-88vzp True True my-composite-resource-88vzp 4m48s
```
The _composite resource_ automatically generated both _managed resources_.
Using `kubectl describe` on a _managed resource_ shows the `Owner References` is
the _composite resource_.
```yaml {copy-lines="1"}
kubectl describe bucket | grep "Owner References" -A5
Owner References:
API Version: custom-api.example.org/v1alpha1
Block Owner Deletion: true
Controller: true
Kind: XTopicBucket
Name: my-composite-resource
```
Each _composite resource_ creates and owns a unique set of _managed resources_.
If you create a second _composite resource_ Crossplane creates a new storage
`bucket` and Pub/Sub `topic`.
```yaml {label="xr", copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: custom-api.example.org/v1alpha1
kind: XTopicBucket
metadata:
name: my-second-composite-resource
spec:
location: "US"
EOF
```
Again, use `kubectl get XTopicBucket` to view both _composite resources_.
```shell {copy-lines="1"}
kubectl get XTopicBucket
NAME SYNCED READY COMPOSITION AGE
my-composite-resource True True topic-with-bucket 8m41s
my-second-composite-resource True True topic-with-bucket 2m4s
```
And see there are two `bucket` and two `topic` _managed resources_.
```shell {copy-lines="1"}
kubectl get bucket
NAME READY SYNCED EXTERNAL-NAME AGE
my-composite-resource-m6lbx True True my-composite-resource-m6lbx 9m18s
my-second-composite-resource-rkhbd True True my-second-composite-resource-rkhbd 2m41s
```
```shell {copy-lines="1"}
kubectl get topic
NAME READY SYNCED EXTERNAL-NAME AGE
my-composite-resource-88vzp True True my-composite-resource-88vzp 9m31s
my-second-composite-resource-4wv89 True True my-second-composite-resource-4wv89 2m54s
```
### Delete the composite resources
Because the _composite resource_ is the `Owner` of the _managed resources_, when
Crossplane deletes the _composite resource_, it also deletes the _managed resources_ automatically.
Delete the new _composite resource_ with `kubectl delete XTopicBucket`.
{{<hint "tip" >}}
Delete a specific _composite resource_ with
`kubectl delete <composite kind> <name>` or
`kubectl delete composite <name>`.
{{< /hint >}}
Delete the second composition
```shell
kubectl delete XTopicBucket my-second-composite-resource
```
{{<hint "note">}}
There may a delay in deleting the _managed resources_. Crossplane is making API
calls to GCP and waits for GCP to confirm they deleted the resources before
updating the state in Kubernetes.
{{</hint >}}
Now a single bucket and topic exist.
```shell {copy-lines="1"}
kubectl get bucket
NAME READY SYNCED EXTERNAL-NAME AGE
my-composite-resource-m6lbx True True my-composite-resource-m6lbx 11m
```
```shell {copy-lines="1"}
kubectl get topic
NAME READY SYNCED EXTERNAL-NAME AGE
my-composite-resource-88vzp True True my-composite-resource-88vzp 11m
```
Delete the other _composite resource_ to remove the last `bucket` and `table`
_managed resources_.
```shell
kubectl delete xtopicbucket my-composite-resource
```
_Composite resources_ are great for creating one or more related resources against
a template, but all _composite resources_ exist at the Kubernetes "cluster
level." There's no isolation between _composite resources_. Crossplane uses
_claims_ to create resources with namespace isolation.
## Create a claim
_Claims_, just like _composite resources_ use the custom API defined in the
_XRD_. Unlike a _composite resource_, Crossplane can create _claims_ in a
namespace.
### Create a new Kubernetes namespace
Create a new namespace with `kubectl create namespace`.
```shell
kubectl create namespace test
```
Look at the _XRD_ to see the parameters for the _claim_.
A _claim_ uses the same {{<hover label="XRDclaim2" line="6" >}}group{{</hover>}}
a _composite resource_ uses but a different
{{<hover label="XRDclaim2" line="8" >}}kind{{</hover>}}.
```yaml {label="XRDclaim2"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
# Removed for brevity
spec:
# Removed for brevity
group: custom-api.example.org
claimNames:
kind: TopicBucket
plural: topicbuckets
```
Like the _composite resource_, create a new object with the
{{<hover label="claim" line="2" >}}custom-api.example.org{{</hover>}} API
endpoint.
The _XRD_
{{<hover label="XRDclaim2" line="8" >}}claimNames.kind{{</hover>}} defines the
{{<hover label="claim" line="3" >}}kind{{</hover>}}.
The {{<hover label="claim" line="7" >}}spec{{</hover>}} uses the same
API options as the _composite resource_.
### Apply the claim
Apply the _claim_ to your Kubernetes cluster.
```yaml {label="claim", copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: custom-api.example.org/v1alpha1
kind: TopicBucket
metadata:
name: claimed-topic-with-bucket
namespace: test
spec:
location: "US"
EOF
```
### Verify the claim
Verify Crossplane created the _claim_ with `kubectl get TopicBucket` in the `test`
namespace.
{{<hint "tip" >}}
View claims with `kubectl get <kind>` or use `kubectl get claim` to view all
_claims_.
{{</hint >}}
```shell {copy-lines="1"}
kubectl get TopicBucket -n test
NAME SYNCED READY CONNECTION-SECRET AGE
claimed-topic-with-bucket True True 4m37s
```
When Crossplane creates a _claim_, a unique _composite resource_ is also
created. View the new _composite resource_ with `kubectl get xtopicbucket`.
```shell {copy-lines="1"}
kubectl get xtopicbucket
NAME SYNCED READY COMPOSITION AGE
claimed-topic-with-bucket-7k2lj True True topic-with-bucket 4m58s
```
The _composite resource_ exists at the "cluster scope" while the _claim_ exists
at the "namespace scope."
Create a second namespace and a second claim.
```shell {copy-lines="all"}
kubectl create namespace test2
cat <<EOF | kubectl apply -f -
apiVersion: custom-api.example.org/v1alpha1
kind: TopicBucket
metadata:
name: second-claimed-topic-with-bucket
namespace: test2
spec:
location: "US"
EOF
```
View the _claims_ in all namespaces with `kubectl get topicbucket -A`
```shell {copy-lines="1"}
kubectl get topicbucket -A
NAMESPACE NAME SYNCED READY CONNECTION-SECRET AGE
test claimed-topic-with-bucket True True 8m48s
test2 second-claimed-topic-with-bucket True True 2m24s
```
Now look at the _composite resources_ at the cluster scope.
```shell {copy-lines="1"}
kubectl get xtopicbucket
NAME SYNCED READY COMPOSITION AGE
claimed-topic-with-bucket-7k2lj True True topic-with-bucket 9m11s
second-claimed-topic-with-bucket-d5x58 True True topic-with-bucket 2m47s
```
Crossplane created a second _composite resource_ for the second _claim_.
Looking at the GCP storage `bucket` and Pub/Sub `topic` shows two of each
resource, one for each claim.
```shell {copy-lines="1"}
kubectl get bucket
NAME READY SYNCED EXTERNAL-NAME AGE
claimed-topic-with-bucket-7k2lj-qf2m6 True True claimed-topic-with-bucket-7k2lj-qf2m6 9m46s
second-claimed-topic-with-bucket-d5x58-drlxr True True second-claimed-topic-with-bucket-d5x58-drlxr 3m22s
```
```shell {copy-lines="1"}
kubectl get topic
NAME READY SYNCED EXTERNAL-NAME AGE
claimed-topic-with-bucket-7k2lj-8xn7t True True claimed-topic-with-bucket-7k2lj-8xn7t 9m59s
second-claimed-topic-with-bucket-d5x58-ctkrp True True second-claimed-topic-with-bucket-d5x58-ctkrp 3m35s
```
### Delete the claims
Removing the _claims_ removes the _composite resources_ and the associated
_managed resources_.
```shell
kubectl delete topicbucket claimed-topic-with-bucket -n test
kubectl delete topicbucket second-claimed-topic-with-bucket -n test2
```
Verify Crossplane removed all the _managed resources_.
```shell
kubectl get bucket
No resources found
```
```shell
kubectl get table
No resources found
```
Claims are powerful tools to give users resources in their own isolated
namespace. But these examples haven't shown how the custom API can change
the settings defined in the _composition_. This _composition patching_ applies
the API settings when creating resources.
[Part 3]({{< ref "provider-gcp-part-3">}}) of this guide covers
_composition patches_ and making all this configuration portable in Crossplane
_packages_.
## Next steps
* [**Continue to part 3**]({{< ref "provider-gcp-part-3">}})** to create a learn
about _patching_ resources and creating Crossplane _packages_.
* Explore GCP resources that Crossplane can configure in the
[Provider CRD reference](https://marketplace.upbound.io/providers/upbound/provider-family-gcp/).
* Join the [Crossplane Slack](https://slack.crossplane.io/) and connect with Crossplane users and contributors.

View File

@ -0,0 +1,659 @@
---
title: GCP Quickstart Part 3
weight: 120
tocHidden: true
---
{{< hint "important" >}}
This guide is part 3 of a series.
Follow [**part 1**]({{<ref "provider-gcp" >}})
to install Crossplane and connect your Kubernetes cluster to GCP.
Follow [**part 2**]({{<ref "provider-gcp-part-2" >}})** to create a _composition_,
_custom resource definition_ and a _claim_.
{{< /hint >}}
[Part 2]({{<ref "provider-gcp-part-2" >}}) created a _composite resource
definition_ to define the schema of the custom API. Users create a _claim_ to
use the custom API and apply their options. Part 2 didn't show how the options
set in a _claim_ change or get applied the associated _composite resources_.
## Prerequisites
* Complete quickstart [part 1]({{<ref "provider-gcp" >}}) and
[Part 2]({{<ref "provider-gcp-part-2" >}}) to install Crossplane and the quickstart
configurations.
{{<expand "Skip parts 1 and 2 and just get started" >}}
1. Add the Crossplane Helm repository and install Crossplane.
```shell
helm repo add \
crossplane-stable https://charts.crossplane.io/stable
helm repo update
&&
helm install crossplane \
crossplane-stable/crossplane \
--namespace crossplane-system \
--create-namespace
```
2. When the Crossplane pods finish installing and are ready, apply the GCP Provider.
```yaml {label="provider",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: upbound-provider-gcp
spec:
package: xpkg.upbound.io/upbound/provider-gcp:v0.28.0
EOF
```
3. Create a file called `gcp-credentials.json` with your GCP service account
JSON file.
{{< hint type="tip" >}}
The
[GCP documentation](https://cloud.google.com/iam/docs/creating-managing-service-account-keys)
provides information on how to generate a service account JSON file.
{{< /hint >}}
4. Create a Kubernetes secret from the GCP JSON file
```shell {label="kube-create-secret",copy-lines="all"}
kubectl create secret \
generic gcp-secret \
-n crossplane-system \
--from-file=creds=./gcp-credentials.json
```
5. Create a _ProviderConfig_
Include your
{{< hover label="providerconfig" line="7" >}}GCP project ID{{< /hover >}} in the
_ProviderConfig_ settings.
{{< hint type="warning" >}}
Find your GCP project ID from the `project_id` field of the
`gcp-credentials.json` file.
{{< /hint >}}
{{< editCode >}}
```yaml {label="providerconfig",copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: gcp.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
projectID: $@<PROJECT_ID>$@
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: gcp-secret
key: creds
EOF
```
{{< /editCode >}}
6. Create a _composition_
```yaml {copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: topic-with-bucket
spec:
compositeTypeRef:
apiVersion: custom-api.example.org/v1alpha1
kind: XTopicBucket
resources:
- name: crossplane-quickstart-bucket
base:
apiVersion: storage.gcp.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
location: US
- name: crossplane-quickstart-topic
base:
apiVersion: pubsub.gcp.upbound.io/v1beta1
kind: Topic
spec:
forProvider:
messageStoragePolicy:
- allowedPersistenceRegions:
- "us-central1"
EOF
```
7. Create a _composite resource definition_
```yaml {copy-lines="all"}
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xtopicbuckets.custom-api.example.org
spec:
group: custom-api.example.org
names:
kind: XTopicBucket
plural: xtopicbuckets
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
location:
type: string
oneOf:
- pattern: '^EU$'
- pattern: '^US$'
required:
- location
claimNames:
kind: TopicBucket
plural: topicbuckets
EOF
```
8. Create a new namespace
```shell
kubectl create namespace test
```
{{</expand >}}
## Enable composition patches
In a _composition_, `patches` map fields in the custom API to fields inside the
_managed resources_.
The example _composition_ has two _managed resources_, a
{{<hover label="compResources" line="8">}}bucket{{</hover>}} and a
{{<hover label="compResources" line="15">}}topic{{</hover>}}.
```yaml {label="compResources"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for Brevity
resources:
- name: crossplane-quickstart-bucket
base:
apiVersion: storage.gcp.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
location: US
- name: crossplane-quickstart-topic
base:
apiVersion: pubsub.gcp.upbound.io/v1beta1
kind: Topic
spec:
forProvider:
messageStoragePolicy:
- allowedPersistenceRegions:
- "us-central1"
```
<!-- vale Google.We = NO -->
The custom API defined a single option,
{{<hover label="xrdSnip" line="12">}}location{{</hover>}}. A
{{<hover label="xrdSnip" line="12">}}location{{</hover>}} can be either
{{<hover label="xrdSnip" line="15">}}EU{{</hover>}} or
{{<hover label="xrdSnip" line="16">}}US{{</hover>}}.
<!-- vale Google.We = YES -->
```yaml {label="xrdSnip"}
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
# Removed for brevity
spec:
group: custom-api.example.org
names:
kind: XDatabase
# Removed for brevity
spec:
type: object
properties:
location:
type: string
oneOf:
- pattern: '^EU$'
- pattern: '^US$'
```
Creating a _composition_ `patch` allows Crossplane to update the settings of a
_composite resource_. Patches apply to an individual _managed resource_
inside the _composition_.
A {{<hover label="patch" line="14">}}patch{{</hover>}} has a
{{<hover label="patch" line="15">}}fromField{{</hover>}} and a
{{<hover label="patch" line="16">}}toField{{</hover>}} specifying which value
_from_ the custom API should apply _to_ a field in the _managed resource_.
Patches can create a
{{<hover label="patch" line="17">}}transform{{</hover>}} to change the _from_
field before it's applied.
The transform
{{<hover label="patch" line="18">}}type{{</hover>}} is what kind of change to
make on the _from_ field. Types of changes could include appending a string,
preforming a math operation or mapping one value to another.
Applying a {{<hover label="patch" line="14">}}patch{{</hover>}} to the
{{<hover label="patch" line="8">}}Topic{{</hover>}} uses the custom API
{{<hover label="patch" line="15">}}spec.location{{</hover>}} field to use as the
_managed resource_
{{<hover label="patch" line="12">}}allowedPersistenceRegions{{</hover>}} value.
<!-- vale Google.We = NO -->
The custom API value "EU" is
{{<hover label="patch" line="20">}}mapped{{</hover>}} to the value
"europe-central2" and "US" is
{{<hover label="patch" line="21">}}mapped{{</hover>}} to the value
"us-central1."
<!-- vale Google.We = YES -->
```yaml {label="patch"}
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
# Removed for Brevity
resources:
- name: crossplane-quickstart-topic
base:
apiVersion: pubsub.gcp.upbound.io/v1beta1
kind: Topic
spec:
forProvider:
messageStoragePolicy:
- allowedPersistenceRegions:
- "us-central1"
patches:
- fromFieldPath: "spec.location"
toFieldPath: "spec.forProvider.messageStoragePolicy[*].allowedPersistenceRegions[*]"
transforms:
- type: map
map:
EU: "europe-central2"
US: "us-central1"
```
<!-- vale Google.We = NO -->
Patching is a powerful tool enabling simpler or abstracted APIs. Developers
aren't required to know the specific GCP region, just the abstracted
option of "EU" or "US."
<!-- vale Google.We = YES -->
### Apply the updated composition
Apply a similar `patch` to the `Bucket` _managed resource_ and apply the updated
_composition_.
```yaml
cat <<EOF | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: topic-with-bucket
spec:
compositeTypeRef:
apiVersion: custom-api.example.org/v1alpha1
kind: XTopicBucket
resources:
- name: crossplane-quickstart-bucket
base:
apiVersion: storage.gcp.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
location: "US"
patches:
- fromFieldPath: "spec.location"
toFieldPath: "spec.forProvider.location"
transforms:
- type: map
map:
EU: "EU"
US: "US"
- name: crossplane-quickstart-topic
base:
apiVersion: pubsub.gcp.upbound.io/v1beta1
kind: Topic
spec:
forProvider:
messageStoragePolicy:
- allowedPersistenceRegions:
- "us-central1"
patches:
- fromFieldPath: "spec.location"
toFieldPath: "spec.forProvider.messageStoragePolicy[*].allowedPersistenceRegions[*]"
transforms:
- type: map
map:
EU: "europe-central2"
US: "us-central1"
EOF
```
### Create a claim
Create a new _claim_ and set the
{{<hover label="claim" line="8" >}}location{{</hover >}} to "EU."
```yaml {label="claim"}
cat <<EOF | kubectl apply -f -
apiVersion: custom-api.example.org/v1alpha1
kind: TopicBucket
metadata:
name: claimed-eu-topic-with-bucket
namespace: test
spec:
location: "EU"
EOF
```
View the _claim_ with `kubectl get claim`
```shell {copy-lines="1"}
kubectl get TopicBucket -n test
NAME SYNCED READY CONNECTION-SECRET AGE
claimed-eu-topic-with-bucket True True 2m26s
```
The claim reports `SYNCED` and `READY` as `True` after Crossplane creates
all the _managed resources_.
Describe the `Topic` resource to see the GCP location is
{{< hover label="topicLocation" line="5">}}europe-central2{{< /hover >}}.
```shell {copy-lines="1",label="topicLocation"}
kubectl describe topic | grep "For Provider" -A3
For Provider:
Message Storage Policy:
Allowed Persistence Regions:
europe-central2
```
Describe the `Bucket` resource to see the GCP location is also set to
{{<hover label="bucketLocation" line="3">}}EU{{</hover>}}.
```shell {copy-lines="1",label="bucketLocation"}
kubectl describe bucket | grep "For Provider" -A1
For Provider:
Location: EU
```
<!-- vale Google.We = NO -->
Using {{<hover label="claim" line="8" >}}location: "EU"{{</hover >}} in the
claim patches the _composite resource_, updating the `Topic` GCP region from
`us-central1` to `europe-central-2` and the `Bucket` from GCP region `US` to GCP
region `EU`.
The developer creating the claim isn't required to know which specific GCP
region or the naming conventions. Using the abstract API options of "EU" or "US"
the developer places their resources in the desired location.
In this example, patching also allows platform teams to ensure all resources are
in the same location.
<!-- vale Google.We = YES -->
Deleting the claim removes the _managed resources_.
{{<hint "note" >}}
The _managed resources_ take up to 5 minutes to delete.
{{< /hint >}}
```shell
kubectl delete TopicBucket claimed-eu-topic-with-bucket -n test
```
## Create a Crossplane configuration package
Creating a configuration package makes your Crossplane custom APIs portable
and versioned.
Crossplane _configuration packages_ allow users to combine their _custom
resource definition_ and _composition_ files into an OCI image.
{{< hint "note" >}}
The [Open Container Initiative](https://opencontainers.org/faq/)
defines the OCI image standard.
An OCI images is a standard way to package data.
{{< /hint >}}
You can host configuration packages in image registries like
[Docker Hub](https://hub.docker.com/) or the
[Upbound Marketplace](https://marketplace.upbound.io/).
Crossplane can download and install configuration packages into a Kubernetes
cluster.
Building and installing configuration packages requires an OCI image compatible
tool.
{{< hint "note" >}}
You can use any software that builds OCI images. This includes
[Docker](https://www.docker.com/) or
[Upbound's Up command-line tool](https://github.com/upbound/up)
{{< /hint >}}
A configuration package includes three files:
* `crossplane.yaml` defines the metadata of the package.
* `definition.yaml` is the _composite resource definition_ for the package.
* `composition.yaml` is the _composition_ template for the package.
<!-- vale gitlab.Substitutions = NO -->
<!-- yaml is in the filename -->
### Create a crossplane.yaml file
<!-- vale gitlab.Substitutions = YES -->
Configuration packages describe their contents and requirements with a
`crossplane.yaml` file.
The `crossplane.yaml` file lists the required Crossplane _providers_ and their
compatible versions as well as the required Crossplane version.
The Crossplane
{{<hover label="xpyaml" line="1" >}}meta.pkg{{</hover>}} API defines the schema
for a
{{<hover label="xpyaml" line="2" >}}Configuration{{</hover>}}.
Inside the {{<hover label="xpyaml" line="5" >}}spec{{</hover>}} define the
required Crossplane
{{<hover label="xpyaml" line="7" >}}version{{</hover>}}.
The {{<hover label="xpyaml" line="8" >}}dependsOn{{</hover>}} section lists the
dependencies for a package.
This package lists the Upbound
{{<hover label="xpyaml" line="9" >}}provider-gcp{{</hover>}}
version {{<hover label="xpyaml" line="10" >}}0.28.0{{</hover>}} or later as a
dependency.
{{<hint "tip" >}}
Crossplane automatically installs dependencies. Dependencies can include other
configuration packages.
{{< /hint >}}
```yaml {label="xpyaml"}
apiVersion: meta.pkg.crossplane.io/v1
kind: Configuration
metadata:
name: crossplane-gcp-quickstart
spec:
crossplane:
version: ">=v1.11.0"
dependsOn:
- provider: xpkg.upbound.io/upbound/provider-gcp
version: ">=v0.28.0"
```
Create a new directory and save the `crossplane.yaml` file.
```yaml {copy-lines="all"}
mkdir crossplane-gcp-quickstart
cat <<EOF > crossplane-gcp-quickstart/crossplane.yaml
apiVersion: meta.pkg.crossplane.io/v1
kind: Configuration
metadata:
name: crossplane-gcp-quickstart
spec:
crossplane:
version: ">=v1.12.0"
dependsOn:
- provider: xpkg.upbound.io/upbound/provider-gcp
version: ">=v0.28.0"
EOF
```
<!-- vale gitlab.Substitutions = NO -->
<!-- yaml is in the filename -->
### Create a definition.yaml file
<!-- vale gitlab.Substitutions = YES -->
A configuration package requires a _composite resource definition_ (XRD) to define the
custom API.
Save the _XRD_ as `definition.yaml` in the same directory as the
`crossplane.yaml` file.
```yaml {copy-lines="all"}
cat <<EOF > crossplane-gcp-quickstart/definition.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xtopicbuckets.custom-api.example.org
spec:
group: custom-api.example.org
names:
kind: XTopicBucket
plural: xtopicbuckets
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
location:
type: string
oneOf:
- pattern: '^EU$'
- pattern: '^US$'
required:
- location
claimNames:
kind: TopicBucket
plural: topicbuckets
EOF
```
<!-- vale gitlab.Substitutions = NO -->
<!-- yaml is in the filename -->
### Create a composition.yaml file
<!-- vale gitlab.Substitutions = YES -->
The _composition_ template creates the _managed resources_ and allows _patches_
to customize the _managed resources_.
Copy the _composition_ into the `composition.yaml` file in the same directory as
`crossplane.yaml`.
```yaml
cat <<EOF > crossplane-gcp-quickstart/composition.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: topic-with-bucket
spec:
compositeTypeRef:
apiVersion: custom-api.example.org/v1alpha1
kind: XTopicBucket
resources:
- name: crossplane-quickstart-bucket
base:
apiVersion: storage.gcp.upbound.io/v1beta1
kind: Bucket
spec:
forProvider:
location: "US"
patches:
- fromFieldPath: "spec.location"
toFieldPath: "spec.forProvider.location"
transforms:
- type: map
map:
EU: "EU"
US: "US"
- name: crossplane-quickstart-topic
base:
apiVersion: pubsub.gcp.upbound.io/v1beta1
kind: Topic
spec:
forProvider:
messageStoragePolicy:
- allowedPersistenceRegions:
- "us-central1"
patches:
- fromFieldPath: "spec.location"
toFieldPath: "spec.forProvider.messageStoragePolicy[*].allowedPersistenceRegions[*]"
transforms:
- type: map
map:
EU: "europe-central2"
US: "us-central1"
EOF
```
### Install the Crossplane command-line
To build a configuration package install the Crossplane Kubernetes command-line
extension.
```shell
wget "https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh"
chmod +x install.sh
./install.sh
sudo mv kubectl-crossplane /usr/bin
```
Verify the Crossplane command-line installed with `kubectl crossplane --help`
```shell
kubectl crossplane --help
Usage: kubectl crossplane <command>
A command line tool for interacting with Crossplane.
Flags:
-h, --help Show context-sensitive help.
-v, --version Print version and quit.
--verbose Print verbose logging statements.
# Ouptut removed for brevity
```
### Build a configuration package
Use the `kubectl crossplane` command to create an `.xpkg` file containing the
custom APIs and Crossplane configuration.
```shell
kubectl crossplane build configuration -f crossplane-gcp-quickstart/ --name="crossplane-gcp-quickstart"
```
Now an `.xpkg` OCI image is inside the `crossplane-gcp-quickstart` directory.
```shell
ls crossplane-gcp-quickstart/
composition.yaml crossplane-gcp-quickstart.xpkg crossplane.yaml definition.yaml
```
## Next steps
* Explore GCP resources that Crossplane can configure in the [Provider CRD reference](https://marketplace.upbound.io/providers/upbound/provider-family-gcp/).
* Join the [Crossplane Slack](https://slack.crossplane.io/) and connect with Crossplane users and contributors.
* Read more about [Crossplane concepts]({{<ref "../concepts" >}})

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
---
title: Install, Uninstall and Upgrade
weight: 300
description: Manage Crossplane installations
---
## [Install Crossplane](./install/)
How to install and customize Crossplane in an existing Kubernetes cluster.
## [Uninstall Crossplane](./uninstall/)
How to remove Crossplane from a Kubernetes cluster.

View File

@ -0,0 +1,342 @@
---
title: Install Crossplane
weight: 100
---
Crossplane installs into an existing Kubernetes cluster, creating the
`Crossplane` pod, enabling the installation of Crossplane _Provider_ resources.
{{< hint type="tip" >}}
If you don't have a Kubernetes cluster create one locally with [Kind](https://kind.sigs.k8s.io/).
{{< /hint >}}
## Prerequisites
* An actively [supported Kubernetes version](https://kubernetes.io/releases/patch-releases/#support-period)
* [Helm](https://helm.sh/docs/intro/install/) version `v3.2.0` or later
## Install Crossplane
Install Crossplane using the Crossplane published _Helm chart_.
### Add the Crossplane Helm repository
Add the Crossplane repository with the `helm repo add` command.
```shell
helm repo add crossplane-stable https://charts.crossplane.io/stable
```
Update the
local Helm chart cache with `helm repo update`.
```shell
helm repo update
```
### Install the Crossplane Helm chart
Install the Crossplane Helm chart with `helm install`.
{{< hint "tip" >}}
View the changes Crossplane makes to your cluster with the
`helm install --dry-run --debug` options. Helm shows what configurations it
applies without making changes to the Kubernetes cluster.
{{< /hint >}}
Crossplane creates and installs into the `crossplane-system` namespace.
```shell
helm install crossplane \
--namespace crossplane-system \
--create-namespace crossplane-stable/crossplane
```
View the installed Crossplane pods with `kubectl get pods -n crossplane-system`.
```shell {copy-lines="1"}
kubectl get pods -n crossplane-system
NAME READY STATUS RESTARTS AGE
crossplane-6d67f8cd9d-g2gjw 1/1 Running 0 26m
crossplane-rbac-manager-86d9b5cf9f-2vc4s 1/1 Running 0 26m
```
{{< hint "tip" >}}
Install a specific version of Crossplane with the `--version <version>` option. For example, to install version `1.10.0`:
```shell
helm install crossplane \
--namespace crossplane-system \
--create-namespace crossplane-stable/crossplane \
--version 1.10.0
```
{{< /hint >}}
## Installed deployments
Crossplane creates two Kubernetes _deployments_ in the `crossplane-system`
namespace to deploy the Crossplane pods.
```shell {copy-lines="1"}
kubectl get deployments -n crossplane-system
NAME READY UP-TO-DATE AVAILABLE AGE
crossplane 1/1 1 1 8m13s
crossplane-rbac-manager 1/1 1 1 8m13s
```
### Crossplane deployment
The Crossplane deployment starts with the `crossplane-init container`. The
`init` container installs the Crossplane _Custom Resource Definitions_ into the
Kubernetes cluster.
After the `init` container finishes, the `crossplane` pod manages two Kubernetes
controllers.
* The _Package Manager controller_ installs the
provider and configuration packages.
* The _Composition controller_ installs and manages the
Crossplane _Composite Resource Definitions_, _Compositions_ and _Claims_.
### Crossplane-rbac-manager deployment
The `crossplane-rbac-manager` creates and manages Kubernetes _ClusterRoles_ for
installed Crossplane _Provider_ and their _Custom Resource Definitions_.
The
[Crossplane RBAC Manger design document](https://github.com/crossplane/crossplane/blob/master/design/design-doc-rbac-manager.md)
has more information on the installed _ClusterRoles_.
## Installation options
### Customize the Crossplane Helm chart
Crossplane supports customizations at install time by configuring the Helm
chart.
Apply customizations with the command line or with a Helm _values_ file.
<!-- vale gitlab.Substitutions = NO -->
<!-- allow lowercase yaml -->
{{<expand "All Crossplane customization options" >}}
{{< table "table table-hover table-striped table-sm">}}
| Parameter | Description | Default |
| --- | --- | --- |
| `affinity` | Add `affinities` to the Crossplane pod deployment. | `{}` |
| `args` | Add custom arguments to the Crossplane pod. | `[]` |
| `configuration.packages` | A list of Configuration packages to install. | `[]` |
| `customAnnotations` | Add custom `annotations` to the Crossplane pod deployment. | `{}` |
| `customLabels` | Add custom `labels` to the Crossplane pod deployment. | `{}` |
| `deploymentStrategy` | The deployment strategy for the Crossplane and RBAC Manager pods. | `"RollingUpdate"` |
| `extraEnvVarsCrossplane` | Add custom environmental variables to the Crossplane pod deployment. Replaces any `.` in a variable name with `_`. For example, `SAMPLE.KEY=value1` becomes `SAMPLE_KEY=value1`. | `{}` |
| `extraEnvVarsRBACManager` | Add custom environmental variables to the RBAC Manager pod deployment. Replaces any `.` in a variable name with `_`. For example, `SAMPLE.KEY=value1` becomes `SAMPLE_KEY=value1`. | `{}` |
| `extraVolumeMountsCrossplane` | Add custom `volumeMounts` to the Crossplane pod. | `{}` |
| `extraVolumesCrossplane` | Add custom `volumes` to the Crossplane pod. | `{}` |
| `hostNetwork` | Enable `hostNetwork` for the Crossplane deployment. Caution: enabling `hostNetwork`` grants the Crossplane Pod access to the host network namespace. | `false` |
| `image.pullPolicy` | The image pull policy used for Crossplane and RBAC Manager pods. | `"IfNotPresent"` |
| `image.repository` | Repository for the Crossplane pod image. | `"crossplane/crossplane"` |
| `image.tag` | The Crossplane image tag. Defaults to the value of `appVersion` in Chart.yaml. | `""` |
| `imagePullSecrets` | The imagePullSecret names to add to the Crossplane ServiceAccount. | `{}` |
| `leaderElection` | Enable [leader election](https://docs.crossplane.io/latest/concepts/pods/#leader-election) for the Crossplane pod. | `true` |
| `metrics.enabled` | Enable Prometheus path, port and scrape annotations and expose port 8080 for both the Crossplane and RBAC Manager pods. | `false` |
| `nodeSelector` | Add `nodeSelectors` to the Crossplane pod deployment. | `{}` |
| `packageCache.configMap` | The name of a ConfigMap to use as the package cache. Disables the default package cache `emptyDir` Volume. | `""` |
| `packageCache.medium` | Set to `Memory` to hold the package cache in a RAM-backed file system. Useful for Crossplane development. | `""` |
| `packageCache.pvc` | The name of a PersistentVolumeClaim to use as the package cache. Disables the default package cache `emptyDir` Volume. | `""` |
| `packageCache.sizeLimit` | The size limit for the package cache. If medium is `Memory` the `sizeLimit` can't exceed Node memory. | `"20Mi"` |
| `podSecurityContextCrossplane` | Add a custom `securityContext` to the Crossplane pod. | `{}` |
| `podSecurityContextRBACManager` | Add a custom `securityContext` to the RBAC Manager pod. | `{}` |
| `priorityClassName` | The PriorityClass name to apply to the Crossplane and RBAC Manager pods. | `""` |
| `provider.packages` | A list of Provider packages to install. | `[]` |
| `rbacManager.affinity` | Add `affinities` to the RBAC Manager pod deployment. | `{}` |
| `rbacManager.args` | Add custom arguments to the RBAC Manager pod. | `[]` |
| `rbacManager.deploy` | Deploy the RBAC Manager pod and its required roles. | `true` |
| `rbacManager.leaderElection` | Enable [leader election](https://docs.crossplane.io/latest/concepts/pods/#leader-election) for the RBAC Manager pod. | `true` |
| `rbacManager.managementPolicy` | Defines the Roles and ClusterRoles the RBAC Manager creates and manages. - A policy of `Basic` creates and binds Roles only for the Crossplane ServiceAccount, Provider ServiceAccounts and creates Crossplane ClusterRoles. - A policy of `All` includes all the `Basic` settings and also creates Crossplane Roles in all namespaces. - Read the Crossplane docs for more information on the [RBAC Roles and ClusterRoles](https://docs.crossplane.io/latest/concepts/pods/#crossplane-clusterroles) | `"Basic"` |
| `rbacManager.nodeSelector` | Add `nodeSelectors` to the RBAC Manager pod deployment. | `{}` |
| `rbacManager.replicas` | The number of RBAC Manager pod `replicas` to deploy. | `1` |
| `rbacManager.skipAggregatedClusterRoles` | Don't install aggregated Crossplane ClusterRoles. | `false` |
| `rbacManager.tolerations` | Add `tolerations` to the RBAC Manager pod deployment. | `[]` |
| `registryCaBundleConfig.key` | The ConfigMap key containing a custom CA bundle to enable fetching packages from registries with unknown or untrusted certificates. | `""` |
| `registryCaBundleConfig.name` | The ConfigMap name containing a custom CA bundle to enable fetching packages from registries with unknown or untrusted certificates. | `""` |
| `replicas` | The number of Crossplane pod `replicas` to deploy. | `1` |
| `resourcesCrossplane.limits.cpu` | CPU resource limits for the Crossplane pod. | `"100m"` |
| `resourcesCrossplane.limits.memory` | Memory resource limits for the Crossplane pod. | `"512Mi"` |
| `resourcesCrossplane.requests.cpu` | CPU resource requests for the Crossplane pod. | `"100m"` |
| `resourcesCrossplane.requests.memory` | Memory resource requests for the Crossplane pod. | `"256Mi"` |
| `resourcesRBACManager.limits.cpu` | CPU resource limits for the RBAC Manager pod. | `"100m"` |
| `resourcesRBACManager.limits.memory` | Memory resource limits for the RBAC Manager pod. | `"512Mi"` |
| `resourcesRBACManager.requests.cpu` | CPU resource requests for the RBAC Manager pod. | `"100m"` |
| `resourcesRBACManager.requests.memory` | Memory resource requests for the RBAC Manager pod. | `"256Mi"` |
| `securityContextCrossplane.allowPrivilegeEscalation` | Enable `allowPrivilegeEscalation` for the Crossplane pod. | `false` |
| `securityContextCrossplane.readOnlyRootFilesystem` | Set the Crossplane pod root file system as read-only. | `true` |
| `securityContextCrossplane.runAsGroup` | The group ID used by the Crossplane pod. | `65532` |
| `securityContextCrossplane.runAsUser` | The user ID used by the Crossplane pod. | `65532` |
| `securityContextRBACManager.allowPrivilegeEscalation` | Enable `allowPrivilegeEscalation` for the RBAC Manager pod. | `false` |
| `securityContextRBACManager.readOnlyRootFilesystem` | Set the RBAC Manager pod root file system as read-only. | `true` |
| `securityContextRBACManager.runAsGroup` | The group ID used by the RBAC Manager pod. | `65532` |
| `securityContextRBACManager.runAsUser` | The user ID used by the RBAC Manager pod. | `65532` |
| `serviceAccount.customAnnotations` | Add custom `annotations` to the Crossplane ServiceAccount. | `{}` |
| `tolerations` | Add `tolerations` to the Crossplane pod deployment. | `[]` |
| `webhooks.enabled` | Enable webhooks for Crossplane and installed Provider packages. | `true` |
| `xfn.args` | Add custom arguments to the Composite functions runner container. | `[]` |
| `xfn.cache.configMap` | The name of a ConfigMap to use as the Composite function runner package cache. Disables the default Composite function runner package cache `emptyDir` Volume. | `""` |
| `xfn.cache.medium` | Set to `Memory` to hold the Composite function runner package cache in a RAM-backed file system. Useful for Crossplane development. | `""` |
| `xfn.cache.pvc` | The name of a PersistentVolumeClaim to use as the Composite function runner package cache. Disables the default Composite function runner package cache `emptyDir` Volume. | `""` |
| `xfn.cache.sizeLimit` | The size limit for the Composite function runner package cache. If medium is `Memory` the `sizeLimit` can't exceed Node memory. | `"1Gi"` |
| `xfn.enabled` | Enable the alpha Composition functions (`xfn`) sidecar container. Also requires Crossplane `args` value `--enable-composition-functions` set. | `false` |
| `xfn.extraEnvVars` | Add custom environmental variables to the Composite function runner container. Replaces any `.` in a variable name with `_`. For example, `SAMPLE.KEY=value1` becomes `SAMPLE_KEY=value1`. | `{}` |
| `xfn.image.pullPolicy` | Composite function runner container image pull policy. | `"IfNotPresent"` |
| `xfn.image.repository` | Composite function runner container image. | `"crossplane/xfn"` |
| `xfn.image.tag` | Composite function runner container image tag. Defaults to the value of `appVersion` in Chart.yaml. | `""` |
| `xfn.resources.limits.cpu` | CPU resource limits for the Composite function runner container. | `"2000m"` |
| `xfn.resources.limits.memory` | Memory resource limits for the Composite function runner container. | `"2Gi"` |
| `xfn.resources.requests.cpu` | CPU resource requests for the Composite function runner container. | `"1000m"` |
| `xfn.resources.requests.memory` | Memory resource requests for the Composite function runner container. | `"1Gi"` |
| `xfn.securityContext.allowPrivilegeEscalation` | Enable `allowPrivilegeEscalation` for the Composite function runner container. | `false` |
| `xfn.securityContext.capabilities.add` | Set Linux capabilities for the Composite function runner container. The default values allow the container to create an unprivileged user namespace for running Composite function containers. | `["SETUID","SETGID"]` |
| `xfn.securityContext.readOnlyRootFilesystem` | Set the Composite function runner container root file system as read-only. | `true` |
| `xfn.securityContext.runAsGroup` | The group ID used by the Composite function runner container. | `65532` |
| `xfn.securityContext.runAsUser` | The user ID used by the Composite function runner container. | `65532` |
| `xfn.securityContext.seccompProfile.type` | Apply a `seccompProfile` to the Composite function runner container. The default value allows the Composite function runner container permissions to use the `unshare` syscall. | `"Unconfined"` |
{{< /table >}}
{{< /expand >}}
<!-- vale gitlab.Substitutions = YES -->
#### Command line customization
Apply custom settings at the command line with
`helm install crossplane --set <setting>=<value>`.
For example, to change the image pull policy:
```shell
helm install crossplane \
--namespace crossplane-system \
--create-namespace \
crossplane-stable/crossplane \
--set image.pullPolicy=Always
```
Helm supports comma-seperated arguments.
For example, to change the image pull policy and number of replicas:
```shell
helm install crossplane \
--namespace crossplane-system \
--create-namespace \
crossplane-stable/crossplane \
--set image.pullPolicy=Always,replicas=2
```
#### Helm values file
Apply custom settings in a Helm _values_ file with
`helm install crossplane -f <filename>`.
A YAML file defines the customized settings.
For example, to change the image pull policy and number of replicas:
Create a YAML with the customized settings.
```yaml
replicas: 2
image:
pullPolicy: Always
```
Apply the file with `helm install`:
```shell
helm install crossplane \
--namespace crossplane-system \
--create-namespace \
crossplane-stable/crossplane \
-f settings.yaml
```
#### Feature flags
Crossplane introduces new features behind feature flags. By default
alpha features are off. Crossplane enables beta features by default. To enable a
feature flag, set the `args` value in the Helm chart. Available feature flags
can be directly found by running `crossplane core start --help`, or by looking
at the table below.
{{< expand "Feature flags" >}}
{{< table caption="Feature flags" >}}
| Status | Flag | Description |
| --- | --- | --- |
| Beta | `--enable-composition-revisions` |Enable support for CompositionRevisions |
| Alpha | `--enable-composition-functions` | Enable support for Composition Functions. |
| Alpha | `--enable-composition-webhook-schema-validation` | Enable Composition validation using schemas. |
| Alpha | `--enable-environment-configs` | Enable support for EnvironmentConfigs. |
| Alpha | `--enable-external-secret-stores` | Enable support for External Secret Stores. |
{{< /table >}}
{{< /expand >}}
Set these flags either in the `values.yaml` file or at install time using the
`--set` flag, for example: `--set
args=["--enable-composition-functions","--enable-composition-webhook-schema-validation"]`.
### Install pre-release Crossplane versions
Install a pre-release versions of Crossplane from the `master` Crossplane Helm channel.
Versions in the `master` channel are under active development and may be unstable.
{{< hint "warning" >}}
Don't use Crossplane `master` releases in production. Only use `stable` channel.
Only use `master` for testing and development.
{{< /hint >}}
#### Add the Crossplane master Helm repository
Add the Crossplane repository with the `helm repo add` command.
```shell
helm repo add crossplane-master https://charts.crossplane.io/master/
```
Update the
local Helm chart cache with `helm repo update`.
```shell
helm repo update
```
#### Install the Crossplane master Helm chart
Install the Crossplane `master` Helm chart with `helm install`.
{{< hint "tip" >}}
View the changes Crossplane makes to your cluster with the
`helm install --dry-run --debug` options. Helm shows what configurations it
applies without making changes to the Kubernetes cluster.
{{< /hint >}}
Crossplane creates and installs into the `crossplane-system` namespace.
```shell
helm install crossplane \
--namespace crossplane-system \
--create-namespace crossplane-master/crossplane \
--devel
```
## Crossplane distributions
Third-party vendors may maintain their own Crossplane distributions. Vendor
supported distribution may have features or tooling that isn't in the
Community Crossplane distribution.
The CNCF certified third-party distributions as
"[conformant](https://github.com/cncf/crossplane-conformance)" with the
Community Crossplane distribution.
### Vendors
Below are vendors providing conformant Crossplane distributions.
#### Upbound
Upbound, the founders of Crossplane, maintains a free and open source
distribution of Crossplane called
[Universal Crossplane](https://www.upbound.io/products/universal-crossplane)
(`UXP`).
Find information on UXP in the
[Upbound UXP documentation](https://docs.upbound.io/uxp/install/).

View File

@ -0,0 +1,183 @@
---
title: Uninstall Crossplane
weight: 300
---
{{<hint "warning" >}}
Resources created by Crossplane aren't deleted if Crossplane isn't uninstalled
in order.
This can leave cloud resources running, requiring manual deletion.
{{< /hint >}}
## Ordered Crossplane uninstall
Most Crossplane resources have dependencies on other Crossplane resources.
For example, a _managed resource_ is dependent on the _provider_.
Failure to delete Crossplane resources in order may prevent Crossplane from
deleting provisioned external resources.
Removing Crossplane resources should happen in the following order:
1. Remove all _composite resource definitions_
2. Remove all remaining _managed resources_
3. Remove all _providers_
Deleting the Crossplane pod removes remaining Crossplane components like _claims_.
{{<hint "tip" >}}
Collect an inventory of all external resources with `kubectl get managed`.
Depending on the size of the Kubernetes API server and number of resources, this
command may take minutes to return.
{{<expand "An example kubectl get managed" >}}
```shell {copy-lines="1"}
kubectl get managed
NAME READY SYNCED EXTERNAL-NAME AGE
securitygroup.ec2.aws.upbound.io/my-db-7mc7h-j84h8 True True sg-0da6e9c29113596b6 3m1s
securitygroup.ec2.aws.upbound.io/my-db-8bhr2-9wsx9 True True sg-02695166f010ec05b 2m26s
NAME READY SYNCED EXTERNAL-NAME AGE
route.ec2.aws.upbound.io/my-db-7mc7h-vw985 True True r-rtb-05822b8df433e4e2b1080289494 3m1s
route.ec2.aws.upbound.io/my-db-8bhr2-7m2wq False True 2m26s
NAME READY SYNCED EXTERNAL-NAME AGE
securitygrouprule.ec2.aws.upbound.io/my-db-7mc7h-mkd9s True True sgrule-778063708 3m1s
securitygrouprule.ec2.aws.upbound.io/my-db-8bhr2-lzr89 False True 2m26s
NAME READY SYNCED EXTERNAL-NAME AGE
routetable.ec2.aws.upbound.io/my-db-7mc7h-mnqvm True True rtb-05822b8df433e4e2b 3m1s
routetable.ec2.aws.upbound.io/my-db-8bhr2-dfhj6 True True rtb-02e875abd25658254 2m26s
NAME READY SYNCED EXTERNAL-NAME AGE
subnet.ec2.aws.upbound.io/my-db-7mc7h-7m49d True True subnet-0c1ab32c5ec129dd1 3m2s
subnet.ec2.aws.upbound.io/my-db-7mc7h-9t64t True True subnet-07075c17c7a72f79e 3m2s
subnet.ec2.aws.upbound.io/my-db-7mc7h-rs8t8 True True subnet-08e88e826a42e55b4 3m2s
subnet.ec2.aws.upbound.io/my-db-8bhr2-9sjpx True True subnet-05d21c7b52f7ac8ca 2m26s
subnet.ec2.aws.upbound.io/my-db-8bhr2-dvrxf True True subnet-0432310376b5d09de 2m26s
subnet.ec2.aws.upbound.io/my-db-8bhr2-t7dpr True True subnet-0080fdcb6e9b70632 2m26s
NAME READY SYNCED EXTERNAL-NAME AGE
vpc.ec2.aws.upbound.io/my-db-7mc7h-ktbbh True True vpc-08d7dd84e0c12f33e 3m3s
vpc.ec2.aws.upbound.io/my-db-8bhr2-mrh2x True True vpc-06994bf323fc1daea 2m26s
NAME READY SYNCED EXTERNAL-NAME AGE
internetgateway.ec2.aws.upbound.io/my-db-7mc7h-s2x4v True True igw-0189c4da07a3142dc 3m1s
internetgateway.ec2.aws.upbound.io/my-db-8bhr2-q7dzl True True igw-01bf2a1dbbebf6a27 2m26s
NAME READY SYNCED EXTERNAL-NAME AGE
routetableassociation.ec2.aws.upbound.io/my-db-7mc7h-28qb4 True True rtbassoc-0718d680b5a0e68fe 3m1s
routetableassociation.ec2.aws.upbound.io/my-db-7mc7h-9hdlr True True rtbassoc-0faaedb88c6e1518c 3m1s
routetableassociation.ec2.aws.upbound.io/my-db-7mc7h-txhmz True True rtbassoc-0e5010724ca027864 3m1s
routetableassociation.ec2.aws.upbound.io/my-db-8bhr2-bvgkt False True 2m26s
routetableassociation.ec2.aws.upbound.io/my-db-8bhr2-d9gbg False True 2m26s
routetableassociation.ec2.aws.upbound.io/my-db-8bhr2-k6k8m False True 2m26s
NAME READY SYNCED EXTERNAL-NAME AGE
instance.rds.aws.upbound.io/my-db-7mc7h-5d6w4 False True my-db-7mc7h-5d6w4 3m1s
instance.rds.aws.upbound.io/my-db-8bhr2-tx9kf False True my-db-8bhr2-tx9kf 2m26s
NAME READY SYNCED EXTERNAL-NAME AGE
subnetgroup.rds.aws.upbound.io/my-db-7mc7h-8c8n9 True True my-db-7mc7h-8c8n9 3m2s
subnetgroup.rds.aws.upbound.io/my-db-8bhr2-mc5ps True True my-db-8bhr2-mc5ps 2m27s
NAME READY SYNCED EXTERNAL-NAME AGE
bucket.s3.aws.upbound.io/crossplane-bucket-867737b10 True True
crossplane-bucket-867737b10 5m26s
```
{{</expand >}}
{{< /hint >}}
### Remove composite resource definitions
Removing installed _composite resource definitions_ removes any
_composite resources_ defined by the _composite resource definition_ and the
_managed resourced_ they created.
View the installed _composite resource definitions_ with `kubectl get xrd`.
```shell {copy-lines="1"}
kubectl get xrd
NAME ESTABLISHED OFFERED AGE
compositepostgresqlinstances.database.example.org True True 40s
```
Delete the _composite resource definitions_ with `kubectl delete xrd`.
```shell
kubectl delete xrd compositepostgresqlinstances.database.example.org
```
### Remove managed resources
Manually delete any _managed resources_ manually created.
Use `kubectl get managed` to view remaining _managed resources_.
```shell {copy-lines="1"}
kubectl get managed
NAME READY SYNCED EXTERNAL-NAME AGE
bucket.s3.aws.upbound.io/crossplane-bucket-867737b10 True True crossplane-bucket-867737b10 8h
```
Use `kubectl delete` to remove the resources.
```shell
kubectl delete bucket.s3.aws.upbound.io/crossplane-bucket-867737b10
```
### Remove Crossplane providers
List the installed _providers_ with `kubectl get providers`.
```shell {copy-lines="1"}
kubectl get providers
NAME INSTALLED HEALTHY PACKAGE AGE
upbound-provider-aws True True xpkg.upbound.io/upbound/provider-aws:v0.27.0 8h
```
Remove the installed _providers_ with `kubectl delete provider`.
```shell
kubectl delete provider upbound-provider-aws
```
## Uninstall the Crossplane deployment
Uninstall Crossplane using Helm with `helm uninstall`
```shell
helm uninstall crossplane --namespace crossplane-system
```
Verify Helm removed the Crossplane pods with `kubectl get pods`
```shell
kubectl get pods -n crossplane-system
No resources found in crossplane-system namespace.
```
## Delete the Crossplane namespace
When Helm installs Crossplane it creates the `crossplane-system` namespace. Helm
doesn't uninstall this namespace with `helm uninstall`.
Manually delete the Crossplane namespace with `kubectl delete namespace`.
```shell
kubectl delete namespace crossplane-system
```
Verify Kubernetes removed the namespace with `kubectl get namespaces`
```shell
kubectl get namespace
NAME STATUS AGE
default Active 2m45s
kube-flannel Active 2m42s
kube-node-lease Active 2m47s
kube-public Active 2m47s
kube-system Active 2m47s
```

View File

@ -0,0 +1,7 @@
---
title: Upgrade Crossplane
weight: 200
draft: true
---
Install, Uninstall, Upgrade