mirror of https://github.com/crossplane/docs.git
v1.12 Docs Release (#414)
This commit is contained in:
parent
b203b5dc7d
commit
7864da34b7
|
@ -7,5 +7,6 @@ labels: release
|
||||||
|
|
||||||
- [ ] Update the `/latest` redirect in [netlify.toml](https://github.com/crossplane/docs/blob/master/netlify.toml#L9)
|
- [ ] Update the `/latest` redirect in [netlify.toml](https://github.com/crossplane/docs/blob/master/netlify.toml#L9)
|
||||||
- [ ] Update `params.latest` in [config.yaml](https://github.com/crossplane/docs/blob/master/config.yaml#L48)
|
- [ ] Update `params.latest` in [config.yaml](https://github.com/crossplane/docs/blob/master/config.yaml#L48)
|
||||||
|
- [ ] Update `version` in the `_index.md` file of `/content/<new latest>`
|
||||||
- [ ] Create a [new release/tag](https://github.com/crossplane/docs/releases/new) named "v<EOL version>-archive" to snapshot EOL'd docs.
|
- [ ] Create a [new release/tag](https://github.com/crossplane/docs/releases/new) named "v<EOL version>-archive" to snapshot EOL'd docs.
|
||||||
- [ ] Remove EOL'd docs version from "/content" directory and run `hugo` locally to check for broken links.
|
- [ ] Remove EOL'd docs version from "/content" directory and run `hugo` locally to check for broken links.
|
|
@ -51,7 +51,7 @@ security:
|
||||||
- ^REVIEW_ID
|
- ^REVIEW_ID
|
||||||
|
|
||||||
params:
|
params:
|
||||||
latest: "1.11"
|
latest: "1.12"
|
||||||
upboundLink: "https://www.upbound.io/"
|
upboundLink: "https://www.upbound.io/"
|
||||||
slackLink: "https://slack.crossplane.io/"
|
slackLink: "https://slack.crossplane.io/"
|
||||||
githubLink: "https://github.com/crossplane/crossplane"
|
githubLink: "https://github.com/crossplane/crossplane"
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
---
|
||||||
|
title: "Overview"
|
||||||
|
weight: -1
|
||||||
|
cascade:
|
||||||
|
version: "1.12"
|
||||||
|
---
|
||||||
|
|
||||||
|
{{< 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.
|
|
@ -1,6 +1,7 @@
|
||||||
---
|
---
|
||||||
title: Concepts
|
title: Concepts
|
||||||
weight: 100
|
weight: 100
|
||||||
|
description: Understand Crossplane's core components
|
||||||
---
|
---
|
||||||
|
|
||||||
Crossplane introduces multiple building blocks that enable you to provision,
|
Crossplane introduces multiple building blocks that enable you to provision,
|
|
@ -1,8 +1,245 @@
|
||||||
---
|
---
|
||||||
title: Composition
|
title: Composite Resources
|
||||||
weight: 304
|
weight: 103
|
||||||
---
|
---
|
||||||
|
|
||||||
|
Crossplane Composite Resources are opinionated Kubernetes Custom Resources that
|
||||||
|
are _composed_ of [Managed Resources][managed-resources]. We often call them XRs
|
||||||
|
for short.
|
||||||
|
|
||||||
|
![Diagram of claims, XRs, and Managed Resources][xrs-and-mrs]
|
||||||
|
|
||||||
|
Composite Resources are designed to let you build your own platform with your
|
||||||
|
own opinionated concepts and APIs without needing to write a Kubernetes
|
||||||
|
controller from scratch. Instead, you define the schema of your XR and teach
|
||||||
|
Crossplane which Managed Resources it should compose (i.e. create) when someone
|
||||||
|
creates the XR you defined.
|
||||||
|
|
||||||
|
If you're already familiar with Composite Resources and looking for a detailed
|
||||||
|
configuration reference or some tips, tricks, and troubleshooting information,
|
||||||
|
try the [Composition Reference][xr-ref].
|
||||||
|
|
||||||
|
Below is an example of a Composite Resource:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: database.example.org/v1alpha1
|
||||||
|
kind: XPostgreSQLInstance
|
||||||
|
metadata:
|
||||||
|
name: my-db
|
||||||
|
spec:
|
||||||
|
parameters:
|
||||||
|
storageGB: 20
|
||||||
|
compositionRef:
|
||||||
|
name: production
|
||||||
|
writeConnectionSecretToRef:
|
||||||
|
namespace: crossplane-system
|
||||||
|
name: my-db-connection-details
|
||||||
|
```
|
||||||
|
|
||||||
|
You define your own XRs, so they can be of whatever API version and kind you
|
||||||
|
like, and contain whatever spec and status fields you need.
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
The first step towards using Composite Resources is configuring Crossplane so
|
||||||
|
that it knows what XRs you'd like to exist, and what to do when someone creates
|
||||||
|
one of those XRs. This is done using a `CompositeResourceDefinition` (XRD)
|
||||||
|
resource and one or more `Composition` resources.
|
||||||
|
|
||||||
|
Once you've configured Crossplane with the details of your new XR you can either
|
||||||
|
create one directly, or use a _claim_. Typically only the folks responsible for
|
||||||
|
configuring Crossplane (often a platform or SRE team) have permission to create
|
||||||
|
XRs directly. Everyone else manages XRs via a lightweight proxy resource called
|
||||||
|
a Composite Resource Claim (or claim for short). More on that later.
|
||||||
|
|
||||||
|
![Diagram combining all Composition concepts][how-it-works]
|
||||||
|
|
||||||
|
> If you're coming from the Terraform world you can think of an XRD as similar
|
||||||
|
> to the `variable` blocks of a Terraform module, while the `Composition` is
|
||||||
|
> the rest of the module's HCL code that describes how to use those variables to
|
||||||
|
> create a bunch of resources. In this analogy the XR or claim is a little like
|
||||||
|
> a `tfvars` file providing inputs to the module.
|
||||||
|
|
||||||
|
### Defining Composite Resources
|
||||||
|
|
||||||
|
A `CompositeResourceDefinition` (or XRD) defines the type and schema of your XR.
|
||||||
|
It lets Crossplane know that you want a particular kind of XR to exist, and what
|
||||||
|
fields that XR should have. An XRD is a little like a `CustomResourceDefinition`
|
||||||
|
(CRD), but slightly more opinionated. Writing an XRD is mostly a matter of
|
||||||
|
specifying an OpenAPI ["structural schema"][crd-docs].
|
||||||
|
|
||||||
|
The XRD that defines the `XPostgreSQLInstance` XR above would look like this:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: apiextensions.crossplane.io/v1
|
||||||
|
kind: CompositeResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: xpostgresqlinstances.database.example.org
|
||||||
|
spec:
|
||||||
|
group: database.example.org
|
||||||
|
names:
|
||||||
|
kind: XPostgreSQLInstance
|
||||||
|
plural: xpostgresqlinstances
|
||||||
|
claimNames:
|
||||||
|
kind: PostgreSQLInstance
|
||||||
|
plural: postgresqlinstances
|
||||||
|
versions:
|
||||||
|
- name: v1alpha1
|
||||||
|
served: true
|
||||||
|
referenceable: true
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
spec:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
parameters:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
storageGB:
|
||||||
|
type: integer
|
||||||
|
required:
|
||||||
|
- storageGB
|
||||||
|
required:
|
||||||
|
- parameters
|
||||||
|
```
|
||||||
|
|
||||||
|
You might notice that the `XPostgreSQLInstance` example above has some fields
|
||||||
|
that don't appear in the XRD, like the `writeConnectionSecretToRef` and
|
||||||
|
`compositionRef` fields. This is because Crossplane automatically injects some
|
||||||
|
standard Crossplane Resource Model (XRM) fields into all XRs.
|
||||||
|
|
||||||
|
### Configuring Composition
|
||||||
|
|
||||||
|
A `Composition` lets Crossplane know what to do when someone creates a Composite
|
||||||
|
Resource. Each `Composition` creates a link between an XR and a set of one or
|
||||||
|
more Managed Resources - when the XR is created, updated, or deleted the set of
|
||||||
|
Managed Resources are created, updated or deleted accordingly.
|
||||||
|
|
||||||
|
You can add multiple Compositions for each XRD, and choose which should be used
|
||||||
|
when XRs are created. This allows a Composition to act like a class of service -
|
||||||
|
for example you could configure one Composition for each environment you
|
||||||
|
support, such as production, staging, and development.
|
||||||
|
|
||||||
|
A basic `Composition` for the above `XPostgreSQLInstance` might look like this:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: apiextensions.crossplane.io/v1
|
||||||
|
kind: Composition
|
||||||
|
metadata:
|
||||||
|
name: example
|
||||||
|
labels:
|
||||||
|
crossplane.io/xrd: xpostgresqlinstances.database.example.org
|
||||||
|
provider: gcp
|
||||||
|
spec:
|
||||||
|
writeConnectionSecretsToNamespace: crossplane-system
|
||||||
|
compositeTypeRef:
|
||||||
|
apiVersion: database.example.org/v1alpha1
|
||||||
|
kind: XPostgreSQLInstance
|
||||||
|
resources:
|
||||||
|
- name: cloudsqlinstance
|
||||||
|
base:
|
||||||
|
apiVersion: database.gcp.crossplane.io/v1beta1
|
||||||
|
kind: CloudSQLInstance
|
||||||
|
spec:
|
||||||
|
forProvider:
|
||||||
|
databaseVersion: POSTGRES_12
|
||||||
|
region: us-central1
|
||||||
|
settings:
|
||||||
|
tier: db-custom-1-3840
|
||||||
|
dataDiskType: PD_SSD
|
||||||
|
ipConfiguration:
|
||||||
|
ipv4Enabled: true
|
||||||
|
authorizedNetworks:
|
||||||
|
- value: "0.0.0.0/0"
|
||||||
|
patches:
|
||||||
|
- type: FromCompositeFieldPath
|
||||||
|
fromFieldPath: spec.parameters.storageGB
|
||||||
|
toFieldPath: spec.forProvider.settings.dataDiskSizeGb
|
||||||
|
```
|
||||||
|
|
||||||
|
The above `Composition` tells Crossplane that when someone creates an
|
||||||
|
`XPostgreSQLInstance` XR Crossplane should create a `CloudSQLInstance` in
|
||||||
|
response. The `storageGB` field of the `XPostgreSQLInstance` should be used to
|
||||||
|
configure the `dataDiskSizeGb` field of the `CloudSQLInstance`. This is only a
|
||||||
|
small subset of the functionality a `Composition` enables - take a look at the
|
||||||
|
[reference page][xr-ref] to learn more.
|
||||||
|
|
||||||
|
> We almost always talk about XRs composing Managed Resources, but actually an
|
||||||
|
> XR can also compose other XRs to allow nested layers of abstraction. XRs don't
|
||||||
|
> support composing arbitrary Kubernetes resources (e.g. Deployments, operators,
|
||||||
|
> etc) directly but you can do so using our [Kubernetes][provider-kubernetes]
|
||||||
|
> and [Helm][provider-helm] providers.
|
||||||
|
|
||||||
|
### Claiming Composite Resources
|
||||||
|
|
||||||
|
Crossplane uses Composite Resource Claims (or just claims, for short) to allow
|
||||||
|
application operators to provision and manage XRs. When we talk about using XRs
|
||||||
|
it's typically implied that the XR is being used via a claim. Claims are almost
|
||||||
|
identical to their corresponding XRs. It helps to think of a claim as an
|
||||||
|
application team’s interface to an XR. You could also think of claims as the
|
||||||
|
public (app team) facing part of the opinionated platform API, while XRs are the
|
||||||
|
private (platform team) facing part.
|
||||||
|
|
||||||
|
A claim for the `XPostgreSQLInstance` XR above would look like this:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: database.example.org/v1alpha1
|
||||||
|
kind: PostgreSQLInstance
|
||||||
|
metadata:
|
||||||
|
namespace: default
|
||||||
|
name: my-db
|
||||||
|
spec:
|
||||||
|
parameters:
|
||||||
|
storageGB: 20
|
||||||
|
compositionRef:
|
||||||
|
name: production
|
||||||
|
writeConnectionSecretToRef:
|
||||||
|
name: my-db-connection-details
|
||||||
|
```
|
||||||
|
|
||||||
|
There are three key differences between an XR and a claim:
|
||||||
|
|
||||||
|
1. Claims are namespaced, while XRs (and Managed Resources) are cluster scoped.
|
||||||
|
1. Claims are of a different `kind` than the XR - by convention the XR's `kind`
|
||||||
|
without the proceeding `X`. For example a `PostgreSQLInstance` claims an
|
||||||
|
`XPostgreSQLInstance`.
|
||||||
|
1. An active claim contains a reference to its corresponding XR, while an XR
|
||||||
|
contains both a reference to the claim an array of references to the managed
|
||||||
|
resources it composes.
|
||||||
|
|
||||||
|
Not all XRs offer a claim - doing so is optional. See the XRD section of the
|
||||||
|
[Composition reference][xr-ref] to learn how to offer a claim.
|
||||||
|
|
||||||
|
![Diagram showing the relationship between claims and XRs][claims-and-xrs]
|
||||||
|
|
||||||
|
Claims may seem a little superfluous at first, but they enable some handy
|
||||||
|
scenarios, including:
|
||||||
|
|
||||||
|
- **Private XRs.** Sometimes a platform team might not want a type of XR to be
|
||||||
|
directly consumed by their application teams. For example because the XR
|
||||||
|
represents 'supporting' infrastructure - consider the above VPC `XNetwork` XR. App
|
||||||
|
teams might create `PostgreSQLInstance` claims that _reference_ (i.e. consume)
|
||||||
|
an `XNetwork`, but they shouldn't be _creating their own_. Similarly, some
|
||||||
|
kinds of XR might be intended only for 'nested' use - intended only to be
|
||||||
|
composed by other XRs.
|
||||||
|
|
||||||
|
- **Global XRs**. Not all infrastructure is conceptually namespaced. Say your
|
||||||
|
organisation uses team scoped namespaces. A `PostgreSQLInstance` that belongs
|
||||||
|
to Team A should probably be part of the `team-a` namespace - you'd represent
|
||||||
|
this by creating a `PostgreSQLInstance` claim in that namespace. On the other
|
||||||
|
hand the `XNetwork` XR we mentioned previously could be referenced (i.e. used)
|
||||||
|
by XRs from many different namespaces - it doesn't exist to serve a particular
|
||||||
|
team.
|
||||||
|
|
||||||
|
- **Pre-provisioned XRs**. Finally, separating claims from XRs allows a platform
|
||||||
|
team to pre-provision certain kinds of XR. Typically an XR is created
|
||||||
|
on-demand in response to the creation of a claim, but it's also possible for a
|
||||||
|
claim to instead request an existing XR. This can allow application teams to
|
||||||
|
instantly claim infrastructure like database instances that would otherwise
|
||||||
|
take minutes to provision on-demand.
|
||||||
|
|
||||||
|
|
||||||
This reference provides detailed examples of defining, configuring, and using
|
This reference provides detailed examples of defining, configuring, and using
|
||||||
Composite Resources in Crossplane. You can also refer to Crossplane's [API
|
Composite Resources in Crossplane. You can also refer to Crossplane's [API
|
||||||
|
@ -37,6 +274,17 @@ spec:
|
||||||
apiVersion: database.example.org/v1alpha1
|
apiVersion: database.example.org/v1alpha1
|
||||||
kind: PostgreSQLInstance
|
kind: PostgreSQLInstance
|
||||||
name: my-db
|
name: my-db
|
||||||
|
# The compositeDeletePolicy specifies the propagation policy that will be used by Crossplane
|
||||||
|
# when deleting the Composite Resource that is associated with the Claim. The default
|
||||||
|
# value is Background, which causes the Composite resource to be deleted using
|
||||||
|
# the kubernetes default propagation policy of Background, and all associated
|
||||||
|
# resources will be deleted simultaneously. The other value for this field is Foreground,
|
||||||
|
# which will cause the Composite resource to be deleted using Foreground Cascading Deletion.
|
||||||
|
# Kubernetes will add a foregroundDeletion finalizer to all of the resources in the
|
||||||
|
# dependency graph, and they will be deleted starting with the edge or leaf nodes and
|
||||||
|
# working back towards the root Composite. See https://kubernetes.io/docs/concepts/architecture/garbage-collection/#cascading-deletion
|
||||||
|
# for more information on cascading deletion.
|
||||||
|
compositeDeletePolicy: Background
|
||||||
# The compositionRef specifies which Composition this XR will use to compose
|
# The compositionRef specifies which Composition this XR will use to compose
|
||||||
# resources when it is created, updated, or deleted. This can be omitted and
|
# resources when it is created, updated, or deleted. This can be omitted and
|
||||||
# will be set automatically if the XRD has a default or enforced composition
|
# will be set automatically if the XRD has a default or enforced composition
|
||||||
|
@ -51,6 +299,27 @@ spec:
|
||||||
environment: production
|
environment: production
|
||||||
region: us-east
|
region: us-east
|
||||||
provider: gcp
|
provider: gcp
|
||||||
|
# The environment is an in-memory object that can be patched from / to during
|
||||||
|
# rendering.
|
||||||
|
# The environment is composed by merging the 'data' of all EnvironmentConfigs
|
||||||
|
# referenced below. It is disposed after every reconcile.
|
||||||
|
# NOTE: EnvironmentConfigs are an alpha feature and need to be enabled with
|
||||||
|
# the '--enable-environment-configs' flag on startup.
|
||||||
|
environment:
|
||||||
|
# EnvironmentConfigs is a list of object references that is made up of
|
||||||
|
# name references and label selectors
|
||||||
|
environmentConfigs:
|
||||||
|
- type: Reference # this is the default
|
||||||
|
ref:
|
||||||
|
name: example-environment
|
||||||
|
- type: Selector
|
||||||
|
selector:
|
||||||
|
- key: stage
|
||||||
|
type: FromCompositeFieldPath # this is the default
|
||||||
|
valueFromFieldPath: spec.parameters.stage
|
||||||
|
- key: provider
|
||||||
|
type: Value
|
||||||
|
value: "gcp"
|
||||||
# The resourceRefs array contains references to all of the resources of which
|
# The resourceRefs array contains references to all of the resources of which
|
||||||
# this XR is composed. Despite being in spec this field isn't intended to be
|
# this XR is composed. Despite being in spec this field isn't intended to be
|
||||||
# configured by humans - Crossplane will take care of keeping it updated.
|
# configured by humans - Crossplane will take care of keeping it updated.
|
||||||
|
@ -167,12 +436,21 @@ spec:
|
||||||
# be written to the connection secret of the XR.
|
# be written to the connection secret of the XR.
|
||||||
connectionSecretKeys:
|
connectionSecretKeys:
|
||||||
- hostname
|
- hostname
|
||||||
|
# Each type of XR may specify a default Composite Delete Policy to be used
|
||||||
|
# when the Claim has no compositeDeletePolicy. The valid values are Background
|
||||||
|
# and Foreground, and the default is Background. See the description of the
|
||||||
|
# compositeDeletePolicy parameter for more information.
|
||||||
|
defaultCompositeDeletePolicy: Background
|
||||||
# Each type of XR may specify a default Composition to be used when none is
|
# Each type of XR may specify a default Composition to be used when none is
|
||||||
# specified (e.g. when the XR has no compositionRef or selector). A similar
|
# specified (e.g. when the XR has no compositionRef or selector). A similar
|
||||||
# enforceCompositionRef field also exists to allow XRs to enforce a specific
|
# enforceCompositionRef field also exists to allow XRs to enforce a specific
|
||||||
# Composition that should always be used.
|
# Composition that should always be used.
|
||||||
defaultCompositionRef:
|
defaultCompositionRef:
|
||||||
name: example
|
name: example
|
||||||
|
# Each type of XR may specify a default Composition Update Policy to be used
|
||||||
|
# when the Claim has no compositionUpdatePolicy. The valid values are Automatic
|
||||||
|
# and Manual and the default is Automatic.
|
||||||
|
defaultCompositionUpdatePolicy: Automatic
|
||||||
# Each type of XR may be served at different versions - e.g. v1alpha1, v1beta1
|
# Each type of XR may be served at different versions - e.g. v1alpha1, v1beta1
|
||||||
# and v1 - simultaneously. Currently Crossplane requires that all versions
|
# and v1 - simultaneously. Currently Crossplane requires that all versions
|
||||||
# have an identical schema, so this is mostly useful to 'promote' a type of XR
|
# have an identical schema, so this is mostly useful to 'promote' a type of XR
|
||||||
|
@ -373,6 +651,45 @@ spec:
|
||||||
fromFieldPath: metadata.labels[some-important-label]
|
fromFieldPath: metadata.labels[some-important-label]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Pause Annotation
|
||||||
|
There is an annotation named `crossplane.io/paused` that you can use on
|
||||||
|
Composite Resources and Composite Resource Claims to temporarily pause
|
||||||
|
reconciliations of their respective controllers on them. An example
|
||||||
|
for a Composite Resource Claim is as follows:
|
||||||
|
```yaml
|
||||||
|
apiVersion: test.com/v1alpha1
|
||||||
|
kind: MyResource
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
crossplane.io/paused: "true"
|
||||||
|
namespace: upbound-system
|
||||||
|
name: my-resource
|
||||||
|
spec:
|
||||||
|
parameters:
|
||||||
|
tagValue: demo-test
|
||||||
|
compositionRef:
|
||||||
|
name: example
|
||||||
|
```
|
||||||
|
where `MyResource` is a Composite Resource Claim kind.
|
||||||
|
When a Composite Resource or a Claim has the `crossplane.io/paused` annotation
|
||||||
|
with its value set to `true`, the Composite Resource controller or the Claim
|
||||||
|
controller pauses reconciliations on the resource until
|
||||||
|
the annotation is removed or its value set to something other than `true`.
|
||||||
|
Before temporarily pausing reconciliations, an event with the type `Synced`,
|
||||||
|
the status `False`, and the reason `ReconcilePaused` is emitted
|
||||||
|
on the resource.
|
||||||
|
Please also note that annotations on a Composite Resource Claim are propagated
|
||||||
|
to the associated Composite Resource but when the
|
||||||
|
`crossplane.io/paused: "true"` annotation is added to a Claim, because
|
||||||
|
reconciliations on the Claim are now paused, this newly added annotation
|
||||||
|
will not be propagated. However, whenever the annotation's value is set to a
|
||||||
|
non-`true` value, reconciliations on the Claim will now resume, and thus the
|
||||||
|
annotation will now be propagated to the associated Composite Resource
|
||||||
|
with a non-`true` value. An implication of the described behavior is that
|
||||||
|
pausing reconciliations on the Claim will not inherently pause reconciliations
|
||||||
|
on the associated Composite Resource.
|
||||||
|
|
||||||
|
|
||||||
### Patch Types
|
### Patch Types
|
||||||
|
|
||||||
You can use the following types of patch in a `Composition`:
|
You can use the following types of patch in a `Composition`:
|
||||||
|
@ -428,6 +745,35 @@ resources:
|
||||||
toFieldPath: spec.forProvider.firewallRules[*].CIDRBlock
|
toFieldPath: spec.forProvider.firewallRules[*].CIDRBlock
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`FromEnvironmentFieldPath`. This type patches from a field within the in-memory
|
||||||
|
environment to a field within the composed resource. It's commonly used to
|
||||||
|
expose a composed resource spec field as an XR spec field.
|
||||||
|
Note that EnvironmentConfigs are an alpha feature and need to be enabled with
|
||||||
|
the `--enable-environment-configs` flag on startup.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Patch from the environment's tier.name field to the composed resource's
|
||||||
|
# spec.forProvider.settings.tier field.
|
||||||
|
- type: FromEnvironmentFieldPath
|
||||||
|
fromFieldPath: tier.name
|
||||||
|
toF/ieldPath: spec.forProvider.settings.tier
|
||||||
|
```
|
||||||
|
|
||||||
|
`ToEnvironmentFieldPath`. This type patches from a composed field to the
|
||||||
|
in-memory environment. Note that, unlike `ToCompositeFieldPath` patches, this
|
||||||
|
is executed before the composed resource is applied on the cluster which means
|
||||||
|
that the `status` is not available.
|
||||||
|
Note that EnvironmentConfigs are an alpha feature and need to be enabled with
|
||||||
|
the `--enable-environment-configs` flag on startup.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Patch from the environment's tier.name field to the composed resource's
|
||||||
|
# spec.forProvider.settings.tier field.
|
||||||
|
- type: ToEnvironmentFieldPath
|
||||||
|
fromFieldPath: spec.forProvider.settings.tier
|
||||||
|
toFieldPath: tier.name
|
||||||
|
```
|
||||||
|
|
||||||
Note that the field to be patched requires some initial value to be set.
|
Note that the field to be patched requires some initial value to be set.
|
||||||
|
|
||||||
`CombineFromComposite`. Combines multiple fields from the XR to produce one
|
`CombineFromComposite`. Combines multiple fields from the XR to produce one
|
||||||
|
@ -454,6 +800,26 @@ composed resource field.
|
||||||
fromFieldPath: Required
|
fromFieldPath: Required
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`CombineFromEnvironment`. Combines multiple fields from the in-memory
|
||||||
|
environment to produce one composed resource field.
|
||||||
|
Note that EnvironmentConfigs are an alpha feature and need to be enabled with
|
||||||
|
the `--enable-environment-configs` flag on startup.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Patch from the environments's location field and region to the composed
|
||||||
|
# resource's spec.forProvider.administratorLogin field.
|
||||||
|
- type: CombineFromEnvironment
|
||||||
|
combine:
|
||||||
|
# The patch will only be applied when all variables have non-zero values.
|
||||||
|
variables:
|
||||||
|
- fromFieldPath: location
|
||||||
|
- fromFieldPath: region
|
||||||
|
strategy: string
|
||||||
|
string:
|
||||||
|
fmt: "%s-%s"
|
||||||
|
toFieldPath: spec.forProvider.administratorLogin
|
||||||
|
```
|
||||||
|
|
||||||
At the time of writing only the `string` combine strategy is supported. It uses
|
At the time of writing only the `string` combine strategy is supported. It uses
|
||||||
[Go string formatting][pkg/fmt] to combine values, so if the XR's location was
|
[Go string formatting][pkg/fmt] to combine values, so if the XR's location was
|
||||||
`us-west` and its claim name was `db` the composed resource's administratorLogin
|
`us-west` and its claim name was `db` the composed resource's administratorLogin
|
||||||
|
@ -478,6 +844,26 @@ would be set to `us-west-db`.
|
||||||
toFieldPath: status.adminDSN
|
toFieldPath: status.adminDSN
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`CombineToEnvironment` is the inverse of `CombineFromEnvironment`.
|
||||||
|
Note that EnvironmentConfigs are an alpha feature and need to be enabled with
|
||||||
|
the `--enable-environment-configs` flag on startup.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Patch from the composed resource's spec.parameters.administratorLogin and
|
||||||
|
# spec.forProvider.domainName fields back to the environment's adminDSN field.
|
||||||
|
- type: CombineToEnvironment
|
||||||
|
combine:
|
||||||
|
variables:
|
||||||
|
- fromFieldPath: spec.parameters.administratorLogin
|
||||||
|
- fromFieldPath: spec.forProvider.domainName
|
||||||
|
strategy: string
|
||||||
|
# Here, our administratorLogin parameter and fullyQualifiedDomainName
|
||||||
|
# status are formatted to a single output string representing a DSN.
|
||||||
|
string:
|
||||||
|
fmt: "mysql://%s@%s:3306/my-database-name"
|
||||||
|
toFieldPath: adminDSN
|
||||||
|
```
|
||||||
|
|
||||||
`PatchSet`. References a named set of patches defined in the `spec.patchSets`
|
`PatchSet`. References a named set of patches defined in the `spec.patchSets`
|
||||||
array of a `Composition`.
|
array of a `Composition`.
|
||||||
|
|
||||||
|
@ -507,20 +893,88 @@ You can use the following types of transform on a value being patched:
|
||||||
au-east: Australia East
|
au-east: Australia East
|
||||||
```
|
```
|
||||||
|
|
||||||
`math`. Transforms values using math. The input value must be an integer.
|
`match`. A more complex version of `map` that can match different kinds of
|
||||||
Currently only `multiply` is supported.
|
patterns. It should be used if more advanced pattern matchings than a simple
|
||||||
|
string equality check are required.
|
||||||
|
The result of the first matching pattern is used as the output of this
|
||||||
|
transform.
|
||||||
|
If no pattern matches, you can either fallback to a given `fallbackValue` or
|
||||||
|
fallback to the input value by setting the `fallbackTo` field to `Input`.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
|
# In the example below, if the value in the 'from' field is 'us-west', the
|
||||||
|
# value in the 'to' field will be set to 'West US'.
|
||||||
|
# If the value in the 'from' field is 'eu-west', the value in the 'to' field
|
||||||
|
# will be set to 'Unknown' because no pattern matches.
|
||||||
|
- type: match
|
||||||
|
match:
|
||||||
|
patterns:
|
||||||
|
- type: literal # Not needed. This is the default.
|
||||||
|
literal: us-west
|
||||||
|
result: West US
|
||||||
|
- type: regexp
|
||||||
|
regexp: '^af-.*'
|
||||||
|
result: Somewhere in Africa
|
||||||
|
fallbackTo: Value # Not needed. This is the default.
|
||||||
|
fallbackValue: Unknown
|
||||||
|
|
||||||
|
# If fallbackTo is set to Input, the output will be the input value if no
|
||||||
|
# pattern matches.
|
||||||
|
# In the example below, if the value in the 'from' field is 'us-west', the
|
||||||
|
# value in the 'to' field will be set to 'West US'.
|
||||||
|
# If the value in the 'from' field is 'eu-west', the value in the 'to' field
|
||||||
|
# will be set to 'eu-west' because no pattern matches.
|
||||||
|
- type: match
|
||||||
|
match:
|
||||||
|
patterns:
|
||||||
|
- type: literal
|
||||||
|
literal: us-west
|
||||||
|
result: West US
|
||||||
|
- type: regexp
|
||||||
|
regexp: '^af-.*'
|
||||||
|
result: Somewhere in Africa
|
||||||
|
fallbackTo: Input
|
||||||
|
```
|
||||||
|
|
||||||
|
`math`. Transforms values using math. The input value must be an integer.
|
||||||
|
* math transform type `Multiply`, multiplies the input by the given value.
|
||||||
|
* math transform type `ClampMin`, sets a minimum value for the output.
|
||||||
|
* math transform type `ClampMax`, sets a maximum value for the output.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# If you omit the field type, by default type is set to `Multiply`
|
||||||
# If the value of the 'from' field is 2, the value of the 'to' field will be set
|
# If the value of the 'from' field is 2, the value of the 'to' field will be set
|
||||||
# to 4.
|
# to 4.
|
||||||
- type: math
|
- type: math
|
||||||
math:
|
math:
|
||||||
multiply: 2
|
multiply: 2
|
||||||
|
|
||||||
|
# This is the same as above
|
||||||
|
# If the value of the 'from' field is 2, the value of the 'to' field will be set
|
||||||
|
# to 4.
|
||||||
|
- type: math
|
||||||
|
math:
|
||||||
|
type: Multiply
|
||||||
|
multiply: 2
|
||||||
|
|
||||||
|
# If the value of the 'from' field is 3, the value of the 'to' field will
|
||||||
|
# be set to 4.
|
||||||
|
- type: math
|
||||||
|
math:
|
||||||
|
type: ClampMin
|
||||||
|
clampMin: 4
|
||||||
|
|
||||||
|
# If the value of the 'from' field is 3, the value of the 'to' field will
|
||||||
|
# be set to 2.
|
||||||
|
- type: math
|
||||||
|
math:
|
||||||
|
type: ClampMax
|
||||||
|
clampMax: 2
|
||||||
```
|
```
|
||||||
|
|
||||||
`string`. Transforms string values.
|
`string`. Transforms string values.
|
||||||
* string transform type `Format`, Currently only Go style fmt is supported. [Go style `fmt`][pkg/fmt] is supported.
|
* string transform type `Format`, Currently only Go style fmt is supported. [Go style `fmt`][pkg/fmt] is supported.
|
||||||
* string transform type `Convert`, accepts one of `ToUpper`, `ToLower`, `ToBase64`, `FromBase64`.
|
* string transform type `Convert`, accepts one of `ToUpper`, `ToLower`, `ToBase64`, `FromBase64`, `ToJson`, `ToSha1`, `ToSha256`, `ToSha512`.
|
||||||
* string transform type `TrimPrefix`, accepts a string to be trimmed from the beginning of the input.
|
* string transform type `TrimPrefix`, accepts a string to be trimmed from the beginning of the input.
|
||||||
* string transform type `TrimSuffix`, accepts a string to be trimmed from the end of the input.
|
* string transform type `TrimSuffix`, accepts a string to be trimmed from the end of the input.
|
||||||
* string transform type `Regexp`, accepts a string for regexp to be applied to.
|
* string transform type `Regexp`, accepts a string for regexp to be applied to.
|
||||||
|
@ -568,6 +1022,19 @@ Currently only `multiply` is supported.
|
||||||
type: Convert
|
type: Convert
|
||||||
convert: FromBase64
|
convert: FromBase64
|
||||||
|
|
||||||
|
# If the value of the 'from' field is not nil, the value of the 'to' field will be
|
||||||
|
# set to raw JSON representation of the 'from' field.
|
||||||
|
- type: string
|
||||||
|
string:
|
||||||
|
type: Convert
|
||||||
|
convert: ToJson
|
||||||
|
|
||||||
|
# The output will be the hash of the JSON representation of the 'from' field.
|
||||||
|
- type: string
|
||||||
|
string:
|
||||||
|
type: Convert
|
||||||
|
convert: ToSha1 # alternatives: 'ToSha256' or 'ToSha512'
|
||||||
|
|
||||||
# If the value of the 'from' field is https://crossplane.io, the value of the 'to' field will
|
# If the value of the 'from' field is https://crossplane.io, the value of the 'to' field will
|
||||||
# be set to crossplane.io
|
# be set to crossplane.io
|
||||||
- type: string
|
- type: string
|
||||||
|
@ -614,6 +1081,17 @@ true converts to integer 1 and float 1.0, while false converts to 0 and 0.0.
|
||||||
toType: int
|
toType: int
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Converting `string` to `float64` additionally supports parsing string in
|
||||||
|
[K8s quantity format](https://pkg.go.dev/k8s.io/apimachinery/pkg/api/resource#Quantity),
|
||||||
|
such as `1000m` or `500 Mi`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- type: convert
|
||||||
|
convert:
|
||||||
|
toType: float64
|
||||||
|
format: quantity
|
||||||
|
```
|
||||||
|
|
||||||
### Connection Details
|
### Connection Details
|
||||||
|
|
||||||
Connection details secret of XR is an aggregated sum of the connection details
|
Connection details secret of XR is an aggregated sum of the connection details
|
||||||
|
@ -706,6 +1184,38 @@ not considered to be 'empty', and thus will pass the readiness check.
|
||||||
|
|
||||||
`None`. Considers the composed resource to be ready as soon as it exists.
|
`None`. Considers the composed resource to be ready as soon as it exists.
|
||||||
|
|
||||||
|
### Composition validation
|
||||||
|
|
||||||
|
Crossplane uses a `Validating Webhook` to inform users of any potential
|
||||||
|
errors in a `Composition`. By default webhooks only perform
|
||||||
|
`logical checks`. `logical checks` enforce requirements that
|
||||||
|
aren't explicitly defined in the schema but Crossplane assumes to hold at runtime.
|
||||||
|
|
||||||
|
#### Experimental validation with schemas
|
||||||
|
|
||||||
|
Enable experimental schema-aware validation in Crossplane
|
||||||
|
through the `--enable-composition-webhook-schema-validation` feature flag. This
|
||||||
|
enables Composition validation against available schemas in the cluster.
|
||||||
|
For example, ensuring that `fieldPaths` are valid and source and destination
|
||||||
|
types match taking into account provided transforms too.
|
||||||
|
|
||||||
|
The `crossplane.io/composition-validation-mode` annotation on the Composition
|
||||||
|
allows setting one of two modes for schema validation:
|
||||||
|
|
||||||
|
- `loose` (default): Validates Compositions against required schemas. If a
|
||||||
|
required schema is missing, schema validation stops, emits a warning and
|
||||||
|
falls back to `logical checks` only.
|
||||||
|
- `strict`: Validates Compositions against required schemas, and rejects them
|
||||||
|
when finding errors. Rejects any Compositions missing required schemas.
|
||||||
|
|
||||||
|
See the [Composition Validating Webhook design document][validation-design-doc]
|
||||||
|
for more information about future development around schema-aware validation.
|
||||||
|
|
||||||
|
#### Disabling webhooks
|
||||||
|
|
||||||
|
Crossplane enables webhooks by default. Turn off webhooks by
|
||||||
|
`webhooks.enabled` to `false` in the provided Helm Chart.
|
||||||
|
|
||||||
### Missing Functionality
|
### Missing Functionality
|
||||||
|
|
||||||
You might find while reading through this reference that Crossplane is missing
|
You might find while reading through this reference that Crossplane is missing
|
||||||
|
@ -716,7 +1226,7 @@ understand that the Crossplane maintainers are growing the feature set of the
|
||||||
community, but we also feel it's critical to avoid bloat and complexity. We
|
community, but we also feel it's critical to avoid bloat and complexity. We
|
||||||
therefore wish to carefully consider each new addition. We feel some features
|
therefore wish to carefully consider each new addition. We feel some features
|
||||||
may be better suited for a real, expressive programming language and intend to
|
may be better suited for a real, expressive programming language and intend to
|
||||||
build an alternative to the `Composition` type as it is documented here per
|
build an alternative to the `Composition` type as it's documented here per
|
||||||
[this proposal][issue-2524].
|
[this proposal][issue-2524].
|
||||||
|
|
||||||
## Tips, Tricks, and Troubleshooting
|
## Tips, Tricks, and Troubleshooting
|
||||||
|
@ -826,14 +1336,19 @@ so:
|
||||||
1. Use a `FromCompositeFieldPath` patch to patch from the 'intermediary' field
|
1. Use a `FromCompositeFieldPath` patch to patch from the 'intermediary' field
|
||||||
you patched to in step 1 to a field on the destination composed resource.
|
you patched to in step 1 to a field on the destination composed resource.
|
||||||
|
|
||||||
[api-docs]: {{<ref "../api-docs/crossplane" >}}
|
|
||||||
[xr-concepts]: {{<ref "../concepts/composition" >}}
|
|
||||||
[crd-docs]: https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/
|
[crd-docs]: https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/
|
||||||
[raise an issue]: https://github.com/crossplane/crossplane/issues/new?assignees=&labels=enhancement&template=feature_request.md
|
[raise an issue]: https://github.com/crossplane/crossplane/issues/new?assignees=&labels=enhancement&template=feature_request.md
|
||||||
[issue-2524]: https://github.com/crossplane/crossplane/issues/2524
|
[issue-2524]: https://github.com/crossplane/crossplane/issues/2524
|
||||||
[field-paths]: https://github.com/kubernetes/community/blob/61f3d0/contributors/devel/sig-architecture/api-conventions.md#selecting-fields
|
[field-paths]: https://github.com/kubernetes/community/blob/61f3d0/contributors/devel/sig-architecture/api-conventions.md#selecting-fields
|
||||||
[pkg/fmt]: https://pkg.go.dev/fmt
|
[pkg/fmt]: https://pkg.go.dev/fmt
|
||||||
[trouble-ref]: {{<ref "troubleshoot" >}}
|
|
||||||
[upbound-marketplace]: https://marketplace.upbound.io
|
[upbound-marketplace]: https://marketplace.upbound.io
|
||||||
[helm-and-gcp]: https://github.com/crossplane-contrib/provider-helm/blob/2dcbdd0/examples/in-composition/composition.yaml
|
[helm-and-gcp]: https://github.com/crossplane-contrib/provider-helm/blob/2dcbdd0/examples/in-composition/composition.yaml
|
||||||
[issue-2024]: https://github.com/crossplane/crossplane/issues/2024
|
[issue-2024]: https://github.com/crossplane/crossplane/issues/2024
|
||||||
|
[xrs-and-mrs]: /media/composition-xrs-and-mrs.svg
|
||||||
|
[how-it-works]: /media/composition-how-it-works.svg
|
||||||
|
[provider-kubernetes]: https://marketplace.upbound.io/providers/crossplane-contrib/provider-kubernetes
|
||||||
|
[provider-helm]: https://marketplace.upbound.io/providers/crossplane-contrib/provider-helm/
|
||||||
|
[claims-and-xrs]: /media/composition-claims-and-xrs.svg
|
||||||
|
[xr-ref]: {{<ref "#compositions" >}}
|
||||||
|
[managed-resources]: {{<ref "managed-resources" >}}
|
||||||
|
[validation-design-doc]: https://github.com/crossplane/crossplane/blob/master/design/design-doc-composition-validating-webhook.md
|
|
@ -5,20 +5,19 @@ weight: 102
|
||||||
|
|
||||||
A Managed Resource (MR) is Crossplane's representation of a resource in an
|
A Managed Resource (MR) is Crossplane's representation of a resource in an
|
||||||
external system - most commonly a cloud provider. Managed Resources are
|
external system - most commonly a cloud provider. Managed Resources are
|
||||||
opinionated, Crossplane Resource Model ([XRM][term-xrm]) compliant Kubernetes
|
opinionated, Crossplane Resource Model ([XRM]({{<ref "../concepts/terminology">}})) compliant Kubernetes
|
||||||
Custom Resources that are installed by a Crossplane [provider].
|
Custom Resources that are installed by a Crossplane [provider]({{<ref "providers" >}}).
|
||||||
|
|
||||||
For example, `RDSInstance` in the AWS Provider corresponds to an actual RDS
|
For example, `RDSInstance` in the AWS Provider corresponds to an actual RDS
|
||||||
Instance in AWS. There is a one-to-one relationship and the changes on managed
|
Instance in AWS. There is a one-to-one relationship and the changes on managed
|
||||||
resources are reflected directly on the corresponding resource in the provider.
|
resources are reflected directly on the corresponding resource in the provider.
|
||||||
Similarly, the `Database` types in the SQL provider represent a PostgreSQL or
|
Similarly, the `Database` types in the SQL provider represent a PostgreSQL or
|
||||||
MySQL database. You can browse [API Reference][api-reference] to discover all
|
MySQL database.
|
||||||
available managed resources.
|
|
||||||
|
|
||||||
Managed Resources are the building blocks of Crossplane. They're designed to be
|
Managed Resources are the building blocks of Crossplane. They're designed to be
|
||||||
_composed_ into higher level, opinionated Custom Resources that Crossplane calls
|
_composed_ into higher level, opinionated Custom Resources that Crossplane calls
|
||||||
Composite Resources or XRs - not used directly. See the
|
Composite Resources or XRs - not used directly. See the
|
||||||
[Composition][composition] documentation for more information.
|
[Composition]({{<ref "composition" >}}) documentation for more information.
|
||||||
|
|
||||||
## Syntax
|
## Syntax
|
||||||
|
|
||||||
|
@ -51,7 +50,7 @@ spec:
|
||||||
```
|
```
|
||||||
|
|
||||||
```console
|
```console
|
||||||
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-1.9/docs/snippets/provision/aws.yaml
|
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-1.10/docs/snippets/provision/aws.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
Creating the above instance will cause Crossplane to provision an RDS instance
|
Creating the above instance will cause Crossplane to provision an RDS instance
|
||||||
|
@ -100,7 +99,7 @@ spec:
|
||||||
```
|
```
|
||||||
|
|
||||||
```console
|
```console
|
||||||
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-1.9/docs/snippets/provision/gcp.yaml
|
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-1.10/docs/snippets/provision/gcp.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
Creating the above instance will cause Crossplane to provision a CloudSQL
|
Creating the above instance will cause Crossplane to provision a CloudSQL
|
||||||
|
@ -167,7 +166,7 @@ spec:
|
||||||
```
|
```
|
||||||
|
|
||||||
```console
|
```console
|
||||||
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-1.9/docs/snippets/provision/azure.yaml
|
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-1.10/docs/snippets/provision/azure.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
Creating the above instance will cause Crossplane to provision a PostgreSQL
|
Creating the above instance will cause Crossplane to provision a PostgreSQL
|
||||||
|
@ -304,6 +303,25 @@ never deletes the external resource in the provider.
|
||||||
> means Crossplane will allow immutable fields to be changed, but will not
|
> means Crossplane will allow immutable fields to be changed, but will not
|
||||||
> actually make the desired change. This is tracked in [this issue][issue-727].
|
> actually make the desired change. This is tracked in [this issue][issue-727].
|
||||||
|
|
||||||
|
#### Pausing Reconciliations
|
||||||
|
If a managed resource being reconciled by the [managed reconciler], has the
|
||||||
|
`crossplane.io/paused` annotation with its value set to `true` as in the
|
||||||
|
following example, then further reconciliations are paused on that resource
|
||||||
|
after emitting an event with the type `Synced`, the status `False`,
|
||||||
|
and the reason `ReconcilePaused`:
|
||||||
|
```yaml
|
||||||
|
apiVersion: ec2.aws.upbound.io/v1beta1
|
||||||
|
kind: VPC
|
||||||
|
metadata:
|
||||||
|
name: paused-vpc
|
||||||
|
annotations:
|
||||||
|
crossplane.io/paused: "true"
|
||||||
|
...
|
||||||
|
```
|
||||||
|
Reconciliations on the managed resource will resume once the
|
||||||
|
`crossplane.io/paused` annotation is removed or its value is set
|
||||||
|
to anything other than `true`.
|
||||||
|
|
||||||
### External Name
|
### External Name
|
||||||
|
|
||||||
By default the name of the managed resource is used as the name of the external
|
By default the name of the managed resource is used as the name of the external
|
||||||
|
@ -429,8 +447,7 @@ the values that are fetched from the provider.
|
||||||
|
|
||||||
Note that if a resource has required fields, you must fill those fields or the
|
Note that if a resource has required fields, you must fill those fields or the
|
||||||
creation of the managed resource will be rejected. So, in those cases, you will
|
creation of the managed resource will be rejected. So, in those cases, you will
|
||||||
need to enter the name of the resource as well as the required fields as
|
need to enter the name of the resource as well as the required fields.
|
||||||
indicated in the [API Reference][api-reference] documentation.
|
|
||||||
|
|
||||||
## Backup and Restore
|
## Backup and Restore
|
||||||
|
|
||||||
|
@ -445,14 +462,11 @@ fields are there and those are enough to import a resource. The tool you're
|
||||||
using needs to store `annotations` and `spec` fields, which most tools do
|
using needs to store `annotations` and `spec` fields, which most tools do
|
||||||
including Velero.
|
including Velero.
|
||||||
|
|
||||||
[term-xrm]: {{<ref "terminology" >}}#crossplane-resource-model
|
|
||||||
[rds]: https://aws.amazon.com/rds/
|
[rds]: https://aws.amazon.com/rds/
|
||||||
[cloudsql]: https://cloud.google.com/sql
|
[cloudsql]: https://cloud.google.com/sql
|
||||||
[composition]: {{<ref "composition" >}}
|
|
||||||
[api-versioning]: https://kubernetes.io/docs/reference/using-api/#api-versioning#api-versioning
|
[api-versioning]: https://kubernetes.io/docs/reference/using-api/#api-versioning#api-versioning
|
||||||
[velero]: https://velero.io/
|
[velero]: https://velero.io/
|
||||||
[api-reference]: {{<ref "../api-docs" >}}
|
|
||||||
[provider]: {{<ref "providers" >}}
|
|
||||||
[issue-727]: https://github.com/crossplane/crossplane/issues/727
|
[issue-727]: https://github.com/crossplane/crossplane/issues/727
|
||||||
[issue-1143]: https://github.com/crossplane/crossplane/issues/1143
|
[issue-1143]: https://github.com/crossplane/crossplane/issues/1143
|
||||||
[managed-api-patterns]: https://github.com/crossplane/crossplane/blob/master/design/one-pager-managed-resource-api-design.md
|
[managed-api-patterns]: https://github.com/crossplane/crossplane/blob/release-1.10/design/one-pager-managed-resource-api-design.md
|
||||||
|
[managed reconciler]: https://github.com/crossplane/crossplane-runtime/blob/84e629b9589852df1322ff1eae4c6e7639cf6e99/pkg/reconciler/managed/reconciler.go#L637
|
|
@ -177,7 +177,7 @@ provided constraints.
|
||||||
> Dependency resolution is a `beta` feature and depends on the `v1beta1`
|
> Dependency resolution is a `beta` feature and depends on the `v1beta1`
|
||||||
> [`Lock` API][lock-api].
|
> [`Lock` API][lock-api].
|
||||||
|
|
||||||
For an example Configuration package, see [getting-started-with-gcp].
|
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
|
To build a Configuration package, navigate to the package root directory and
|
||||||
execute the following command:
|
execute the following command:
|
||||||
|
@ -379,8 +379,10 @@ package without considering the version of Crossplane that is installed.
|
||||||
|
|
||||||
### spec.controllerConfigRef
|
### spec.controllerConfigRef
|
||||||
|
|
||||||
> This field is only available when installing a `Provider` and is an `alpha`
|
{{< hint "warning" >}}
|
||||||
> feature that depends on the `v1alpha1` [`ControllerConfig` API][controller-config-docs].
|
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
|
Valid values: name of a `ControllerConfig` object
|
||||||
|
|
||||||
|
@ -491,7 +493,6 @@ by [pre-pulling images] onto nodes in the cluster.
|
||||||
[provider-docs]: https://doc.crds.dev/github.com/crossplane/crossplane/meta.pkg.crossplane.io/Provider/v1
|
[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
|
[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
|
[lock-api]: https://doc.crds.dev/github.com/crossplane/crossplane/pkg.crossplane.io/Lock/v1beta1
|
||||||
[getting-started-with-gcp]: https://github.com/crossplane/crossplane/tree/release-1.9/docs/snippets/package/gcp
|
|
||||||
[specification]: https://github.com/Masterminds/semver#basic-comparisons
|
[specification]: https://github.com/Masterminds/semver#basic-comparisons
|
||||||
[composition]: {{<ref "composition" >}}
|
[composition]: {{<ref "composition" >}}
|
||||||
[IAM Roles for Service Accounts]: https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html
|
[IAM Roles for Service Accounts]: https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html
|
|
@ -3,8 +3,8 @@ title: Providers
|
||||||
weight: 101
|
weight: 101
|
||||||
---
|
---
|
||||||
|
|
||||||
Providers are Crossplane packages that bundle a set of [Managed
|
Providers are Crossplane packages that bundle a set of
|
||||||
Resources][managed-resources] and their respective controllers to allow
|
[Managed Resources]({{<ref "managed-resources" >}}) and their respective controllers to allow
|
||||||
Crossplane to provision the respective infrastructure resource.
|
Crossplane to provision the respective infrastructure resource.
|
||||||
|
|
||||||
## Installing Providers
|
## Installing Providers
|
||||||
|
@ -65,8 +65,7 @@ spec:
|
||||||
You can see that there is a reference to a key in a specific `Secret`. The value
|
You can see that there is a reference to a key in a specific `Secret`. The value
|
||||||
of that key should contain the credentials that the controller will use. The
|
of that key should contain the credentials that the controller will use. The
|
||||||
documentation of each provider should give you an idea of how that credentials
|
documentation of each provider should give you an idea of how that credentials
|
||||||
blob should look like. See [Getting Started][getting-started] guide for more
|
blob should look like.
|
||||||
details.
|
|
||||||
|
|
||||||
The following is an example usage of AWS `ProviderConfig`, referenced by a
|
The following is an example usage of AWS `ProviderConfig`, referenced by a
|
||||||
`RDSInstance`:
|
`RDSInstance`:
|
||||||
|
@ -90,8 +89,7 @@ will attempt to use a `ProviderConfig` named `default`.
|
||||||
|
|
||||||
<!-- Named Links -->
|
<!-- Named Links -->
|
||||||
|
|
||||||
[getting-started]: {{<ref "../getting-started/install-configure" >}}
|
|
||||||
[Google Cloud Platform (GCP) Service Account]: {{<ref "../cloud-providers/gcp/gcp-provider" >}}
|
[Google Cloud Platform (GCP) Service Account]: "../cloud-providers/gcp/gcp-provider"
|
||||||
[Microsoft Azure Service Principal]: {{<ref "../cloud-providers/azure/azure-provider" >}}
|
[Microsoft Azure Service Principal]: "../cloud-providers/azure/azure-provider"
|
||||||
[Amazon Web Services (AWS) IAM User]: {{<ref "../cloud-providers/aws/aws-provider" >}}
|
[Amazon Web Services (AWS) IAM User]: "../cloud-providers/aws/aws-provider"
|
||||||
[managed-resources]: {{<ref "managed-resources" >}}
|
|
|
@ -2,7 +2,6 @@
|
||||||
title: Terminology
|
title: Terminology
|
||||||
weight: 110
|
weight: 110
|
||||||
---
|
---
|
||||||
|
|
||||||
## A Note on Style
|
## A Note on Style
|
||||||
|
|
||||||
Each type of Kubernetes resource has a ‘Pascal case’ name - i.e. a title case
|
Each type of Kubernetes resource has a ‘Pascal case’ name - i.e. a title case
|
|
@ -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.
|
|
@ -0,0 +1,464 @@
|
||||||
|
---
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Crossplane also acts as a
|
||||||
|
[Kubernetes Controller](https://kubernetes.io/docs/concepts/architecture/controller/)
|
||||||
|
to monitor 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. |
|
||||||
|
| [Composite Resource Definitions]({{<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 _Custom Resource_
|
||||||
|
{{< hover label="xr2" line="3" >}}kind{{</hover>}}.
|
||||||
|
* A {{< hover label="specGroup" line="8" >}}versions.schema{{</hover>}} section
|
||||||
|
to define the _Custom 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 settings.
|
||||||
|
|
||||||
|
The following _Composite Resource Definition_ defines a {{<hover label="specVersions" line="17" >}}storage{{< /hover >}}
|
||||||
|
parameter. The size 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:
|
||||||
|
- size
|
||||||
|
```
|
||||||
|
|
||||||
|
A _Custom Resource Definition_ can define a wide variety of settings and options.
|
||||||
|
|
||||||
|
Creating a _Custom Resource Definition_ enables the creation of _Custom
|
||||||
|
Resources_ but can also create a _Claim_.
|
||||||
|
|
||||||
|
_Custom 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"}
|
||||||
|
# Custom 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 _Custom
|
||||||
|
Resource Definition_.
|
||||||
|
|
||||||
|
_Claims_ look like _Custom Resources_, but they're namespace scoped,
|
||||||
|
while _Custom 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 _Custom 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"}
|
||||||
|
# Custom 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
|
||||||
|
_Custom Resource Definition_.
|
||||||
|
|
||||||
|
The _Claim_ {{<hover label="claim" line="3">}}kind{{< /hover >}} matches the
|
||||||
|
_Custom 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 define a {{<hover label="claim" line="6">}}namespace{{</hover >}}.
|
||||||
|
The _Custom Resource Definition_ defines the
|
||||||
|
{{<hover label="claim" line="7">}}spec{{< /hover >}} like a _Custom Resource_.
|
||||||
|
|
||||||
|
|
||||||
|
_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" >}})
|
|
@ -0,0 +1,928 @@
|
||||||
|
---
|
||||||
|
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 >}}
|
||||||
|
|
||||||
|
This section creates a _[Composition](#create-a-composition)_,
|
||||||
|
_[Custom Resource Definition](#define-a-composite-resource)_ and a
|
||||||
|
_[Claim](#create-a-claim)_
|
||||||
|
to create a custom Kubernetes API to create AWS resources.
|
||||||
|
|
||||||
|
## 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-aws/latest/crds).
|
||||||
|
* Join the [Crossplane Slack](https://slack.crossplane.io/) and connect with Crossplane users and contributors.
|
|
@ -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
|
||||||
|
doesn't need 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 doesn't need 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 Universal Crossplane (UXP)](https://github.com/upbound/universal-crossplane)
|
||||||
|
{{< /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-aws/latest/crds).
|
||||||
|
* 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
|
@ -0,0 +1,218 @@
|
||||||
|
---
|
||||||
|
title: Azure Quickstart
|
||||||
|
weight: 110
|
||||||
|
---
|
||||||
|
|
||||||
|
Connect Crossplane to Microsoft Azure to create and manage cloud resources from Kubernetes with the [Upbound Azure Provider](https://marketplace.upbound.io/providers/upbound/provider-azure).
|
||||||
|
|
||||||
|
This guide walks you through the steps required to get started with the Upbound Azure Provider. This includes installing Crossplane, configuring the provider to authenticate to Azure and creating a _Managed Resource_ in Azure directly from your Kubernetes cluster.
|
||||||
|
|
||||||
|
- [Prerequisites](#prerequisites)
|
||||||
|
- [Install the Azure provider](#install-the-azure-provider)
|
||||||
|
- [Create a Kubernetes secret for Azure](#create-a-kubernetes-secret-for-azure)
|
||||||
|
- [Install the Azure command-line](#install-the-azure-command-line)
|
||||||
|
- [Create an Azure service principal](#create-an-azure-service-principal)
|
||||||
|
- [Create a Kubernetes secret with the Azure credentials](#create-a-kubernetes-secret-with-the-azure-credentials)
|
||||||
|
- [Create a ProviderConfig](#create-a-providerconfig)
|
||||||
|
- [Create a managed resource](#create-a-managed-resource)
|
||||||
|
- [Delete the managed resource](#delete-the-managed-resource)
|
||||||
|
- [Next steps](#next-steps)
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
This quickstart requires:
|
||||||
|
* a Kubernetes cluster with at least 3 GB of RAM
|
||||||
|
* permissions to create pods and secrets in the Kubernetes cluster
|
||||||
|
* [Helm] version `v3.2.0` or later
|
||||||
|
* an Azure account with permissions to create an Azure [service principal](https://learn.microsoft.com/en-us/azure/active-directory/develop/app-objects-and-service-principals#service-principal-object) and an [Azure Resource Group](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/manage-resource-groups-portal)
|
||||||
|
|
||||||
|
{{< hint type="tip" >}}
|
||||||
|
If you don't have a Kubernetes cluster create one locally with [minikube](https://minikube.sigs.k8s.io/docs/start/) or [kind](https://kind.sigs.k8s.io/).
|
||||||
|
{{< /hint >}}
|
||||||
|
|
||||||
|
|
||||||
|
{{< hint type="note" >}}
|
||||||
|
All commands use the current `kubeconfig` context and configuration.
|
||||||
|
{{< /hint >}}
|
||||||
|
|
||||||
|
## Install the Azure provider
|
||||||
|
|
||||||
|
Install the provider into the Kubernetes cluster with a Kubernetes configuration file.
|
||||||
|
|
||||||
|
```shell {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.29.0
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
The {{< hover label="provider" line="3">}}kind: Provider{{< /hover >}} uses the Crossplane `Provider` _Custom Resource Definition_ to connect your Kubernetes cluster to your cloud provider.
|
||||||
|
|
||||||
|
Verify the provider installed with `kubectl get providers`.
|
||||||
|
|
||||||
|
{{< hint type="note" >}}
|
||||||
|
It may take up to five minutes for the provider to list `HEALTHY` as `True`.
|
||||||
|
{{< /hint >}}
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl get providers
|
||||||
|
NAME INSTALLED HEALTHY PACKAGE AGE
|
||||||
|
upbound-provider-azure True True xpkg.upbound.io/upbound/provider-azure:v0.29.0 3m3s
|
||||||
|
```
|
||||||
|
|
||||||
|
A provider installs their own Kubernetes _Custom Resource Definitions_ (CRDs). These CRDs allow you to create Azure resources directly inside Kubernetes.
|
||||||
|
|
||||||
|
You can view the new CRDs with `kubectl get crds`. Every CRD maps to a unique Azure service Crossplane can provision and manage.
|
||||||
|
|
||||||
|
{{< hint type="tip" >}}
|
||||||
|
All the supported CRDs are also available in the [Upbound Marketplace](https://marketplace.upbound.io/providers/upbound/provider-azure/latest/crds).
|
||||||
|
{{< /hint >}}
|
||||||
|
|
||||||
|
|
||||||
|
## Create a Kubernetes secret for Azure
|
||||||
|
The provider requires credentials to create and manage Azure resources. Providers use a Kubernetes _Secret_ to connect the credentials to the provider.
|
||||||
|
|
||||||
|
{{< hint type="note" >}}
|
||||||
|
Other authentication methods exist and are beyond the scope of this guide. The [Provider documentation](https://marketplace.upbound.io/providers/upbound/provider-azure/latest/docs/configuration) contains information on alternative authentication methods.
|
||||||
|
{{< /hint >}}
|
||||||
|
|
||||||
|
First generate a Kubernetes _Secret_ from your Azure JSON file and then configure the Provider to use it.
|
||||||
|
|
||||||
|
### Install the Azure command-line
|
||||||
|
Generating an [authentication file](https://docs.microsoft.com/en-us/azure/developer/go/azure-sdk-authorization#use-file-based-authentication) requires the Azure command-line.
|
||||||
|
Follow the documentation from Microsoft to [Download and install the Azure command-line](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli).
|
||||||
|
|
||||||
|
Log in to the Azure command-line.
|
||||||
|
|
||||||
|
```command
|
||||||
|
az login
|
||||||
|
```
|
||||||
|
### Create an Azure service principal
|
||||||
|
Follow the Azure documentation to [find your Subscription ID](https://docs.microsoft.com/en-us/azure/azure-portal/get-subscription-tenant-id) from the Azure Portal.
|
||||||
|
|
||||||
|
Using the Azure command-line and provide your Subscription ID create a service principal and authentication file.
|
||||||
|
|
||||||
|
```shell {copy-lines="all"}
|
||||||
|
az ad sp create-for-rbac \
|
||||||
|
--sdk-auth \
|
||||||
|
--role Owner \
|
||||||
|
--scopes /subscriptions/<Subscription ID>
|
||||||
|
```
|
||||||
|
|
||||||
|
Save your Azure JSON output as `azure-credentials.json`.
|
||||||
|
|
||||||
|
{{< hint type="note" >}}
|
||||||
|
The [Configuration](https://marketplace.upbound.io/providers/upbound/provider-azure/latest/docs/configuration) section of the Provider documentation describes other authentication methods.
|
||||||
|
{{< /hint >}}
|
||||||
|
|
||||||
|
### Create a Kubernetes secret with the Azure credentials
|
||||||
|
A Kubernetes generic secret has a name and contents. Use {{< hover label="kube-create-secret" line="1">}}kubectl create secret{{< /hover >}} to generate the secret object named {{< hover label="kube-create-secret" line="2">}}azure-secret{{< /hover >}} in the {{< hover label="kube-create-secret" line="3">}}crossplane-system{{</ hover >}} namespace.
|
||||||
|
|
||||||
|
<!-- vale gitlab.Substitutions = NO -->
|
||||||
|
<!-- ignore .json file name -->
|
||||||
|
Use the {{< hover label="kube-create-secret" line="4">}}--from-file={{</hover>}} argument to set the value to the contents of the {{< hover label="kube-create-secret" line="4">}}azure-credentials.json{{< /hover >}} file.
|
||||||
|
<!-- vale gitlab.Substitutions = YES -->
|
||||||
|
```shell {label="kube-create-secret",copy-lines="all"}
|
||||||
|
kubectl create secret \
|
||||||
|
generic azure-secret \
|
||||||
|
-n crossplane-system \
|
||||||
|
--from-file=creds=./azure-credentials.json
|
||||||
|
```
|
||||||
|
|
||||||
|
View the secret with `kubectl describe secret`
|
||||||
|
|
||||||
|
{{< hint type="note" >}}
|
||||||
|
The size may be larger if there are extra blank spaces in your text file.
|
||||||
|
{{< /hint >}}
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl describe secret azure-secret -n crossplane-system
|
||||||
|
Name: azure-secret
|
||||||
|
Namespace: crossplane-system
|
||||||
|
Labels: <none>
|
||||||
|
Annotations: <none>
|
||||||
|
|
||||||
|
Type: Opaque
|
||||||
|
|
||||||
|
Data
|
||||||
|
====
|
||||||
|
creds: 629 bytes
|
||||||
|
```
|
||||||
|
|
||||||
|
## Create a ProviderConfig
|
||||||
|
A `ProviderConfig` customizes the settings of the Azure Provider.
|
||||||
|
|
||||||
|
Apply the {{< hover label="providerconfig" line="2">}}ProviderConfig{{</ hover >}} with the command:
|
||||||
|
```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
|
||||||
|
```
|
||||||
|
|
||||||
|
This attaches the Azure credentials, saved as a Kubernetes secret, as a {{< hover label="providerconfig" line="9">}}secretRef{{</ hover>}}.
|
||||||
|
|
||||||
|
The {{< hover label="providerconfig" line="11">}}spec.credentials.secretRef.name{{< /hover >}} value is the name of the Kubernetes secret containing the Azure credentials in the {{< hover label="providerconfig" line="10">}}spec.credentials.secretRef.namespace{{< /hover >}}.
|
||||||
|
|
||||||
|
|
||||||
|
## Create a managed resource
|
||||||
|
A _managed resource_ is anything Crossplane creates and manages outside of the Kubernetes cluster. This creates an Azure Resource group with Crossplane. The Resource group is a _managed resource_.
|
||||||
|
|
||||||
|
{{< hint type="tip" >}}
|
||||||
|
A resource group is one of the fastest Azure resources to provision.
|
||||||
|
{{< /hint >}}
|
||||||
|
|
||||||
|
```yaml {label="xr",copy-lines="all"}
|
||||||
|
cat <<EOF | kubectl apply -f -
|
||||||
|
apiVersion: azure.upbound.io/v1beta1
|
||||||
|
kind: ResourceGroup
|
||||||
|
metadata:
|
||||||
|
name: example-rg
|
||||||
|
spec:
|
||||||
|
forProvider:
|
||||||
|
location: "East US"
|
||||||
|
providerConfigRef:
|
||||||
|
name: default
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
Notice the {{< hover label="xr" line="2">}}apiVersion{{< /hover >}} and {{< hover label="xr" line="3">}}kind{{</hover >}} are from the `Provider's` CRDs.
|
||||||
|
|
||||||
|
The {{< hover label="xr" line="5">}}metadata.name{{< /hover >}} value is the name of the created resource group in Azure.
|
||||||
|
This example uses the name `example-rg`.
|
||||||
|
|
||||||
|
The {{< hover label="xr" line="8">}}spec.forProvider.location{{< /hover >}} tells Azure which Azure region to use when deploying resources. The region can be any [Azure geography](https://azure.microsoft.com/en-us/explore/global-infrastructure/geographies/) code.
|
||||||
|
|
||||||
|
Use `kubectl get resourcegroup` to verify Crossplane created the resource group.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl get ResourceGroup
|
||||||
|
NAME READY SYNCED EXTERNAL-NAME AGE
|
||||||
|
example-rg True True example-rg 4m58s
|
||||||
|
```
|
||||||
|
|
||||||
|
## Delete the managed resource
|
||||||
|
Before shutting down your Kubernetes cluster, delete the resource group just created.
|
||||||
|
|
||||||
|
Use `kubectl delete resource-group` to remove the bucket.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl delete resourcegroup example-rg
|
||||||
|
resourcegroup.azure.upbound.io "example-rg" deleted
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next steps
|
||||||
|
* Explore Azure resources that can Crossplane can configure in the [Provider CRD reference](https://marketplace.upbound.io/providers/upbound/provider-azure/latest/crds).
|
||||||
|
* Join the [Crossplane Slack](https://slack.crossplane.io/) and connect with Crossplane users and contributors.
|
|
@ -0,0 +1,224 @@
|
||||||
|
---
|
||||||
|
title: GCP Quickstart
|
||||||
|
weight: 140
|
||||||
|
---
|
||||||
|
|
||||||
|
Connect Crossplane to Google GCP to create and manage cloud resources from Kubernetes with the [Upbound GCP Provider](https://marketplace.upbound.io/providers/upbound/provider-gcp/).
|
||||||
|
|
||||||
|
This guide walks you through the steps required to get started with the Upbound GCP Provider. This includes installing Crossplane, configuring the provider to authenticate to GCP and creating a _Managed Resource_ in GCP directly from your Kubernetes cluster.
|
||||||
|
|
||||||
|
- [Prerequisites](#prerequisites)
|
||||||
|
- [Install the GCP provider](#install-the-gcp-provider)
|
||||||
|
- [Create a Kubernetes secret for GCP](#create-a-kubernetes-secret-for-gcp)
|
||||||
|
- [Generate a GCP service account JSON file](#generate-a-gcp-service-account-json-file)
|
||||||
|
- [Create a Kubernetes secret with the GCP credentials](#create-a-kubernetes-secret-with-the-gcp-credentials)
|
||||||
|
- [Create a ProviderConfig](#create-a-providerconfig)
|
||||||
|
- [Create a managed resource](#create-a-managed-resource)
|
||||||
|
- [Delete the managed resource](#delete-the-managed-resource)
|
||||||
|
- [Next steps](#next-steps)
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
This quickstart requires:
|
||||||
|
* a Kubernetes cluster with at least 3 GB of RAM
|
||||||
|
* permissions to create pods and secrets in the Kubernetes cluster
|
||||||
|
* [Helm](https://helm.sh/) version `v3.2.0` or later
|
||||||
|
* a GCP account with permissions to create a storage bucket
|
||||||
|
* GCP [account keys](https://cloud.google.com/iam/docs/creating-managing-service-account-keys)
|
||||||
|
* GCP [Project ID](https://support.google.com/googleapi/answer/7014113?hl=en)
|
||||||
|
|
||||||
|
{{< hint type="tip" >}}
|
||||||
|
If you don't have a Kubernetes cluster create one locally with [minikube](https://minikube.sigs.k8s.io/docs/start/) or [kind](https://kind.sigs.k8s.io/).
|
||||||
|
{{< /hint >}}
|
||||||
|
|
||||||
|
|
||||||
|
{{< hint type="note" >}}
|
||||||
|
All commands use the current `kubeconfig` context and configuration.
|
||||||
|
{{< /hint >}}
|
||||||
|
|
||||||
|
## Install the GCP provider
|
||||||
|
|
||||||
|
Install the provider into the Kubernetes cluster with a Kubernetes configuration file.
|
||||||
|
|
||||||
|
```shell {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.15.0
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
The {{< hover label="provider" line="3">}}kind: Provider{{< /hover >}} uses the Crossplane `Provider` _Custom Resource Definition_ to connect your Kubernetes cluster to your cloud provider.
|
||||||
|
|
||||||
|
Verify the provider installed with `kubectl get providers`.
|
||||||
|
|
||||||
|
{{< hint type="note" >}}
|
||||||
|
It may take up to five minutes for the provider to list `HEALTHY` as `True`.
|
||||||
|
{{< /hint >}}
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl get providers
|
||||||
|
NAME INSTALLED HEALTHY PACKAGE AGE
|
||||||
|
upbound-provider-gcp True False xpkg.upbound.io/upbound/provider-gcp:v0.15.0 8s
|
||||||
|
```
|
||||||
|
|
||||||
|
A provider installs their own Kubernetes _Custom Resource Definitions_ (CRDs). These CRDs allow you to create GCP resources directly inside Kubernetes.
|
||||||
|
|
||||||
|
You can view the new CRDs with `kubectl get crds`. Every CRD maps to a unique GCP service Crossplane can provision and manage.
|
||||||
|
|
||||||
|
{{< hint type="tip" >}}
|
||||||
|
All the supported CRDs are also available in the [Upbound Marketplace](https://marketplace.upbound.io/providers/upbound/provider-gcp/latest/crds).
|
||||||
|
{{< /hint >}}
|
||||||
|
|
||||||
|
## Create a Kubernetes secret for GCP
|
||||||
|
The provider requires credentials to create and manage GCP resources. Providers use a Kubernetes _Secret_ to connect the credentials to the provider.
|
||||||
|
|
||||||
|
First generate a Kubernetes _Secret_ from a Google Cloud service account JSON file and then configure the Provider to use it.
|
||||||
|
|
||||||
|
{{< hint type="note" >}}
|
||||||
|
Other authentication methods exist and are beyond the scope of this guide. The [Provider documentation](https://marketplace.upbound.io/providers/upbound/provider-gcp/latest/docs/configuration) contains information on alternative authentication methods.
|
||||||
|
{{< /hint >}}
|
||||||
|
|
||||||
|
### Generate a GCP service account JSON file
|
||||||
|
For basic user authentication, use a Google Cloud 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 >}}
|
||||||
|
|
||||||
|
Save this JSON file as `gcp-credentials.json`
|
||||||
|
|
||||||
|
{{< hint type="note" >}}
|
||||||
|
The [Configuration](https://marketplace.upbound.io/providers/upbound/provider-gcp/latest/docs/configuration) section of the Provider documentation describes other authentication methods.
|
||||||
|
{{< /hint >}}
|
||||||
|
|
||||||
|
### Create a Kubernetes secret with the GCP credentials
|
||||||
|
<!-- vale gitlab.Substitutions = NO -->
|
||||||
|
<!-- ignore .json file name -->
|
||||||
|
A Kubernetes generic secret has a name and contents. Use {{< hover label="kube-create-secret" line="1">}}kubectl create secret{{< /hover >}} to generate the secret object named {{< hover label="kube-create-secret" line="2">}}gcp-secret{{< /hover >}} in the {{< hover label="kube-create-secret" line="3">}}crossplane-system{{</ hover >}} namespace.
|
||||||
|
Use the {{< hover label="kube-create-secret" line="4">}}--from-file={{</hover>}} argument to set the value to the contents of the {{< hover label="kube-create-secret" line="4">}}gcp-credentials.json{{< /hover >}} file.
|
||||||
|
<!-- vale gitlab.Substitutions = YES -->
|
||||||
|
|
||||||
|
```shell {label="kube-create-secret",copy-lines="all"}
|
||||||
|
kubectl create secret \
|
||||||
|
generic gcp-secret \
|
||||||
|
-n crossplane-system \
|
||||||
|
--from-file=creds=./gcp-credentials.json
|
||||||
|
```
|
||||||
|
|
||||||
|
View the secret with `kubectl describe secret`
|
||||||
|
|
||||||
|
{{< hint type="note" >}}
|
||||||
|
The size may be larger if there are extra blank spaces in your text file.
|
||||||
|
{{< /hint >}}
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl describe secret gcp-secret -n crossplane-system
|
||||||
|
Name: gcp-secret
|
||||||
|
Namespace: crossplane-system
|
||||||
|
Labels: <none>
|
||||||
|
Annotations: <none>
|
||||||
|
|
||||||
|
Type: Opaque
|
||||||
|
|
||||||
|
Data
|
||||||
|
====
|
||||||
|
creds: 2330 bytes
|
||||||
|
```
|
||||||
|
|
||||||
|
## Create a ProviderConfig
|
||||||
|
A `ProviderConfig` customizes the settings of the GCP Provider.
|
||||||
|
|
||||||
|
Apply the {{< hover label="providerconfig" line="2">}}ProviderConfig{{</ hover >}}. Include your {{< hover label="providerconfig" line="7" >}}GCP project ID{{< /hover >}}.
|
||||||
|
|
||||||
|
{{< hint type="warning" >}}
|
||||||
|
Add your GCP `project ID` into the output below.
|
||||||
|
{{< /hint >}}
|
||||||
|
|
||||||
|
```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
|
||||||
|
```
|
||||||
|
|
||||||
|
This attaches the GCP credentials, saved as a Kubernetes secret, as a {{< hover label="providerconfig" line="9">}}secretRef{{</ hover>}}.
|
||||||
|
|
||||||
|
The {{< hover label="providerconfig" line="12">}}spec.credentials.secretRef.name{{< /hover >}} value is the name of the Kubernetes secret containing the GCP credentials in the {{< hover label="providerconfig" line="11">}}spec.credentials.secretRef.namespace{{< /hover >}}.
|
||||||
|
|
||||||
|
|
||||||
|
## Create a managed resource
|
||||||
|
A _managed resource_ is anything Crossplane creates and manages outside of the Kubernetes cluster. This creates a GCP storage bucket with Crossplane. The storage bucket is a _managed resource_.
|
||||||
|
|
||||||
|
This generates a random name for the storage bucket starting with {{< hover label="xr" line="1" >}}crossplane-bucket{{< /hover >}}
|
||||||
|
|
||||||
|
```yaml {label="xr",copy-lines="all"}
|
||||||
|
bucket=$(echo "crossplane-bucket-"$(head -n 4096 /dev/urandom | openssl sha1 | tail -c 10))
|
||||||
|
cat <<EOF | kubectl apply -f -
|
||||||
|
apiVersion: storage.gcp.upbound.io/v1beta1
|
||||||
|
kind: Bucket
|
||||||
|
metadata:
|
||||||
|
name: $bucket
|
||||||
|
spec:
|
||||||
|
forProvider:
|
||||||
|
location: US
|
||||||
|
storageClass: MULTI_REGIONAL
|
||||||
|
providerConfigRef:
|
||||||
|
name: default
|
||||||
|
deletionPolicy: Delete
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
Notice the {{< hover label="xr" line="3">}}apiVersion{{< /hover >}} and {{< hover label="xr" line="4">}}kind{{</hover >}} are from the `Provider's` CRDs.
|
||||||
|
|
||||||
|
|
||||||
|
The {{< hover label="xr" line="6">}}metadata.name{{< /hover >}} value is the name of the created GCP storage bucket.
|
||||||
|
This example uses the generated name `crossplane-bucket-<hash>` in the {{< hover label="xr" line="6">}}$bucket{{</hover >}} variable.
|
||||||
|
|
||||||
|
{{< hover label="xr" line="10" >}}spec.storageClass{{< /hover >}} defines the GCP storage bucket is [single-region, dual-region or multi-region](https://cloud.google.com/storage/docs/locations#key-concepts).
|
||||||
|
|
||||||
|
{{< hover label="xr" line="9">}}spec.forProvider.location{{< /hover >}} is a [GCP location based](https://cloud.google.com/storage/docs/locations) on the {{< hover label="xr" line="10" >}}storageClass{{< /hover >}}.
|
||||||
|
|
||||||
|
Use `kubectl get buckets` to verify Crossplane created the bucket.
|
||||||
|
|
||||||
|
{{< hint type="tip" >}}
|
||||||
|
Crossplane created the bucket when the values `READY` and `SYNCED` are `True`.
|
||||||
|
This may take up to 5 minutes.
|
||||||
|
{{< /hint >}}
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl get bucket
|
||||||
|
NAME READY SYNCED EXTERNAL-NAME AGE
|
||||||
|
crossplane-bucket-cf2b6d853 True True crossplane-bucket-cf2b6d853 3m3s
|
||||||
|
```
|
||||||
|
|
||||||
|
Optionally, log into the [GCP Console](https://console.cloud.google.com/) and see the storage bucket inside GCP.
|
||||||
|
|
||||||
|
## Delete the managed resource
|
||||||
|
Before shutting down your Kubernetes cluster, delete the S3 bucket just created.
|
||||||
|
|
||||||
|
Use `kubectl delete bucket <bucketname>` to remove the bucket.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
kubectl delete bucket $bucket
|
||||||
|
bucket.storage.gcp.upbound.io "crossplane-bucket-b7cf6b590" deleted
|
||||||
|
```
|
||||||
|
|
||||||
|
Look in the [GCP Console](https://console.cloud.google.com/) to confirm Crossplane deleted the bucket from GCP.
|
||||||
|
|
||||||
|
|
||||||
|
## Next steps
|
||||||
|
* Explore GCP resources that can Crossplane can configure in the [Provider CRD reference](https://marketplace.upbound.io/providers/upbound/provider-gcp/latest/crds).
|
||||||
|
* Join the [Crossplane Slack](https://slack.crossplane.io/) and connect with Crossplane users and contributors.
|
|
@ -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.
|
|
@ -0,0 +1,337 @@
|
||||||
|
---
|
||||||
|
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
|
||||||
|
* [Kubernetes](https://kubernetes.io/releases/) version `v1.16.0` or later
|
||||||
|
* [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.
|
||||||
|
|
||||||
|
{{<expand "All Crossplane customization options" >}}
|
||||||
|
{{< table "table table-hover table-striped table-sm">}}
|
||||||
|
| Parameter | Description | Default |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `affinity` | Enable pod affinity for the Crossplane pods. | `{}` |
|
||||||
|
| `args` | Optional arguments passed to the Crossplane pods. | `{}` |
|
||||||
|
| `configuration.packages` | A list of Crossplane _Configuration_ packages to install together with Crossplane. | `[]` |
|
||||||
|
| `customAnnotations` | Add custom annotations to the Crossplane deployments and pods. | `{}` |
|
||||||
|
| `customLabels` | Add custom labels to the Crossplane deployments and pods. | `{}` |
|
||||||
|
| `deploymentStrategy` | The deployment strategy for the Crossplane and RBAC Manager pods. | `RollingUpdate` |
|
||||||
|
| `extraEnvVarsCrossplane` | List of extra environment variables to set in the Crossplane deployment. **Note**: Helm replaces all dot `.` values with underscores `_` (example: `SAMPLE.KEY=value1` becomes `SAMPLE_KEY=value1`). | `{}` |
|
||||||
|
| `extraEnvVarsRBACManager` | List of extra environment variables to set in the Crossplane RBAC Manager deployment. **Note**: Helm replaces all dot `.` values with underscores `_` (example: `SAMPLE.KEY=value1` becomes `SAMPLE_KEY=value1`). | `{}` |
|
||||||
|
| `image.pullPolicy` | Image pull policy used in all Crossplane containers. | `IfNotPresent` |
|
||||||
|
| `image.repository` | Image repository for the Crossplane pods. | `crossplane/crossplane` |
|
||||||
|
| `image.tag` | Image tag used to install the Crossplane pod image. | `master` |
|
||||||
|
| `imagePullSecrets` | Names of image pull secrets to use. | `{}` |
|
||||||
|
| `leaderElection` | Enable leader election for the Crossplane Manager pods. | `true` |
|
||||||
|
| `metrics.enabled` | Expose Crossplane and RBAC Manager pod metrics endpoints. | `false` |
|
||||||
|
| `nodeSelector` | Enable a node selector for the Crossplane pods. | `{}` |
|
||||||
|
| `packageCache.configMap` | A [Kubernetes `configMap`](https://kubernetes.io/docs/concepts/storage/volumes/#configmap) to define the Crossplane _Configuration_ package cache. Configuring `packageCache.configMap` disables the [Kubernetes `emptyDir`](https://kubernetes.io/docs/concepts/storage/volumes/#emptydir). Crossplane ignores the `packageCache.configMap` when using `packageCache.pvc`. | `""` |
|
||||||
|
| `packageCache.medium` | The [Kubernetes `emptyDir`](https://kubernetes.io/docs/concepts/storage/volumes/#emptydir) medium used for the Crossplane _Configuration_ package cache. Unused with `packageCache.pvc` or `packageCache.configMap` set. | `""` |
|
||||||
|
| `packageCache.pvc` | Name of the [Kubernetes `PersistentVolumeClaim`](https://kubernetes.io/docs/concepts/storage/volumes/#persistentvolumeclaim) used for the Crossplane _Configuration_ package cache. The `packageCache.pvc` takes precedence over `packageCache.configMap` and disables the [Kubernetes `emptyDir`](https://kubernetes.io/docs/concepts/storage/volumes/#emptydir). | `""` |
|
||||||
|
| `packageCache.sizeLimit` | The size limit of the [Kubernetes `emptyDir`](https://kubernetes.io/docs/concepts/storage/volumes/#emptydir) used for the Crossplane _Configuration_ package cache. Unused with `packageCache.pvc` or `packageCache.configMap` set. | `5Mi` |
|
||||||
|
| `podSecurityContextCrossplane` | Configure a [Kubernetes `securityContext`](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) for the Crossplane pods. | `{}` |
|
||||||
|
| `podSecurityContextCrossplane` | Configure a [Kubernetes `securityContext`](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) for the Crossplane RBAC Manager pod. | `{}` |
|
||||||
|
| `priorityClassName` | The priority class name for Crossplane and RBAC Manager pods. | `""` |
|
||||||
|
| `provider.packages` | A list of Crossplane _Provider_ packages to install together with Crossplane. | `[]` |
|
||||||
|
| `rbacManager.affinity` | Enable affinity for the Crossplane RBAC Manager pod. | `{}` |
|
||||||
|
| `rbacManager.deploy` | Deploy the Crossplane RBAC Manager pod and its required roles. | `true` |
|
||||||
|
| `rbacManager.leaderElection` | Enable the leader election for the Crossplane RBAC Managers pod. | `true` |
|
||||||
|
| `rbacManager.managementPolicy`| The extent to which the Crossplane RBAC manager manages permissions. Setting `rbacManager.managementPolicy` to `All` the Crossplane RBAC contoller manages all Crossplane controller and user roles. Setting `rbacManager.managementPolicy` to `Basic` the Crossplane RBAC controller only manages `crossplane-admin`, `crossplane-edit`, and `crossplane-view` user roles. | `All` |
|
||||||
|
| `rbacManager.nodeSelector` | Enable a node selector for the Crossplane RBAC Manager pod. | `{}` |
|
||||||
|
| `rbacManager.replicas` | The number of replicas to run for the Crossplane RBAC Manager pods. | `1` |
|
||||||
|
| `rbacManager.skipAggregatedClusterRoles` | Don't deploy RBAC aggregated ClusterRoles. | `false` |
|
||||||
|
| `rbacManager.tolerations` | Enable tolerations for Crossplane RBAC Managers pod. | `[]` |
|
||||||
|
| `registryCaBundleConfig.key` | Key to use from the _ConfigMap_ containing a CA bundle for fetching from package registries. | `{}` |
|
||||||
|
| `registryCaBundleConfig.name` | Name of _ConfigMap_ containing a CA bundle for fetching from package registries. | `{}` |
|
||||||
|
| `replicas` | The number of replicas to run for the Crossplane pods. | `1` |
|
||||||
|
| `resourcesCrossplane.limits.cpu` | CPU resource limits for the Crossplane pods. | `100m` |
|
||||||
|
| `resourcesCrossplane.limits.memory` | Memory resource limits for the Crossplane pods. | `512Mi` |
|
||||||
|
| `resourcesCrossplane.requests.cpu` | CPU resource requests for the Crossplane pods. | `100m` |
|
||||||
|
| `resourcesCrossplane.requests.memory` | Memory resource requests for the Crossplane pods. | `256Mi` |
|
||||||
|
| `resourcesRBACManager.limits.cpu` | CPU resource limits for the Crossplane RBAC Manager pod. | `100m` |
|
||||||
|
| `resourcesRBACManager.limits.memory` | Memory resource limits for the Crossplane RBAC Manager pod. | `512Mi` |
|
||||||
|
| `resourcesRBACManager.requests.cpu` | CPU resource requests for the Crossplane RBAC Manager pod. | `100m` |
|
||||||
|
| `resourcesRBACManager.requests.memory` | Memory resource requests value the Crossplane RBAC Manager pod. | `256Mi` |
|
||||||
|
| `securityContextCrossplane.allowPrivilegeEscalation` | Allow privilege escalation for the Crossplane pods. | `false` |
|
||||||
|
| `securityContextCrossplane.readOnlyRootFilesystem` | Set a read only root file system for the Crossplane pods. | `true` |
|
||||||
|
| `securityContextCrossplane.runAsGroup` | A _run as group_ for the Crossplane pods. | `65532` |
|
||||||
|
| `securityContextCrossplane.runAsUser` | A _run as user_ for the Crossplane pods. | `65532` |
|
||||||
|
| `securityContextRBACManager.allowPrivilegeEscalation` | Allow privilege escalation for the Crossplane RBAC Manager pod. | `false` |
|
||||||
|
| `securityContextRBACManager.readOnlyRootFilesystem` | Set a read only root file system for the Crossplane RBAC Manager pod. | `true` |
|
||||||
|
| `securityContextRBACManager.runAsGroup` | The _run as group_ for the Crossplane RBAC Manager pod. | `65532` |
|
||||||
|
| `securityContextRBACManager.runAsUser` | The _run as user_ for the Crossplane RBAC Manager pod. | `65532` |
|
||||||
|
| `serviceAccount.customAnnotations` | Add custom annotations to the Crossplane service account. | `{}` |
|
||||||
|
| `tolerations` | Enable tolerations for Crossplane pod. | `[]` |
|
||||||
|
| `webhooks.enabled` | Enable webhooks for Crossplane as well as packages installed by Crossplane. | `false` |
|
||||||
|
| `xfn.args` | Optional arguments passed to the _Composite Resource Functions_ sidecar container. | `{}` |
|
||||||
|
| `xfn.cache.medium` | The [Kubernetes `emptyDir`](https://kubernetes.io/docs/concepts/storage/volumes/#emptydir) medium used for the _Composite Resource Functions_ sidecar container cache. Unused with `xfn.cache.pvc` set. | `""` |
|
||||||
|
| `xfn.cache.pvc` | Name of the [Kubernetes `PersistentVolumeClaim`](https://kubernetes.io/docs/concepts/storage/volumes/#persistentvolumeclaim) used for the _Composite Resource Functions_ sidecar container cache. The `xfn.cache.pvc` disables the _Composite Resource Functions_ [Kubernetes `emptyDir`](https://kubernetes.io/docs/concepts/storage/volumes/#emptydir). | `""` |
|
||||||
|
| `xfn.cache.sizeLimit` | The size limit of the [Kubernetes `emptyDir`](https://kubernetes.io/docs/concepts/storage/volumes/#emptydir) used for the _Composite Resource Functions_ sidecar container cache. Unused with `xfn.cache.pvc` set. | `1Gi` |
|
||||||
|
| `xfn.enabled` | Enable Crossplane _Composite Resource Functions_. Enabling _Composite Resource Functions_ also requires `args` set with `--enable-composition-functions`. | `false` |
|
||||||
|
| `xfn.extraEnvVars` | List of extra environment variables to set in the _Composite Resource Functions_ sidecar container. **Note**: Helm replaces all dot `.` values with underscores `_` (example: `SAMPLE.KEY=value1` becomes `SAMPLE_KEY=value1`). | `{}` |
|
||||||
|
| `xfn.image.pullPolicy` | Image pull policy used in the _Composite Resource Functions_ sidecar container. | `IfNotPresent` |
|
||||||
|
| `xfn.image.repository` | Image repository for the _Composite Resource Functions_ sidecar container. | `crossplane/xfn` |
|
||||||
|
| `xfn.image.tag` | Image tag used to install the _Composite Resource Functions_ sidecar container. | The installed Crossplane version. |
|
||||||
|
| `xfn.imagePullSecrets` | Names of image pull secrets to use when installing the _Composite Resource Functions_ sidecar container. | `{}` |
|
||||||
|
| `xfn.limits.cpu` | CPU resource limits for the Crossplane RBAC Manager pod. | `2000m` |
|
||||||
|
| `xfn.limits.memory` | Memory resource limits for the Crossplane RBAC Manager pod. | `2Gi` |
|
||||||
|
| `xfn.requests.cpu` | CPU resource requests for the Crossplane RBAC Manager pod. | `1000m` |
|
||||||
|
| `xfn.requests.memory` | Memory resource requests value the Crossplane RBAC Manager pod. | `1Gi` |
|
||||||
|
| `xfn.securityContext.allowPrivilegeEscalation` | Allow privilege escalation for the Crossplane RBAC Manager pod. | `false` |
|
||||||
|
| `xfn.securityContext.readOnlyRootFilesystem` | Set a read only root file system for the Crossplane RBAC Manager pod. | `true` |
|
||||||
|
| `xfn.securityContext.runAsGroup` | The _run as group_ for the Crossplane RBAC Manager pod. | `65532` |
|
||||||
|
| `xfn.securityContext.runAsUser` | The _run as user_ for the Crossplane RBAC Manager pod. | `65532` |
|
||||||
|
{{< /table >}}
|
||||||
|
{{< /expand >}}
|
||||||
|
|
||||||
|
#### 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 multiple, 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 usually introduces new features behind feature flags. By default
|
||||||
|
alpha features are off, while beta features are enabled. 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/).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
```
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
title: Upgrade Crossplane
|
||||||
|
weight: 200
|
||||||
|
draft: true
|
||||||
|
---
|
||||||
|
|
||||||
|
Install, Uninstall, Upgrade
|
|
@ -1,27 +0,0 @@
|
||||||
---
|
|
||||||
title: "Overview"
|
|
||||||
weight: -1
|
|
||||||
cascade:
|
|
||||||
version: "1.9"
|
|
||||||
---
|
|
||||||
|
|
||||||
{{< img src="/media/banner.png" alt="Crossplane Popsicle Truck" size="large" >}}
|
|
||||||
|
|
||||||
|
|
||||||
Crossplane is an open source Kubernetes add-on that transforms your cluster into
|
|
||||||
a **universal control plane**. Crossplane enables platform teams to assemble
|
|
||||||
infrastructure from multiple vendors, and expose higher level self-service APIs
|
|
||||||
for application teams to consume, without having to write any code.
|
|
||||||
|
|
||||||
Crossplane extends your Kubernetes cluster to support orchestrating any
|
|
||||||
infrastructure or managed service. Compose Crossplane's granular resources into
|
|
||||||
higher level abstractions that can be versioned, managed, deployed and consumed
|
|
||||||
using your favorite tools and existing processes. [Install Crossplane]({{<ref "getting-started/install-configure" >}}) into any
|
|
||||||
Kubernetes cluster to get started.
|
|
||||||
|
|
||||||
Crossplane is a [Cloud Native Compute Foundation][cncf] project.
|
|
||||||
|
|
||||||
<!-- Named Links -->
|
|
||||||
|
|
||||||
|
|
||||||
[cncf]: https://www.cncf.io/
|
|
|
@ -1,20 +0,0 @@
|
||||||
---
|
|
||||||
title: API Documentation
|
|
||||||
weight: 400
|
|
||||||
---
|
|
||||||
|
|
||||||
Crossplane packages offer API types in a cluster by installing CRDs or XRDs.
|
|
||||||
Packages that are pushed to `xpkg.upbound.io` have auto-generated documentation
|
|
||||||
for their API types on the [Upbound Marketplace]. You can access documentation
|
|
||||||
for the most recent release of any package by navigating to
|
|
||||||
`https://marketplace.upbound.io/{provider|configuration}/<org>/<repo>`.
|
|
||||||
|
|
||||||
Crossplane repositories that do not contain providers or configurations, but do
|
|
||||||
publish CRDs, are served on [doc.crds.dev]. For instance, the
|
|
||||||
[crossplane/crossplane] repository.
|
|
||||||
|
|
||||||
<!-- Named Links -->
|
|
||||||
|
|
||||||
[Upbound Marketplace]: https://marketplace.upbound.io
|
|
||||||
[doc.crds.dev]: https://doc.crds.dev/
|
|
||||||
[crossplane/crossplane]: https://doc.crds.dev/github.com/crossplane/crossplane
|
|
|
@ -1,141 +0,0 @@
|
||||||
---
|
|
||||||
apiVersion: apiextensions.k8s.io/v1
|
|
||||||
kind: CustomResourceDefinition
|
|
||||||
metadata:
|
|
||||||
annotations:
|
|
||||||
controller-gen.kubebuilder.io/version: v0.8.0
|
|
||||||
creationTimestamp: null
|
|
||||||
name: configurations.meta.pkg.crossplane.io
|
|
||||||
spec:
|
|
||||||
group: meta.pkg.crossplane.io
|
|
||||||
names:
|
|
||||||
kind: Configuration
|
|
||||||
listKind: ConfigurationList
|
|
||||||
plural: configurations
|
|
||||||
singular: configuration
|
|
||||||
scope: Namespaced
|
|
||||||
versions:
|
|
||||||
- name: v1
|
|
||||||
schema:
|
|
||||||
openAPIV3Schema:
|
|
||||||
description: A Configuration is the description of a Crossplane Configuration
|
|
||||||
package.
|
|
||||||
properties:
|
|
||||||
apiVersion:
|
|
||||||
description: 'APIVersion defines the versioned schema of this representation
|
|
||||||
of an object. Servers should convert recognized schemas to the latest
|
|
||||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
|
||||||
type: string
|
|
||||||
kind:
|
|
||||||
description: 'Kind is a string value representing the REST resource this
|
|
||||||
object represents. Servers may infer this from the endpoint the client
|
|
||||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
|
||||||
type: string
|
|
||||||
metadata:
|
|
||||||
type: object
|
|
||||||
spec:
|
|
||||||
description: ConfigurationSpec specifies the configuration of a Configuration.
|
|
||||||
properties:
|
|
||||||
crossplane:
|
|
||||||
description: Semantic version constraints of Crossplane that package
|
|
||||||
is compatible with.
|
|
||||||
properties:
|
|
||||||
version:
|
|
||||||
description: Semantic version constraints of Crossplane that package
|
|
||||||
is compatible with.
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- version
|
|
||||||
type: object
|
|
||||||
dependsOn:
|
|
||||||
description: Dependencies on other packages.
|
|
||||||
items:
|
|
||||||
description: Dependency is a dependency on another package. One
|
|
||||||
of Provider or Configuration may be supplied.
|
|
||||||
properties:
|
|
||||||
configuration:
|
|
||||||
description: Configuration is the name of a Configuration package
|
|
||||||
image.
|
|
||||||
type: string
|
|
||||||
provider:
|
|
||||||
description: Provider is the name of a Provider package image.
|
|
||||||
type: string
|
|
||||||
version:
|
|
||||||
description: Version is the semantic version constraints of
|
|
||||||
the dependency image.
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- version
|
|
||||||
type: object
|
|
||||||
type: array
|
|
||||||
type: object
|
|
||||||
required:
|
|
||||||
- spec
|
|
||||||
type: object
|
|
||||||
served: true
|
|
||||||
storage: true
|
|
||||||
- name: v1alpha1
|
|
||||||
schema:
|
|
||||||
openAPIV3Schema:
|
|
||||||
description: A Configuration is the description of a Crossplane Configuration
|
|
||||||
package.
|
|
||||||
properties:
|
|
||||||
apiVersion:
|
|
||||||
description: 'APIVersion defines the versioned schema of this representation
|
|
||||||
of an object. Servers should convert recognized schemas to the latest
|
|
||||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
|
||||||
type: string
|
|
||||||
kind:
|
|
||||||
description: 'Kind is a string value representing the REST resource this
|
|
||||||
object represents. Servers may infer this from the endpoint the client
|
|
||||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
|
||||||
type: string
|
|
||||||
metadata:
|
|
||||||
type: object
|
|
||||||
spec:
|
|
||||||
description: ConfigurationSpec specifies the configuration of a Configuration.
|
|
||||||
properties:
|
|
||||||
crossplane:
|
|
||||||
description: Semantic version constraints of Crossplane that package
|
|
||||||
is compatible with.
|
|
||||||
properties:
|
|
||||||
version:
|
|
||||||
description: Semantic version constraints of Crossplane that package
|
|
||||||
is compatible with.
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- version
|
|
||||||
type: object
|
|
||||||
dependsOn:
|
|
||||||
description: Dependencies on other packages.
|
|
||||||
items:
|
|
||||||
description: Dependency is a dependency on another package. One
|
|
||||||
of Provider or Configuration may be supplied.
|
|
||||||
properties:
|
|
||||||
configuration:
|
|
||||||
description: Configuration is the name of a Configuration package
|
|
||||||
image.
|
|
||||||
type: string
|
|
||||||
provider:
|
|
||||||
description: Provider is the name of a Provider package image.
|
|
||||||
type: string
|
|
||||||
version:
|
|
||||||
description: Version is the semantic version constraints of
|
|
||||||
the dependency image.
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- version
|
|
||||||
type: object
|
|
||||||
type: array
|
|
||||||
type: object
|
|
||||||
required:
|
|
||||||
- spec
|
|
||||||
type: object
|
|
||||||
served: true
|
|
||||||
storage: false
|
|
||||||
status:
|
|
||||||
acceptedNames:
|
|
||||||
kind: ""
|
|
||||||
plural: ""
|
|
||||||
conditions: []
|
|
||||||
storedVersions: []
|
|
|
@ -1,263 +0,0 @@
|
||||||
---
|
|
||||||
apiVersion: apiextensions.k8s.io/v1
|
|
||||||
kind: CustomResourceDefinition
|
|
||||||
metadata:
|
|
||||||
annotations:
|
|
||||||
controller-gen.kubebuilder.io/version: v0.8.0
|
|
||||||
creationTimestamp: null
|
|
||||||
name: providers.meta.pkg.crossplane.io
|
|
||||||
spec:
|
|
||||||
group: meta.pkg.crossplane.io
|
|
||||||
names:
|
|
||||||
kind: Provider
|
|
||||||
listKind: ProviderList
|
|
||||||
plural: providers
|
|
||||||
singular: provider
|
|
||||||
scope: Namespaced
|
|
||||||
versions:
|
|
||||||
- name: v1
|
|
||||||
schema:
|
|
||||||
openAPIV3Schema:
|
|
||||||
description: A Provider is the description of a Crossplane Provider package.
|
|
||||||
properties:
|
|
||||||
apiVersion:
|
|
||||||
description: 'APIVersion defines the versioned schema of this representation
|
|
||||||
of an object. Servers should convert recognized schemas to the latest
|
|
||||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
|
||||||
type: string
|
|
||||||
kind:
|
|
||||||
description: 'Kind is a string value representing the REST resource this
|
|
||||||
object represents. Servers may infer this from the endpoint the client
|
|
||||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
|
||||||
type: string
|
|
||||||
metadata:
|
|
||||||
type: object
|
|
||||||
spec:
|
|
||||||
description: ProviderSpec specifies the configuration of a Provider.
|
|
||||||
properties:
|
|
||||||
controller:
|
|
||||||
description: Configuration for the packaged Provider's controller.
|
|
||||||
properties:
|
|
||||||
image:
|
|
||||||
description: Image is the packaged Provider controller image.
|
|
||||||
type: string
|
|
||||||
permissionRequests:
|
|
||||||
description: PermissionRequests for RBAC rules required for this
|
|
||||||
provider's controller to function. The RBAC manager is responsible
|
|
||||||
for assessing the requested permissions.
|
|
||||||
items:
|
|
||||||
description: PolicyRule holds information that describes a policy
|
|
||||||
rule, but does not contain information about who the rule
|
|
||||||
applies to or which namespace the rule applies to.
|
|
||||||
properties:
|
|
||||||
apiGroups:
|
|
||||||
description: APIGroups is the name of the APIGroup that
|
|
||||||
contains the resources. If multiple API groups are specified,
|
|
||||||
any action requested against one of the enumerated resources
|
|
||||||
in any API group will be allowed.
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
nonResourceURLs:
|
|
||||||
description: NonResourceURLs is a set of partial urls that
|
|
||||||
a user should have access to. *s are allowed, but only
|
|
||||||
as the full, final step in the path Since non-resource
|
|
||||||
URLs are not namespaced, this field is only applicable
|
|
||||||
for ClusterRoles referenced from a ClusterRoleBinding.
|
|
||||||
Rules can either apply to API resources (such as "pods"
|
|
||||||
or "secrets") or non-resource URL paths (such as "/api"), but
|
|
||||||
not both.
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
resourceNames:
|
|
||||||
description: ResourceNames is an optional white list of
|
|
||||||
names that the rule applies to. An empty set means that
|
|
||||||
everything is allowed.
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
resources:
|
|
||||||
description: Resources is a list of resources this rule
|
|
||||||
applies to. '*' represents all resources.
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
verbs:
|
|
||||||
description: Verbs is a list of Verbs that apply to ALL
|
|
||||||
the ResourceKinds contained in this rule. '*' represents
|
|
||||||
all verbs.
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
required:
|
|
||||||
- verbs
|
|
||||||
type: object
|
|
||||||
type: array
|
|
||||||
type: object
|
|
||||||
crossplane:
|
|
||||||
description: Semantic version constraints of Crossplane that package
|
|
||||||
is compatible with.
|
|
||||||
properties:
|
|
||||||
version:
|
|
||||||
description: Semantic version constraints of Crossplane that package
|
|
||||||
is compatible with.
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- version
|
|
||||||
type: object
|
|
||||||
dependsOn:
|
|
||||||
description: Dependencies on other packages.
|
|
||||||
items:
|
|
||||||
description: Dependency is a dependency on another package. One
|
|
||||||
of Provider or Configuration may be supplied.
|
|
||||||
properties:
|
|
||||||
configuration:
|
|
||||||
description: Configuration is the name of a Configuration package
|
|
||||||
image.
|
|
||||||
type: string
|
|
||||||
provider:
|
|
||||||
description: Provider is the name of a Provider package image.
|
|
||||||
type: string
|
|
||||||
version:
|
|
||||||
description: Version is the semantic version constraints of
|
|
||||||
the dependency image.
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- version
|
|
||||||
type: object
|
|
||||||
type: array
|
|
||||||
required:
|
|
||||||
- controller
|
|
||||||
type: object
|
|
||||||
required:
|
|
||||||
- spec
|
|
||||||
type: object
|
|
||||||
served: true
|
|
||||||
storage: true
|
|
||||||
- name: v1alpha1
|
|
||||||
schema:
|
|
||||||
openAPIV3Schema:
|
|
||||||
description: A Provider is the description of a Crossplane Provider package.
|
|
||||||
properties:
|
|
||||||
apiVersion:
|
|
||||||
description: 'APIVersion defines the versioned schema of this representation
|
|
||||||
of an object. Servers should convert recognized schemas to the latest
|
|
||||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
|
||||||
type: string
|
|
||||||
kind:
|
|
||||||
description: 'Kind is a string value representing the REST resource this
|
|
||||||
object represents. Servers may infer this from the endpoint the client
|
|
||||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
|
||||||
type: string
|
|
||||||
metadata:
|
|
||||||
type: object
|
|
||||||
spec:
|
|
||||||
description: ProviderSpec specifies the configuration of a Provider.
|
|
||||||
properties:
|
|
||||||
controller:
|
|
||||||
description: Configuration for the packaged Provider's controller.
|
|
||||||
properties:
|
|
||||||
image:
|
|
||||||
description: Image is the packaged Provider controller image.
|
|
||||||
type: string
|
|
||||||
permissionRequests:
|
|
||||||
description: PermissionRequests for RBAC rules required for this
|
|
||||||
provider's controller to function. The RBAC manager is responsible
|
|
||||||
for assessing the requested permissions.
|
|
||||||
items:
|
|
||||||
description: PolicyRule holds information that describes a policy
|
|
||||||
rule, but does not contain information about who the rule
|
|
||||||
applies to or which namespace the rule applies to.
|
|
||||||
properties:
|
|
||||||
apiGroups:
|
|
||||||
description: APIGroups is the name of the APIGroup that
|
|
||||||
contains the resources. If multiple API groups are specified,
|
|
||||||
any action requested against one of the enumerated resources
|
|
||||||
in any API group will be allowed.
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
nonResourceURLs:
|
|
||||||
description: NonResourceURLs is a set of partial urls that
|
|
||||||
a user should have access to. *s are allowed, but only
|
|
||||||
as the full, final step in the path Since non-resource
|
|
||||||
URLs are not namespaced, this field is only applicable
|
|
||||||
for ClusterRoles referenced from a ClusterRoleBinding.
|
|
||||||
Rules can either apply to API resources (such as "pods"
|
|
||||||
or "secrets") or non-resource URL paths (such as "/api"), but
|
|
||||||
not both.
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
resourceNames:
|
|
||||||
description: ResourceNames is an optional white list of
|
|
||||||
names that the rule applies to. An empty set means that
|
|
||||||
everything is allowed.
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
resources:
|
|
||||||
description: Resources is a list of resources this rule
|
|
||||||
applies to. '*' represents all resources.
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
verbs:
|
|
||||||
description: Verbs is a list of Verbs that apply to ALL
|
|
||||||
the ResourceKinds contained in this rule. '*' represents
|
|
||||||
all verbs.
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
required:
|
|
||||||
- verbs
|
|
||||||
type: object
|
|
||||||
type: array
|
|
||||||
type: object
|
|
||||||
crossplane:
|
|
||||||
description: Semantic version constraints of Crossplane that package
|
|
||||||
is compatible with.
|
|
||||||
properties:
|
|
||||||
version:
|
|
||||||
description: Semantic version constraints of Crossplane that package
|
|
||||||
is compatible with.
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- version
|
|
||||||
type: object
|
|
||||||
dependsOn:
|
|
||||||
description: Dependencies on other packages.
|
|
||||||
items:
|
|
||||||
description: Dependency is a dependency on another package. One
|
|
||||||
of Provider or Configuration may be supplied.
|
|
||||||
properties:
|
|
||||||
configuration:
|
|
||||||
description: Configuration is the name of a Configuration package
|
|
||||||
image.
|
|
||||||
type: string
|
|
||||||
provider:
|
|
||||||
description: Provider is the name of a Provider package image.
|
|
||||||
type: string
|
|
||||||
version:
|
|
||||||
description: Version is the semantic version constraints of
|
|
||||||
the dependency image.
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- version
|
|
||||||
type: object
|
|
||||||
type: array
|
|
||||||
required:
|
|
||||||
- controller
|
|
||||||
type: object
|
|
||||||
required:
|
|
||||||
- spec
|
|
||||||
type: object
|
|
||||||
served: true
|
|
||||||
storage: false
|
|
||||||
status:
|
|
||||||
acceptedNames:
|
|
||||||
kind: ""
|
|
||||||
plural: ""
|
|
||||||
conditions: []
|
|
||||||
storedVersions: []
|
|
|
@ -1,6 +0,0 @@
|
||||||
---
|
|
||||||
title: crossplane
|
|
||||||
weight: 401
|
|
||||||
layout: redirect
|
|
||||||
to: https://doc.crds.dev/github.com/crossplane/crossplane
|
|
||||||
---
|
|
|
@ -1,147 +0,0 @@
|
||||||
---
|
|
||||||
title: Adding Amazon Web Services (AWS) to Crossplane
|
|
||||||
tocHidden: true
|
|
||||||
---
|
|
||||||
|
|
||||||
In this guide, we will walk through the steps necessary to configure your AWS
|
|
||||||
account to be ready for integration with Crossplane. This will be done by adding
|
|
||||||
an AWS `ProviderConfig` resource type, which enables Crossplane to communicate with an
|
|
||||||
AWS account.
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
Prior to adding AWS to Crossplane, following steps need to be taken
|
|
||||||
|
|
||||||
- Crossplane is installed in a k8s cluster
|
|
||||||
- `provider-aws` is installed in the same cluster
|
|
||||||
- `kubectl` is configured to communicate with the same cluster
|
|
||||||
|
|
||||||
## Step 1: Configure `aws` CLI
|
|
||||||
|
|
||||||
Crossplane uses [AWS security credentials], and stores them as a [secret] which
|
|
||||||
is managed by an AWS `ProviderConfig` instance. In addition, the AWS default region is
|
|
||||||
also used for targeting a specific region. Crossplane requires to have [`aws`
|
|
||||||
command line tool] [installed] and [configured]. Once installed, the credentials
|
|
||||||
and configuration will reside in `~/.aws/credentials` and `~/.aws/config`
|
|
||||||
respectively.
|
|
||||||
|
|
||||||
## Step 2: Setup `aws` ProviderConfig
|
|
||||||
|
|
||||||
Run `setup.sh` to read `aws` credentials and region, and create an `aws
|
|
||||||
provider` instance in Crossplane:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -O https://raw.githubusercontent.com/crossplane/crossplane/release-1.9/docs/snippets/configure/aws/providerconfig.yaml
|
|
||||||
curl -O https://raw.githubusercontent.com/crossplane/crossplane/release-1.9/docs/snippets/configure/aws/setup.sh
|
|
||||||
chmod +x setup.sh
|
|
||||||
./setup.sh [--profile aws_profile]
|
|
||||||
```
|
|
||||||
|
|
||||||
The `--profile` switch is optional and specifies the [aws named profile] that
|
|
||||||
was set in Step 1. If not provided, the `default` profile will be selected.
|
|
||||||
|
|
||||||
Once the script is successfully executed, Crossplane will use the specified aws
|
|
||||||
account and region in the given named profile to create subsequent AWS managed
|
|
||||||
resources.
|
|
||||||
|
|
||||||
You can confirm the existence of the AWS `ProviderConfig` by running:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl get providerconfig default
|
|
||||||
```
|
|
||||||
|
|
||||||
## Optional: Setup AWS Provider Manually
|
|
||||||
|
|
||||||
An AWS [user][aws user] with `Administrative` privileges is needed to enable
|
|
||||||
Crossplane to create the required resources. Once the user is provisioned, an
|
|
||||||
[Access Key][] needs to be created so the user can have API access.
|
|
||||||
|
|
||||||
Using the set of [access key credentials][AWS security credentials] for the user
|
|
||||||
with the right access, we need to [install][install-aws] [`aws cli`][aws command
|
|
||||||
line tool], and then [configure][aws-cli-configure] it.
|
|
||||||
|
|
||||||
When the AWS cli is configured, the credentials and configuration will be in
|
|
||||||
`~/.aws/credentials` and `~/.aws/config` respectively. These will be consumed in
|
|
||||||
the next step.
|
|
||||||
|
|
||||||
When configuring the AWS cli, the user credentials could be configured under a
|
|
||||||
specific [AWS named profile][], or under `default`. Without loss of generality,
|
|
||||||
in this guide let's assume that the credentials are configured under the
|
|
||||||
`aws_profile` profile (which could also be `default`). We'll use this profile to
|
|
||||||
setup cloud provider in the next section.
|
|
||||||
|
|
||||||
Crossplane uses the AWS user credentials that were configured in the previous
|
|
||||||
step to create resources in AWS. These credentials will be stored as a
|
|
||||||
[secret][kubernetes secret] in Kubernetes, and will be used by an AWS
|
|
||||||
`ProviderConfig` instance. The default AWS region is also pulled from the cli
|
|
||||||
configuration, and added to the AWS provider.
|
|
||||||
|
|
||||||
To store the credentials as a secret, run:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# retrieve profile's credentials, save it under 'default' profile, and base64 encode it
|
|
||||||
BASE64ENCODED_AWS_ACCOUNT_CREDS=$(echo -e "[default]\naws_access_key_id = $(aws configure get aws_access_key_id --profile $aws_profile)\naws_secret_access_key = $(aws configure get aws_secret_access_key --profile $aws_profile)" | base64 | tr -d "\n")
|
|
||||||
```
|
|
||||||
|
|
||||||
Next, we'll need to create an AWS provider configuration:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cat > provider.yaml <<EOF
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Secret
|
|
||||||
metadata:
|
|
||||||
name: aws-account-creds
|
|
||||||
namespace: crossplane-system
|
|
||||||
type: Opaque
|
|
||||||
data:
|
|
||||||
creds: ${BASE64ENCODED_AWS_ACCOUNT_CREDS}
|
|
||||||
---
|
|
||||||
apiVersion: aws.crossplane.io/v1beta1
|
|
||||||
kind: ProviderConfig
|
|
||||||
metadata:
|
|
||||||
name: default
|
|
||||||
spec:
|
|
||||||
credentials:
|
|
||||||
source: Secret
|
|
||||||
secretRef:
|
|
||||||
namespace: crossplane-system
|
|
||||||
name: aws-account-creds
|
|
||||||
key: creds
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# apply it to the cluster:
|
|
||||||
kubectl apply -f "provider.yaml"
|
|
||||||
|
|
||||||
# delete the credentials variable
|
|
||||||
unset BASE64ENCODED_AWS_ACCOUNT_CREDS
|
|
||||||
```
|
|
||||||
|
|
||||||
The output will look like the following:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
secret/aws-user-creds created
|
|
||||||
provider.aws.crossplane.io/default created
|
|
||||||
```
|
|
||||||
|
|
||||||
Crossplane resources use the `ProviderConfig` named `default` if no specific
|
|
||||||
`ProviderConfig` is specified, so this `ProviderConfig` will be the default for
|
|
||||||
all AWS resources.
|
|
||||||
|
|
||||||
<!-- Named Links -->
|
|
||||||
|
|
||||||
[`aws` command line tool]: https://aws.amazon.com/cli/
|
|
||||||
[AWS SDK for GO]: https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/setting-up.html
|
|
||||||
[installed]: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html
|
|
||||||
[configured]: https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html
|
|
||||||
[AWS security credentials]: https://docs.aws.amazon.com/general/latest/gr/aws-security-credentials.html
|
|
||||||
[secret]:https://kubernetes.io/docs/concepts/configuration/secret/
|
|
||||||
[aws named profile]: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html
|
|
||||||
[aws user]: https://docs.aws.amazon.com/mediapackage/latest/ug/setting-up-create-iam-user.html
|
|
||||||
[Access Key]: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html
|
|
||||||
[AWS security credentials]: https://docs.aws.amazon.com/general/latest/gr/aws-security-credentials.html
|
|
||||||
[aws command line tool]: https://aws.amazon.com/cli/
|
|
||||||
[install-aws]: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html
|
|
||||||
[aws-cli-configure]: https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html
|
|
||||||
[kubernetes secret]: https://kubernetes.io/docs/concepts/configuration/secret/
|
|
||||||
[AWS named profile]: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html
|
|
|
@ -1,132 +0,0 @@
|
||||||
---
|
|
||||||
title: Adding Microsoft Azure to Crossplane
|
|
||||||
tocHidden: true
|
|
||||||
---
|
|
||||||
|
|
||||||
In this guide, we will walk through the steps necessary to configure your Azure
|
|
||||||
account to be ready for integration with Crossplane. The general steps we will
|
|
||||||
take are summarized below:
|
|
||||||
|
|
||||||
* Create a new service principal (account) that Crossplane will use to create
|
|
||||||
and manage Azure resources
|
|
||||||
* Add the required permissions to the account
|
|
||||||
* Consent to the permissions using an administrator account
|
|
||||||
|
|
||||||
## Preparing your Microsoft Azure Account
|
|
||||||
|
|
||||||
In order to manage resources in Azure, you must provide credentials for a Azure
|
|
||||||
service principal that Crossplane can use to authenticate. This assumes that you
|
|
||||||
have already [set up the Azure CLI
|
|
||||||
client](https://docs.microsoft.com/en-us/cli/azure/authenticate-azure-cli?view=azure-cli-latest)
|
|
||||||
with your credentials.
|
|
||||||
|
|
||||||
Create a JSON file that contains all the information needed to connect and
|
|
||||||
authenticate to Azure:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# create service principal with Owner role
|
|
||||||
az ad sp create-for-rbac --sdk-auth --role Owner > crossplane-azure-provider-key.json
|
|
||||||
```
|
|
||||||
|
|
||||||
Take note of the `clientID` value from the JSON file that we just created, and
|
|
||||||
save it to an environment variable:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export AZURE_CLIENT_ID=<clientId value from json file>
|
|
||||||
```
|
|
||||||
|
|
||||||
Now add the required permissions to the service principal that will allow it to
|
|
||||||
manage the necessary resources in Azure:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# add required Azure Active Directory permissions
|
|
||||||
az ad app permission add --id ${AZURE_CLIENT_ID} --api 00000002-0000-0000-c000-000000000000 --api-permissions 1cda74f2-2616-4834-b122-5cb1b07f8a59=Role 78c8a3c8-a07e-4b9e-af1b-b5ccab50a175=Role
|
|
||||||
|
|
||||||
# grant (activate) the permissions
|
|
||||||
az ad app permission grant --id ${AZURE_CLIENT_ID} --api 00000002-0000-0000-c000-000000000000 --expires never
|
|
||||||
```
|
|
||||||
|
|
||||||
You might see an error similar to the following, but that is OK, the permissions
|
|
||||||
should have gone through still:
|
|
||||||
|
|
||||||
```console
|
|
||||||
Operation failed with status: 'Conflict'. Details: 409 Client Error: Conflict for url: https://graph.windows.net/e7985bc4-a3b3-4f37-b9d2-fa256023b1ae/oauth2PermissionGrants?api-version=1.6
|
|
||||||
```
|
|
||||||
|
|
||||||
Finally, you need to grant admin permissions on the Azure Active Directory to
|
|
||||||
the service principal because it will need to create other service principals
|
|
||||||
for your `AKSCluster`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# grant admin consent to the service princinpal you created
|
|
||||||
az ad app permission admin-consent --id "${AZURE_CLIENT_ID}"
|
|
||||||
```
|
|
||||||
|
|
||||||
Note: You might need `Global Administrator` role to `Grant admin consent for
|
|
||||||
Default Directory`. Please contact the administrator of your Azure subscription.
|
|
||||||
To check your role, go to `Azure Active Directory` -> `Roles and
|
|
||||||
administrators`. You can find your role(s) by clicking on `Your Role (Preview)`
|
|
||||||
|
|
||||||
After these steps are completed, you should have the following file on your
|
|
||||||
local filesystem:
|
|
||||||
|
|
||||||
* `crossplane-azure-provider-key.json`
|
|
||||||
|
|
||||||
## Setup Azure ProviderConfig
|
|
||||||
|
|
||||||
Before creating any resources, we need to create and configure an Azure cloud
|
|
||||||
provider resource in Crossplane, which stores the cloud account information in
|
|
||||||
it. All the requests from Crossplane to Azure Cloud will use the credentials
|
|
||||||
attached to this provider resource. The following command assumes that you have
|
|
||||||
a `crossplane-azure-provider-key.json` file that belongs to the account you’d
|
|
||||||
like Crossplane to use.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
BASE64ENCODED_AZURE_ACCOUNT_CREDS=$(base64 crossplane-azure-provider-key.json | tr -d "\n")
|
|
||||||
```
|
|
||||||
|
|
||||||
Now we’ll create our `Secret` that contains the credential and `ProviderConfig`
|
|
||||||
resource that refers to that secret:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cat > provider.yaml <<EOF
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Secret
|
|
||||||
metadata:
|
|
||||||
name: azure-account-creds
|
|
||||||
namespace: crossplane-system
|
|
||||||
type: Opaque
|
|
||||||
data:
|
|
||||||
credentials: ${BASE64ENCODED_AZURE_ACCOUNT_CREDS}
|
|
||||||
---
|
|
||||||
apiVersion: azure.crossplane.io/v1beta1
|
|
||||||
kind: ProviderConfig
|
|
||||||
metadata:
|
|
||||||
name: default
|
|
||||||
spec:
|
|
||||||
credentials:
|
|
||||||
source: Secret
|
|
||||||
secretRef:
|
|
||||||
namespace: crossplane-system
|
|
||||||
name: azure-account-creds
|
|
||||||
key: credentials
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# apply it to the cluster:
|
|
||||||
kubectl apply -f "provider.yaml"
|
|
||||||
|
|
||||||
# delete the credentials variable
|
|
||||||
unset BASE64ENCODED_AZURE_ACCOUNT_CREDS
|
|
||||||
```
|
|
||||||
|
|
||||||
The output will look like the following:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
secret/azure-user-creds created
|
|
||||||
provider.azure.crossplane.io/default created
|
|
||||||
```
|
|
||||||
|
|
||||||
Crossplane resources use the `ProviderConfig` named `default` if no specific
|
|
||||||
`ProviderConfig` is specified, so this `ProviderConfig` will be the default for
|
|
||||||
all Azure resources.
|
|
|
@ -1,268 +0,0 @@
|
||||||
---
|
|
||||||
title: Adding Google Cloud Platform (GCP) to Crossplane
|
|
||||||
tocHidden: true
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
In this guide, we will walk through the steps necessary to configure your GCP
|
|
||||||
account to be ready for integration with Crossplane. The general steps we will
|
|
||||||
take are summarized below:
|
|
||||||
|
|
||||||
* Create a new example project that all resources will be deployed to
|
|
||||||
* Enable required APIs such as Kubernetes and CloudSQL
|
|
||||||
* Create a service account that will be used to perform GCP operations from
|
|
||||||
Crossplane
|
|
||||||
* Assign necessary roles to the service account
|
|
||||||
* Enable billing
|
|
||||||
|
|
||||||
For your convenience, the specific steps to accomplish those tasks are provided
|
|
||||||
for you below using either the `gcloud` command line tool, or the GCP console in
|
|
||||||
a web browser. You can choose whichever you are more comfortable with.
|
|
||||||
|
|
||||||
## Option 1: gcloud Command Line Tool
|
|
||||||
|
|
||||||
If you have the `gcloud` tool installed, you can run the commands below from the
|
|
||||||
crossplane directory.
|
|
||||||
|
|
||||||
Instructions for installing `gcloud` can be found in the [Google
|
|
||||||
docs](https://cloud.google.com/sdk/install).
|
|
||||||
|
|
||||||
### Using `gcp-credentials.sh`
|
|
||||||
|
|
||||||
Crossplane provides a helper script for configuring GCP credentials. This script
|
|
||||||
will prompt you for the organization, project, and billing account that will be
|
|
||||||
used by `gcloud` when creating a project, service account, and credentials file
|
|
||||||
(`crossplane-gcp-provider-key.json`). The chosen project and created service
|
|
||||||
account will have access to the services and roles sufficient to run the
|
|
||||||
Crossplane GCP examples.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -O https://raw.githubusercontent.com/crossplane/crossplane/release-1.9/docs/snippets/configure/gcp/credentials.sh
|
|
||||||
./credentials.sh
|
|
||||||
# ... EXAMPLE OUTPUT ONLY
|
|
||||||
# export ORGANIZATION_ID=987654321
|
|
||||||
# export PROJECT_ID=crossplane-example-1234
|
|
||||||
# export EXAMPLE_SA=example-1234@crossplane-example-1234.iam.gserviceaccount.com
|
|
||||||
# export BASE64ENCODED_GCP_PROVIDER_CREDS=$(base64 crossplane-gcp-provider-key.json | tr -d "\n")
|
|
||||||
```
|
|
||||||
|
|
||||||
After running `gcp-credentials.sh`, a series of `export` commands will be shown.
|
|
||||||
Copy and paste the `export` commands that are provided. These variable names
|
|
||||||
will be referenced throughout the Crossplane examples, generally with a `sed`
|
|
||||||
command.
|
|
||||||
|
|
||||||
You will also find a `crossplane-gcp-provider-key.json` file in the current
|
|
||||||
working directory. Be sure to remove this file when you are done with the
|
|
||||||
example projects.
|
|
||||||
|
|
||||||
### Running `gcloud` by hand
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# list your organizations (if applicable), take note of the specific organization ID you want to use
|
|
||||||
# if you have more than one organization (not common)
|
|
||||||
gcloud organizations list
|
|
||||||
|
|
||||||
# create a new project (project id must be <=30 characters)
|
|
||||||
export EXAMPLE_PROJECT_ID=crossplane-example-123
|
|
||||||
gcloud projects create $EXAMPLE_PROJECT_ID --enable-cloud-apis # [--organization $ORGANIZATION_ID]
|
|
||||||
|
|
||||||
# or, record the PROJECT_ID value of an existing project
|
|
||||||
# export EXAMPLE_PROJECT_ID=$(gcloud projects list --filter NAME=$EXAMPLE_PROJECT_NAME --format="value(PROJECT_ID)")
|
|
||||||
|
|
||||||
# link billing to the new project
|
|
||||||
gcloud beta billing accounts list
|
|
||||||
gcloud beta billing projects link $EXAMPLE_PROJECT_ID --billing-account=$ACCOUNT_ID
|
|
||||||
|
|
||||||
# enable Kubernetes API
|
|
||||||
gcloud --project $EXAMPLE_PROJECT_ID services enable container.googleapis.com
|
|
||||||
|
|
||||||
# enable CloudSQL API
|
|
||||||
gcloud --project $EXAMPLE_PROJECT_ID services enable sqladmin.googleapis.com
|
|
||||||
|
|
||||||
# enable Redis API
|
|
||||||
gcloud --project $EXAMPLE_PROJECT_ID services enable redis.googleapis.com
|
|
||||||
|
|
||||||
# enable Compute API
|
|
||||||
gcloud --project $EXAMPLE_PROJECT_ID services enable compute.googleapis.com
|
|
||||||
|
|
||||||
# enable Service Networking API
|
|
||||||
gcloud --project $EXAMPLE_PROJECT_ID services enable servicenetworking.googleapis.com
|
|
||||||
|
|
||||||
# enable Additional APIs needed for the example or project
|
|
||||||
# See `gcloud services list` for a complete list
|
|
||||||
|
|
||||||
# create service account
|
|
||||||
gcloud --project $EXAMPLE_PROJECT_ID iam service-accounts create example-123 --display-name "Crossplane Example"
|
|
||||||
|
|
||||||
# export service account email
|
|
||||||
export EXAMPLE_SA="example-123@$EXAMPLE_PROJECT_ID.iam.gserviceaccount.com"
|
|
||||||
|
|
||||||
# create service account key (this will create a `crossplane-gcp-provider-key.json` file in your current working directory)
|
|
||||||
gcloud --project $EXAMPLE_PROJECT_ID iam service-accounts keys create --iam-account $EXAMPLE_SA crossplane-gcp-provider-key.json
|
|
||||||
|
|
||||||
# assign roles
|
|
||||||
gcloud projects add-iam-policy-binding $EXAMPLE_PROJECT_ID --member "serviceAccount:$EXAMPLE_SA" --role="roles/iam.serviceAccountUser"
|
|
||||||
gcloud projects add-iam-policy-binding $EXAMPLE_PROJECT_ID --member "serviceAccount:$EXAMPLE_SA" --role="roles/cloudsql.admin"
|
|
||||||
gcloud projects add-iam-policy-binding $EXAMPLE_PROJECT_ID --member "serviceAccount:$EXAMPLE_SA" --role="roles/container.admin"
|
|
||||||
gcloud projects add-iam-policy-binding $EXAMPLE_PROJECT_ID --member "serviceAccount:$EXAMPLE_SA" --role="roles/redis.admin"
|
|
||||||
gcloud projects add-iam-policy-binding $EXAMPLE_PROJECT_ID --member "serviceAccount:$EXAMPLE_SA" --role="roles/compute.networkAdmin"
|
|
||||||
gcloud projects add-iam-policy-binding $EXAMPLE_PROJECT_ID --member "serviceAccount:$EXAMPLE_SA" --role="roles/storage.admin"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Option 2: GCP Console in a Web Browser
|
|
||||||
|
|
||||||
If you chose to use the `gcloud` tool, you can skip this section entirely.
|
|
||||||
|
|
||||||
Create a GCP example project which we will use to host our example GKE cluster,
|
|
||||||
as well as our example CloudSQL instance.
|
|
||||||
|
|
||||||
- Login into [GCP Console](https://console.cloud.google.com)
|
|
||||||
- Create a [new
|
|
||||||
project](https://console.cloud.google.com/flows/enableapi?apiid=container.googleapis.com,sqladmin.googleapis.com,redis.googleapis.com)
|
|
||||||
(either stand alone or under existing organization)
|
|
||||||
- Create Example Service Account
|
|
||||||
- Navigate to: [Create Service
|
|
||||||
Account](https://console.cloud.google.com/iam-admin/serviceaccounts)
|
|
||||||
- `Service Account Name`: type "example"
|
|
||||||
- `Service Account ID`: leave auto assigned
|
|
||||||
- `Service Account Description`: type "Crossplane example"
|
|
||||||
- Click `Create and Continue` button
|
|
||||||
- This should advance to the next section `2 Grant this service account to
|
|
||||||
project (optional)`
|
|
||||||
- We will assign this account 4 roles:
|
|
||||||
- `Service Account User`
|
|
||||||
- `Cloud SQL Admin`
|
|
||||||
- `Kubernetes Engine Admin`
|
|
||||||
- `Compute Network Admin`
|
|
||||||
- Click `Continue` button
|
|
||||||
- This should advance to the next section `3 Grant users access to this
|
|
||||||
service account (optional)`
|
|
||||||
- We don't need to assign any user or admin roles to this account for the
|
|
||||||
example purposes, so you can leave following two fields blank:
|
|
||||||
- `Service account users role`
|
|
||||||
- `Service account admins role`
|
|
||||||
- Next, we will create and export service account key
|
|
||||||
- Click `+ Create Key` button.
|
|
||||||
- This should open a `Create Key` side panel
|
|
||||||
- Select `json` for the Key type (should be selected by default)
|
|
||||||
- Click `Create`
|
|
||||||
- This should show `Private key saved to your computer` confirmation
|
|
||||||
dialog
|
|
||||||
- You also should see `crossplane-example-1234-[suffix].json` file in your
|
|
||||||
browser's Download directory
|
|
||||||
- Save (copy or move) this file into example (this) directory, with new
|
|
||||||
name `crossplane-gcp-provider-key.json`
|
|
||||||
- Enable `Cloud SQL API`
|
|
||||||
- Navigate to [Cloud SQL Admin
|
|
||||||
API](https://console.developers.google.com/apis/api/sqladmin.googleapis.com/overview)
|
|
||||||
- Click `Enable`
|
|
||||||
- Enable `Kubernetes Engine API`
|
|
||||||
- Navigate to [Kubernetes Engine
|
|
||||||
API](https://console.developers.google.com/apis/api/container.googleapis.com/overview)
|
|
||||||
- Click `Enable`
|
|
||||||
- Enable `Cloud Memorystore for Redis`
|
|
||||||
- Navigate to [Cloud Memorystore for
|
|
||||||
Redis](https://console.developers.google.com/apis/api/redis.googleapis.com/overview)
|
|
||||||
- Click `Enable`
|
|
||||||
- Enable `Compute Engine API`
|
|
||||||
- Navigate to [Compute Engine
|
|
||||||
API](https://console.developers.google.com/apis/api/compute.googleapis.com/overview)
|
|
||||||
- Click `Enable`
|
|
||||||
- Enable `Service Networking API`
|
|
||||||
- Navigate to [Service Networking
|
|
||||||
API](https://console.developers.google.com/apis/api/servicenetworking.googleapis.com/overview)
|
|
||||||
- Click `Enable`
|
|
||||||
|
|
||||||
### Enable Billing
|
|
||||||
|
|
||||||
You will need to enable billing for your account in order to create and use
|
|
||||||
Kubernetes clusters with GKE.
|
|
||||||
|
|
||||||
- Go to [GCP Console](https://console.cloud.google.com)
|
|
||||||
- Select example project
|
|
||||||
- Click `Enable Billing`
|
|
||||||
- Go to [Kubernetes Clusters](https://console.cloud.google.com/kubernetes/list)
|
|
||||||
- Click `Enable Billing`
|
|
||||||
|
|
||||||
## Setup GCP ProviderConfig
|
|
||||||
|
|
||||||
Before creating any resources, we need to create and configure a GCP cloud
|
|
||||||
`ProviderConfig` resource in Crossplane, which stores the cloud account
|
|
||||||
information in it. All the requests from Crossplane to GCP will use the
|
|
||||||
credentials attached to this `ProviderConfig` resource. The following command
|
|
||||||
assumes that you have a `crossplane-gcp-provider-key.json` file that belongs to
|
|
||||||
the account that will be used by Crossplane, which has GCP project id. You
|
|
||||||
should be able to get the project id from the JSON credentials file or from the
|
|
||||||
GCP console. Without loss of generality, let's assume the project id is
|
|
||||||
`my-cool-gcp-project` in this guide.
|
|
||||||
|
|
||||||
First, let's encode the credential file contents and put it in a variable:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# base64 encode the GCP credentials
|
|
||||||
BASE64ENCODED_GCP_PROVIDER_CREDS=$(base64 crossplane-gcp-provider-key.json | tr -d "\n")
|
|
||||||
```
|
|
||||||
|
|
||||||
Next, store the project ID of the GCP project in which you would like to
|
|
||||||
provision infrastructure as a variable:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# replace this with your own gcp project id
|
|
||||||
PROJECT_ID=my-cool-gcp-project
|
|
||||||
```
|
|
||||||
|
|
||||||
Finally, store the namespace in which you want to save the provider's secret as
|
|
||||||
a variable:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# change this namespace value if you want to use a different namespace (e.g. gitlab-managed-apps)
|
|
||||||
PROVIDER_SECRET_NAMESPACE=crossplane-system
|
|
||||||
```
|
|
||||||
|
|
||||||
Now we’ll create the `Secret` resource that contains the credential, and
|
|
||||||
`ProviderConfig` resource which refers to that secret:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cat > provider.yaml <<EOF
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Secret
|
|
||||||
metadata:
|
|
||||||
name: gcp-account-creds
|
|
||||||
namespace: ${PROVIDER_SECRET_NAMESPACE}
|
|
||||||
type: Opaque
|
|
||||||
data:
|
|
||||||
creds: ${BASE64ENCODED_GCP_PROVIDER_CREDS}
|
|
||||||
---
|
|
||||||
apiVersion: gcp.crossplane.io/v1beta1
|
|
||||||
kind: ProviderConfig
|
|
||||||
metadata:
|
|
||||||
name: default
|
|
||||||
spec:
|
|
||||||
# replace this with your own gcp project id
|
|
||||||
projectID: ${PROJECT_ID}
|
|
||||||
credentials:
|
|
||||||
source: Secret
|
|
||||||
secretRef:
|
|
||||||
namespace: ${PROVIDER_SECRET_NAMESPACE}
|
|
||||||
name: gcp-account-creds
|
|
||||||
key: creds
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# apply it to the cluster:
|
|
||||||
kubectl apply -f "provider.yaml"
|
|
||||||
|
|
||||||
# delete the credentials
|
|
||||||
unset BASE64ENCODED_GCP_PROVIDER_CREDS
|
|
||||||
```
|
|
||||||
|
|
||||||
The output will look like the following:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
secret/gcp-account-creds created
|
|
||||||
provider.gcp.crossplane.io/default created
|
|
||||||
```
|
|
||||||
|
|
||||||
Crossplane resources use the `ProviderConfig` named `default` if no specific
|
|
||||||
`ProviderConfig` is specified, so this `ProviderConfig` will be the default for
|
|
||||||
all GCP resources.
|
|
|
@ -1,250 +0,0 @@
|
||||||
---
|
|
||||||
title: Composite Resources
|
|
||||||
weight: 103
|
|
||||||
---
|
|
||||||
|
|
||||||
Crossplane Composite Resources are opinionated Kubernetes Custom Resources that
|
|
||||||
are _composed_ of [Managed Resources][managed-resources]. We often call them XRs
|
|
||||||
for short.
|
|
||||||
|
|
||||||
![Diagram of claims, XRs, and Managed Resources][xrs-and-mrs]
|
|
||||||
|
|
||||||
Composite Resources are designed to let you build your own platform with your
|
|
||||||
own opinionated concepts and APIs without needing to write a Kubernetes
|
|
||||||
controller from scratch. Instead, you define the schema of your XR and teach
|
|
||||||
Crossplane which Managed Resources it should compose (i.e. create) when someone
|
|
||||||
creates the XR you defined.
|
|
||||||
|
|
||||||
If you're already familiar with Composite Resources and looking for a detailed
|
|
||||||
configuration reference or some tips, tricks, and troubleshooting information,
|
|
||||||
try the [Composition Reference][xr-ref].
|
|
||||||
|
|
||||||
Below is an example of a Composite Resource:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: database.example.org/v1alpha1
|
|
||||||
kind: XPostgreSQLInstance
|
|
||||||
metadata:
|
|
||||||
name: my-db
|
|
||||||
spec:
|
|
||||||
parameters:
|
|
||||||
storageGB: 20
|
|
||||||
compositionRef:
|
|
||||||
name: production
|
|
||||||
writeConnectionSecretToRef:
|
|
||||||
namespace: crossplane-system
|
|
||||||
name: my-db-connection-details
|
|
||||||
```
|
|
||||||
|
|
||||||
You define your own XRs, so they can be of whatever API version and kind you
|
|
||||||
like, and contain whatever spec and status fields you need.
|
|
||||||
|
|
||||||
## How It Works
|
|
||||||
|
|
||||||
The first step towards using Composite Resources is configuring Crossplane so
|
|
||||||
that it knows what XRs you'd like to exist, and what to do when someone creates
|
|
||||||
one of those XRs. This is done using a `CompositeResourceDefinition` (XRD)
|
|
||||||
resource and one or more `Composition` resources.
|
|
||||||
|
|
||||||
Once you've configured Crossplane with the details of your new XR you can either
|
|
||||||
create one directly, or use a _claim_. Typically only the folks responsible for
|
|
||||||
configuring Crossplane (often a platform or SRE team) have permission to create
|
|
||||||
XRs directly. Everyone else manages XRs via a lightweight proxy resource called
|
|
||||||
a Composite Resource Claim (or claim for short). More on that later.
|
|
||||||
|
|
||||||
![Diagram combining all Composition concepts][how-it-works]
|
|
||||||
|
|
||||||
> If you're coming from the Terraform world you can think of an XRD as similar
|
|
||||||
> to the `variable` blocks of a Terraform module, while the `Composition` is
|
|
||||||
> the rest of the module's HCL code that describes how to use those variables to
|
|
||||||
> create a bunch of resources. In this analogy the XR or claim is a little like
|
|
||||||
> a `tfvars` file providing inputs to the module.
|
|
||||||
|
|
||||||
### Defining Composite Resources
|
|
||||||
|
|
||||||
A `CompositeResourceDefinition` (or XRD) defines the type and schema of your XR.
|
|
||||||
It lets Crossplane know that you want a particular kind of XR to exist, and what
|
|
||||||
fields that XR should have. An XRD is a little like a `CustomResourceDefinition`
|
|
||||||
(CRD), but slightly more opinionated. Writing an XRD is mostly a matter of
|
|
||||||
specifying an OpenAPI ["structural schema"][crd-docs].
|
|
||||||
|
|
||||||
The XRD that defines the `XPostgreSQLInstance` XR above would look like this:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: apiextensions.crossplane.io/v1
|
|
||||||
kind: CompositeResourceDefinition
|
|
||||||
metadata:
|
|
||||||
name: xpostgresqlinstances.database.example.org
|
|
||||||
spec:
|
|
||||||
group: database.example.org
|
|
||||||
names:
|
|
||||||
kind: XPostgreSQLInstance
|
|
||||||
plural: xpostgresqlinstances
|
|
||||||
claimNames:
|
|
||||||
kind: PostgreSQLInstance
|
|
||||||
plural: postgresqlinstances
|
|
||||||
versions:
|
|
||||||
- name: v1alpha1
|
|
||||||
served: true
|
|
||||||
referenceable: true
|
|
||||||
schema:
|
|
||||||
openAPIV3Schema:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
spec:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
parameters:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
storageGB:
|
|
||||||
type: integer
|
|
||||||
required:
|
|
||||||
- storageGB
|
|
||||||
required:
|
|
||||||
- parameters
|
|
||||||
```
|
|
||||||
|
|
||||||
You might notice that the `XPostgreSQLInstance` example above has some fields
|
|
||||||
that don't appear in the XRD, like the `writeConnectionSecretToRef` and
|
|
||||||
`compositionRef` fields. This is because Crossplane automatically injects some
|
|
||||||
standard Crossplane Resource Model (XRM) fields into all XRs.
|
|
||||||
|
|
||||||
### Configuring Composition
|
|
||||||
|
|
||||||
A `Composition` lets Crossplane know what to do when someone creates a Composite
|
|
||||||
Resource. Each `Composition` creates a link between an XR and a set of one or
|
|
||||||
more Managed Resources - when the XR is created, updated, or deleted the set of
|
|
||||||
Managed Resources are created, updated or deleted accordingly.
|
|
||||||
|
|
||||||
You can add multiple Compositions for each XRD, and choose which should be used
|
|
||||||
when XRs are created. This allows a Composition to act like a class of service -
|
|
||||||
for example you could configure one Composition for each environment you
|
|
||||||
support, such as production, staging, and development.
|
|
||||||
|
|
||||||
A basic `Composition` for the above `XPostgreSQLInstance` might look like this:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: apiextensions.crossplane.io/v1
|
|
||||||
kind: Composition
|
|
||||||
metadata:
|
|
||||||
name: example
|
|
||||||
labels:
|
|
||||||
crossplane.io/xrd: xpostgresqlinstances.database.example.org
|
|
||||||
provider: gcp
|
|
||||||
spec:
|
|
||||||
writeConnectionSecretsToNamespace: crossplane-system
|
|
||||||
compositeTypeRef:
|
|
||||||
apiVersion: database.example.org/v1alpha1
|
|
||||||
kind: XPostgreSQLInstance
|
|
||||||
resources:
|
|
||||||
- name: cloudsqlinstance
|
|
||||||
base:
|
|
||||||
apiVersion: database.gcp.crossplane.io/v1beta1
|
|
||||||
kind: CloudSQLInstance
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
databaseVersion: POSTGRES_12
|
|
||||||
region: us-central1
|
|
||||||
settings:
|
|
||||||
tier: db-custom-1-3840
|
|
||||||
dataDiskType: PD_SSD
|
|
||||||
ipConfiguration:
|
|
||||||
ipv4Enabled: true
|
|
||||||
authorizedNetworks:
|
|
||||||
- value: "0.0.0.0/0"
|
|
||||||
patches:
|
|
||||||
- type: FromCompositeFieldPath
|
|
||||||
fromFieldPath: spec.parameters.storageGB
|
|
||||||
toFieldPath: spec.forProvider.settings.dataDiskSizeGb
|
|
||||||
```
|
|
||||||
|
|
||||||
The above `Composition` tells Crossplane that when someone creates an
|
|
||||||
`XPostgreSQLInstance` XR Crossplane should create a `CloudSQLInstance` in
|
|
||||||
response. The `storageGB` field of the `XPostgreSQLInstance` should be used to
|
|
||||||
configure the `dataDiskSizeGb` field of the `CloudSQLInstance`. This is only a
|
|
||||||
small subset of the functionality a `Composition` enables - take a look at the
|
|
||||||
[reference page][xr-ref] to learn more.
|
|
||||||
|
|
||||||
> We almost always talk about XRs composing Managed Resources, but actually an
|
|
||||||
> XR can also compose other XRs to allow nested layers of abstraction. XRs don't
|
|
||||||
> support composing arbitrary Kubernetes resources (e.g. Deployments, operators,
|
|
||||||
> etc) directly but you can do so using our [Kubernetes][provider-kubernetes]
|
|
||||||
> and [Helm][provider-helm] providers.
|
|
||||||
|
|
||||||
### Claiming Composite Resources
|
|
||||||
|
|
||||||
Crossplane uses Composite Resource Claims (or just claims, for short) to allow
|
|
||||||
application operators to provision and manage XRs. When we talk about using XRs
|
|
||||||
it's typically implied that the XR is being used via a claim. Claims are almost
|
|
||||||
identical to their corresponding XRs. It helps to think of a claim as an
|
|
||||||
application team’s interface to an XR. You could also think of claims as the
|
|
||||||
public (app team) facing part of the opinionated platform API, while XRs are the
|
|
||||||
private (platform team) facing part.
|
|
||||||
|
|
||||||
A claim for the `XPostgreSQLInstance` XR above would look like this:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: database.example.org/v1alpha1
|
|
||||||
kind: PostgreSQLInstance
|
|
||||||
metadata:
|
|
||||||
namespace: default
|
|
||||||
name: my-db
|
|
||||||
spec:
|
|
||||||
parameters:
|
|
||||||
storageGB: 20
|
|
||||||
compositionRef:
|
|
||||||
name: production
|
|
||||||
writeConnectionSecretToRef:
|
|
||||||
name: my-db-connection-details
|
|
||||||
```
|
|
||||||
|
|
||||||
There are three key differences between an XR and a claim:
|
|
||||||
|
|
||||||
1. Claims are namespaced, while XRs (and Managed Resources) are cluster scoped.
|
|
||||||
1. Claims are of a different `kind` than the XR - by convention the XR's `kind`
|
|
||||||
without the proceeding `X`. For example a `PostgreSQLInstance` claims an
|
|
||||||
`XPostgreSQLInstance`.
|
|
||||||
1. An active claim contains a reference to its corresponding XR, while an XR
|
|
||||||
contains both a reference to the claim an array of references to the managed
|
|
||||||
resources it composes.
|
|
||||||
|
|
||||||
Not all XRs offer a claim - doing so is optional. See the XRD section of the
|
|
||||||
[Composition reference][xr-ref] to learn how to offer a claim.
|
|
||||||
|
|
||||||
![Diagram showing the relationship between claims and XRs][claims-and-xrs]
|
|
||||||
|
|
||||||
Claims may seem a little superfluous at first, but they enable some handy
|
|
||||||
scenarios, including:
|
|
||||||
|
|
||||||
- **Private XRs.** Sometimes a platform team might not want a type of XR to be
|
|
||||||
directly consumed by their application teams. For example because the XR
|
|
||||||
represents 'supporting' infrastructure - consider the above VPC `XNetwork` XR. App
|
|
||||||
teams might create `PostgreSQLInstance` claims that _reference_ (i.e. consume)
|
|
||||||
an `XNetwork`, but they shouldn't be _creating their own_. Similarly, some
|
|
||||||
kinds of XR might be intended only for 'nested' use - intended only to be
|
|
||||||
composed by other XRs.
|
|
||||||
|
|
||||||
- **Global XRs**. Not all infrastructure is conceptually namespaced. Say your
|
|
||||||
organisation uses team scoped namespaces. A `PostgreSQLInstance` that belongs
|
|
||||||
to Team A should probably be part of the `team-a` namespace - you'd represent
|
|
||||||
this by creating a `PostgreSQLInstance` claim in that namespace. On the other
|
|
||||||
hand the `XNetwork` XR we mentioned previously could be referenced (i.e. used)
|
|
||||||
by XRs from many different namespaces - it doesn't exist to serve a particular
|
|
||||||
team.
|
|
||||||
|
|
||||||
- **Pre-provisioned XRs**. Finally, separating claims from XRs allows a platform
|
|
||||||
team to pre-provision certain kinds of XR. Typically an XR is created
|
|
||||||
on-demand in response to the creation of a claim, but it's also possible for a
|
|
||||||
claim to instead request an existing XR. This can allow application teams to
|
|
||||||
instantly claim infrastructure like database instances that would otherwise
|
|
||||||
take minutes to provision on-demand.
|
|
||||||
|
|
||||||
[managed-resources]: {{<ref "managed-resources" >}}
|
|
||||||
[xrs-and-mrs]: /media/composition-xrs-and-mrs.svg
|
|
||||||
[xr-ref]: {{<ref "../reference/composition" >}}
|
|
||||||
[how-it-works]: /media/composition-how-it-works.svg
|
|
||||||
[crd-docs]: https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/
|
|
||||||
[provider-kubernetes]: https://marketplace.upbound.io/providers/crossplane-contrib/provider-kubernetes
|
|
||||||
[provider-helm]: https://marketplace.upbound.io/providers/crossplane-contrib/provider-helm/
|
|
||||||
[claims-and-xrs]: /media/composition-claims-and-xrs.svg
|
|
|
@ -1,17 +0,0 @@
|
||||||
---
|
|
||||||
title: Contributing
|
|
||||||
weight: 1000
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
The best place to start if you're thinking about contributing to Crossplane is
|
|
||||||
our [`CONTRIBUTING.md`] file. The following documents supplement that guide.
|
|
||||||
|
|
||||||
1. [Provider Development Guide]
|
|
||||||
2. [Observability Developer Guide]
|
|
||||||
3. [Release Process]
|
|
||||||
|
|
||||||
[`CONTRIBUTING.md`]: https://github.com/crossplane/crossplane/blob/master/CONTRIBUTING.md
|
|
||||||
[Provider Development Guide]: {{<ref "provider_development_guide" >}}
|
|
||||||
[Observability Developer Guide]: {{<ref "observability_developer_guide" >}}
|
|
||||||
[Release Process]: {{<ref "release-process" >}}
|
|
|
@ -1,135 +0,0 @@
|
||||||
---
|
|
||||||
title: Adding Secret Store Support
|
|
||||||
weight: 1004
|
|
||||||
---
|
|
||||||
|
|
||||||
To add support for [External Secret Stores] in a provider, we need the following
|
|
||||||
changes at a high level:
|
|
||||||
|
|
||||||
1. Bump Crossplane Runtime and Crossplane Tools to latest and generate existing
|
|
||||||
resources to include `PublishConnectionDetails` API.
|
|
||||||
2. Add a new Type and CRD for Secret StoreConfig.
|
|
||||||
3. Add feature flag for enabling External Secret Store support.
|
|
||||||
4. Add Secret Store Connection Details Manager as a `ConnectionPublisher` if
|
|
||||||
feature enabled.
|
|
||||||
|
|
||||||
In this document, we will go through each step in details. You can check
|
|
||||||
[this PR as a complete example].
|
|
||||||
|
|
||||||
> If your provider is a Terrajet based provider, then please check
|
|
||||||
> [this PR instead].
|
|
||||||
|
|
||||||
## Steps
|
|
||||||
|
|
||||||
**1. Bump Crossplane Runtime and Crossplane Tools to latest and generate
|
|
||||||
existing resources to include `PublishConnectionDetails` API.**
|
|
||||||
|
|
||||||
We need a workaround for code generation since latest runtime both adds new API
|
|
||||||
but also adds a new interface to managed.resourceSpec. Without this workaround,
|
|
||||||
expect errors similar to below:
|
|
||||||
|
|
||||||
```console
|
|
||||||
16:40:56 [ .. ] go generate darwin_amd64
|
|
||||||
angryjet: error: error loading packages using pattern ./...: /Users/hasanturken/ Workspace/crossplane/provider-gcp/apis/cache/v1beta1/zz_ generated.managedlist.go:27:14: cannot use &l.Items[i] (value of type * CloudMemorystoreInstance) as "github.com/crossplane/crossplane-runtime/pkg/ resource".Managed value in assignment: missing method GetPublishConnectionDetailsTo
|
|
||||||
exit status 1
|
|
||||||
apis/generate.go:30: running "go": exit status 1
|
|
||||||
16:41:04 [FAIL]
|
|
||||||
make[1]: *** [go.generate] Error 1
|
|
||||||
make: *** [generate] Error 2
|
|
||||||
```
|
|
||||||
|
|
||||||
First, we need to consume a temporary runtime version together with the latest
|
|
||||||
Crossplane Tools:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
go mod edit -replace=github.com/crossplane/crossplane-runtime=github.com/turkenh/crossplane-runtime@v0.0.0-20220314141040-6f74175d3c1f
|
|
||||||
go get github.com/crossplane/crossplane-tools@master
|
|
||||||
|
|
||||||
go mod tidy
|
|
||||||
```
|
|
||||||
|
|
||||||
Then, remove `trivialVersions=true` in the file `api/generate.go`:
|
|
||||||
|
|
||||||
```diff
|
|
||||||
-//go:generate go run -tags generate sigs.k8s.io/controller-tools/cmd/controller-gen object:headerFile=../hack/boilerplate.go.txt paths=./... crd:trivialVersions=true,crdVersions=v1 output:artifacts:config=../package/crds
|
|
||||||
+//go:generate go run -tags generate sigs.k8s.io/controller-tools/cmd/controller-gen object:headerFile=../hack/boilerplate.go.txt paths=./... crd:crdVersions=v1 output:artifacts:config=../package/crds
|
|
||||||
```
|
|
||||||
|
|
||||||
Now, we can generate CRDs with `PublishConnectionDetailsTo` API:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
make generate
|
|
||||||
```
|
|
||||||
|
|
||||||
Finally, we can revert our workaround by consuming the latest Crossplane
|
|
||||||
Runtime:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
go mod edit -dropreplace=github.com/crossplane/crossplane-runtime
|
|
||||||
go get github.com/crossplane/crossplane-runtime@master
|
|
||||||
go mod tidy
|
|
||||||
make generate
|
|
||||||
```
|
|
||||||
|
|
||||||
**2. Add a new Type and CRD for Secret StoreConfig.**
|
|
||||||
|
|
||||||
See [this commit as an example on how to add the type]. It is expected to be
|
|
||||||
almost same for all providers except groupName which includes the name short
|
|
||||||
name of the provider (e.g. `gcp.crossplane.io`)
|
|
||||||
|
|
||||||
Generate the CRD with:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
make generate
|
|
||||||
```
|
|
||||||
|
|
||||||
**3. Add feature flag for enabling External Secret Store support.**
|
|
||||||
|
|
||||||
We will add a feature flag to enable the feature which would be off by default.
|
|
||||||
As part of this step, we will also create a `default` `StoreConfig` during
|
|
||||||
provider start up, which stores connection secrets into the same Kubernetes
|
|
||||||
cluster.
|
|
||||||
|
|
||||||
To be consistent across all providers, please define
|
|
||||||
`--enable-external-secret-stores` as a boolean which is false by default.
|
|
||||||
|
|
||||||
See [this commit as an example for adding the feature flag].
|
|
||||||
|
|
||||||
**4. Add Secret Store Connection Details Manager as a `ConnectionPublisher` if
|
|
||||||
feature enabled.**
|
|
||||||
|
|
||||||
Add the following to the Setup function controller. Unfortunately this step
|
|
||||||
requires some dirty work as we need to this for all types:
|
|
||||||
|
|
||||||
```diff
|
|
||||||
func SetupServiceAccountKey(mgr ctrl.Manager, o controller.Options) error {
|
|
||||||
name := managed.ControllerName(v1alpha1.ServiceAccountKeyGroupKind)
|
|
||||||
|
|
||||||
+ cps := []managed.ConnectionPublisher{managed.NewAPISecretPublisher(mgr.GetClient(), mgr.GetScheme())}
|
|
||||||
+ if o.Features.Enabled(features.EnableAlphaExternalSecretStores) {
|
|
||||||
+ cps = append(cps, connection.NewDetailsManager(mgr.GetClient(), scv1alpha1.StoreConfigGroupVersionKind))
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
r := managed.NewReconciler(mgr,
|
|
||||||
resource.ManagedKind(v1alpha1.ServiceAccountKeyGroupVersionKind),
|
|
||||||
managed.WithInitializers(),
|
|
||||||
managed.WithExternalConnecter(&serviceAccountKeyServiceConnector{client: mgr.GetClient()}),
|
|
||||||
managed.WithPollInterval(o.PollInterval),
|
|
||||||
managed.WithLogger(o.Logger.WithValues("controller", name)),
|
|
||||||
- managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))))
|
|
||||||
+ managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))),
|
|
||||||
+ managed.WithConnectionPublishers(cps...))
|
|
||||||
|
|
||||||
return ctrl.NewControllerManagedBy(mgr).
|
|
||||||
Named(name).
|
|
||||||
```
|
|
||||||
|
|
||||||
You can check [this commit as an example for changes in Setup functions] as an
|
|
||||||
example.
|
|
||||||
|
|
||||||
[External Secret Stores]: https://github.com/crossplane/crossplane/blob/master/design/design-doc-external-secret-stores.md
|
|
||||||
[this PR as a complete example]: https://github.com/crossplane/provider-gcp/pull/421
|
|
||||||
[this PR instead]: https://github.com/crossplane-contrib/provider-jet-template/pull/23/commits
|
|
||||||
[this commit as an example on how to add the type]: https://github.com/crossplane-contrib/provider-aws/pull/1242/commits/d8a2df323fa2489d82bf1843d2fe338de033c61d
|
|
||||||
[this commit as an example for adding the feature flag]: https://github.com/crossplane/provider-gcp/pull/421/commits/b5898c62dc6668d9918496de8aa9bc365c371f82
|
|
||||||
[this commit as an example for changes in Setup functions]: https://github.com/crossplane/provider-gcp/pull/421/commits/9700d0c4fdb7e1fba8805afa309c1b1c7aa167a6
|
|
|
@ -1,194 +0,0 @@
|
||||||
---
|
|
||||||
title: Observability Developer Guide
|
|
||||||
weight: 1002
|
|
||||||
---
|
|
||||||
|
|
||||||
## Introduction
|
|
||||||
|
|
||||||
Observability is crucial to Crossplane users; both those operating Crossplane
|
|
||||||
and those using Crossplane to operate their infrastructure. Crossplane currently
|
|
||||||
approaches observability via Kubernetes events and structured logs.
|
|
||||||
|
|
||||||
## Goals
|
|
||||||
|
|
||||||
In short, a non-admin user and an admin user should both be able to debug any
|
|
||||||
issues only by inspecting logs and events. There should be no need to rebuild
|
|
||||||
the Crossplane binary or to reach out to a Crossplane developer.
|
|
||||||
|
|
||||||
A user should be able to:
|
|
||||||
|
|
||||||
* Debug an issue without rebuilding the Crossplane binary
|
|
||||||
* Understand an issue without contacting a cluster admin
|
|
||||||
* Ask a cluster admin to check the logs for more details about the reason the
|
|
||||||
issue happened, if the details are not part of the error message
|
|
||||||
|
|
||||||
A cluster admin should be able to:
|
|
||||||
|
|
||||||
* Debug an issue without rebuilding the Crossplane binary
|
|
||||||
* Debug an issue only by looking at the logs
|
|
||||||
* Debug an issue without needing to contact a Crossplane developer
|
|
||||||
|
|
||||||
## Error reporting in the logs
|
|
||||||
|
|
||||||
Error reporting in the logs is mostly intended for consumption by Crossplane
|
|
||||||
cluster admins. A cluster admin should be able to debug any issue by inspecting
|
|
||||||
the logs, without needing to add more logs themselves or contact a Crossplane
|
|
||||||
developer. This means that logs should contain:
|
|
||||||
|
|
||||||
* Error messages, at either the info or debug level as contextually appropriate
|
|
||||||
* Any context leading up to an error, typically at debug level, so that the
|
|
||||||
errors can be debugged
|
|
||||||
|
|
||||||
## Error reporting as events
|
|
||||||
|
|
||||||
Error reporting as Kubernetes events is primarily aimed toward end-users of
|
|
||||||
Crossplane who are not cluster admins. Crossplane typically runs as a Kubernetes
|
|
||||||
pod, and thus it is unlikely that most users of Crossplane will have access to
|
|
||||||
its logs. [Events], on the other hand, are available as top-level Kubernetes
|
|
||||||
objects, and show up the objects they relate to when running `kubectl describe`.
|
|
||||||
|
|
||||||
Events should be recorded in the following cases:
|
|
||||||
|
|
||||||
* A significant operation is taken on a resource
|
|
||||||
* The state of a resource is changed
|
|
||||||
* An error occurs
|
|
||||||
|
|
||||||
The events recorded in these cases can be thought of as forming an event log of
|
|
||||||
things that happen for the resources that Crossplane manages. Each event should
|
|
||||||
refer back to the relevant controller and resource, and use other fields of the
|
|
||||||
Event kind as appropriate.
|
|
||||||
|
|
||||||
More details about examples of how to interact with events can be found in the
|
|
||||||
guide to [debugging an application cluster].
|
|
||||||
|
|
||||||
## Choosing between methods of error reporting
|
|
||||||
|
|
||||||
There are many ways to report errors, such as:
|
|
||||||
|
|
||||||
* Metrics
|
|
||||||
* Events
|
|
||||||
* Logging
|
|
||||||
* Tracing
|
|
||||||
|
|
||||||
It can be confusing to figure out which one is appropriate in a given situation.
|
|
||||||
This section will try to offer advice and a mindset that can be used to help
|
|
||||||
make this decision.
|
|
||||||
|
|
||||||
Let's set the context by listing the different user scenarios where error
|
|
||||||
reporting may be consumed. Here are the typical scenarios as we imagine them:
|
|
||||||
|
|
||||||
1. A person **using** a system needs to figure out why things aren't working as
|
|
||||||
expected, and whether they made a mistake that they can correct.
|
|
||||||
2. A person **operating** a service needs to monitor the service's **health**,
|
|
||||||
both now and historically.
|
|
||||||
3. A person **debugging** a problem which happened in a **live environment**
|
|
||||||
(often an **operator** of the system) needs information to figure out what
|
|
||||||
happened.
|
|
||||||
4. A person **developing** the software wants to **observe** what is happening.
|
|
||||||
5. A person **debugging** the software in a **development environment**
|
|
||||||
(typically a **developer** of the system) wants to debug a problem (there is
|
|
||||||
a lot of overlap between this and the live environment debugging scenario).
|
|
||||||
|
|
||||||
The goal is to satisfy the users in all of the scenarios. We'll refer to the
|
|
||||||
scenarios by number.
|
|
||||||
|
|
||||||
The short version is: we should do whatever satisfies all of the scenarios.
|
|
||||||
Logging and events are the recommendations for satisfying the scenarios,
|
|
||||||
although they don't cover scenario 2.
|
|
||||||
|
|
||||||
The longer version is:
|
|
||||||
|
|
||||||
* Scenario 1 is best served by events in the context of Crossplane, since the
|
|
||||||
users may not have access to read logs or metrics, and even if they did, it
|
|
||||||
would be hard to relate them back to the event the user is trying to
|
|
||||||
understand.
|
|
||||||
* Scenario 2 is best served by metrics, because they can be aggregated and
|
|
||||||
understood as a whole. And because they can be used to track things over time.
|
|
||||||
* Scenario 3 is best served by either logging that contains all the information
|
|
||||||
about and leading up to the event. Request-tracing systems are also useful for
|
|
||||||
this scenario.
|
|
||||||
* Scenario 4 is usually logs, maybe at a more verbose level than normal. But it
|
|
||||||
could be an attached debugger or some other type of tool. It could also be a
|
|
||||||
test suite.
|
|
||||||
* Scenario 5 is usually either logs, up to the highest imaginable verbosity, or
|
|
||||||
an attached debugging session. If there's a gap in reporting, it could involve
|
|
||||||
adding some print statements to get more logging.
|
|
||||||
|
|
||||||
As for the question of how to decide whether to log or not, we believe it helps
|
|
||||||
to try to visualize which of the scenarios the error or information in question
|
|
||||||
will be used for. We recommend starting with reporting as much information as
|
|
||||||
possible, but with configurable runtime behavior so that, for example, debugging
|
|
||||||
logs don't show up in production normally.
|
|
||||||
|
|
||||||
For the question of what constitutes an error, errors should be actionable by a
|
|
||||||
human. See the [Dave Cheney article] on this topic for some more discussion.
|
|
||||||
|
|
||||||
## In Practice
|
|
||||||
|
|
||||||
Crossplane provides two observability libraries as part of crossplane-runtime:
|
|
||||||
|
|
||||||
* [`event`] emits Kubernetes events.
|
|
||||||
* [`logging`] produces structured logs. Refer to its package documentation for
|
|
||||||
additional context on its API choices.
|
|
||||||
|
|
||||||
Keep the following in mind when using the above libraries:
|
|
||||||
|
|
||||||
* [Do] [not] use package level loggers or event recorders. Instantiate them in
|
|
||||||
`main()` and plumb them down to where they're needed.
|
|
||||||
* Each [`Reconciler`] implementation should use its own `logging.Logger` and
|
|
||||||
`event.Recorder`. Implementations are strongly encouraged to default to using
|
|
||||||
`logging.NewNopLogger()` and `event.NewNopRecorder()`, and accept a functional
|
|
||||||
loggers and recorder via variadic options. See for example the [managed
|
|
||||||
resource reconciler].
|
|
||||||
* Each controller should use its name as its event recorder's name, and include
|
|
||||||
its name under the `controller` structured logging key. The controllers name
|
|
||||||
should be of the form `controllertype/resourcekind`, for example
|
|
||||||
`managed/cloudsqlinstance` or `stacks/stackdefinition`. Controller names
|
|
||||||
should always be lowercase.
|
|
||||||
* Logs and events should typically be emitted by the `Reconcile` method of the
|
|
||||||
`Reconciler` implementation; not by functions called by `Reconcile`. Author
|
|
||||||
the methods orchestrated by `Reconcile` as if they were a library; prefer
|
|
||||||
surfacing useful information for the `Reconciler` to log (for example by
|
|
||||||
[wrapping errors]) over plumbing loggers and event recorders down to
|
|
||||||
increasingly deeper layers of code.
|
|
||||||
* Almost nothing is worth logging at info level. When deciding which logging
|
|
||||||
level to use, consider a production deployment of Crossplane reconciling tens
|
|
||||||
or hundreds of managed resources. If in doubt, pick debug. You can easily
|
|
||||||
increase the log level later if it proves warranted.
|
|
||||||
* The above is true even for errors; consider the audience. Is this an error
|
|
||||||
only the Crossplane cluster operator can fix? Does it indicate a significant
|
|
||||||
degradation of Crossplane's functionality? If so, log it at info. If the error
|
|
||||||
pertains to a single Crossplane resource emit an event instead.
|
|
||||||
* Always log errors under the structured logging key `error` (e.g.
|
|
||||||
`log.Debug("boom!, "error", err)`). Many logging implementations (including
|
|
||||||
Crossplane's) add context like stack traces for this key.
|
|
||||||
* Emit events liberally; they're rate limited and deduplicated.
|
|
||||||
* Follow [API conventions] when emitting events; ensure event reasons are unique
|
|
||||||
and `CamelCase`.
|
|
||||||
* Consider emitting events and logs when a terminal condition is encountered
|
|
||||||
(e.g. `Reconcile` returns) over logging logic flow. i.e. Prefer one log line
|
|
||||||
that reads "encountered an error fooing the bar" over two log lines that read
|
|
||||||
"about to foo the bar" and "encountered an error". Recall that if the audience
|
|
||||||
is a developer debugging Crossplane they will be provided a stack trace with
|
|
||||||
file and line context when an error is logged.
|
|
||||||
* Consider including the `reconcile.Request`, and the resource's UID and
|
|
||||||
resource version (not API version) under the keys `request`, `uid`, and
|
|
||||||
`version`. Doing so allows log readers to determine what specific version of a
|
|
||||||
resource the log pertains to.
|
|
||||||
|
|
||||||
Finally, when in doubt, aim for consistency with existing Crossplane controller
|
|
||||||
implementations.
|
|
||||||
|
|
||||||
<!-- Named Links -->
|
|
||||||
|
|
||||||
[Events]: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.21/#event-v1-core
|
|
||||||
[debugging an application cluster]: https://kubernetes.io/docs/tasks/debug-application-cluster/
|
|
||||||
[Dave Cheney article]: https://dave.cheney.net/2015/11/05/lets-talk-about-logging
|
|
||||||
[`event`]: https://godoc.org/github.com/crossplane/crossplane-runtime/pkg/event
|
|
||||||
[`logging`]: https://godoc.org/github.com/crossplane/crossplane-runtime/pkg/logging
|
|
||||||
[Do]: https://peter.bourgon.org/go-best-practices-2016/#logging-and-instrumentation
|
|
||||||
[not]: https://dave.cheney.net/2017/01/23/the-package-level-logger-anti-pattern
|
|
||||||
[`Reconciler`]: https://godoc.org/sigs.k8s.io/controller-runtime/pkg/reconcile#Reconciler
|
|
||||||
[managed resource reconciler]: https://github.com/crossplane/crossplane-runtime/blob/a6bb0/pkg/reconciler/managed/reconciler.go#L436
|
|
||||||
[wrapping errors]: https://godoc.org/github.com/pkg/errors#Wrap
|
|
||||||
[API conventions]: https://github.com/kubernetes/community/blob/09f55c6/contributors/devel/sig-architecture/api-conventions.md#events
|
|
|
@ -1,657 +0,0 @@
|
||||||
---
|
|
||||||
title: Provider Development Guide
|
|
||||||
weight: 1001
|
|
||||||
---
|
|
||||||
|
|
||||||
Crossplane allows you to manage infrastructure directly from Kubernetes. Each
|
|
||||||
infrastructure API resource that Crossplane orchestrates is known as a "managed
|
|
||||||
resource". This guide will walk through the process of adding support for a new
|
|
||||||
kind of managed resource to a Crossplane Provider.
|
|
||||||
|
|
||||||
> You can watch [TBS Episode 18] to follow along the live implementation of GCP PubSub
|
|
||||||
managed resource.
|
|
||||||
|
|
||||||
> If there is a corresponding Terraform Provider, please consider generating
|
|
||||||
a Crossplane Provider with [Terrajet] by following the
|
|
||||||
[Generating a Crossplane Provider guide].
|
|
||||||
|
|
||||||
> If you plan to implement a managed resource for AWS, please see the
|
|
||||||
[code generation guide].
|
|
||||||
|
|
||||||
## What Makes a Crossplane Infrastructure Resource
|
|
||||||
|
|
||||||
Crossplane builds atop Kubernetes's powerful architecture in which declarative
|
|
||||||
configuration, known as resources, are continually 'reconciled' with reality by
|
|
||||||
one or more controllers. A controller is an endless loop that:
|
|
||||||
|
|
||||||
1. Observes the desired state (the declarative configuration resource).
|
|
||||||
1. Observes the actual state (the thing said configuration resource represents).
|
|
||||||
1. Tries to make the actual state match the desired state.
|
|
||||||
|
|
||||||
Typical Crossplane managed infrastructure consists of two configuration
|
|
||||||
resources and one controller. The GCP Provider's support for Google Cloud
|
|
||||||
Memorystore illustrates this. First, the configuration resources:
|
|
||||||
|
|
||||||
1. A [managed resource]. Managed resources are cluster scoped, high-fidelity
|
|
||||||
representations of a resource in an external system such as a cloud
|
|
||||||
provider's API. Managed resources are _non-portable_ across external systems
|
|
||||||
(i.e. cloud providers); they're tightly coupled to the implementation details
|
|
||||||
of the external resource they represent. Managed resources are defined by a
|
|
||||||
Provider. The GCP Provider's [`CloudMemorystoreInstance`] resource is an
|
|
||||||
example of a managed resource.
|
|
||||||
1. A provider. Providers enable access to an external system, typically by
|
|
||||||
indicating a Kubernetes Secret containing any credentials required to
|
|
||||||
authenticate to the system, as well as any other metadata required to
|
|
||||||
connect. Providers are cluster scoped, like managed resources and classes.
|
|
||||||
The GCP [`ProviderConfig`] is an example of a provider. Note that provider is a
|
|
||||||
somewhat overloaded term in the Crossplane ecosystem - it's also used to
|
|
||||||
refer to the controller manager for a particular cloud, for example
|
|
||||||
`provider-gcp`.
|
|
||||||
|
|
||||||
A managed resource is powered by a controller. This controller is responsible
|
|
||||||
for taking instances of the aforementioned high-fidelity managed resource kind
|
|
||||||
and reconciling them with an external system. The `CloudMemorystoreInstance`
|
|
||||||
controller watches for changes to `CloudMemorystoreInstance` resources and calls
|
|
||||||
Google's Cloud Memorystore API to create, update, or delete an instance as
|
|
||||||
necessary.
|
|
||||||
|
|
||||||
Crossplane does not require controllers to be written in any particular
|
|
||||||
language. The Kubernetes API server is our API boundary, so any process capable
|
|
||||||
of [watching the API server] and updating resources can be a Crossplane
|
|
||||||
controller.
|
|
||||||
|
|
||||||
## Getting Started
|
|
||||||
|
|
||||||
At the time of writing all Crossplane Services controllers are written in Go,
|
|
||||||
and built using [crossplane-runtime]. While it is possible to write a controller
|
|
||||||
using any language and tooling with a Kubernetes client this set of tools are
|
|
||||||
the "[golden path]". They're well supported, broadly used, and provide a shared
|
|
||||||
language with the Crossplane community. This guide targets [crossplane-runtime
|
|
||||||
v0.9.0]. It assumes the reader is familiar with the Kubernetes [API Conventions]
|
|
||||||
and the [kubebuilder book].
|
|
||||||
|
|
||||||
> If you are building a new provider from scratch, instead of adding new
|
|
||||||
resources to an already existing one, please use [provider-template] repository
|
|
||||||
as a template by hitting the `Use this template` button in GitHub UI. It
|
|
||||||
codifies most of the best practices used by the Crossplane community so far and
|
|
||||||
is the easiest way to start a new provider.
|
|
||||||
|
|
||||||
## Defining Resource Kinds
|
|
||||||
|
|
||||||
Let's assume we want to add Crossplane support for your favourite cloud's
|
|
||||||
database-as-a-service. Your favourite cloud brands these instances as "Favourite
|
|
||||||
DB instances". Under the hood they're powered by the open source FancySQL
|
|
||||||
engine. We'll name the new managed resource kind `FavouriteDBInstance`.
|
|
||||||
|
|
||||||
The first step toward implementing a new managed service is to define the code
|
|
||||||
level schema of its configuration resources. These are referred to as
|
|
||||||
[resources], (resource) [kinds], and [objects] interchangeably. The kubebuilder
|
|
||||||
scaffolding is a good starting point for any new Crossplane API kind.
|
|
||||||
|
|
||||||
> Note that while Crossplane was originally derived from kubebuilder scaffolds
|
|
||||||
> its patterns have diverged somewhat. It is _possible_ to use kubebuilder to
|
|
||||||
> scaffold a resource, but the author must be careful to adapt said resource to
|
|
||||||
> Crossplane patterns. It may often be quicker to copy and modify a v1beta1 or
|
|
||||||
> above resource from the same provider repository, rather than using
|
|
||||||
> kubebuilder.
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubebuilder create api \
|
|
||||||
--group example --version v1alpha1 --kind FavouriteDBInstance \
|
|
||||||
--resource=true --controller=false --namespaced=false
|
|
||||||
```
|
|
||||||
|
|
||||||
The above command should produce a scaffold similar to the below example:
|
|
||||||
|
|
||||||
```go
|
|
||||||
type FavouriteDBInstanceSpec struct {
|
|
||||||
// INSERT ADDITIONAL SPEC FIELDS - desired state of infrastructure
|
|
||||||
// Important: Run "make" to regenerate code after modifying this file
|
|
||||||
}
|
|
||||||
|
|
||||||
// FavouriteDBInstanceStatus defines the observed state of FavouriteDBInstance
|
|
||||||
type FavouriteDBInstanceStatus struct {
|
|
||||||
// INSERT ADDITIONAL STATUS FIELD - define observed state of infrastructure
|
|
||||||
// Important: Run "make" to regenerate code after modifying this file
|
|
||||||
}
|
|
||||||
|
|
||||||
// +kubebuilder:object:root=true
|
|
||||||
|
|
||||||
// FavouriteDBInstance is the Schema for the favouritedbinstance API
|
|
||||||
// +kubebuilder:resource:scope=Cluster
|
|
||||||
type FavouriteDBInstance struct {
|
|
||||||
metav1.TypeMeta `json:",inline"`
|
|
||||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
|
||||||
|
|
||||||
Spec FavouriteDBInstanceeSpec `json:"spec,omitempty"`
|
|
||||||
Status FavouriteDBInstanceStatus `json:"status,omitempty"`
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Crossplane requires that these newly generated API type scaffolds be extended
|
|
||||||
with a set of struct fields, getters, and setters that are standard to all
|
|
||||||
Crossplane resource kinds. The getters and setter methods required to satisfy
|
|
||||||
crossplane-runtime interfaces are omitted from the below examples for brevity.
|
|
||||||
They can be added by hand, but new services are encouraged to use [`angryjet`]
|
|
||||||
to generate them automatically using a `//go:generate` comment per the
|
|
||||||
[`angryjet` documentation].
|
|
||||||
|
|
||||||
Note that in many cases a suitable provider will already exist. Frequently
|
|
||||||
adding support for a new managed service requires only the definition of the
|
|
||||||
managed resource itself.
|
|
||||||
|
|
||||||
### Managed Resource Kinds
|
|
||||||
|
|
||||||
Managed resources must:
|
|
||||||
|
|
||||||
* Satisfy crossplane-runtime's [`resource.Managed`] interface.
|
|
||||||
* Embed a [`ResourceStatus`] struct in their `Status` struct.
|
|
||||||
* Embed a [`ResourceSpec`] struct in their `Spec` struct.
|
|
||||||
* Embed a `Parameters` struct in their `Spec` struct.
|
|
||||||
* Use the `+kubebuilder:subresource:status` [comment marker].
|
|
||||||
* Use the `+kubebuilder:resource:scope=Cluster` [comment marker].
|
|
||||||
|
|
||||||
The `Parameters` struct should be a _high fidelity_ representation of the
|
|
||||||
writeable fields of the external resource's API. Put otherwise, if your
|
|
||||||
favourite cloud represents Favourite DB instances as a JSON object then
|
|
||||||
`FavouriteDBParameters` should marshal to a something as close to that JSON
|
|
||||||
object as possible while still complying with Kubernetes API conventions.
|
|
||||||
|
|
||||||
For example, assume the external API object for Favourite DB instance was:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"id": 42,
|
|
||||||
"name": "mycoolinstance",
|
|
||||||
"fanciness_level": 100,
|
|
||||||
"version": "2.3",
|
|
||||||
"status": "ONLINE",
|
|
||||||
"hostname": "cool.fcp.example.org"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Further assume the `id`, `status`, and `hostname` fields were output only, and
|
|
||||||
the `version` field was optional. The `FavouriteDBInstance` managed resource
|
|
||||||
should look as follows:
|
|
||||||
|
|
||||||
```go
|
|
||||||
// FavouriteDBInstanceParameters define the desired state of an FavouriteDB
|
|
||||||
// instance. Most fields map directly to an Instance:
|
|
||||||
// https://favourite.example.org/api/v1/db#Instance
|
|
||||||
type FavouriteDBInstanceParameters struct {
|
|
||||||
|
|
||||||
// We're still working on a standard for naming external resources. See
|
|
||||||
// https://github.com/crossplane/crossplane/issues/624 for context.
|
|
||||||
|
|
||||||
// Name of this instance.
|
|
||||||
Name string `json:"name"`
|
|
||||||
|
|
||||||
// Note that fanciness_level becomes fancinessLevel below. Kubernetes API
|
|
||||||
// conventions trump cloud provider fidelity.
|
|
||||||
|
|
||||||
// FancinessLevel specifies exactly how fancy this instance is.
|
|
||||||
FancinessLevel int `json:"fancinessLevel"`
|
|
||||||
|
|
||||||
// Version specifies what version of FancySQL this instance will run.
|
|
||||||
// +optional
|
|
||||||
Version *string `json:"version,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// A FavouriteDBInstanceSpec defines the desired state of a FavouriteDBInstance.
|
|
||||||
type FavouriteDBInstanceSpec struct {
|
|
||||||
xpv1.ResourceSpec `json:",inline"`
|
|
||||||
ForProvider FavouriteDBInstanceParameters `json:"forProvider"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// A FavouriteDBInstanceStatus represents the observed state of a
|
|
||||||
// FavouriteDBInstance.
|
|
||||||
type FavouriteDBInstanceStatus struct {
|
|
||||||
xpv1.ResourceStatus `json:",inline"`
|
|
||||||
|
|
||||||
// Note that we add the three "output only" fields here in the status,
|
|
||||||
// instead of the parameters. We want this representation to be high
|
|
||||||
// fidelity just like the parameters.
|
|
||||||
|
|
||||||
// ID of this instance.
|
|
||||||
ID int `json:"id,omitempty"`
|
|
||||||
|
|
||||||
// Status of this instance.
|
|
||||||
Status string `json:"status,omitempty"`
|
|
||||||
|
|
||||||
// Hostname of this instance.
|
|
||||||
Hostname string `json:"hostname,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// A FavouriteDBInstance is a managed resource that represents a Favourite DB
|
|
||||||
// instance.
|
|
||||||
// +kubebuilder:subresource:status
|
|
||||||
type FavouriteDBInstance struct {
|
|
||||||
metav1.TypeMeta `json:",inline"`
|
|
||||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
|
||||||
|
|
||||||
Spec FavouriteDBInstanceSpec `json:"spec"`
|
|
||||||
Status FavouriteDBInstanceStatus `json:"status,omitempty"`
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that Crossplane uses the GoDoc strings of API kinds to generate user facing
|
|
||||||
API documentation. __Document all fields__ and prefer GoDoc that assumes the
|
|
||||||
reader is running `kubectl explain`, or reading an API reference, not reading
|
|
||||||
the code. Refer to the [Managed Resource API Patterns] one pager for more detail
|
|
||||||
on authoring high fidelity managed resources.
|
|
||||||
|
|
||||||
### Provider Kinds
|
|
||||||
|
|
||||||
You'll typically only need to add a new Provider kind if you're creating an
|
|
||||||
infrastructure provider that adds support for a new infrastructure provider.
|
|
||||||
|
|
||||||
Providers must:
|
|
||||||
|
|
||||||
* Be named exactly `ProviderConfig`.
|
|
||||||
* Embed a [`ProviderSpec`] struct in their `Spec` struct.
|
|
||||||
* Use the `+kubebuilder:resource:scope=Cluster` [comment marker].
|
|
||||||
|
|
||||||
The Favourite Cloud `ProviderConfig` would look as follows. Note that the cloud to
|
|
||||||
which it belongs should be indicated by its API group, i.e. its API Version
|
|
||||||
would be `favouritecloud.crossplane.io/v1alpha1` or similar.
|
|
||||||
|
|
||||||
```go
|
|
||||||
// A ProviderSpec defines the desired state of a Provider.
|
|
||||||
type ProviderSpec struct {
|
|
||||||
xpv1.ProviderSpec `json:",inline"`
|
|
||||||
|
|
||||||
// Information required outside of the Secret referenced in the embedded
|
|
||||||
// xpv1.ProviderSpec that is required to authenticate to the provider.
|
|
||||||
// ProjectID is used as an example here.
|
|
||||||
ProjectID string `json:"projectID"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Provider configures a Favourite Cloud 'provider', i.e. a connection to a
|
|
||||||
// particular Favourite Cloud project using a particular Favourite Cloud service
|
|
||||||
// account.
|
|
||||||
type Provider struct {
|
|
||||||
metav1.TypeMeta `json:",inline"`
|
|
||||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
|
||||||
|
|
||||||
Spec ProviderSpec `json:"spec"`
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Finishing Touches
|
|
||||||
|
|
||||||
At this point we've defined the managed resource necessary to start
|
|
||||||
building controllers. Before moving on to the controllers:
|
|
||||||
|
|
||||||
* Add any kubebuilder [comment markers] that may be useful for your resource.
|
|
||||||
Comment markers can be used to validate input, or add additional columns to
|
|
||||||
the standard `kubectl get` output, among other things.
|
|
||||||
* Run `make reviewable` to generate Custom Resource Definitions and additional
|
|
||||||
helper methods for your new resource kinds.
|
|
||||||
* Make sure any package documentation (i.e. `// Package v1alpha1...` GoDoc,
|
|
||||||
including package level comment markers) are in a file named `doc.go`.
|
|
||||||
kubebuilder adds them to `groupversion_info.go`, but several code generation
|
|
||||||
tools only check `doc.go`.
|
|
||||||
|
|
||||||
Finally, add convenience [`GroupVersionKind`] variables for each new resource
|
|
||||||
kind. These are typically added to either `register.go` or
|
|
||||||
`groupversion_info.go` depending on which version of kubebuilder scaffolded the
|
|
||||||
API type:
|
|
||||||
|
|
||||||
```go
|
|
||||||
// FavouriteDBInstance type metadata.
|
|
||||||
var (
|
|
||||||
FavouriteDBInstanceKind = reflect.TypeOf(FavouriteDBInstance{}).Name()
|
|
||||||
FavouriteDBInstanceKindAPIVersion = FavouriteDBInstanceKind + "." + GroupVersion.String()
|
|
||||||
FavouriteDBInstanceGroupVersionKind = GroupVersion.WithKind(FavouriteDBInstanceKind)
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
Consider opening a draft pull request and asking a Crossplane maintainer for
|
|
||||||
review before you start work on the controller!
|
|
||||||
|
|
||||||
## Adding Controllers
|
|
||||||
|
|
||||||
Crossplane controllers, like those scaffolded by kubebuilder, are built around
|
|
||||||
the [controller-runtime] library. controller-runtime flavoured controllers
|
|
||||||
encapsulate most of their domain-specific logic in a [`reconcile.Reconciler`]
|
|
||||||
implementation. Most Crossplane controllers are one of the three kinds mentioned
|
|
||||||
under [What Makes a Crossplane Infrastructure Resource]. Each of these controller kinds
|
|
||||||
are similar enough across implementations that [crossplane-runtime] provides
|
|
||||||
'default' reconcilers. These reconcilers encode what the Crossplane community
|
|
||||||
has learned about managing external systems and narrow the problem space from
|
|
||||||
reconciling a Kubernetes resource kind with an arbitrary system down to
|
|
||||||
Crossplane-specific tasks.
|
|
||||||
|
|
||||||
crossplane-runtime provides the following `reconcile.Reconcilers`:
|
|
||||||
|
|
||||||
* The [`managed.Reconciler`] reconciles managed resources with external systems
|
|
||||||
by instantiating a client of the external API and using it to create, update,
|
|
||||||
or delete the external resource as necessary.
|
|
||||||
|
|
||||||
Crossplane controllers typically differ sufficiently from those scaffolded by
|
|
||||||
kubebuilder that there is little value in using kubebuilder to generate a
|
|
||||||
controller scaffold.
|
|
||||||
|
|
||||||
### Managed Resource Controllers
|
|
||||||
|
|
||||||
Managed resource controllers should use [`managed.NewReconciler`] to wrap a
|
|
||||||
managed-resource specific implementation of [`managed.ExternalConnecter`]. Parts
|
|
||||||
of `managed.Reconciler`'s behaviour is customisable; refer to the
|
|
||||||
[`managed.NewReconciler`] GoDoc for a list of options. The following is an
|
|
||||||
example controller for the `FavouriteDBInstance` managed resource we defined
|
|
||||||
earlier:
|
|
||||||
|
|
||||||
```go
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
||||||
|
|
||||||
// An API client of the hypothetical FavouriteDB service.
|
|
||||||
"github.com/fcp-sdk/v1/services/database"
|
|
||||||
|
|
||||||
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
|
|
||||||
"github.com/crossplane/crossplane-runtime/pkg/meta"
|
|
||||||
"github.com/crossplane/crossplane-runtime/pkg/resource"
|
|
||||||
"github.com/crossplane/crossplane-runtime/pkg/reconciler/managed"
|
|
||||||
|
|
||||||
"github.com/crossplane/provider-fcp/apis/database/v1alpha3"
|
|
||||||
fcpv1alpha3 "github.com/crossplane/provider-fcp/apis/v1alpha3"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FavouriteDBInstanceController struct{}
|
|
||||||
|
|
||||||
// SetupWithManager instantiates a new controller using a managed.Reconciler
|
|
||||||
// configured to reconcile FavouriteDBInstances using an ExternalClient produced by
|
|
||||||
// connecter, which satisfies the ExternalConnecter interface.
|
|
||||||
func (c *FavouriteDBInstanceController) SetupWithManager(mgr ctrl.Manager) error {
|
|
||||||
return ctrl.NewControllerManagedBy(mgr).
|
|
||||||
Named(strings.ToLower(fmt.Sprintf("%s.%s", v1alpha3.FavouriteDBInstanceKind, v1alpha3.Group))).
|
|
||||||
For(&v1alpha3.FavouriteDBInstance{}).
|
|
||||||
Complete(managed.NewReconciler(mgr,
|
|
||||||
resource.ManagedKind(v1alpha3.FavouriteDBInstanceGroupVersionKind),
|
|
||||||
managed.WithExternalConnecter(&connecter{client: mgr.GetClient()})))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connecter satisfies the resource.ExternalConnecter interface.
|
|
||||||
type connecter struct{ client client.Client }
|
|
||||||
|
|
||||||
// Connect to the supplied resource.Managed (presumed to be a
|
|
||||||
// FavouriteDBInstance) by using the Provider it references to create a new
|
|
||||||
// database client.
|
|
||||||
func (c *connecter) Connect(ctx context.Context, mg resource.Managed) (managed.ExternalClient, error) {
|
|
||||||
// Assert that resource.Managed we were passed in fact contains a
|
|
||||||
// FavouriteDBInstance. We told NewControllerManagedBy that this was a
|
|
||||||
// controller For FavouriteDBInstance, so something would have to go
|
|
||||||
// horribly wrong for us to encounter another type.
|
|
||||||
i, ok := mg.(*v1alpha3.FavouriteDBInstance)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("managed resource is not a FavouriteDBInstance")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the Provider referenced by the FavouriteDBInstance.
|
|
||||||
p := &fcpv1alpha3.Provider{}
|
|
||||||
if err := c.client.Get(ctx, meta.NamespacedNameOf(i.Spec.ProviderReference), p); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "cannot get Provider")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the Secret referenced by the Provider.
|
|
||||||
s := &corev1.Secret{}
|
|
||||||
n := types.NamespacedName{Namespace: p.Namespace, Name: p.Spec.Secret.Name}
|
|
||||||
if err := c.client.Get(ctx, n, s); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "cannot get Provider secret")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create and return a new database client using the credentials read from
|
|
||||||
// our Provider's Secret.
|
|
||||||
client, err := database.NewClient(ctx, s.Data[p.Spec.Secret.Key])
|
|
||||||
return &external{client: client}, errors.Wrap(err, "cannot create client")
|
|
||||||
}
|
|
||||||
|
|
||||||
// External satisfies the resource.ExternalClient interface.
|
|
||||||
type external struct{ client database.Client }
|
|
||||||
|
|
||||||
// Observe the existing external resource, if any. The managed.Reconciler
|
|
||||||
// calls Observe in order to determine whether an external resource needs to be
|
|
||||||
// created, updated, or deleted.
|
|
||||||
func (e *external) Observe(ctx context.Context, mg resource.Managed) (managed.ExternalObservation, error) {
|
|
||||||
i, ok := mg.(*v1alpha3.FavouriteDBInstance)
|
|
||||||
if !ok {
|
|
||||||
return managed.ExternalObservation{}, errors.New("managed resource is not a FavouriteDBInstance")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use our FavouriteDB API client to get an up to date view of the external
|
|
||||||
// resource.
|
|
||||||
existing, err := e.client.GetInstance(ctx, i.Spec.Name)
|
|
||||||
|
|
||||||
// If we encounter an error indicating the external resource does not exist
|
|
||||||
// we want to let the managed.Reconciler know so it can create it.
|
|
||||||
if database.IsNotFound(err) {
|
|
||||||
return managed.ExternalObservation{ResourceExists: false}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Any other errors are wrapped (as is good Go practice) and returned to the
|
|
||||||
// managed.Reconciler. It will update the "Synced" status condition
|
|
||||||
// of the managed resource to reflect that the most recent reconcile failed
|
|
||||||
// and ensure the reconcile is reattempted after a brief wait.
|
|
||||||
if err != nil {
|
|
||||||
return managed.ExternalObservation{}, errors.Wrap(err, "cannot get instance")
|
|
||||||
}
|
|
||||||
|
|
||||||
// The external resource exists. Copy any output-only fields to their
|
|
||||||
// corresponding entries in our status field.
|
|
||||||
i.Status.Status = existing.GetStatus()
|
|
||||||
i.Status.Hostname = existing.GetHostname()
|
|
||||||
i.Status.ID = existing.GetID()
|
|
||||||
|
|
||||||
// Update our "Ready" status condition to reflect the status of the external
|
|
||||||
// resource. Most managed resources use the below well known reasons that
|
|
||||||
// the "Ready" status may be true or false, but managed resource authors
|
|
||||||
// are welcome to define and use their own.
|
|
||||||
switch i.Status.Status {
|
|
||||||
case database.StatusOnline:
|
|
||||||
resource.SetBindable(i)
|
|
||||||
i.SetConditions(xpv1.Available())
|
|
||||||
case database.StatusCreating:
|
|
||||||
i.SetConditions(xpv1.Creating())
|
|
||||||
case database.StatusDeleting:
|
|
||||||
i.SetConditions(xpv1.Deleting())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, we report what we know about the external resource. In this
|
|
||||||
// hypothetical case FancinessLevel is the only field that can be updated
|
|
||||||
// after creation time, so the resource does not need to be updated if
|
|
||||||
// the actual fanciness level matches our desired fanciness level. Any
|
|
||||||
// ConnectionDetails we return will be published to the managed resource's
|
|
||||||
// connection secret if it specified one.
|
|
||||||
o := managed.ExternalObservation{
|
|
||||||
ResourceExists: true,
|
|
||||||
ResourceUpToDate: existing.GetFancinessLevel == i.Spec.FancinessLevel,
|
|
||||||
ConnectionDetails: managed.ConnectionDetails{
|
|
||||||
xpv1.ResourceCredentialsSecretUserKey: []byte(existing.GetUsername()),
|
|
||||||
xpv1.ResourceCredentialsSecretEndpointKey: []byte(existing.GetHostname()),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return o, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new external resource based on the specification of our managed
|
|
||||||
// resource. managed.Reconciler only calls Create if Observe reported
|
|
||||||
// that the external resource did not exist.
|
|
||||||
func (e *external) Create(ctx context.Context, mg resource.Managed) (managed.ExternalCreation, error) {
|
|
||||||
i, ok := mg.(*v1alpha3.FavouriteDBInstance)
|
|
||||||
if !ok {
|
|
||||||
return managed.ExternalCreation{}, errors.New("managed resource is not a FavouriteDBInstance")
|
|
||||||
}
|
|
||||||
// Indicate that we're about to create the instance. Remember ExternalClient
|
|
||||||
// authors can use a bespoke condition reason here in cases where Creating
|
|
||||||
// doesn't make sense.
|
|
||||||
i.SetConditions(xpv1.Creating())
|
|
||||||
|
|
||||||
// Create must return any connection details that are set or returned only
|
|
||||||
// at creation time. The managed.Reconciler will merge any details
|
|
||||||
// with those returned during the Observe phase.
|
|
||||||
password := database.GeneratePassword()
|
|
||||||
cd := managed.ConnectionDetails{xpv1.ResourceCredentialsSecretPasswordKey: []byte(password)}
|
|
||||||
|
|
||||||
// Create a new instance.
|
|
||||||
new := database.Instance{Name: i.Name, FancinessLevel: i.FancinessLevel, Version: i.Version}
|
|
||||||
err := e.client.CreateInstance(ctx, new, password)
|
|
||||||
|
|
||||||
// Note that we use resource.Ignore to squash any error that indicates the
|
|
||||||
// external resource already exists. Create implementations must not return
|
|
||||||
// an error if asked to create a resource that already exists. Real managed
|
|
||||||
// resource controllers are advised to avoid unintentially 'adoptign' an
|
|
||||||
// existing, unrelated external resource, per
|
|
||||||
// https://github.com/crossplane/crossplane-runtime/issues/27
|
|
||||||
return managed.ExternalCreation{ConnectionDetails: cd}, errors.Wrap(resource.Ignore(database.IsExists, err), "cannot create instance")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the existing external resource to match the specifications of our
|
|
||||||
// managed resource. managed.Reconciler only calls Update if Observe
|
|
||||||
// reported that the external resource was not up to date.
|
|
||||||
func (e *external) Update(ctx context.Context, mg resource.Managed) (managed.ExternalUpdate, error) {
|
|
||||||
i, ok := mg.(*v1alpha3.FavouriteDBInstance)
|
|
||||||
if !ok {
|
|
||||||
return managed.ExternalUpdate{}, errors.New("managed resource is not a FavouriteDBInstance")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recall that FancinessLevel is the only field that we _can_ update.
|
|
||||||
new := database.Instance{Name: i.Name, FancinessLevel: i.FancinessLevel}
|
|
||||||
err := e.client.UpdateInstance(ctx, new)
|
|
||||||
return managed.ExternalUpdate{}, errors.Wrap(err, "cannot update instance")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete the external resource. managed.Reconciler only calls Delete
|
|
||||||
// when a managed resource with the 'Delete' deletion policy (the default) has
|
|
||||||
// been deleted.
|
|
||||||
func (e *external) Delete(ctx context.Context, mg resource.Managed) error {
|
|
||||||
i, ok := mg.(*v1alpha3.FavouriteDBInstance)
|
|
||||||
if !ok {
|
|
||||||
return errors.New("managed resource is not a FavouriteDBInstance")
|
|
||||||
}
|
|
||||||
// Indicate that we're about to delete the instance.
|
|
||||||
i.SetConditions(xpv1.Deleting())
|
|
||||||
|
|
||||||
// Delete the instance.
|
|
||||||
err := e.client.DeleteInstance(ctx, i.Spec.Name)
|
|
||||||
|
|
||||||
// Note that we use resource.Ignore to squash any error that indicates the
|
|
||||||
// external resource does not exist. Delete implementations must not return
|
|
||||||
// an error when asked to delete a non-existent external resource.
|
|
||||||
return errors.Wrap(resource.Ignore(database.IsNotFound, err), "cannot delete instance")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Wrapping Up
|
|
||||||
|
|
||||||
Once all your controllers are in place you'll want to test them. Note that most
|
|
||||||
projects under the [crossplane org] [favor] table driven tests that use Go's
|
|
||||||
standard library `testing` package over kubebuilder's Gingko based tests. Please
|
|
||||||
do not add or proliferate Gingko based tests.
|
|
||||||
|
|
||||||
Finally, don't forget to plumb any newly added resource kinds and controllers up
|
|
||||||
to your controller manager. Simple providers may do this for each type within
|
|
||||||
within `main()`, but most more complicated providers take an approach in which
|
|
||||||
each package exposes an `AddToScheme` (for resource kinds) or `SetupWithManager`
|
|
||||||
(for controllers) function that invokes the same function within its child
|
|
||||||
packages, resulting in a `main.go` like:
|
|
||||||
|
|
||||||
```go
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client/config"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/manager/signals"
|
|
||||||
|
|
||||||
crossplaneapis "github.com/crossplane/crossplane/apis"
|
|
||||||
|
|
||||||
fcpapis "github.com/crossplane/provider-fcp/apis"
|
|
||||||
"github.com/crossplane/provider-fcp/pkg/controller"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
cfg, err := config.GetConfig()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
mgr, err := manager.New(cfg, manager.Options{SyncPeriod: 1 * time.Hour})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := crossplaneapis.AddToScheme(mgr.GetScheme()); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := fcpapis.AddToScheme(mgr.GetScheme()); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := controller.SetupWithManager(mgr); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
panic(mgr.Start(signals.SetupSignalHandler()))
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## In Review
|
|
||||||
|
|
||||||
In this guide we walked through the process of defining the resource kinds and
|
|
||||||
controllers necessary to build support for new managed infrastructure; possibly
|
|
||||||
even a completely new infrastructure provider. Please do not hesitate to [reach
|
|
||||||
out] to the Crossplane maintainers and community for help designing and
|
|
||||||
implementing support for new managed services. We would highly value any
|
|
||||||
feedback you may have about the development process!
|
|
||||||
|
|
||||||
<!-- Named Links -->
|
|
||||||
[crossplane-runtime v0.9.0]: https://github.com/crossplane/crossplane-runtime/releases/tag/v0.9.0
|
|
||||||
[TBS Episode 18]: https://www.youtube.com/watch?v=rvQ8N0u3rkE&t=7s
|
|
||||||
[What Makes a Crossplane Infrastructure Resource]: #what-makes-a-crossplane-infrastructure-resource
|
|
||||||
[managed resource]: {{<ref "../concepts/managed-resources" >}}
|
|
||||||
[`CloudMemorystoreInstance`]: https://github.com/crossplane/provider-gcp/blob/85a6ed3c669a021f1d61be51b2cbe2714b0bc70b/apis/cache/v1beta1/cloudmemorystore_instance_types.go#L184
|
|
||||||
[`ProviderConfig`]: https://github.com/crossplane/provider-gcp/blob/be5aaf6/apis/v1beta1/providerconfig_types.go#L39
|
|
||||||
[watching the API server]: https://kubernetes.io/docs/reference/using-api/api-concepts/#efficient-detection-of-changes
|
|
||||||
[controller-runtime]: https://github.com/kubernetes-sigs/controller-runtime
|
|
||||||
[crossplane-runtime]: https://github.com/crossplane/crossplane-runtime/
|
|
||||||
[golden path]: https://charity.wtf/2018/12/02/software-sprawl-the-golden-path-and-scaling-teams-with-agency/
|
|
||||||
[API Conventions]: https://github.com/kubernetes/community/blob/c6e1e89a/contributors/devel/sig-architecture/api-conventions.md
|
|
||||||
[kubebuilder book]: https://book.kubebuilder.io/
|
|
||||||
[resources]: https://kubebuilder.io/cronjob-tutorial/gvks.html#kinds-and-resources
|
|
||||||
[kinds]: https://kubebuilder.io/cronjob-tutorial/gvks.html#kinds-and-resources
|
|
||||||
[objects]: https://kubernetes.io/docs/concepts/#kubernetes-objects
|
|
||||||
[comment marker]: https://kubebuilder.io/reference/markers.html
|
|
||||||
[comment markers]: https://kubebuilder.io/reference/markers.html
|
|
||||||
[`resource.Managed`]: https://godoc.org/github.com/crossplane/crossplane-runtime/pkg/resource#Managed
|
|
||||||
[`managed.Reconciler`]: https://godoc.org/github.com/crossplane/crossplane-runtime/pkg/reconciler/managed#Reconciler
|
|
||||||
[`managed.NewReconciler`]: https://godoc.org/github.com/crossplane/crossplane-runtime/pkg/reconciler/managed#NewReconciler
|
|
||||||
[`managed.ExternalConnecter`]: https://godoc.org/github.com/crossplane/crossplane-runtime/pkg/reconciler/managed#ExternalConnecter
|
|
||||||
[`managed.ExternalClient`]: https://godoc.org/github.com/crossplane/crossplane-runtime/pkg/reconciler/managed#ExternalClient
|
|
||||||
[`ResourceSpec`]: https://godoc.org/github.com/crossplane/crossplane-runtime/apis/common/v1#ResourceSpec
|
|
||||||
[`ResourceStatus`]: https://godoc.org/github.com/crossplane/crossplane-runtime/apis/common/v1#ResourceStatus
|
|
||||||
[`ProviderSpec`]: https://godoc.org/github.com/crossplane/crossplane-runtime/apis/common/v1#ProviderSpec
|
|
||||||
['managed.ExternalConnecter`]: https://godoc.org/github.com/crossplane/crossplane-runtime/pkg/reconciler/managed#ExternalConnecter
|
|
||||||
[opening a Crossplane issue]: https://github.com/crossplane/crossplane/issues/new/choose
|
|
||||||
[`GroupVersionKind`]: https://godoc.org/k8s.io/apimachinery/pkg/runtime/schema#GroupVersionKind
|
|
||||||
[`reconcile.Reconciler`]: https://godoc.org/sigs.k8s.io/controller-runtime/pkg/reconcile#Reconciler
|
|
||||||
[favor]: https://github.com/crossplane/crossplane/issues/452
|
|
||||||
[reach out]: https://github.com/crossplane/crossplane#get-involved
|
|
||||||
[crossplane org]: https://github.com/crossplane
|
|
||||||
[`angryjet`]: https://github.com/crossplane/crossplane-tools
|
|
||||||
[Managed Resource API Patterns]: https://github.com/crossplane/crossplane/blob/master/design/one-pager-managed-resource-api-design.md
|
|
||||||
[Crossplane CLI]: https://github.com/crossplane/crossplane-cli#quick-start-stacks
|
|
||||||
[`angryjet` documentation]: https://github.com/crossplane/crossplane-tools/blob/master/README.md
|
|
||||||
[code generation guide]: https://github.com/crossplane-contrib/provider-aws/blob/master/CODE_GENERATION.md
|
|
||||||
[Terrajet]: https://github.com/crossplane/terrajet
|
|
||||||
[Generating a Crossplane Provider guide]: https://github.com/crossplane/terrajet/blob/main/docs/generating-a-provider.md
|
|
||||||
[provider-template]: https://github.com/crossplane/provider-template
|
|
|
@ -1,266 +0,0 @@
|
||||||
---
|
|
||||||
title: Release Process
|
|
||||||
weight: 1003
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
This document is meant to be a complete end-to-end guide for how to release new
|
|
||||||
versions of software for Crossplane and its related projects.
|
|
||||||
|
|
||||||
## tl;dr Process Overview
|
|
||||||
|
|
||||||
All the details are available in the sections below, but we'll start this guide
|
|
||||||
with a very high level sequential overview for how to run the release process.
|
|
||||||
These steps apply to all Crossplane projects, all of which utilize [Github
|
|
||||||
Actions](https://github.com/features/actions) for pipelines.
|
|
||||||
|
|
||||||
1. **feature freeze**: Merge all completed features into main development branch
|
|
||||||
of all repos to begin "feature freeze" period.
|
|
||||||
1. **pin dependencies**: Update the go module on main development branch to
|
|
||||||
depend on stable versions of dependencies if needed.
|
|
||||||
1. **branch repo**: Create a new release branch using the GitHub UI for the
|
|
||||||
repo.
|
|
||||||
1. **release branch prep**: Make any release-specific updates on the release
|
|
||||||
branch (typically documentation).
|
|
||||||
1. **tag release**: Run the `Tag` action on the _release branch_ with the
|
|
||||||
desired version (e.g. `v0.14.0`).
|
|
||||||
1. **build/publish**: Run the `CI` and `Configurations` action on the release
|
|
||||||
branch with the version that was just tagged.
|
|
||||||
1. **tag next pre-release**: Run the `tag` action on the main development branch
|
|
||||||
with the `rc.0` for the next release (e.g. `v0.15.0-rc.0`).
|
|
||||||
1. **verify**: Verify all artifacts have been published successfully, perform
|
|
||||||
sanity testing.
|
|
||||||
1. **promote**: Run the `Promote` action to promote release to desired
|
|
||||||
channel(s).
|
|
||||||
1. **release notes**: Publish well authored and complete release notes on
|
|
||||||
GitHub.
|
|
||||||
1. **announce**: Announce the release on Twitter, Slack, etc.
|
|
||||||
|
|
||||||
## Detailed Process
|
|
||||||
|
|
||||||
This section will walk through the release process in more fine grained and
|
|
||||||
prescriptive detail.
|
|
||||||
|
|
||||||
### Feature Freeze
|
|
||||||
|
|
||||||
Feature freeze should be performed on all repos. In order to start the feature
|
|
||||||
freeze period, the following conditions should be met:
|
|
||||||
|
|
||||||
|
|
||||||
* All issues in the
|
|
||||||
[milestone](https://github.com/crossplane/crossplane/milestones) should be
|
|
||||||
closed
|
|
||||||
* Sanity testing has been performed on main development branch
|
|
||||||
|
|
||||||
### Pin Dependencies
|
|
||||||
|
|
||||||
It is a best practice to release Crossplane projects with "pinned" dependencies
|
|
||||||
to specific stable versions. For example, after crossplane-runtime has been
|
|
||||||
released, we want to update the main Crossplane repo to use that specific
|
|
||||||
released version.
|
|
||||||
|
|
||||||
To update a dependency to a specific version, simply edit the `go.mod` file to
|
|
||||||
point to the desired version, then run `go mod tidy`.
|
|
||||||
|
|
||||||
### Create Release Branch
|
|
||||||
|
|
||||||
Creating the release branch can be done within the [GitHub
|
|
||||||
UI](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-and-deleting-branches-within-your-repository).
|
|
||||||
Basically, you just use the branch selector drop down and type in the name of
|
|
||||||
the new release branch, e.g. `release-0.5`. Release branch names always follow
|
|
||||||
the convention of `release-[minor-semver]`.
|
|
||||||
|
|
||||||
If this is the first ever release branch being created in a repo (uncommon), you
|
|
||||||
should also set up branch protection rules for the `release-*` pattern. You can
|
|
||||||
find existing examples in the
|
|
||||||
<a href="https://github.com/crossplane/crossplane/settings/branches" data-proofer-ignore>Crossplane repo
|
|
||||||
settings</a>.
|
|
||||||
|
|
||||||
{{<hint "important">}}
|
|
||||||
Only maintainers can view the repo settings.
|
|
||||||
{{< /hint >}}
|
|
||||||
|
|
||||||
At this point, the `HEAD` commit in the release branch will be our release
|
|
||||||
candidate. The build pipeline will automatically be started due to the create
|
|
||||||
branch event, so we can start to perform testing on this build. Note that it
|
|
||||||
should be the exact same as what is currently in main development branch since
|
|
||||||
they are using the same commit and have the same tag. Also note that this is not
|
|
||||||
the official release build since we have not made the official release tag yet
|
|
||||||
(e.g. `v0.5.0`).
|
|
||||||
|
|
||||||
### Release Branch Prep
|
|
||||||
|
|
||||||
Some repos may not require any release branch prep. This is desirable as it
|
|
||||||
reduces the burden of running a new release. If this is the case for the repo
|
|
||||||
being released, you may skip this step.
|
|
||||||
|
|
||||||
In the core Crossplane repository, we need to update the release branch docs and
|
|
||||||
examples to point to the new versions that we will be releasing soon.
|
|
||||||
|
|
||||||
* Documentation, such as pinning
|
|
||||||
[snippet](https://github.com/crossplane/crossplane/blob/release-0.14/docs/snippets)
|
|
||||||
links to the current release branch.
|
|
||||||
* searching for `:v` will help a lot here
|
|
||||||
|
|
||||||
#### Bug Fixes in Release Branch
|
|
||||||
|
|
||||||
During our testing of the release candidate, we may find issues or bugs that we
|
|
||||||
triage and decide we want to fix before the release goes out. In order to fix a
|
|
||||||
bug in the release branch, the following process is recommended:
|
|
||||||
|
|
||||||
1. Make the bug fix into main development branch first through the normal PR
|
|
||||||
process
|
|
||||||
1. If the applicable code has already been removed from the main development
|
|
||||||
branch then simply fix the bug directly in the release branch by opening
|
|
||||||
a PR directly against the release branch
|
|
||||||
1. Backport the fix by performing a cherry-pick of the fix's commit hash
|
|
||||||
(**not** the merge commit) from main development branch into the release
|
|
||||||
branch. For example, to backport a fix from the main development branch to
|
|
||||||
`v0.5.0`, something like the following should be used:
|
|
||||||
|
|
||||||
```console
|
|
||||||
git fetch --all
|
|
||||||
git checkout -b release-0.5 upstream/release-0.5
|
|
||||||
git cherry-pick -x <fix commit hash>
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Open a PR with the cherry-pick commit targeting the release-branch
|
|
||||||
|
|
||||||
After all bugs have been fixed and backported to the release branch, we can move
|
|
||||||
on to tagging the final release commit.
|
|
||||||
|
|
||||||
### Tag Release
|
|
||||||
|
|
||||||
Now it's time to run the `Tag` action on the release branch.
|
|
||||||
|
|
||||||
Run the tag action by going to the repo's "Actions" tab in the Github UI. You
|
|
||||||
will be prompted for the desired branch and the version you are tagging. The
|
|
||||||
latest commit on the selected branch will be the commit that is tagged.
|
|
||||||
|
|
||||||
### Draft Release Notes
|
|
||||||
|
|
||||||
We're getting close to starting the official release, so you should take this
|
|
||||||
opportunity to draft up the release notes. You can create a [new release draft
|
|
||||||
here](https://github.com/crossplane/crossplane/releases/new). Make sure you
|
|
||||||
select "This is a pre-release" and hit "Save draft" when you are ready to share
|
|
||||||
and collect feedback. Do **not** hit "Publish release" yet.
|
|
||||||
|
|
||||||
You can see and follow the template and structure from [previous
|
|
||||||
releases](https://github.com/crossplane/crossplane/releases).
|
|
||||||
|
|
||||||
### Build and Publish
|
|
||||||
|
|
||||||
Run the `CI` action on the release branch. This will build and publish the
|
|
||||||
official release with the correct version tag and all of its release artifacts
|
|
||||||
will be published.
|
|
||||||
|
|
||||||
If there are any `Configuration` packages that are built in the repo, you must
|
|
||||||
also run the `Configurations` action on the release branch. This will build,
|
|
||||||
tag, and publish the `Configuration` packages to the configured OCI image
|
|
||||||
registry.
|
|
||||||
|
|
||||||
After the pipeline runs successfully, you should verify that all artifacts have
|
|
||||||
been published to:
|
|
||||||
|
|
||||||
For all repos:
|
|
||||||
* [Docker Hub](https://hub.docker.com/repository/docker/crossplane)
|
|
||||||
|
|
||||||
For all repos with Helm charts:
|
|
||||||
* [S3 releases bucket](https://releases.crossplane.io/)
|
|
||||||
* [Helm chart repository](https://charts.crossplane.io/)
|
|
||||||
|
|
||||||
For crossplane/crossplane:
|
|
||||||
* [Docs website](https://docs.crossplane.io)
|
|
||||||
* [Configuration Packages](https://marketplace.upbound.io)
|
|
||||||
|
|
||||||
### Tag Next Pre-release
|
|
||||||
|
|
||||||
The next step is to create the pre-release tag for the `HEAD` commit in main
|
|
||||||
development branch. This tag serves as an indication of when the release was
|
|
||||||
branched from the main development branch and is also important for generating
|
|
||||||
future versions of the main development branch builds since that [versioning
|
|
||||||
process](https://github.com/upbound/build/blob/master/makelib/common.mk#L182-L196)
|
|
||||||
is based on `git describe --tags`.
|
|
||||||
|
|
||||||
> NOTE: the `build` submodule uses the latest tag by timestamp on the branch
|
|
||||||
> which the commit it is building resides on. If there were no prep commits made
|
|
||||||
> on the release branch, then its `HEAD` is even with the main development
|
|
||||||
> branch (i.e. the stable tag and the next pre-release tag will be on the same
|
|
||||||
> commit). This means that we must tag the pre-release version _after_ the
|
|
||||||
> stable version to ensure subsequent builds use the next pre-release tag as
|
|
||||||
> their base. If there are additional commits on the release branch before the
|
|
||||||
> stable tag is created, then the pre-release tag could be created first.
|
|
||||||
|
|
||||||
To accomplish this, run the `Tag` action for the repo on the main development
|
|
||||||
branch branch. You will be prompted to enter the `version` for the tag. Since
|
|
||||||
this tag will essentially be the start of pre-releases working towards the
|
|
||||||
**next** version, the `version` should be the **next** release number, plus a
|
|
||||||
trailing tag to indicate it is a pre-release. The current convention is to use
|
|
||||||
`*-rc.0`. For example, when we are releasing the `v0.9.0` release and we are
|
|
||||||
ready for the main development branch to start working towards the **next**
|
|
||||||
release of `v0.10.0`, we would make the tag `v0.10.0-rc.0`
|
|
||||||
|
|
||||||
After the tag action has succeeded, verify in the [GitHub
|
|
||||||
UI](https://github.com/crossplane/crossplane/tags) that the tag was successfully
|
|
||||||
applied to the correct commit.
|
|
||||||
|
|
||||||
The main development branch can now be opened for new features since we have a
|
|
||||||
safe release branch to continue bug fixes and improvements for the release
|
|
||||||
itself. Essentially, the main development branch is free to now diverge from the
|
|
||||||
release branch.
|
|
||||||
|
|
||||||
### Promote
|
|
||||||
|
|
||||||
If everything looks good with the official versioned release that we just
|
|
||||||
published, we can go ahead and run the `Promote` action on the release branch.
|
|
||||||
This is a very quick pipeline that doesn't rebuild anything, it simply makes
|
|
||||||
metadata changes to the published release to also include the release in the
|
|
||||||
channel of your choice.
|
|
||||||
|
|
||||||
Run the `Promote` action on the release branch and input the version you would
|
|
||||||
like to promote (e.g. `v0.5.0`) and the channel you'd like to promote it to.
|
|
||||||
|
|
||||||
After the `Promote` actions have succeeded, verify on DockerHub and the Helm
|
|
||||||
chart repository that the release has been promoted to the right channels.
|
|
||||||
|
|
||||||
### Publish Release Notes
|
|
||||||
|
|
||||||
Now that the release has been published and verified, you can publish the
|
|
||||||
[release notes](https://github.com/crossplane/crossplane/releases) that you
|
|
||||||
drafted earlier. After incorporating all feedback, you can now click on the
|
|
||||||
"Publish release" button.
|
|
||||||
|
|
||||||
This will send an email notification with the release notes to all watchers of
|
|
||||||
the repo.
|
|
||||||
|
|
||||||
### Announce Release
|
|
||||||
|
|
||||||
We have completed the entire release, so it's now time to announce it to the
|
|
||||||
world. Using the [@crossplane_io](https://twitter.com/crossplane_io) Twitter
|
|
||||||
account, tweet about the new release and blog. You'll see examples from the
|
|
||||||
previous releases, such as this tweet for
|
|
||||||
[v0.4](https://twitter.com/crossplane_io/status/1189307636350705664).
|
|
||||||
|
|
||||||
Post a link to this tweet on the Slack #announcements channel, then copy a link
|
|
||||||
to that and post it in the #general channel.
|
|
||||||
|
|
||||||
### Patch Releases
|
|
||||||
|
|
||||||
We also have the ability to run patch releases to update previous releases that
|
|
||||||
have already been published. These patch releases are always run from the last
|
|
||||||
release branch, we do **not** create a new release branch for a patch release.
|
|
||||||
|
|
||||||
The basic flow is **very** similar to a normal release, but with a few less
|
|
||||||
steps. Please refer to details for each step in the sections above.
|
|
||||||
|
|
||||||
* Fix any bugs in the main development branch first and then `cherry-pick -x` to
|
|
||||||
the release branch
|
|
||||||
* If main development branch has already removed the relevant code then make
|
|
||||||
your fix directly in the release branch
|
|
||||||
* After all testing on the release branch look good and any docs/tests have been
|
|
||||||
updated with the new version number, run the `Tag` action on the release
|
|
||||||
branch with the new patch version (e.g. `v0.5.1`)
|
|
||||||
* Run the normal `CI` action on the release branch to build and publish the
|
|
||||||
release
|
|
||||||
* Publish release notes
|
|
||||||
* Run `Promote` action to promote the patch release to the appropriate channels
|
|
|
@ -1,20 +0,0 @@
|
||||||
---
|
|
||||||
title: FAQ
|
|
||||||
weight: 1200
|
|
||||||
---
|
|
||||||
|
|
||||||
### Where did the name Crossplane come from?
|
|
||||||
|
|
||||||
Crossplane is the fusing of cross-cloud control plane. We wanted to use a noun
|
|
||||||
that refers to the entity responsible for connecting different cloud providers
|
|
||||||
and acts as control plane across them. Cross implies “cross-cloud” and “plane”
|
|
||||||
brings in “control plane”.
|
|
||||||
|
|
||||||
### What's up with popsicle?
|
|
||||||
|
|
||||||
We believe in a multi-flavor cloud.
|
|
||||||
|
|
||||||
### Related Projects
|
|
||||||
See [Related Projects].
|
|
||||||
|
|
||||||
[Related Projects]: {{<ref "related_projects" >}}
|
|
|
@ -1,83 +0,0 @@
|
||||||
---
|
|
||||||
title: Related Projects
|
|
||||||
weight: 1201
|
|
||||||
---
|
|
||||||
|
|
||||||
While there are many projects that address similar issues, none of them
|
|
||||||
encapsulate the full use case that Crossplane addresses. This list is not
|
|
||||||
exhaustive and is not meant to provide a deep analysis of the following
|
|
||||||
projects, but instead to motivate why Crossplane was created.
|
|
||||||
|
|
||||||
## Open Service Broker and Service Catalog
|
|
||||||
|
|
||||||
The [Open Service Broker] and the [Kubernetes Service Catalog] are able to
|
|
||||||
dynamically provision cloud services from Kubernetes. As a result it shares
|
|
||||||
similar goals with Crossplane. However, service broker does not have the
|
|
||||||
ability to define, compose, and publish your own infrastructure resources to
|
|
||||||
the Kubernetes API in a no-code way. Crossplane goes further by enabling
|
|
||||||
infrastructure operators to hide infrastructure complexity and include policy
|
|
||||||
guardrails, with a team-centric approach and a strong separation of concerns,
|
|
||||||
so applications can easily and safely consume the infrastructure they need,
|
|
||||||
using any tool that works with the Kubernetes API. Solutions like the [GCP
|
|
||||||
implementation of Open Service Broker][GCP OSB] have been deprecated in favor
|
|
||||||
of a more Kubernetes-native solution, but one that is Google-specific.
|
|
||||||
|
|
||||||
## GCP Config Connector
|
|
||||||
|
|
||||||
The [GCP Config Connector] is the GCP replacement for Open Service Broker, and
|
|
||||||
implements a set of Kubernetes controllers that are able to provision managed
|
|
||||||
services in GCP. It defines a set of CRDs for managed services like CloudSQL,
|
|
||||||
and controllers that can provision them via their cloud APIs. It is similar to
|
|
||||||
Crossplane in that it can provision managed services in GCP. Crossplane goes
|
|
||||||
further by enabling you to provision managed services from any cloud
|
|
||||||
provider and the ability to define, compose, and publish your own
|
|
||||||
infrastructure resources in a no-code way. Crossplane supports a team-centric
|
|
||||||
approach with a strong separation of concerns, that enables applications to
|
|
||||||
easily and safely consume the infrastructure they need, using any tool that
|
|
||||||
works with the Kubernetes API. GCP Config Connector is open source as of May
|
|
||||||
12, 2022.
|
|
||||||
|
|
||||||
## AWS Controllers for Kubernetes
|
|
||||||
|
|
||||||
The [AWS Controllers for Kubernetes] is a recent project that implements a set of
|
|
||||||
Kubernetes controllers that are able to provision managed services in AWS. It
|
|
||||||
defines a set of CRDs for managed services like DynamoDB, and controllers that
|
|
||||||
can provision them. It is similar to Crossplane in that
|
|
||||||
it can provision managed services in AWS. Crossplane goes further by
|
|
||||||
enabling you to provision managed services from any cloud provider and the
|
|
||||||
ability to define, compose, and publish your own infrastructure API types in
|
|
||||||
Kubernetes in a no-code way. Crossplane supports a team-centric approach with a
|
|
||||||
strong separation of concerns, that enables applications to easily and safely
|
|
||||||
consume the infrastructure they need, using any tool that works with the
|
|
||||||
Kubernetes API.
|
|
||||||
|
|
||||||
## AWS CloudFormation, GCP Deployment Manager, and Others
|
|
||||||
|
|
||||||
These products offer a declarative model for deploying and provisioning
|
|
||||||
infrastructure in each of the respective cloud providers. They only work for
|
|
||||||
one cloud provider, are generally closed source, and offer little or no
|
|
||||||
extensibility points, let alone being able to extend the Kubernetes API to
|
|
||||||
provide your own infrastructure abstractions in a no-code way. We have
|
|
||||||
considered using some of these products as a way to implement resource
|
|
||||||
controllers in Crossplane. These projects use an Infrastructure as Code
|
|
||||||
approach to management, while Crossplane offers an API-driven control plane.
|
|
||||||
|
|
||||||
## Terraform and Pulumi
|
|
||||||
|
|
||||||
[Terraform] and [Pulumi] are tools for provisioning infrastructure across cloud
|
|
||||||
providers that offer a declarative configuration language with support for
|
|
||||||
templating, composability, referential integrity and dependency management.
|
|
||||||
Terraform can declaratively manage any compatible API and perform changes when
|
|
||||||
the tool is run by a human or in a deployment pipeline. Terraform is an
|
|
||||||
Infrastructure as Code tool, while Crossplane offers an API-driven control
|
|
||||||
plane.
|
|
||||||
|
|
||||||
<!-- Named Links -->
|
|
||||||
|
|
||||||
[Open Service Broker]: https://www.openservicebrokerapi.org/
|
|
||||||
[Kubernetes Service Catalog]: https://github.com/kubernetes-retired/service-catalog
|
|
||||||
[GCP OSB]: https://cloud.google.com/kubernetes-engine/docs/concepts/google-cloud-platform-service-broker
|
|
||||||
[GCP Config Connector]: https://github.com/GoogleCloudPlatform/k8s-config-connector
|
|
||||||
[AWS Controllers for Kubernetes]: https://github.com/aws-controllers-k8s/community
|
|
||||||
[Terraform]: https://www.terraform.io/
|
|
||||||
[Pulumi]: https://www.pulumi.com/
|
|
|
@ -1,25 +0,0 @@
|
||||||
---
|
|
||||||
title: "Getting Started"
|
|
||||||
weight: 1
|
|
||||||
---
|
|
||||||
|
|
||||||
{{< img src="/media/banner.png" alt="Crossplane Popsicle Truck" size="large" >}}
|
|
||||||
|
|
||||||
|
|
||||||
Crossplane is an open source Kubernetes add-on that transforms your cluster into
|
|
||||||
a **universal control plane**. Crossplane enables platform teams to assemble
|
|
||||||
infrastructure from multiple vendors, and expose higher level self-service APIs
|
|
||||||
for application teams to consume, without having to write any code.
|
|
||||||
|
|
||||||
Crossplane extends your Kubernetes cluster to support orchestrating any
|
|
||||||
infrastructure or managed service. Compose Crossplane's granular resources into
|
|
||||||
higher level abstractions that can be versioned, managed, deployed and consumed
|
|
||||||
using your favorite tools and existing processes. [Install Crossplane]({{<ref "install-configure" >}}) into any
|
|
||||||
Kubernetes cluster to get started.
|
|
||||||
|
|
||||||
Crossplane is a [Cloud Native Compute Foundation][cncf] project.
|
|
||||||
|
|
||||||
<!-- Named Links -->
|
|
||||||
|
|
||||||
|
|
||||||
[cncf]: https://www.cncf.io/
|
|
|
@ -1,673 +0,0 @@
|
||||||
---
|
|
||||||
title: Create a Configuration
|
|
||||||
weight: 4
|
|
||||||
---
|
|
||||||
|
|
||||||
In the [previous section] we were able to create a PostgreSQL database because
|
|
||||||
we had installed a configuration package that defined the `PostgreSQLInstance`
|
|
||||||
type and a `Composition` of managed resources that mapped to it. Crossplane
|
|
||||||
allows you to define your own composite resources (XRs) and compositions, then
|
|
||||||
package them up to be easily distributed as OCI images. This allows you to
|
|
||||||
construct a reproducible platform that exposes infrastructure APIs at your
|
|
||||||
desired level of abstraction, and can be installed into any Crossplane cluster.
|
|
||||||
|
|
||||||
## Create a Configuration Directory
|
|
||||||
|
|
||||||
We are going to build the same configuration package that we previously
|
|
||||||
installed. It will consist of three files:
|
|
||||||
|
|
||||||
* `crossplane.yaml` - Metadata about the configuration.
|
|
||||||
* `definition.yaml` - The XRD.
|
|
||||||
* `composition.yaml` - The Composition.
|
|
||||||
|
|
||||||
Crossplane can create a configuration from any directory with a valid
|
|
||||||
`crossplane.yaml` metadata file at its root, and one or more XRDs or
|
|
||||||
Compositions. The directory structure does not matter, as long as the
|
|
||||||
`crossplane.yaml` file is at the root. Note that a configuration need not
|
|
||||||
contain one XRD and one composition - it could include only an XRD, only a
|
|
||||||
composition, several compositions, or any combination thereof.
|
|
||||||
|
|
||||||
Before we go any further, we must create a directory in which to build our
|
|
||||||
configuration:
|
|
||||||
|
|
||||||
```console
|
|
||||||
mkdir crossplane-config
|
|
||||||
cd crossplane-config
|
|
||||||
```
|
|
||||||
|
|
||||||
We'll create the aforementioned three files in this directory, then build them
|
|
||||||
into a package.
|
|
||||||
|
|
||||||
> Note that `definition.yaml` and `composition.yaml` could be created directly
|
|
||||||
> in the Crossplane cluster without packaging them into a configuration. This
|
|
||||||
> can be useful for testing compositions before pushing them to a registry.
|
|
||||||
|
|
||||||
## Create CompositeResourceDefinition
|
|
||||||
|
|
||||||
First we'll create a `CompositeResourceDefinition` (XRD) to define the schema of
|
|
||||||
our `XPostgreSQLInstance` and its `PostgreSQLInstance` resource claim.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: apiextensions.crossplane.io/v1
|
|
||||||
kind: CompositeResourceDefinition
|
|
||||||
metadata:
|
|
||||||
name: xpostgresqlinstances.database.example.org
|
|
||||||
spec:
|
|
||||||
group: database.example.org
|
|
||||||
names:
|
|
||||||
kind: XPostgreSQLInstance
|
|
||||||
plural: xpostgresqlinstances
|
|
||||||
claimNames:
|
|
||||||
kind: PostgreSQLInstance
|
|
||||||
plural: postgresqlinstances
|
|
||||||
connectionSecretKeys:
|
|
||||||
- username
|
|
||||||
- password
|
|
||||||
- endpoint
|
|
||||||
- port
|
|
||||||
versions:
|
|
||||||
- name: v1alpha1
|
|
||||||
served: true
|
|
||||||
referenceable: true
|
|
||||||
schema:
|
|
||||||
openAPIV3Schema:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
spec:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
parameters:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
storageGB:
|
|
||||||
type: integer
|
|
||||||
required:
|
|
||||||
- storageGB
|
|
||||||
required:
|
|
||||||
- parameters
|
|
||||||
```
|
|
||||||
|
|
||||||
```console
|
|
||||||
curl -OL https://raw.githubusercontent.com/crossplane/crossplane/release-1.9/docs/snippets/package/definition.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
> You might notice that the XRD we created specifies both "names" and "claim
|
|
||||||
> names". This is because the composite resource it defines offers a composite
|
|
||||||
> resource claim (XRC).
|
|
||||||
|
|
||||||
## Create Compositions
|
|
||||||
|
|
||||||
Now we'll specify which managed resources our `XPostgreSQLInstance` XR
|
|
||||||
and its claim could be composed of, and how they should be configured. We do
|
|
||||||
this by defining a `Composition` that can satisfy the XR we defined above. In
|
|
||||||
this case, our `Composition` will specify how to provision a public PostgreSQL
|
|
||||||
instance on the chosen provider.
|
|
||||||
|
|
||||||
{{< tabs >}}
|
|
||||||
{{< tab "AWS (Default VPC)" >}}
|
|
||||||
|
|
||||||
> Note that this Composition will create an RDS instance using your default VPC,
|
|
||||||
> which may or may not allow connections from the internet depending on how it
|
|
||||||
> is configured. Select the AWS (New VPC) Composition if you wish to create an
|
|
||||||
> RDS instance that will allow traffic from the internet.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: apiextensions.crossplane.io/v1
|
|
||||||
kind: Composition
|
|
||||||
metadata:
|
|
||||||
name: xpostgresqlinstances.aws.database.example.org
|
|
||||||
labels:
|
|
||||||
provider: aws
|
|
||||||
guide: quickstart
|
|
||||||
vpc: default
|
|
||||||
spec:
|
|
||||||
writeConnectionSecretsToNamespace: crossplane-system
|
|
||||||
compositeTypeRef:
|
|
||||||
apiVersion: database.example.org/v1alpha1
|
|
||||||
kind: XPostgreSQLInstance
|
|
||||||
resources:
|
|
||||||
- name: rdsinstance
|
|
||||||
base:
|
|
||||||
apiVersion: database.aws.crossplane.io/v1beta1
|
|
||||||
kind: RDSInstance
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
region: us-east-1
|
|
||||||
dbInstanceClass: db.t2.small
|
|
||||||
masterUsername: masteruser
|
|
||||||
engine: postgres
|
|
||||||
engineVersion: "12"
|
|
||||||
skipFinalSnapshotBeforeDeletion: true
|
|
||||||
publiclyAccessible: true
|
|
||||||
writeConnectionSecretToRef:
|
|
||||||
namespace: crossplane-system
|
|
||||||
patches:
|
|
||||||
- fromFieldPath: "metadata.uid"
|
|
||||||
toFieldPath: "spec.writeConnectionSecretToRef.name"
|
|
||||||
transforms:
|
|
||||||
- type: string
|
|
||||||
string:
|
|
||||||
fmt: "%s-postgresql"
|
|
||||||
- fromFieldPath: "spec.parameters.storageGB"
|
|
||||||
toFieldPath: "spec.forProvider.allocatedStorage"
|
|
||||||
connectionDetails:
|
|
||||||
- fromConnectionSecretKey: username
|
|
||||||
- fromConnectionSecretKey: password
|
|
||||||
- fromConnectionSecretKey: endpoint
|
|
||||||
- fromConnectionSecretKey: port
|
|
||||||
```
|
|
||||||
|
|
||||||
```console
|
|
||||||
curl -OL https://raw.githubusercontent.com/crossplane/crossplane/release-1.9/docs/snippets/package/aws/composition.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
{{< /tab >}}
|
|
||||||
{{< tab "AWS (New VPC)" >}}
|
|
||||||
|
|
||||||
> Note: this `Composition` for AWS also includes several networking managed
|
|
||||||
> resources that are required to provision a publicly available PostgreSQL
|
|
||||||
> instance. Composition enables scenarios such as this, as well as far more
|
|
||||||
> complex ones. See the [composition] documentation for more information.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: apiextensions.crossplane.io/v1
|
|
||||||
kind: Composition
|
|
||||||
metadata:
|
|
||||||
name: vpcpostgresqlinstances.aws.database.example.org
|
|
||||||
labels:
|
|
||||||
provider: aws
|
|
||||||
guide: quickstart
|
|
||||||
vpc: new
|
|
||||||
spec:
|
|
||||||
writeConnectionSecretsToNamespace: crossplane-system
|
|
||||||
compositeTypeRef:
|
|
||||||
apiVersion: database.example.org/v1alpha1
|
|
||||||
kind: XPostgreSQLInstance
|
|
||||||
resources:
|
|
||||||
- name: vpc
|
|
||||||
base:
|
|
||||||
apiVersion: ec2.aws.crossplane.io/v1beta1
|
|
||||||
kind: VPC
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
region: us-east-1
|
|
||||||
cidrBlock: 192.168.0.0/16
|
|
||||||
enableDnsSupport: true
|
|
||||||
enableDnsHostNames: true
|
|
||||||
- name: subnet-a
|
|
||||||
base:
|
|
||||||
apiVersion: ec2.aws.crossplane.io/v1beta1
|
|
||||||
kind: Subnet
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
zone: us-east-1a
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
region: us-east-1
|
|
||||||
cidrBlock: 192.168.64.0/18
|
|
||||||
vpcIdSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
availabilityZone: us-east-1a
|
|
||||||
- name: subnet-b
|
|
||||||
base:
|
|
||||||
apiVersion: ec2.aws.crossplane.io/v1beta1
|
|
||||||
kind: Subnet
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
zone: us-east-1b
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
region: us-east-1
|
|
||||||
cidrBlock: 192.168.128.0/18
|
|
||||||
vpcIdSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
availabilityZone: us-east-1b
|
|
||||||
- name: subnet-c
|
|
||||||
base:
|
|
||||||
apiVersion: ec2.aws.crossplane.io/v1beta1
|
|
||||||
kind: Subnet
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
zone: us-east-1c
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
region: us-east-1
|
|
||||||
cidrBlock: 192.168.192.0/18
|
|
||||||
vpcIdSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
availabilityZone: us-east-1c
|
|
||||||
- name: dbsubnetgroup
|
|
||||||
base:
|
|
||||||
apiVersion: database.aws.crossplane.io/v1beta1
|
|
||||||
kind: DBSubnetGroup
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
region: us-east-1
|
|
||||||
description: An excellent formation of subnetworks.
|
|
||||||
subnetIdSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
- name: internetgateway
|
|
||||||
base:
|
|
||||||
apiVersion: ec2.aws.crossplane.io/v1beta1
|
|
||||||
kind: InternetGateway
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
region: us-east-1
|
|
||||||
vpcIdSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
- name: routetable
|
|
||||||
base:
|
|
||||||
apiVersion: ec2.aws.crossplane.io/v1beta1
|
|
||||||
kind: RouteTable
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
region: us-east-1
|
|
||||||
vpcIdSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
routes:
|
|
||||||
- destinationCidrBlock: 0.0.0.0/0
|
|
||||||
gatewayIdSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
associations:
|
|
||||||
- subnetIdSelector:
|
|
||||||
matchLabels:
|
|
||||||
zone: us-east-1a
|
|
||||||
- subnetIdSelector:
|
|
||||||
matchLabels:
|
|
||||||
zone: us-east-1b
|
|
||||||
- subnetIdSelector:
|
|
||||||
matchLabels:
|
|
||||||
zone: us-east-1c
|
|
||||||
- name: securitygroup
|
|
||||||
base:
|
|
||||||
apiVersion: ec2.aws.crossplane.io/v1beta1
|
|
||||||
kind: SecurityGroup
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
region: us-east-1
|
|
||||||
vpcIdSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
groupName: crossplane-getting-started
|
|
||||||
description: Allow access to PostgreSQL
|
|
||||||
ingress:
|
|
||||||
- fromPort: 5432
|
|
||||||
toPort: 5432
|
|
||||||
ipProtocol: tcp
|
|
||||||
ipRanges:
|
|
||||||
- cidrIp: 0.0.0.0/0
|
|
||||||
description: Everywhere
|
|
||||||
- name: rdsinstance
|
|
||||||
base:
|
|
||||||
apiVersion: database.aws.crossplane.io/v1beta1
|
|
||||||
kind: RDSInstance
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
region: us-east-1
|
|
||||||
dbSubnetGroupNameSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
vpcSecurityGroupIDSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
dbInstanceClass: db.t2.small
|
|
||||||
masterUsername: masteruser
|
|
||||||
engine: postgres
|
|
||||||
engineVersion: "12"
|
|
||||||
skipFinalSnapshotBeforeDeletion: true
|
|
||||||
publiclyAccessible: true
|
|
||||||
writeConnectionSecretToRef:
|
|
||||||
namespace: crossplane-system
|
|
||||||
patches:
|
|
||||||
- fromFieldPath: "metadata.uid"
|
|
||||||
toFieldPath: "spec.writeConnectionSecretToRef.name"
|
|
||||||
transforms:
|
|
||||||
- type: string
|
|
||||||
string:
|
|
||||||
fmt: "%s-postgresql"
|
|
||||||
- fromFieldPath: "spec.parameters.storageGB"
|
|
||||||
toFieldPath: "spec.forProvider.allocatedStorage"
|
|
||||||
connectionDetails:
|
|
||||||
- fromConnectionSecretKey: username
|
|
||||||
- fromConnectionSecretKey: password
|
|
||||||
- fromConnectionSecretKey: endpoint
|
|
||||||
- fromConnectionSecretKey: port
|
|
||||||
```
|
|
||||||
|
|
||||||
```console
|
|
||||||
curl -OL https://raw.githubusercontent.com/crossplane/crossplane/release-1.9/docs/snippets/package/aws-with-vpc/composition.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
{{< /tab >}}
|
|
||||||
{{< tab "GCP" >}}
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: apiextensions.crossplane.io/v1
|
|
||||||
kind: Composition
|
|
||||||
metadata:
|
|
||||||
name: xpostgresqlinstances.gcp.database.example.org
|
|
||||||
labels:
|
|
||||||
provider: gcp
|
|
||||||
guide: quickstart
|
|
||||||
spec:
|
|
||||||
writeConnectionSecretsToNamespace: crossplane-system
|
|
||||||
compositeTypeRef:
|
|
||||||
apiVersion: database.example.org/v1alpha1
|
|
||||||
kind: XPostgreSQLInstance
|
|
||||||
resources:
|
|
||||||
- name: cloudsqlinstance
|
|
||||||
base:
|
|
||||||
apiVersion: database.gcp.crossplane.io/v1beta1
|
|
||||||
kind: CloudSQLInstance
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
databaseVersion: POSTGRES_12
|
|
||||||
region: us-central1
|
|
||||||
settings:
|
|
||||||
tier: db-custom-1-3840
|
|
||||||
dataDiskType: PD_SSD
|
|
||||||
ipConfiguration:
|
|
||||||
ipv4Enabled: true
|
|
||||||
authorizedNetworks:
|
|
||||||
- value: "0.0.0.0/0"
|
|
||||||
writeConnectionSecretToRef:
|
|
||||||
namespace: crossplane-system
|
|
||||||
patches:
|
|
||||||
- fromFieldPath: "metadata.uid"
|
|
||||||
toFieldPath: "spec.writeConnectionSecretToRef.name"
|
|
||||||
transforms:
|
|
||||||
- type: string
|
|
||||||
string:
|
|
||||||
fmt: "%s-postgresql"
|
|
||||||
- fromFieldPath: "spec.parameters.storageGB"
|
|
||||||
toFieldPath: "spec.forProvider.settings.dataDiskSizeGb"
|
|
||||||
connectionDetails:
|
|
||||||
- fromConnectionSecretKey: username
|
|
||||||
- fromConnectionSecretKey: password
|
|
||||||
- fromConnectionSecretKey: endpoint
|
|
||||||
- type: FromValue
|
|
||||||
name: port
|
|
||||||
value: "5432"
|
|
||||||
```
|
|
||||||
|
|
||||||
```console
|
|
||||||
curl -OL https://raw.githubusercontent.com/crossplane/docs/master/content/v1.9/snippets/package/gcp/composition.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
{{< /tab >}}
|
|
||||||
{{< tab "Azure" >}}
|
|
||||||
|
|
||||||
> Note: the `Composition` for Azure also includes a `ResourceGroup` and
|
|
||||||
> `PostgreSQLServerFirewallRule` that are required to provision a publicly
|
|
||||||
> available PostgreSQL instance on Azure. Composition enables scenarios such as
|
|
||||||
> this, as well as far more complex ones. See the [composition] documentation
|
|
||||||
> for more information.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: apiextensions.crossplane.io/v1
|
|
||||||
kind: Composition
|
|
||||||
metadata:
|
|
||||||
name: xpostgresqlinstances.azure.database.example.org
|
|
||||||
labels:
|
|
||||||
provider: azure
|
|
||||||
guide: quickstart
|
|
||||||
spec:
|
|
||||||
writeConnectionSecretsToNamespace: crossplane-system
|
|
||||||
compositeTypeRef:
|
|
||||||
apiVersion: database.example.org/v1alpha1
|
|
||||||
kind: XPostgreSQLInstance
|
|
||||||
resources:
|
|
||||||
- name: resourcegroup
|
|
||||||
base:
|
|
||||||
apiVersion: azure.crossplane.io/v1alpha3
|
|
||||||
kind: ResourceGroup
|
|
||||||
spec:
|
|
||||||
location: West US 2
|
|
||||||
- name: postgresqlserver
|
|
||||||
base:
|
|
||||||
apiVersion: database.azure.crossplane.io/v1beta1
|
|
||||||
kind: PostgreSQLServer
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
administratorLogin: myadmin
|
|
||||||
resourceGroupNameSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
location: West US 2
|
|
||||||
sslEnforcement: Disabled
|
|
||||||
version: "9.6"
|
|
||||||
sku:
|
|
||||||
tier: GeneralPurpose
|
|
||||||
capacity: 2
|
|
||||||
family: Gen5
|
|
||||||
writeConnectionSecretToRef:
|
|
||||||
namespace: crossplane-system
|
|
||||||
patches:
|
|
||||||
- fromFieldPath: "metadata.uid"
|
|
||||||
toFieldPath: "spec.writeConnectionSecretToRef.name"
|
|
||||||
transforms:
|
|
||||||
- type: string
|
|
||||||
string:
|
|
||||||
fmt: "%s-postgresql"
|
|
||||||
- fromFieldPath: "spec.parameters.storageGB"
|
|
||||||
toFieldPath: "spec.forProvider.storageProfile.storageMB"
|
|
||||||
transforms:
|
|
||||||
- type: math
|
|
||||||
math:
|
|
||||||
multiply: 1024
|
|
||||||
connectionDetails:
|
|
||||||
- fromConnectionSecretKey: username
|
|
||||||
- fromConnectionSecretKey: password
|
|
||||||
- fromConnectionSecretKey: endpoint
|
|
||||||
- type: FromValue
|
|
||||||
name: port
|
|
||||||
value: "5432"
|
|
||||||
- name: firewallrule
|
|
||||||
base:
|
|
||||||
apiVersion: database.azure.crossplane.io/v1alpha3
|
|
||||||
kind: PostgreSQLServerFirewallRule
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
serverNameSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
resourceGroupNameSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
properties:
|
|
||||||
startIpAddress: 0.0.0.0
|
|
||||||
endIpAddress: 255.255.255.254
|
|
||||||
```
|
|
||||||
|
|
||||||
```console
|
|
||||||
curl -OL https://raw.githubusercontent.com/crossplane/crossplane/release-1.9/docs/snippets/package/azure/composition.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
{{< /tab >}}
|
|
||||||
{{< /tabs >}}
|
|
||||||
|
|
||||||
## Build and Push The Configuration
|
|
||||||
|
|
||||||
Finally, we'll author our metadata file then build and push our configuration
|
|
||||||
so that Crossplane users may install it.
|
|
||||||
|
|
||||||
> Note that Crossplane pushes packages to an OCI registry - currently [Docker
|
|
||||||
> Hub] by default. You may need to run `docker login` before you are able to
|
|
||||||
> push a package.
|
|
||||||
|
|
||||||
{{< tabs >}}
|
|
||||||
{{< tab "AWS (Default VPC)" >}}
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: meta.pkg.crossplane.io/v1
|
|
||||||
kind: Configuration
|
|
||||||
metadata:
|
|
||||||
name: getting-started-with-aws
|
|
||||||
annotations:
|
|
||||||
guide: quickstart
|
|
||||||
provider: aws
|
|
||||||
vpc: default
|
|
||||||
spec:
|
|
||||||
crossplane:
|
|
||||||
version: ">=v1.4.0-0"
|
|
||||||
dependsOn:
|
|
||||||
- provider: xpkg.upbound.io/crossplane-contrib/provider-aws
|
|
||||||
version: ">=v0.18.2"
|
|
||||||
```
|
|
||||||
|
|
||||||
```console
|
|
||||||
curl -OL https://raw.githubusercontent.com/crossplane/crossplane/release-1.9/docs/snippets/package/aws/crossplane.yaml
|
|
||||||
|
|
||||||
kubectl crossplane build configuration
|
|
||||||
```
|
|
||||||
|
|
||||||
You should see a file in your working directory with a `.xpkg` extension. The
|
|
||||||
Crossplane CLI will automatically tag and push it to the registry of your
|
|
||||||
choosing in the next step if it is the only `.xpkg` in the directory. Otherwise
|
|
||||||
you may specify a specific package by using the `-f` flag.
|
|
||||||
|
|
||||||
```console
|
|
||||||
# Set this to the Docker Hub username or OCI registry you wish to use.
|
|
||||||
REG=my-package-repo
|
|
||||||
kubectl crossplane push configuration ${REG}/getting-started-with-aws:v1.9.1
|
|
||||||
```
|
|
||||||
|
|
||||||
> Note that the Crossplane CLI will not follow symbolic links for files in the
|
|
||||||
> root package directory.
|
|
||||||
|
|
||||||
{{< /tab >}}
|
|
||||||
{{< tab "AWS (Default VPC)" >}}
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: meta.pkg.crossplane.io/v1
|
|
||||||
kind: Configuration
|
|
||||||
metadata:
|
|
||||||
name: getting-started-with-aws-with-vpc
|
|
||||||
annotations:
|
|
||||||
guide: quickstart
|
|
||||||
provider: aws
|
|
||||||
vpc: new
|
|
||||||
spec:
|
|
||||||
crossplane:
|
|
||||||
version: ">=v1.4.0-0"
|
|
||||||
dependsOn:
|
|
||||||
- provider: xpkg.upbound.io/crossplane-contrib/provider-aws
|
|
||||||
version: ">=v0.18.2"
|
|
||||||
```
|
|
||||||
|
|
||||||
```console
|
|
||||||
curl -OL https://raw.githubusercontent.com/crossplane/crossplane/release-1.9/docs/snippets/package/aws-with-vpc/crossplane.yaml
|
|
||||||
|
|
||||||
kubectl crossplane build configuration
|
|
||||||
```
|
|
||||||
|
|
||||||
You should see a file in your working directory with a `.xpkg` extension. The
|
|
||||||
Crossplane CLI will automatically tag and push it to the registry of your
|
|
||||||
choosing in the next step if it is the only `.xpkg` in the directory. Otherwise
|
|
||||||
you may specify a specific package by using the `-f` flag.
|
|
||||||
|
|
||||||
```console
|
|
||||||
# Set this to the Docker Hub username or OCI registry you wish to use.
|
|
||||||
REG=my-package-repo
|
|
||||||
kubectl crossplane push configuration ${REG}/getting-started-with-aws-with-vpc:v1.9.1
|
|
||||||
```
|
|
||||||
|
|
||||||
> Note that the Crossplane CLI will not follow symbolic links for files in the
|
|
||||||
> root package directory.
|
|
||||||
|
|
||||||
{{< /tab >}}
|
|
||||||
{{< tab "GCP" >}}
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: meta.pkg.crossplane.io/v1
|
|
||||||
kind: Configuration
|
|
||||||
metadata:
|
|
||||||
name: getting-started-with-gcp
|
|
||||||
annotations:
|
|
||||||
guide: quickstart
|
|
||||||
provider: gcp
|
|
||||||
spec:
|
|
||||||
crossplane:
|
|
||||||
version: ">=v1.4.0-0"
|
|
||||||
dependsOn:
|
|
||||||
- provider: xpkg.upbound.io/crossplane-contrib/provider-gcp
|
|
||||||
version: ">=v0.13.0"
|
|
||||||
```
|
|
||||||
|
|
||||||
```console
|
|
||||||
curl -OL https://raw.githubusercontent.com/crossplane/docs/master/content/v1.9/snippets/package/gcp/crossplane.yaml
|
|
||||||
|
|
||||||
kubectl crossplane build configuration
|
|
||||||
```
|
|
||||||
|
|
||||||
You should see a file in your working directory with a `.xpkg` extension. The
|
|
||||||
Crossplane CLI will automatically tag and push it to the registry of your
|
|
||||||
choosing in the next step if it is the only `.xpkg` in the directory. Otherwise
|
|
||||||
you may specify a specific package by using the `-f` flag.
|
|
||||||
|
|
||||||
```console
|
|
||||||
# Set this to the Docker Hub username or OCI registry you wish to use.
|
|
||||||
REG=my-package-repo
|
|
||||||
kubectl crossplane push configuration ${REG}/getting-started-with-gcp:v1.9.1
|
|
||||||
```
|
|
||||||
|
|
||||||
> Note that the Crossplane CLI will not follow symbolic links for files in the
|
|
||||||
> root package directory.
|
|
||||||
|
|
||||||
{{< /tab >}}
|
|
||||||
{{< tab "Azure" >}}
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: meta.pkg.crossplane.io/v1
|
|
||||||
kind: Configuration
|
|
||||||
metadata:
|
|
||||||
name: getting-started-with-azure
|
|
||||||
annotations:
|
|
||||||
guide: quickstart
|
|
||||||
provider: azure
|
|
||||||
spec:
|
|
||||||
crossplane:
|
|
||||||
version: ">=v1.4.0-0"
|
|
||||||
dependsOn:
|
|
||||||
- provider: xpkg.upbound.io/crossplane-contrib/provider-azure
|
|
||||||
version: ">=v0.13.0"
|
|
||||||
```
|
|
||||||
|
|
||||||
```console
|
|
||||||
curl -OL https://raw.githubusercontent.com/crossplane/crossplane/release-1.9/docs/snippets/package/azure/crossplane.yaml
|
|
||||||
|
|
||||||
kubectl crossplane build configuration
|
|
||||||
```
|
|
||||||
|
|
||||||
You should see a file in your working directory with a `.xpkg` extension. The
|
|
||||||
Crossplane CLI will automatically tag and push it to the registry of your
|
|
||||||
choosing in the next step if it is the only `.xpkg` in the directory. Otherwise
|
|
||||||
you may specify a specific package by using the `-f` flag.
|
|
||||||
|
|
||||||
```console
|
|
||||||
# Set this to the Docker Hub username or OCI registry you wish to use.
|
|
||||||
REG=my-package-repo
|
|
||||||
kubectl crossplane push configuration ${REG}/getting-started-with-azure:v1.9.1
|
|
||||||
```
|
|
||||||
|
|
||||||
> Note that the Crossplane CLI will not follow symbolic links for files in the
|
|
||||||
> root package directory.
|
|
||||||
|
|
||||||
{{< /tab >}}
|
|
||||||
{{< /tabs >}}
|
|
||||||
|
|
||||||
That's it! You've now built and pushed your package. Take a look at the
|
|
||||||
Crossplane [packages] documentation for more information about installing and
|
|
||||||
working with packages, or read about other Crossplane [concepts].
|
|
||||||
|
|
||||||
## Clean Up
|
|
||||||
|
|
||||||
To clean up, you can simply delete your package directory:
|
|
||||||
|
|
||||||
```console
|
|
||||||
cd ..
|
|
||||||
rm -rf crossplane-config
|
|
||||||
```
|
|
||||||
|
|
||||||
<!-- Named Links -->
|
|
||||||
|
|
||||||
[previous section]: {{<ref "provision-infrastructure" >}}
|
|
||||||
[composed]: {{<ref "../concepts/composition" >}}
|
|
||||||
[composition]: {{<ref "../concepts/composition" >}}
|
|
||||||
[Docker Hub]: https://hub.docker.com/
|
|
||||||
[packages]: {{<ref "../concepts/packages" >}}
|
|
||||||
[concepts]: {{<ref "../concepts" >}}
|
|
|
@ -1,483 +0,0 @@
|
||||||
---
|
|
||||||
title: Install & Configure
|
|
||||||
weight: 2
|
|
||||||
---
|
|
||||||
## Choosing Your Crossplane Distribution
|
|
||||||
|
|
||||||
Users looking to use Crossplane for the first time have two options available to
|
|
||||||
them today. The first way is to use the version of Crossplane which is
|
|
||||||
maintained and released by the community and found on the [Crossplane GitHub].
|
|
||||||
|
|
||||||
The second option is to use a vendor supported Crossplane distribution. These
|
|
||||||
distributions are [certified by the CNCF] to be conformant with Crossplane, but
|
|
||||||
may include additional features or tooling around it that makes it easier to use
|
|
||||||
in production environments.
|
|
||||||
|
|
||||||
{{% tabs "Crossplane Distros" %}}
|
|
||||||
|
|
||||||
{{% tab "Crossplane (upstream)" %}}
|
|
||||||
|
|
||||||
## Start with Upstream Crossplane
|
|
||||||
|
|
||||||
Installing Crossplane into an existing Kubernetes cluster will require a bit
|
|
||||||
more setup, but can provide more flexibility for users who need it.
|
|
||||||
|
|
||||||
### Get a Kubernetes Cluster
|
|
||||||
<!-- inside Crossplane (upstream) -->
|
|
||||||
{{% tabs "Kubernetes Clusters" %}}
|
|
||||||
|
|
||||||
{{% tab "macOS via Homebrew" %}}
|
|
||||||
|
|
||||||
For macOS via Homebrew use the following:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
brew upgrade
|
|
||||||
brew install kind
|
|
||||||
brew install kubectl
|
|
||||||
brew install helm
|
|
||||||
kind create cluster --image kindest/node:v1.23.0 --wait 5m
|
|
||||||
```
|
|
||||||
<!-- close "macOS via Homebrew" -->
|
|
||||||
{{% /tab %}}
|
|
||||||
|
|
||||||
{{% tab "macOS / Linux" %}}
|
|
||||||
|
|
||||||
For macOS / Linux use the following:
|
|
||||||
|
|
||||||
* [Kubernetes cluster]
|
|
||||||
* [Kind]
|
|
||||||
* [Minikube], minimum version `v0.28+`
|
|
||||||
* etc.
|
|
||||||
|
|
||||||
* [Helm], minimum version `v3.0.0+`.
|
|
||||||
|
|
||||||
<!-- close "macOS / Linux" -->
|
|
||||||
{{% /tab %}}
|
|
||||||
|
|
||||||
{{% tab "Windows" %}}
|
|
||||||
For Windows use the following:
|
|
||||||
|
|
||||||
* [Kubernetes cluster]
|
|
||||||
* [Kind]
|
|
||||||
* [Minikube], minimum version `v0.28+`
|
|
||||||
* etc.
|
|
||||||
|
|
||||||
* [Helm], minimum version `v3.0.0+`.
|
|
||||||
|
|
||||||
<!-- close "Windows" -->
|
|
||||||
{{% /tab %}}
|
|
||||||
|
|
||||||
<!-- close "Kubernetes Clusters" -->
|
|
||||||
{{% /tabs %}}
|
|
||||||
|
|
||||||
### Install Crossplane
|
|
||||||
|
|
||||||
{{% tabs "install with helm" %}}
|
|
||||||
|
|
||||||
{{% tab "Helm 3 (stable)" %}}
|
|
||||||
Use Helm 3 to install the latest official `stable` release of Crossplane, suitable for community use and testing:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl create namespace crossplane-system
|
|
||||||
helm repo add crossplane-stable https://charts.crossplane.io/stable
|
|
||||||
helm repo update
|
|
||||||
|
|
||||||
helm install crossplane --namespace crossplane-system crossplane-stable/crossplane
|
|
||||||
```
|
|
||||||
|
|
||||||
<!-- close "Helm 3 (stable)" -->
|
|
||||||
{{% /tab %}}
|
|
||||||
|
|
||||||
{{% tab "Helm 3 (latest)" %}}
|
|
||||||
<!-- fold start -->
|
|
||||||
Use Helm 3 to install the latest pre-release version of Crossplane:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl create namespace crossplane-system
|
|
||||||
|
|
||||||
helm repo add crossplane-master https://charts.crossplane.io/master/
|
|
||||||
helm repo update
|
|
||||||
helm search repo crossplane-master --devel
|
|
||||||
|
|
||||||
helm install crossplane --namespace crossplane-system crossplane-master/crossplane \
|
|
||||||
--devel --version <version>
|
|
||||||
```
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
helm install crossplane --namespace crossplane-system crossplane-master/crossplane \
|
|
||||||
--version 0.11.0-rc.100.gbc5d311 --devel
|
|
||||||
```
|
|
||||||
<!-- close "Helm 3 (latest)" -->
|
|
||||||
{{% /tab %}}
|
|
||||||
<!-- close "install with helm" -->
|
|
||||||
{{% /tabs %}}
|
|
||||||
|
|
||||||
### Check Crossplane Status
|
|
||||||
|
|
||||||
```bash
|
|
||||||
helm list -n crossplane-system
|
|
||||||
|
|
||||||
kubectl get all -n crossplane-system
|
|
||||||
```
|
|
||||||
|
|
||||||
## Install Crossplane CLI
|
|
||||||
|
|
||||||
The Crossplane CLI extends `kubectl` with functionality to build, push, and
|
|
||||||
install [Crossplane packages]:
|
|
||||||
|
|
||||||
{{% tabs "crossplane CLI" %}}
|
|
||||||
|
|
||||||
{{% tab "Stable" %}}
|
|
||||||
```bash
|
|
||||||
curl -sL https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh | sh
|
|
||||||
```
|
|
||||||
<!-- close "Stable" -->
|
|
||||||
{{% /tab %}}
|
|
||||||
|
|
||||||
{{% tab "Latest" %}}
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -sL https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh | XP_CHANNEL=master sh
|
|
||||||
```
|
|
||||||
|
|
||||||
You may also specify `XP_VERSION` for download if you would like to select a
|
|
||||||
specific version from the given release channel. If a version is not specified
|
|
||||||
the latest version from the release channel will be used.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -sL https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh | XP_CHANNEL=master XP_VERSION=v1.0.0-rc.0.130.g94f34fd3 sh
|
|
||||||
```
|
|
||||||
<!-- close "Latest" -->
|
|
||||||
{{% /tab %}}
|
|
||||||
|
|
||||||
<!-- close "crossplane CLI" -->
|
|
||||||
{{% /tabs %}}
|
|
||||||
|
|
||||||
## Select a Getting Started Configuration
|
|
||||||
|
|
||||||
Crossplane goes beyond simply modelling infrastructure primitives as custom
|
|
||||||
resources - it enables you to define new custom resources with schemas of your
|
|
||||||
choosing. We call these "composite resources" (XRs). Composite resources compose
|
|
||||||
managed resources -- Kubernetes custom resources that offer a high fidelity
|
|
||||||
representation of an infrastructure primitive, like an SQL instance or a
|
|
||||||
firewall rule.
|
|
||||||
|
|
||||||
We use two special Crossplane resources to define and configure these new custom
|
|
||||||
resources:
|
|
||||||
|
|
||||||
- A `CompositeResourceDefinition` (XRD) _defines_ a new kind of composite
|
|
||||||
resource, including its schema. An XRD may optionally _offer_ a claim (XRC).
|
|
||||||
- A `Composition` specifies which resources a composite resource will be
|
|
||||||
composed of, and how they should be configured. You can create multiple
|
|
||||||
`Composition` options for each composite resource.
|
|
||||||
|
|
||||||
XRDs and Compositions may be packaged and installed as a _configuration_. A
|
|
||||||
configuration is a [package] of composition configuration that can easily be
|
|
||||||
installed to Crossplane by creating a declarative `Configuration` resource, or
|
|
||||||
by using `kubectl crossplane install configuration`.
|
|
||||||
|
|
||||||
In the examples below we will install a configuration that defines a new
|
|
||||||
`XPostgreSQLInstance` XR and `PostgreSQLInstance` XRC that takes a
|
|
||||||
single `storageGB` parameter, and creates a connection `Secret` with keys for
|
|
||||||
`username`, `password`, and `endpoint`. A `Configuration` exists for each
|
|
||||||
provider that can satisfy a `PostgreSQLInstance`. Let's get started!
|
|
||||||
|
|
||||||
{{% tabs "getting started" %}}
|
|
||||||
|
|
||||||
{{% tab "AWS (Default VPC)" %}}
|
|
||||||
### Install Configuration Package
|
|
||||||
|
|
||||||
> If you prefer to see the contents of this configuration package and how it is
|
|
||||||
> constructed prior to install, skip ahead to the [create a configuration]
|
|
||||||
> section.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl crossplane install configuration registry.upbound.io/xp/getting-started-with-aws:v1.9.1
|
|
||||||
```
|
|
||||||
|
|
||||||
Wait until all packages become healthy:
|
|
||||||
```bash
|
|
||||||
watch kubectl get pkg
|
|
||||||
```
|
|
||||||
|
|
||||||
### Get AWS Account Keyfile
|
|
||||||
|
|
||||||
Using an AWS account with permissions to manage RDS databases:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
AWS_PROFILE=default && echo -e "[default]\naws_access_key_id = $(aws configure get aws_access_key_id --profile $AWS_PROFILE)\naws_secret_access_key = $(aws configure get aws_secret_access_key --profile $AWS_PROFILE)" > creds.conf
|
|
||||||
```
|
|
||||||
|
|
||||||
### Create a Provider Secret
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl create secret generic aws-creds -n crossplane-system --from-file=creds=./creds.conf
|
|
||||||
```
|
|
||||||
|
|
||||||
### Configure the Provider
|
|
||||||
|
|
||||||
We will create the following `ProviderConfig` object to configure credentials
|
|
||||||
for AWS Provider:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: aws.crossplane.io/v1beta1
|
|
||||||
kind: ProviderConfig
|
|
||||||
metadata:
|
|
||||||
name: default
|
|
||||||
spec:
|
|
||||||
credentials:
|
|
||||||
source: Secret
|
|
||||||
secretRef:
|
|
||||||
namespace: crossplane-system
|
|
||||||
name: aws-creds
|
|
||||||
key: creds
|
|
||||||
```
|
|
||||||
```console
|
|
||||||
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-1.9/docs/snippets/configure/aws/providerconfig.yaml
|
|
||||||
```
|
|
||||||
<!-- close "AWS (Default VPC)" -->
|
|
||||||
{{% /tab %}}
|
|
||||||
|
|
||||||
{{% tab "AWS (New VPC)" %}}
|
|
||||||
### Install Configuration Package
|
|
||||||
|
|
||||||
> If you prefer to see the contents of this configuration package and how it is
|
|
||||||
> constructed prior to install, skip ahead to the [create a configuration]
|
|
||||||
> section.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl crossplane install configuration registry.upbound.io/xp/getting-started-with-aws-with-vpc:v1.9.1
|
|
||||||
```
|
|
||||||
|
|
||||||
Wait until all packages become healthy:
|
|
||||||
```bash
|
|
||||||
watch kubectl get pkg
|
|
||||||
```
|
|
||||||
|
|
||||||
### Get AWS Account Keyfile
|
|
||||||
|
|
||||||
Using an AWS account with permissions to manage RDS databases:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
AWS_PROFILE=default && echo -e "[default]\naws_access_key_id = $(aws configure get aws_access_key_id --profile $AWS_PROFILE)\naws_secret_access_key = $(aws configure get aws_secret_access_key --profile $AWS_PROFILE)" > creds.conf
|
|
||||||
```
|
|
||||||
|
|
||||||
### Create a Provider Secret
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl create secret generic aws-creds -n crossplane-system --from-file=creds=./creds.conf
|
|
||||||
```
|
|
||||||
|
|
||||||
### Configure the Provider
|
|
||||||
|
|
||||||
We will create the following `ProviderConfig` object to configure credentials
|
|
||||||
for AWS Provider:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: aws.crossplane.io/v1beta1
|
|
||||||
kind: ProviderConfig
|
|
||||||
metadata:
|
|
||||||
name: default
|
|
||||||
spec:
|
|
||||||
credentials:
|
|
||||||
source: Secret
|
|
||||||
secretRef:
|
|
||||||
namespace: crossplane-system
|
|
||||||
name: aws-creds
|
|
||||||
key: creds
|
|
||||||
```
|
|
||||||
```console
|
|
||||||
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-1.9/docs/snippets/configure/aws/providerconfig.yaml
|
|
||||||
```
|
|
||||||
<!-- close "AWS (New VPC)" -->
|
|
||||||
{{% /tab %}}
|
|
||||||
|
|
||||||
{{% tab "GCP" %}}
|
|
||||||
|
|
||||||
### Install Configuration Package
|
|
||||||
|
|
||||||
> If you prefer to see the contents of this configuration package and how it is
|
|
||||||
> constructed prior to install, skip ahead to the [create a configuration]
|
|
||||||
> section.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl crossplane install configuration registry.upbound.io/xp/getting-started-with-gcp:v1.9.1
|
|
||||||
```
|
|
||||||
|
|
||||||
Wait until all packages become healthy:
|
|
||||||
```
|
|
||||||
watch kubectl get pkg
|
|
||||||
```
|
|
||||||
|
|
||||||
### Get GCP Account Keyfile
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# replace this with your own gcp project id and the name of the service account
|
|
||||||
# that will be created.
|
|
||||||
PROJECT_ID=my-project
|
|
||||||
NEW_SA_NAME=test-service-account-name
|
|
||||||
|
|
||||||
# create service account
|
|
||||||
SA="${NEW_SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
|
|
||||||
gcloud iam service-accounts create $NEW_SA_NAME --project $PROJECT_ID
|
|
||||||
|
|
||||||
# enable cloud API
|
|
||||||
SERVICE="sqladmin.googleapis.com"
|
|
||||||
gcloud services enable $SERVICE --project $PROJECT_ID
|
|
||||||
|
|
||||||
# grant access to cloud API
|
|
||||||
ROLE="roles/cloudsql.admin"
|
|
||||||
gcloud projects add-iam-policy-binding --role="$ROLE" $PROJECT_ID --member "serviceAccount:$SA"
|
|
||||||
|
|
||||||
# create service account keyfile
|
|
||||||
gcloud iam service-accounts keys create creds.json --project $PROJECT_ID --iam-account $SA
|
|
||||||
```
|
|
||||||
|
|
||||||
### Create a Provider Secret
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl create secret generic gcp-creds -n crossplane-system --from-file=creds=./creds.json
|
|
||||||
```
|
|
||||||
|
|
||||||
### Configure the Provider
|
|
||||||
|
|
||||||
We will create the following `ProviderConfig` object to configure credentials
|
|
||||||
for GCP Provider:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# replace this with your own gcp project id
|
|
||||||
PROJECT_ID=my-project
|
|
||||||
echo "apiVersion: gcp.crossplane.io/v1beta1
|
|
||||||
kind: ProviderConfig
|
|
||||||
metadata:
|
|
||||||
name: default
|
|
||||||
spec:
|
|
||||||
projectID: ${PROJECT_ID}
|
|
||||||
credentials:
|
|
||||||
source: Secret
|
|
||||||
secretRef:
|
|
||||||
namespace: crossplane-system
|
|
||||||
name: gcp-creds
|
|
||||||
key: creds" | kubectl apply -f -
|
|
||||||
```
|
|
||||||
<!-- close "GCP" -->
|
|
||||||
{{% /tab %}}
|
|
||||||
|
|
||||||
{{% tab "Azure" %}}
|
|
||||||
|
|
||||||
### Install Configuration Package
|
|
||||||
|
|
||||||
> If you prefer to see the contents of this configuration package and how it is
|
|
||||||
> constructed prior to install, skip ahead to the [create a configuration]
|
|
||||||
> section.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl crossplane install configuration registry.upbound.io/xp/getting-started-with-azure:v1.9.1
|
|
||||||
```
|
|
||||||
|
|
||||||
Wait until all packages become healthy:
|
|
||||||
```
|
|
||||||
watch kubectl get pkg
|
|
||||||
```
|
|
||||||
|
|
||||||
### Get Azure Principal Keyfile
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# create service principal with Owner role
|
|
||||||
az ad sp create-for-rbac --role Contributor --scopes /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx > "creds.json"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Create a Provider Secret
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl create secret generic azure-creds -n crossplane-system --from-file=creds=./creds.json
|
|
||||||
```
|
|
||||||
|
|
||||||
### Configure the Provider
|
|
||||||
|
|
||||||
We will create the following `ProviderConfig` object to configure credentials
|
|
||||||
for Azure Provider:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: azure.crossplane.io/v1beta1
|
|
||||||
kind: ProviderConfig
|
|
||||||
metadata:
|
|
||||||
name: default
|
|
||||||
spec:
|
|
||||||
credentials:
|
|
||||||
source: Secret
|
|
||||||
secretRef:
|
|
||||||
namespace: crossplane-system
|
|
||||||
name: azure-creds
|
|
||||||
key: creds
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-1.9/docs/snippets/configure/azure/providerconfig.yaml
|
|
||||||
```
|
|
||||||
<!-- close "Azure" -->
|
|
||||||
{{% /tab %}}
|
|
||||||
|
|
||||||
{{% /tabs %}}
|
|
||||||
|
|
||||||
## Next Steps
|
|
||||||
|
|
||||||
Now that you have configured Crossplane with support for `PostgreSQLInstance`,
|
|
||||||
you can [provision infrastructure].
|
|
||||||
<!-- close "Crossplane (upstream)" -->
|
|
||||||
{{% /tab %}}
|
|
||||||
|
|
||||||
{{% tab "Downstream Distribution" %}}
|
|
||||||
## Start with a Downstream Distribution
|
|
||||||
|
|
||||||
Upbound, the founders of Crossplane, maintains a free and open source downstream
|
|
||||||
distribution of Crossplane which makes getting started with Crossplane easy.
|
|
||||||
Universal Crossplane, or UXP for short, connects to Upbound's hosted management
|
|
||||||
console and Registry to make it easier to develop, debug, and manage Provider
|
|
||||||
and Configuration packages.
|
|
||||||
|
|
||||||
[Get started with Universal Crossplane] on the Upbound Documentation site.
|
|
||||||
|
|
||||||
<i>Want see another hosted Crossplane service listed? Please [reach out on
|
|
||||||
Slack][Slack] and our community will highlight it here!</i>
|
|
||||||
|
|
||||||
<!-- close "Downstream Distribution" -->
|
|
||||||
{{% /tab %}}
|
|
||||||
|
|
||||||
<!-- close "Crossplane Distros" -->
|
|
||||||
{{% /tabs %}}
|
|
||||||
|
|
||||||
## More Info
|
|
||||||
|
|
||||||
* See [Install] and [Configure] docs for installing alternate versions and more
|
|
||||||
detailed instructions.
|
|
||||||
|
|
||||||
* See [Uninstall] docs for cleaning up resources, packages, and Crossplane
|
|
||||||
itself.
|
|
||||||
|
|
||||||
* See [Providers] for installing and using different providers beyond AWS, GCP
|
|
||||||
and Azure mentionded in this guide.
|
|
||||||
|
|
||||||
<!-- Named Links -->
|
|
||||||
|
|
||||||
[package]: {{<ref "../concepts/packages" >}}
|
|
||||||
[provision infrastructure]: {{<ref "provision-infrastructure" >}}
|
|
||||||
[create a configuration]: {{<ref "create-configuration" >}}
|
|
||||||
[Install]: {{<ref "../reference/install" >}}
|
|
||||||
[Configure]: {{<ref "../reference/configure" >}}
|
|
||||||
[Uninstall]: {{<ref "../reference/uninstall" >}}
|
|
||||||
[Kubernetes cluster]: https://kubernetes.io/docs/setup/
|
|
||||||
[Minikube]: https://minikube.sigs.k8s.io/docs/start/
|
|
||||||
[Helm]:https://helm.sh/docs/intro/using_helm/
|
|
||||||
[Kind]: https://kind.sigs.k8s.io/docs/user/quick-start/
|
|
||||||
[Crossplane packages]: {{<ref "../concepts/packages" >}}
|
|
||||||
[Slack]: http://slack.crossplane.io/
|
|
||||||
[up]: https://github.com/upbound/up
|
|
||||||
[Upbound documentation]: https://https://docs.upbound.io//docs
|
|
||||||
[Providers]: {{<ref "../concepts/providers" >}}
|
|
||||||
[Universal Crossplane]: https://https://docs.upbound.io/uxp/
|
|
||||||
[Get started with Universal Crossplane]: https://docs.upbound.io/uxp/install
|
|
||||||
[certified by the CNCF]: https://github.com/cncf/crossplane-conformance
|
|
||||||
[Crossplane GitHub]: https://github.com/crossplane/crossplane
|
|
|
@ -1,273 +0,0 @@
|
||||||
---
|
|
||||||
title: Provision Infrastructure
|
|
||||||
weight: 3
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
Composite resources (XRs) are always cluster scoped - they exist outside of any
|
|
||||||
namespace. This allows an XR to represent infrastructure that might be consumed
|
|
||||||
from several different namespaces. This is often true for VPC networks - an
|
|
||||||
infrastructure operator may wish to define a VPC network XR and an SQL instance
|
|
||||||
XR, only the latter of which may be managed by application operators. The
|
|
||||||
application operators are restricted to their team's namespace, but their SQL
|
|
||||||
instances should all be attached to the VPC network that the infrastructure
|
|
||||||
operator manages. Crossplane enables scenarios like this by allowing the
|
|
||||||
infrastructure operator to offer their application operators a _composite
|
|
||||||
resource claim_ (XRC). An XRC is a namespaced proxy for an XR; the schema of an
|
|
||||||
XRC is identical to that of its corresponding XR. When an application operator
|
|
||||||
creates an XRC, a corresponding backing XR is created automatically. This model
|
|
||||||
has similarities to [Persistent Volumes (PV) and Persistent Volume Claims (PVC)]
|
|
||||||
in Kubernetes.
|
|
||||||
|
|
||||||
## Claim Your Infrastructure
|
|
||||||
|
|
||||||
The `Configuration` package we installed in the last section:
|
|
||||||
|
|
||||||
- Defines a `XPostgreSQLInstance` XR.
|
|
||||||
- Offers a `PostgreSQLInstance` claim (XRC) for said XR.
|
|
||||||
- Creates a `Composition` that can satisfy our XR.
|
|
||||||
|
|
||||||
This means that we can create a `PostgreSQLInstance` XRC in the `default`
|
|
||||||
namespace to provision a PostgreSQL instance and all the supporting
|
|
||||||
infrastructure (VPCs, firewall rules, resource groups, etc) that it may need!
|
|
||||||
|
|
||||||
{{< tabs >}}
|
|
||||||
{{< tab "AWS (Default VPC)" >}}
|
|
||||||
|
|
||||||
> Note that this resource will create an RDS instance using your default VPC,
|
|
||||||
> which may or may not allow connections from the internet depending on how it
|
|
||||||
> is configured.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: database.example.org/v1alpha1
|
|
||||||
kind: PostgreSQLInstance
|
|
||||||
metadata:
|
|
||||||
name: my-db
|
|
||||||
namespace: default
|
|
||||||
spec:
|
|
||||||
parameters:
|
|
||||||
storageGB: 20
|
|
||||||
compositionSelector:
|
|
||||||
matchLabels:
|
|
||||||
provider: aws
|
|
||||||
vpc: default
|
|
||||||
writeConnectionSecretToRef:
|
|
||||||
name: db-conn
|
|
||||||
```
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-1.9/docs/snippets/compose/claim-aws.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
{{< /tab >}}
|
|
||||||
{{< tab "AWS (New VPC)" >}}
|
|
||||||
|
|
||||||
> Note that this resource also includes several networking managed resources
|
|
||||||
> that are required to provision a publicly available PostgreSQL instance.
|
|
||||||
> Composition enables scenarios such as this, as well as far more complex ones.
|
|
||||||
> See the [composition] documentation for more information.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: database.example.org/v1alpha1
|
|
||||||
kind: PostgreSQLInstance
|
|
||||||
metadata:
|
|
||||||
name: my-db
|
|
||||||
namespace: default
|
|
||||||
spec:
|
|
||||||
parameters:
|
|
||||||
storageGB: 20
|
|
||||||
compositionSelector:
|
|
||||||
matchLabels:
|
|
||||||
provider: aws
|
|
||||||
vpc: new
|
|
||||||
writeConnectionSecretToRef:
|
|
||||||
name: db-conn
|
|
||||||
```
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-1.9/docs/snippets/compose/claim-aws.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
{{< /tab >}}
|
|
||||||
{{< tab "GCP" >}}
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: database.example.org/v1alpha1
|
|
||||||
kind: PostgreSQLInstance
|
|
||||||
metadata:
|
|
||||||
name: my-db
|
|
||||||
namespace: default
|
|
||||||
spec:
|
|
||||||
parameters:
|
|
||||||
storageGB: 20
|
|
||||||
compositionSelector:
|
|
||||||
matchLabels:
|
|
||||||
provider: gcp
|
|
||||||
writeConnectionSecretToRef:
|
|
||||||
name: db-conn
|
|
||||||
```
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-1.9/docs/snippets/compose/claim-gcp.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
{{< /tab >}}
|
|
||||||
{{< tab "Azure" >}}
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: database.example.org/v1alpha1
|
|
||||||
kind: PostgreSQLInstance
|
|
||||||
metadata:
|
|
||||||
name: my-db
|
|
||||||
namespace: default
|
|
||||||
spec:
|
|
||||||
parameters:
|
|
||||||
storageGB: 20
|
|
||||||
compositionSelector:
|
|
||||||
matchLabels:
|
|
||||||
provider: azure
|
|
||||||
writeConnectionSecretToRef:
|
|
||||||
name: db-conn
|
|
||||||
```
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-1.9/docs/snippets/compose/claim-azure.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
{{< /tab >}}
|
|
||||||
{{< /tabs >}}
|
|
||||||
|
|
||||||
After creating the `PostgreSQLInstance` Crossplane will begin provisioning a
|
|
||||||
database instance on your provider of choice. Once provisioning is complete, you
|
|
||||||
should see `READY: True` in the output when you run:
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl get postgresqlinstance my-db
|
|
||||||
```
|
|
||||||
|
|
||||||
> Note: while waiting for the `PostgreSQLInstance` to become ready, you
|
|
||||||
> may want to look at other resources in your cluster. The following commands
|
|
||||||
> will allow you to view groups of Crossplane resources:
|
|
||||||
>
|
|
||||||
> - `kubectl get claim`: get all resources of all claim kinds, like `PostgreSQLInstance`.
|
|
||||||
> - `kubectl get composite`: get all resources that are of composite kind, like `XPostgreSQLInstance`.
|
|
||||||
> - `kubectl get managed`: get all resources that represent a unit of external
|
|
||||||
> infrastructure.
|
|
||||||
> - `kubectl get <name-of-provider>`: get all resources related to `<provider>`.
|
|
||||||
> - `kubectl get crossplane`: get all resources related to Crossplane.
|
|
||||||
|
|
||||||
Try the following command to watch your provisioned resources become ready:
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl get crossplane -l crossplane.io/claim-name=my-db
|
|
||||||
```
|
|
||||||
|
|
||||||
Once your `PostgreSQLInstance` is ready, you should see a `Secret` in the `default`
|
|
||||||
namespace named `db-conn` that contains keys that we defined in XRD. If they were
|
|
||||||
filled by the composition, then they should appear:
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ kubectl describe secrets db-conn
|
|
||||||
Name: db-conn
|
|
||||||
Namespace: default
|
|
||||||
...
|
|
||||||
|
|
||||||
Type: connection.crossplane.io/v1alpha1
|
|
||||||
|
|
||||||
Data
|
|
||||||
====
|
|
||||||
password: 27 bytes
|
|
||||||
port: 4 bytes
|
|
||||||
username: 25 bytes
|
|
||||||
endpoint: 45 bytes
|
|
||||||
```
|
|
||||||
|
|
||||||
## Consume Your Infrastructure
|
|
||||||
|
|
||||||
Because connection secrets are written as a Kubernetes `Secret` they can easily
|
|
||||||
be consumed by Kubernetes primitives. The most basic building block in
|
|
||||||
Kubernetes is the `Pod`. Let's define a `Pod` that will show that we are able to
|
|
||||||
connect to our newly provisioned database.
|
|
||||||
|
|
||||||
> Note that if you're using a hosted Crossplane you'll need to copy the db-conn
|
|
||||||
> connection secret over to your own Kubernetes cluster and run this pod there.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Pod
|
|
||||||
metadata:
|
|
||||||
name: see-db
|
|
||||||
namespace: default
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: see-db
|
|
||||||
image: postgres:12
|
|
||||||
command: ['psql']
|
|
||||||
args: ['-c', 'SELECT current_database();']
|
|
||||||
env:
|
|
||||||
- name: PGDATABASE
|
|
||||||
value: postgres
|
|
||||||
- name: PGHOST
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: db-conn
|
|
||||||
key: endpoint
|
|
||||||
- name: PGUSER
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: db-conn
|
|
||||||
key: username
|
|
||||||
- name: PGPASSWORD
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: db-conn
|
|
||||||
key: password
|
|
||||||
- name: PGPORT
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: db-conn
|
|
||||||
key: port
|
|
||||||
```
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-1.9/docs/snippets/compose/pod.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
This `Pod` simply connects to a PostgreSQL database and prints its name, so you
|
|
||||||
should see the following output (or similar) after creating it if you run
|
|
||||||
`kubectl logs see-db`:
|
|
||||||
|
|
||||||
```SQL
|
|
||||||
current_database
|
|
||||||
------------------
|
|
||||||
postgres
|
|
||||||
(1 row)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Clean Up
|
|
||||||
|
|
||||||
To clean up the `Pod`, run:
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl delete pod see-db
|
|
||||||
```
|
|
||||||
|
|
||||||
To clean up the infrastructure that was provisioned, you can delete the
|
|
||||||
`PostgreSQLInstance` XRC:
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl delete postgresqlinstance my-db
|
|
||||||
```
|
|
||||||
|
|
||||||
## Next Steps
|
|
||||||
|
|
||||||
Now you have seen how to provision and consume complex infrastructure via
|
|
||||||
composition. In the [next section] you will learn how compose and package your
|
|
||||||
own infrastructure APIs.
|
|
||||||
|
|
||||||
<!-- Named Links -->
|
|
||||||
|
|
||||||
[Persistent Volumes (PV) and Persistent Volume Claims (PVC)]: https://kubernetes.io/docs/concepts/storage/persistent-volumes/
|
|
||||||
[composition]: {{<ref "../concepts/composition" >}}
|
|
||||||
[setup]: {{<ref "install-configure" >}}
|
|
||||||
[next section]: {{<ref "create-configuration" >}}
|
|
|
@ -1,28 +0,0 @@
|
||||||
---
|
|
||||||
title: Guides
|
|
||||||
weight: 200
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
This section contains guides for using Crossplane in specific scenarios or
|
|
||||||
alongside other technologies. If you are interested in writing and
|
|
||||||
maintaining a guide for your own use-case please feel free to [open an issue] to
|
|
||||||
add it! Also check out the [The Binding Status], a biweekly livestream show
|
|
||||||
where Crossplane maintainers welcome guests from the cloud-native community and
|
|
||||||
show off [demos] integrating with the projects they work on.
|
|
||||||
|
|
||||||
- [Upgrading to v0.14]
|
|
||||||
- [Upgrading to v1.x]
|
|
||||||
- [Vault Provider Credential Injection]
|
|
||||||
-
|
|
||||||
|
|
||||||
<!-- Named Links -->
|
|
||||||
|
|
||||||
[open an issue]: https://github.com/crossplane/crossplane/issues/new
|
|
||||||
[The Binding Status]: https://youtube.com/playlist?list=PL510POnNVaaYFuK-B_SIUrpIonCtLVOzT
|
|
||||||
[demos]: https://github.com/crossplane/tbs
|
|
||||||
[Upgrading to v0.14]: {{<ref "upgrading-to-v0.14.md" >}}
|
|
||||||
[Upgrading to v1.x]: {{<ref "upgrading-to-v1.x.md" >}}
|
|
||||||
[Vault Provider Credential Injection]: {{<ref "vault-injection" >}}
|
|
||||||
|
|
||||||
|
|
|
@ -1,154 +0,0 @@
|
||||||
---
|
|
||||||
title: Composition Revisions
|
|
||||||
weight: 260
|
|
||||||
---
|
|
||||||
|
|
||||||
This guide discusses the use of "Composition Revisions" to safely make and roll
|
|
||||||
back changes to a Crossplane [`Composition`][composition-type]. It assumes
|
|
||||||
familiarity with Crossplane, and particularly with
|
|
||||||
[Composition][composition-term].
|
|
||||||
|
|
||||||
> Composition Revisions are an __alpha feature__. They are not yet recommended
|
|
||||||
> for production use, and are disabled by default.
|
|
||||||
|
|
||||||
A `Composition` configures how Crossplane should reconcile a Composite Resource
|
|
||||||
(XR). Put otherwise, when you create an XR the selected `Composition` determines
|
|
||||||
what managed resources Crossplane will create in response. Let's say for example
|
|
||||||
that you define a `PlatformDB` XR, which represents your organisation's common
|
|
||||||
database configuration of an Azure MySQL Server and a few firewall rules. The
|
|
||||||
`Composition` contains the 'base' configuration for the MySQL server and the
|
|
||||||
firewall rules that is extended by the configuration for the `PlatformDB`.
|
|
||||||
|
|
||||||
There is a one-to-many relationship between a `Composition` and the XRs that use
|
|
||||||
it. You might define a `Composition` named `big-platform-db` that is used by ten
|
|
||||||
different `PlatformDB` XRs. Usually, in the interest of self-service, the
|
|
||||||
`Composition` is managed by a different team from the actual `PlatformDB` XRs.
|
|
||||||
For example the `Composition` may be written and maintained by a platform team
|
|
||||||
member, while individual application teams create `PlatformDB` XRs that use said
|
|
||||||
`Composition`.
|
|
||||||
|
|
||||||
Each `Composition` is mutable - you can update it as your organisation's needs
|
|
||||||
change. However, without Composition Revisions updating a `Composition` can be a
|
|
||||||
risky process. Crossplane constantly uses the `Composition` to ensure that your
|
|
||||||
actual infrastructure - your MySQL Servers and firewall rules - match your
|
|
||||||
desired state. If you have 10 `PlatformDB` XRs all using the `big-platform-db`
|
|
||||||
`Composition`, all 10 of those XRs will be instantly updated in accordance with
|
|
||||||
any updates you make to the `big-platform-db` `Composition`.
|
|
||||||
|
|
||||||
Composition Revisions allow XRs to opt out of automatic updates. Instead you can
|
|
||||||
update your XRs to leverage the latest `Composition` settings at your own pace.
|
|
||||||
This enables you to [canary] changes to your infrastructure, or to roll back
|
|
||||||
some XRs to previous `Composition` settings without rolling back all XRs.
|
|
||||||
|
|
||||||
## Enabling Composition Revisions
|
|
||||||
|
|
||||||
Composition Revisions are an alpha feature. They are not yet recommended for
|
|
||||||
production use, and are disabled by default. Start Crossplane with the
|
|
||||||
`--enable-composition-revisions` flag to enable Composition Revision support.
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl create namespace crossplane-system
|
|
||||||
helm install crossplane --namespace crossplane-system crossplane-stable/crossplane --set args='{--enable-composition-revisions}'
|
|
||||||
```
|
|
||||||
|
|
||||||
See the [getting started guide][install-guide] for more information on
|
|
||||||
installing Crossplane.
|
|
||||||
|
|
||||||
## Using Composition Revisions
|
|
||||||
|
|
||||||
When you enable Composition Revisions three things happen:
|
|
||||||
|
|
||||||
1. Crossplane creates a `CompositionRevision` for each `Composition` update.
|
|
||||||
1. Composite Resources gain a `spec.compositionRevisionRef` field that specifies
|
|
||||||
which `CompositionRevision` they use.
|
|
||||||
1. Composite Resources gain a `spec.compositionUpdatePolicy` field that
|
|
||||||
specifies how they should be updated to new Composition Revisions.
|
|
||||||
|
|
||||||
Each time you edit a `Composition` Crossplane will automatically create a
|
|
||||||
`CompositionRevision` that represents that 'revision' of the `Composition` -
|
|
||||||
that unique state. Each revision is allocated an increasing revision number.
|
|
||||||
This gives `CompositionRevision` consumers an idea about which revision is
|
|
||||||
'newest'.
|
|
||||||
|
|
||||||
Crossplane distinguishes between the 'newest' and the 'current' revision of a
|
|
||||||
`Composition`. That is, if you revert a `Composition` to a previous state that
|
|
||||||
corresponds to an existing `CompositionRevision` that revision will become
|
|
||||||
'current' even if it is not the 'newest' revision (i.e. the most latest _unique_
|
|
||||||
`Composition` configuration).
|
|
||||||
|
|
||||||
You can discover which revisions exist using `kubectl`:
|
|
||||||
|
|
||||||
```console
|
|
||||||
# Find all revisions of the Composition named 'example'
|
|
||||||
kubectl get compositionrevision -l crossplane.io/composition-name=example
|
|
||||||
```
|
|
||||||
|
|
||||||
This should produce output something like:
|
|
||||||
|
|
||||||
```console
|
|
||||||
NAME REVISION CURRENT AGE
|
|
||||||
example-18pdg 1 False 4m36s
|
|
||||||
example-2bgdr 2 True 73s
|
|
||||||
example-xjrdm 3 False 61s
|
|
||||||
```
|
|
||||||
|
|
||||||
> A `Composition` is a mutable resource that you can update as your needs
|
|
||||||
> change over time. Each `CompositionRevision` is an immutable snapshot of those
|
|
||||||
> needs at a particular point in time.
|
|
||||||
|
|
||||||
Crossplane behaves the same way by default whether Composition Revisions are
|
|
||||||
enabled or not. This is because when you enable Composition Revisions all XRs
|
|
||||||
default to the `Automatic` `compositionUpdatePolicy`. XRs support two update
|
|
||||||
policies:
|
|
||||||
|
|
||||||
* `Automatic`: Automatically use the current `CompositionRevision`. (Default)
|
|
||||||
* `Manual`: Require manual intervention to change `CompositionRevision`.
|
|
||||||
|
|
||||||
The below XR uses the `Manual` policy. When this policy is used the XR will
|
|
||||||
select the current `CompositionRevision` when it is first created, but must
|
|
||||||
manually be updated when you wish it to use another `CompositionRevision`.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: example.org/v1alpha1
|
|
||||||
kind: PlatformDB
|
|
||||||
metadata:
|
|
||||||
name: example
|
|
||||||
spec:
|
|
||||||
parameters:
|
|
||||||
storageGB: 20
|
|
||||||
# The Manual policy specifies that you do not want this XR to update to the
|
|
||||||
# current CompositionRevision automatically.
|
|
||||||
compositionUpdatePolicy: Manual
|
|
||||||
compositionRef:
|
|
||||||
name: example
|
|
||||||
writeConnectionSecretToRef:
|
|
||||||
name: db-conn
|
|
||||||
```
|
|
||||||
|
|
||||||
Crossplane sets an XR's `compositionRevisionRef` automatically at creation time
|
|
||||||
regardless of your chosen `compositionUpdatePolicy`. If you choose the `Manual`
|
|
||||||
policy you must edit the `compositionRevisionRef` field when you want your XR to
|
|
||||||
use a different `CompositionRevision`.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: example.org/v1alpha1
|
|
||||||
kind: PlatformDB
|
|
||||||
metadata:
|
|
||||||
name: example
|
|
||||||
spec:
|
|
||||||
parameters:
|
|
||||||
storageGB: 20
|
|
||||||
compositionUpdatePolicy: Manual
|
|
||||||
compositionRef:
|
|
||||||
name: example
|
|
||||||
# Update the referenced CompositionRevision if and when you are ready.
|
|
||||||
compositionRevisionRef:
|
|
||||||
name: example-18pdg
|
|
||||||
writeConnectionSecretToRef:
|
|
||||||
name: db-conn
|
|
||||||
```
|
|
||||||
|
|
||||||
[composition-type]: {{<ref "../concepts/composition" >}}
|
|
||||||
[composition-term]: {{<ref "../concepts/terminology" >}}#composition
|
|
||||||
[canary]: https://martinfowler.com/bliki/CanaryRelease.html
|
|
||||||
[install-guide]: {{<ref "../getting-started/install-configure" >}}
|
|
|
@ -1,340 +0,0 @@
|
||||||
---
|
|
||||||
title: Multi-Tenant Crossplane
|
|
||||||
weight: 240
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
This guide describes how to use Crossplane effectively in multi-tenant
|
|
||||||
environments by utilizing Kubernetes primitives and compatible policy
|
|
||||||
enforcement projects in the cloud-native ecosystem.
|
|
||||||
|
|
||||||
## TL;DR
|
|
||||||
|
|
||||||
Infrastructure operators in multi-tenant Crossplane environments typically
|
|
||||||
utilize composition and Kubernetes RBAC to define lightweight, standardized
|
|
||||||
policies that dictate what level of self-service developers are given when
|
|
||||||
requesting infrastructure. This is primarily achieved through exposing abstract
|
|
||||||
resource types at the namespace scope, defining `Roles` for teams and
|
|
||||||
individuals within that namespace, and patching the `spec.providerConfigRef` of
|
|
||||||
the underlying managed resources so that they use a specific `ProviderConfig`
|
|
||||||
and credentials when provisioned from each namespace. Larger organizations, or
|
|
||||||
those with more complex environments, may choose to incorporate third-party
|
|
||||||
policy engines, or scale to multiple Crossplane clusters. The following sections
|
|
||||||
describe each of these scenarios in greater detail.
|
|
||||||
|
|
||||||
- [TL;DR](#tldr)
|
|
||||||
- [Background](#background)
|
|
||||||
- [Cluster-Scoped Managed Resources](#cluster-scoped-managed-resources)
|
|
||||||
- [Namespace Scoped Claims](#namespace-scoped-claims)
|
|
||||||
- [Single Cluster Multi-Tenancy](#single-cluster-multi-tenancy)
|
|
||||||
- [Composition as an Isolation Mechanism](#composition-as-an-isolation-mechanism)
|
|
||||||
- [Namespaces as an Isolation Mechanism](#namespaces-as-an-isolation-mechanism)
|
|
||||||
- [Policy Enforcement with Open Policy Agent](#policy-enforcement-with-open-policy-agent)
|
|
||||||
- [Multi-Cluster Multi-Tenancy](#multi-cluster-multi-tenancy)
|
|
||||||
- [Reproducible Platforms with Configuration Packages](#reproducible-platforms-with-configuration-packages)
|
|
||||||
- [Control Plane of Control Planes](#control-plane-of-control-planes)
|
|
||||||
- [Service Provisioning using Open Service Broker API](#service-provisioning-using-open-service-broker-api)
|
|
||||||
|
|
||||||
## Background
|
|
||||||
|
|
||||||
Crossplane is designed to run in multi-tenant environments where many teams are
|
|
||||||
consuming the services and abstractions provided by infrastructure operators in
|
|
||||||
the cluster. This functionality is facilitated by two major design patterns in
|
|
||||||
the Crossplane ecosystem.
|
|
||||||
|
|
||||||
### Cluster-Scoped Managed Resources
|
|
||||||
|
|
||||||
Typically, Crossplane providers, which supply granular [managed resources] that
|
|
||||||
reflect an external API, authenticate by using a `ProviderConfig` object that
|
|
||||||
points to a credentials source (such as a Kubernetes `Secret`, the `Pod`
|
|
||||||
filesystem, or an environment variable). Then, every managed resource references
|
|
||||||
a `ProviderConfig` that points to credentials with sufficient permissions to
|
|
||||||
manage that resource type.
|
|
||||||
|
|
||||||
For example, the following `ProviderConfig` for `provider-aws` points to a
|
|
||||||
Kubernetes `Secret` with AWS credentials.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: aws.crossplane.io/v1beta1
|
|
||||||
kind: ProviderConfig
|
|
||||||
metadata:
|
|
||||||
name: cool-aws-creds
|
|
||||||
spec:
|
|
||||||
credentials:
|
|
||||||
source: Secret
|
|
||||||
secretRef:
|
|
||||||
namespace: crossplane-system
|
|
||||||
name: aws-creds
|
|
||||||
key: creds
|
|
||||||
```
|
|
||||||
|
|
||||||
If a user desired for these credentials to be used to provision an
|
|
||||||
`RDSInstance`, they would reference the `ProviderConfig` in the object manifest:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: database.aws.crossplane.io/v1beta1
|
|
||||||
kind: RDSInstance
|
|
||||||
metadata:
|
|
||||||
name: rdsmysql
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
region: us-east-1
|
|
||||||
dbInstanceClass: db.t3.medium
|
|
||||||
masterUsername: masteruser
|
|
||||||
allocatedStorage: 20
|
|
||||||
engine: mysql
|
|
||||||
engineVersion: "5.6.35"
|
|
||||||
skipFinalSnapshotBeforeDeletion: true
|
|
||||||
providerConfigRef:
|
|
||||||
name: cool-aws-creds # name of ProviderConfig above
|
|
||||||
writeConnectionSecretToRef:
|
|
||||||
namespace: crossplane-system
|
|
||||||
name: aws-rdsmysql-conn
|
|
||||||
```
|
|
||||||
|
|
||||||
Since both the `ProviderConfig` and all managed resources are cluster-scoped,
|
|
||||||
the RDS controller in `provider-aws` will resolve this reference by fetching the
|
|
||||||
`ProviderConfig`, obtaining the credentials it points to, and using those
|
|
||||||
credentials to reconcile the `RDSInstance`. This means that anyone who has been
|
|
||||||
given [RBAC] to manage `RDSInstance` objects can use any credentials to do so.
|
|
||||||
In practice, Crossplane assumes that only folks acting as infrastructure
|
|
||||||
administrators or platform builders will interact directly with cluster-scoped
|
|
||||||
resources.
|
|
||||||
|
|
||||||
### Namespace Scoped Claims
|
|
||||||
|
|
||||||
While managed resources exist at the cluster scope, composite resources, which
|
|
||||||
are defined using a **CompositeResourceDefinition (XRD)** may exist at either
|
|
||||||
the cluster or namespace scope. Platform builders define XRDs and
|
|
||||||
**Compositions** that specify what granular managed resources should be created
|
|
||||||
in response to the creation of an instance of the XRD. More information about
|
|
||||||
this architecture can be found in the [Composition] documentation.
|
|
||||||
|
|
||||||
Every XRD is exposed at the cluster scope, but only those with `spec.claimNames`
|
|
||||||
defined will have a namespace-scoped variant.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: apiextensions.crossplane.io/v1
|
|
||||||
kind: CompositeResourceDefinition
|
|
||||||
metadata:
|
|
||||||
name: xmysqlinstances.example.org
|
|
||||||
spec:
|
|
||||||
group: example.org
|
|
||||||
names:
|
|
||||||
kind: XMySQLInstance
|
|
||||||
plural: xmysqlinstances
|
|
||||||
claimNames:
|
|
||||||
kind: MySQLInstance
|
|
||||||
plural: mysqlinstances
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
When the example above is created, Crossplane will produce two
|
|
||||||
[CustomResourceDefinitions]:
|
|
||||||
1. A cluster-scoped type with `kind: XMySQLInstance`. This is referred to as a
|
|
||||||
**Composite Resource (XR)**.
|
|
||||||
2. A namespace-scoped type with `kind: MySQLInstance`. This is referred to as a
|
|
||||||
**Claim (XRC)**.
|
|
||||||
|
|
||||||
Platform builders may choose to define an arbitrary number of Compositions that
|
|
||||||
map to these types, meaning that creating a `MySQLInstance` in a given namespace
|
|
||||||
can result in the creations of any set of managed resources at the cluster
|
|
||||||
scope. For instance, creating a `MySQLInstance` could result in the creation of
|
|
||||||
the `RDSInstance` defined above.
|
|
||||||
|
|
||||||
## Single Cluster Multi-Tenancy
|
|
||||||
|
|
||||||
Depending on the size and scope of an organization, platform teams may choose to
|
|
||||||
run one central Crossplane control plane, or many different ones for each team
|
|
||||||
or business unit. This section will focus on servicing multiple teams within a
|
|
||||||
single cluster, which may or may not be one of many other Crossplane clusters in
|
|
||||||
the organization.
|
|
||||||
|
|
||||||
### Composition as an Isolation Mechanism
|
|
||||||
|
|
||||||
While managed resources always reflect every field that the underlying provider
|
|
||||||
API exposes, XRDs can have any schema that a platform builder chooses. The
|
|
||||||
fields in the XRD schema can then be patched onto fields in the underlying
|
|
||||||
managed resource defined in a Composition, essentially exposing those fields as
|
|
||||||
configurable to the consumer of the XR or XRC.
|
|
||||||
|
|
||||||
This feature serves as a lightweight policy mechanism by only giving the
|
|
||||||
consumer the ability to customize the underlying resources to the extent the
|
|
||||||
platform builder desires. For instance, in the examples above, a platform
|
|
||||||
builder may choose to define a `spec.location` field in the schema of the
|
|
||||||
`XMySQLInstance` that is an enum with options `east` and `west`. In the
|
|
||||||
Composition, those fields could map to the `RDSInstance` `spec.region` field,
|
|
||||||
making the value either `us-east-1` or `us-west-1`. If no other patches were
|
|
||||||
defined for the `RDSInstance`, giving a user the ability (using RBAC) to create
|
|
||||||
a `XMySQLInstance` / `MySQLInstance` would be akin to giving the ability to
|
|
||||||
create a very specifically configured `RDSInstance`, where they can only decide
|
|
||||||
the region where it lives and they are restricted to two options.
|
|
||||||
|
|
||||||
This model is in contrast to many infrastructure as code tools where the end
|
|
||||||
user must have provider credentials to create the underlying resources that are
|
|
||||||
rendered from the abstraction. Crossplane takes a different approach, defining
|
|
||||||
various credentials in the cluster (using the `ProviderConfig`), then giving
|
|
||||||
only the provider controllers the ability to utilize those credentials and
|
|
||||||
provision infrastructure on the users behalf. This creates a consistent
|
|
||||||
permission model, even when using many providers with differing IAM models, by
|
|
||||||
standardizing on Kubernetes RBAC.
|
|
||||||
|
|
||||||
### Namespaces as an Isolation Mechanism
|
|
||||||
|
|
||||||
While the ability to define abstract schemas and patches to concrete resource
|
|
||||||
types using composition is powerful, the ability to define Claim types at the
|
|
||||||
namespace scope enhances the functionality further by enabling RBAC to be
|
|
||||||
applied with namespace restrictions. Most users in a cluster do not have access
|
|
||||||
to cluster-scoped resources as they are considered only relevant to
|
|
||||||
infrastructure admins by both Kubernetes and Crossplane.
|
|
||||||
|
|
||||||
Building on our simple `XMySQLInstance` / `MySQLInstance` example, a platform
|
|
||||||
builder may choose to define permissions on `MySQLInstance` at the namespace
|
|
||||||
scope using a `Role`. This allows for giving users the ability to create and
|
|
||||||
manage `MySQLInstances` in their given namespace, but not the ability to see
|
|
||||||
those defined in other namespaces.
|
|
||||||
|
|
||||||
Furthermore, because the `metadata.namespace` is a field on the XRC, patching can
|
|
||||||
be utilized to configure managed resources based on the namespace in which the
|
|
||||||
corresponding XRC was defined. This is especially useful if a platform builder
|
|
||||||
wants to designate specific credentials or a set of credentials that users in a
|
|
||||||
given namespace can utilize when provisioning infrastructure using an XRC. This
|
|
||||||
can be accomplished today by creating one or more `ProviderConfig` objects that
|
|
||||||
include the name of the namespace in the `ProviderConfig` name. For example, if
|
|
||||||
any `MySQLInstance` created in the `team-1` namespace should use specific AWS
|
|
||||||
credentials when the provider controller creates the underlying `RDSInstance`,
|
|
||||||
the platform builder could:
|
|
||||||
|
|
||||||
1. Define a `ProviderConfig` with name `team-1`.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: aws.crossplane.io/v1beta1
|
|
||||||
kind: ProviderConfig
|
|
||||||
metadata:
|
|
||||||
name: team-1
|
|
||||||
spec:
|
|
||||||
credentials:
|
|
||||||
source: Secret
|
|
||||||
secretRef:
|
|
||||||
namespace: crossplane-system
|
|
||||||
name: team-1-creds
|
|
||||||
key: creds
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Define a `Composition` that patches the namespace of the Claim reference in the XR
|
|
||||||
to the `providerConfigRef` of the `RDSInstance`.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
...
|
|
||||||
resources:
|
|
||||||
- base:
|
|
||||||
apiVersion: database.aws.crossplane.io/v1beta1
|
|
||||||
kind: RDSInstance
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
...
|
|
||||||
patches:
|
|
||||||
- fromFieldPath: spec.claimRef.namespace
|
|
||||||
toFieldPath: spec.providerConfigRef.name
|
|
||||||
policy:
|
|
||||||
fromFieldPath: Required
|
|
||||||
```
|
|
||||||
|
|
||||||
This would result in the `RDSInstance` using the `ProviderConfig` of whatever
|
|
||||||
namespace the corresponding `MySQLInstance` was created in.
|
|
||||||
|
|
||||||
> Note that this model currently only allows for a single `ProviderConfig` per
|
|
||||||
> namespace. However, future Crossplane releases should allow for defining a set
|
|
||||||
> of `ProviderConfig` that can be selected from using [Multiple Source Field
|
|
||||||
> patching].
|
|
||||||
|
|
||||||
### Policy Enforcement with Open Policy Agent
|
|
||||||
|
|
||||||
In some Crossplane deployment models, only using composition and RBAC to define
|
|
||||||
policy will not be flexible enough. However, because Crossplane brings
|
|
||||||
management of external infrastructure to the Kubernetes API, it is well suited
|
|
||||||
to integrate with other projects in the cloud-native ecosystem. Organizations
|
|
||||||
and individuals that need a more robust policy engine, or just prefer a more
|
|
||||||
general language for defining policy, often turn to [Open Policy Agent] (OPA).
|
|
||||||
OPA allows platform builders to write custom logic in [Rego], a domain-specific
|
|
||||||
language. Writing policy in this manner allows for not only incorporating the
|
|
||||||
information available in the specific resource being evaluated, but also using
|
|
||||||
other state represented in the cluster. Crossplane users typically install OPA's
|
|
||||||
[Gatekeeper] to make policy management as streamlined as possible.
|
|
||||||
|
|
||||||
> A live demo of using OPA with Crossplane can be viewed [here].
|
|
||||||
|
|
||||||
## Multi-Cluster Multi-Tenancy
|
|
||||||
|
|
||||||
Organizations that deploy Crossplane across many clusters typically take
|
|
||||||
advantage of two major features that make managing multiple control planes much
|
|
||||||
simpler.
|
|
||||||
|
|
||||||
### Reproducible Platforms with Configuration Packages
|
|
||||||
|
|
||||||
[Configuration packages] allow platform builders to package their XRDs and
|
|
||||||
Compositions into [OCI images] that can be distributed via any OCI-compliant
|
|
||||||
image registry. These packages can also declare dependencies on providers,
|
|
||||||
meaning that a single package can declare all of the granular managed resources,
|
|
||||||
the controllers that must be deployed to reconcile them, and the abstract types
|
|
||||||
that expose the underlying resources using composition.
|
|
||||||
|
|
||||||
Organizations with many Crossplane deployments utilize Configuration packages to
|
|
||||||
reproduce their platform in each cluster. This can be as simple as installing
|
|
||||||
Crossplane with the flag to automatically install a Configuration package
|
|
||||||
alongside it.
|
|
||||||
|
|
||||||
```
|
|
||||||
helm install crossplane --namespace crossplane-system crossplane-stable/crossplane --set configuration.packages={"registry.upbound.io/xp/getting-started-with-aws:latest"}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Control Plane of Control Planes
|
|
||||||
|
|
||||||
Taking the multi-cluster multi-tenancy model one step further, some
|
|
||||||
organizations opt to manage their many Crossplane clusters using a single
|
|
||||||
central Crossplane control plane. This requires setting up the central cluster,
|
|
||||||
then using a provider to spin up new clusters (such as an [EKS Cluster] using
|
|
||||||
[provider-aws]), then using [provider-helm] to install Crossplane into the new
|
|
||||||
remote cluster, potentially bundling a common Configuration package into each
|
|
||||||
install using the method described above.
|
|
||||||
|
|
||||||
This advanced pattern allows for full management of Crossplane clusters using
|
|
||||||
Crossplane itself, and when done properly, is a scalable solution to providing
|
|
||||||
dedicated control planes to many tenants within a single organization.
|
|
||||||
|
|
||||||
### Service Provisioning using Open Service Broker API
|
|
||||||
|
|
||||||
Another way to achieve multi-cluster multi-tenancy is by leveraging the
|
|
||||||
possibilities of the [Open Service Broker API] specification and tie it
|
|
||||||
together with Crossplane.
|
|
||||||
|
|
||||||
A possible architecture could look like this: Crossplane and the
|
|
||||||
[Crossplane Service Broker] are running on the central control plane cluster.
|
|
||||||
The Crossplane objects which represent the service offerings and service plans,
|
|
||||||
the XRDs and Compositions, leverage [provider-helm] to spin up service instances
|
|
||||||
on one or many service clusters. The end-user uses the [Kubernetes Service Catalog]
|
|
||||||
to order services via the Crossplane Service Broker. A demo of this concept can be
|
|
||||||
found under [vshn/application-catalog-demo].
|
|
||||||
|
|
||||||
This way even a tight integration of Crossplane in to [Cloudfoundry] is possible.
|
|
||||||
|
|
||||||
<!-- Named Links -->
|
|
||||||
[managed resources]: {{<ref "../concepts/managed-resources" >}}
|
|
||||||
[RBAC]: https://kubernetes.io/docs/reference/access-authn-authz/rbac/
|
|
||||||
[Composition]: {{<ref "../concepts/composition" >}}
|
|
||||||
[CustomResourceDefinitions]: https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/
|
|
||||||
[Open Policy Agent]: https://www.openpolicyagent.org/
|
|
||||||
[Rego]: https://www.openpolicyagent.org/docs/latest/policy-language/
|
|
||||||
[Gatekeeper]: https://open-policy-agent.github.io/gatekeeper/website/docs/
|
|
||||||
[here]: https://youtu.be/TaF0_syejXc
|
|
||||||
[Multiple Source Field patching]: https://github.com/crossplane/crossplane/pull/2093
|
|
||||||
[Configuration packages]: {{<ref "../concepts/packages" >}}
|
|
||||||
[OCI images]: https://github.com/opencontainers/image-spec
|
|
||||||
[EKS Cluster]: https://marketplace.upbound.io/providers/crossplane-contrib/provider-aws/latest/resources/eks.aws.crossplane.io/Cluster/v1beta1
|
|
||||||
[provider-aws]: https://marketplace.upbound.io/providers/crossplane-contrib/provider-aws
|
|
||||||
[provider-helm]: https://marketplace.upbound.io/providers/crossplane-contrib/provider-helm/
|
|
||||||
[Open Service Broker API]: https://github.com/openservicebrokerapi/servicebroker
|
|
||||||
[Crossplane Service Broker]: https://github.com/vshn/crossplane-service-broker
|
|
||||||
[Cloudfoundry]: https://www.cloudfoundry.org/
|
|
||||||
[Kubernetes Service Catalog]: https://github.com/kubernetes-sigs/service-catalog
|
|
||||||
[vshn/application-catalog-demo]: https://github.com/vshn/application-catalog-demo
|
|
|
@ -1,52 +0,0 @@
|
||||||
---
|
|
||||||
title: Self-Signed CA Certs
|
|
||||||
toc: true
|
|
||||||
weight: 270
|
|
||||||
indent: true
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
> Using self-signed certificates is not advised in production, it is
|
|
||||||
recommended to only use self-signed certificates for testing.
|
|
||||||
|
|
||||||
When Crossplane loads Configuration and Provider Packages from private
|
|
||||||
registries, it must be configured to trust the CA and Intermediate certs.
|
|
||||||
|
|
||||||
Crossplane needs to be installed via the Helm chart with the
|
|
||||||
`registryCaBundleConfig.name` and `registryCaBundleConfig.key` parameters
|
|
||||||
defined. See [Install Crossplane]({{< ref "../getting-started/install-configure" >}}).
|
|
||||||
|
|
||||||
## Configure
|
|
||||||
|
|
||||||
1. Create a CA Bundle (A file containing your Root and Intermediate
|
|
||||||
certificates in a specific order). This can be done with any text editor or
|
|
||||||
from the command line, so long as the resulting file contains all required crt
|
|
||||||
files in the proper order. In many cases, this will be either a single
|
|
||||||
self-signed Root CA crt file, or an Intermediate crt and Root crt file. The
|
|
||||||
order of the crt files should be from lowest to highest in signing order.
|
|
||||||
For example, if you have a chain of two certificates below your Root
|
|
||||||
certificate, you place the bottom level Intermediate cert at the beginning of
|
|
||||||
the file, then the Intermediate cert that singed that cert, then the Root cert
|
|
||||||
that signed that cert.
|
|
||||||
|
|
||||||
2. Save the files as `[yourdomain].ca-bundle`.
|
|
||||||
|
|
||||||
3. Create a Kubernetes ConfigMap in your Crossplane system namespace:
|
|
||||||
|
|
||||||
```
|
|
||||||
kubectl -n [Crossplane system namespace] create cm ca-bundle-config \
|
|
||||||
--from-file=ca-bundle=./[yourdomain].ca-bundle
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Set the `registryCaBundleConfig.name` Helm chart parameter to
|
|
||||||
`ca-bundle-config` and the `registryCaBundleConfig.key` parameter to
|
|
||||||
`ca-bundle`.
|
|
||||||
|
|
||||||
> Providing Helm with parameter values is convered in the Helm docs,
|
|
||||||
[Helm install](https://helm.sh/docs/helm/helm_install/). An example block
|
|
||||||
in an `override.yaml` file would look like this:
|
|
||||||
```
|
|
||||||
registryCaBundleConfig:
|
|
||||||
name: ca-bundle-config
|
|
||||||
key: ca-bundle
|
|
||||||
```
|
|
|
@ -1,162 +0,0 @@
|
||||||
---
|
|
||||||
title: Upgrading to v0.14
|
|
||||||
weight: 210
|
|
||||||
---
|
|
||||||
|
|
||||||
Crossplane made a small handful of breaking changes in v0.14. The most broadly
|
|
||||||
impactful change was updating the `CompositeResourceDefinition` (XRD) schema to
|
|
||||||
support defining multiple versions of a composite resource (XR) at once. This
|
|
||||||
guide covers how to upgrade from v0.13 of Crossplane to v0.14.
|
|
||||||
|
|
||||||
- [Updating CompositeResourceDefinitions](#updating-compositeresourcedefinitions)
|
|
||||||
- [Updating Packages](#updating-packages)
|
|
||||||
|
|
||||||
## Updating CompositeResourceDefinitions
|
|
||||||
|
|
||||||
In v0.14 the schema of XRD was updated to support defining multiple versions of
|
|
||||||
an XR. This update requires manual update steps. To upgrade from v0.13 to v0.14
|
|
||||||
you must:
|
|
||||||
|
|
||||||
1. Ensure you have up-to-date YAML representations of all of your XRDs.
|
|
||||||
1. `helm upgrade` your Crossplane release.
|
|
||||||
1. Update and apply all of your XRDs.
|
|
||||||
|
|
||||||
Note that Crossplane will not actively reconcile your XRs between steps 2 and 3,
|
|
||||||
and you will see some errors in the events and logs, but your managed resources
|
|
||||||
(and thus infrastructure) will continue to run. Follow the below steps in order
|
|
||||||
to update your XRDs for v0.14:
|
|
||||||
|
|
||||||
1. Rename `spec.crdSpecTemplate` to `spec.versions`.
|
|
||||||
1. Move `spec.versions.group` to `spec.group`.
|
|
||||||
1. Move `spec.versions.names` to `spec.names`.
|
|
||||||
1. Rename `spec.versions.version` to `spec.versions.name`
|
|
||||||
1. Rename `spec.versions.validation` (if set) to `spec.versions.schema`.
|
|
||||||
1. Rename `spec.versions.additionalPrinterColumns[].JSONPath` (if set) to
|
|
||||||
`spec.versions.additionalPrinterColumns[].jsonPath`.
|
|
||||||
1. Set `spec.versions.served` to `true`.
|
|
||||||
1. Set `spec.versions.referenceable` to `true`.
|
|
||||||
1. Make `spec.versions` a single element array.
|
|
||||||
|
|
||||||
For example, the below XRD:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: apiextensions.crossplane.io/v1alpha1
|
|
||||||
kind: CompositeResourceDefinition
|
|
||||||
metadata:
|
|
||||||
name: xpostgresqlinstances.database.example.org
|
|
||||||
spec:
|
|
||||||
claimNames:
|
|
||||||
kind: PostgreSQLInstance
|
|
||||||
plural: postgresqlinstances
|
|
||||||
connectionSecretKeys:
|
|
||||||
- username
|
|
||||||
- password
|
|
||||||
- endpoint
|
|
||||||
- port
|
|
||||||
crdSpecTemplate:
|
|
||||||
group: database.example.org
|
|
||||||
version: v1alpha1
|
|
||||||
names:
|
|
||||||
kind: XPostgreSQLInstance
|
|
||||||
plural: xpostgresqlinstances
|
|
||||||
validation:
|
|
||||||
openAPIV3Schema:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
spec:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
parameters:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
storageGB:
|
|
||||||
type: integer
|
|
||||||
required:
|
|
||||||
- storageGB
|
|
||||||
required:
|
|
||||||
- parameters
|
|
||||||
```
|
|
||||||
|
|
||||||
Would become:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: apiextensions.crossplane.io/v1alpha1
|
|
||||||
kind: CompositeResourceDefinition
|
|
||||||
metadata:
|
|
||||||
name: xpostgresqlinstances.database.example.org
|
|
||||||
spec:
|
|
||||||
group: database.example.org
|
|
||||||
names:
|
|
||||||
kind: XPostgreSQLInstance
|
|
||||||
plural: xpostgresqlinstances
|
|
||||||
claimNames:
|
|
||||||
kind: PostgreSQLInstance
|
|
||||||
plural: postgresqlinstances
|
|
||||||
connectionSecretKeys:
|
|
||||||
- username
|
|
||||||
- password
|
|
||||||
- endpoint
|
|
||||||
- port
|
|
||||||
versions:
|
|
||||||
- name: v1alpha1
|
|
||||||
served: true
|
|
||||||
referenceable: true
|
|
||||||
schema:
|
|
||||||
openAPIV3Schema:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
spec:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
parameters:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
storageGB:
|
|
||||||
type: integer
|
|
||||||
required:
|
|
||||||
- storageGB
|
|
||||||
required:
|
|
||||||
- parameters
|
|
||||||
```
|
|
||||||
|
|
||||||
## Updating Packages
|
|
||||||
|
|
||||||
A minor breaking change was made to on-disk package types
|
|
||||||
(`meta.pkg.crossplane.io`). In v0.13, the `spec.crossplane` field was present to
|
|
||||||
specify a compatible Crossplane version range, but it was not honored by the
|
|
||||||
package manager when packages were installed. The field was refactored to
|
|
||||||
`spec.crossplane.version` meaning that packages that previously specified
|
|
||||||
`spec.crossplane` will fail to parse when building with the Crossplane CLI or
|
|
||||||
installing into a Crossplane Kubernetes cluster. If `spec.crossplane` was not
|
|
||||||
specified, packages compatible with Crossplane v0.13 will continue to be
|
|
||||||
compatible in v0.14. This is true for both `Provider` and `Configuration`
|
|
||||||
packages.
|
|
||||||
|
|
||||||
The following example shows how a `Configuration` package that specified
|
|
||||||
`spec.crossplane` can be updated to specify Crossplane version constraints that
|
|
||||||
will be honored by the package manager in v0.14:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: meta.pkg.crossplane.io/v1alpha1
|
|
||||||
kind: Configuration
|
|
||||||
metadata:
|
|
||||||
name: my-configuration
|
|
||||||
spec:
|
|
||||||
crossplane: ">=v0.13.0"
|
|
||||||
```
|
|
||||||
|
|
||||||
Would become:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: meta.pkg.crossplane.io/v1alpha1
|
|
||||||
kind: Configuration
|
|
||||||
metadata:
|
|
||||||
name: my-configuration
|
|
||||||
spec:
|
|
||||||
crossplane:
|
|
||||||
version: ">=v0.13.0"
|
|
||||||
```
|
|
||||||
|
|
||||||
Please note that while `spec.dependsOn` is also a valid field in on-disk package
|
|
||||||
types, it is not yet honored by the package manager and will be ignored at
|
|
||||||
installation time.
|
|
|
@ -1,46 +0,0 @@
|
||||||
---
|
|
||||||
title: Upgrading to v1.x
|
|
||||||
weight: 220
|
|
||||||
---
|
|
||||||
|
|
||||||
Crossplane versions post v1.0 do not introduce any breaking changes, but may
|
|
||||||
make some backward compatible changes to the core Crossplane CRDs. Helm [does
|
|
||||||
not currently touch CRDs](https://github.com/helm/helm/issues/6581) when a chart
|
|
||||||
is upgraded, so Crossplane has moved to [managing its own
|
|
||||||
CRDs](https://github.com/crossplane/crossplane/pull/2160) as of v1.2.0. However,
|
|
||||||
for versions prior to v1.2.0, you must manually apply the appropriate CRDs
|
|
||||||
before upgrading.
|
|
||||||
|
|
||||||
## Upgrading to v1.0.x or v1.1.x
|
|
||||||
|
|
||||||
To upgrade from the currently installed version, run:
|
|
||||||
|
|
||||||
```console
|
|
||||||
# Update to the latest CRDs.
|
|
||||||
kubectl apply -k https://github.com/crossplane/crossplane//cluster?ref=<release-branch>
|
|
||||||
|
|
||||||
# Update to the latest stable Helm chart for the desired version
|
|
||||||
helm --namespace crossplane-system upgrade crossplane crossplane-stable/crossplane --version <version>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Upgrading to v1.2.x and Subsequent Versions
|
|
||||||
|
|
||||||
Since `v1.2.0`, we do not include any custom resource instances in our Helm chart.
|
|
||||||
This means the `Lock` object and `Provider`s and `Configuration`s you might have
|
|
||||||
possibly installed via Helm values will get deleted when you upgrade to `v1.2.x`.
|
|
||||||
The following commands will instruct Helm not to delete any instances of those
|
|
||||||
types:
|
|
||||||
|
|
||||||
```console
|
|
||||||
for name in $(kubectl get locks.pkg.crossplane.io -o name); do kubectl annotate $name 'helm.sh/resource-policy=keep'; done
|
|
||||||
for name in $(kubectl get providers.pkg.crossplane.io -o name); do kubectl annotate $name 'helm.sh/resource-policy=keep'; done
|
|
||||||
for name in $(kubectl get configurations.pkg.crossplane.io -o name); do kubectl annotate $name 'helm.sh/resource-policy=keep'; done
|
|
||||||
```
|
|
||||||
|
|
||||||
After annotations are in place you can upgrade from the currently installed version
|
|
||||||
by running:
|
|
||||||
|
|
||||||
```console
|
|
||||||
# Update to the latest stable Helm chart for the desired version
|
|
||||||
helm --namespace crossplane-system upgrade crossplane crossplane-stable/crossplane --version <version>
|
|
||||||
```
|
|
|
@ -1,478 +0,0 @@
|
||||||
---
|
|
||||||
title: Vault as an External Secret Store
|
|
||||||
weight: 230
|
|
||||||
---
|
|
||||||
|
|
||||||
This guide walks through the steps required to configure Crossplane and
|
|
||||||
its Providers to use [Vault] as an [External Secret Store]. For the sake of
|
|
||||||
completeness, we will also include steps for Vault installation and setup,
|
|
||||||
however, you can skip those and use your existing Vault.
|
|
||||||
|
|
||||||
> External Secret Stores are an alpha feature. They are not yet recommended for
|
|
||||||
> production use, and are disabled by default.
|
|
||||||
|
|
||||||
Crossplane consumes and also produces sensitive information to operate which
|
|
||||||
could be categorized as follows:
|
|
||||||
|
|
||||||
1. **Provider credentials:** These are the credentials required for Providers
|
|
||||||
to authenticate against external APIs. For example, AWS Access/Secret keys, GCP
|
|
||||||
service account json, etc.
|
|
||||||
2. **Connection Details:** Once an infrastructure provisioned, we usually
|
|
||||||
need some connection data to consume it. Most of the time, this
|
|
||||||
information includes sensitive information like usernames, passwords or access
|
|
||||||
keys.
|
|
||||||
3. **Sensitive Inputs to Managed Resources:** There are some Managed resources
|
|
||||||
which expect input parameters that could be sensitive. Initial password of a
|
|
||||||
managed database is a good example of this category.
|
|
||||||
|
|
||||||
It is already possible to use Vault for the 1st category (i.e. Provider
|
|
||||||
Credentials) as described in [the previous guide]. The 3rd use case is relatively
|
|
||||||
rare and being tracked with [this issue].
|
|
||||||
|
|
||||||
In this guide we will focus on the 2nd category, which is storing Connection
|
|
||||||
Details for managed resources in Vault.
|
|
||||||
|
|
||||||
## Steps
|
|
||||||
|
|
||||||
> Some steps in this guide duplicates [the previous guide] on Vault injection.
|
|
||||||
> However, for convenience, we put them here as well with minor
|
|
||||||
> changes/improvements.
|
|
||||||
|
|
||||||
At a high level we will run the following steps:
|
|
||||||
|
|
||||||
- Install and Unseal Vault.
|
|
||||||
- Configure Vault with Kubernetes Auth.
|
|
||||||
- Install and Configure Crossplane by enabling the feature.
|
|
||||||
- Install and Configure Provider GCP by enabling the feature.
|
|
||||||
- Deploy a Composition and CompositeResourceDefinition.
|
|
||||||
- Create a Claim.
|
|
||||||
- Verify all secrets land in Vault as expected.
|
|
||||||
|
|
||||||
For simplicity, we will deploy Vault into the same cluster as Crossplane,
|
|
||||||
however, this is not a requirement as long as Vault has Kubernetes auth enabled
|
|
||||||
for the cluster where Crossplane is running.
|
|
||||||
|
|
||||||
### Prepare Vault
|
|
||||||
|
|
||||||
1. Install Vault Helm Chart
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl create ns vault-system
|
|
||||||
|
|
||||||
helm repo add hashicorp https://helm.releases.hashicorp.com --force-update
|
|
||||||
helm -n vault-system upgrade --install vault hashicorp/vault
|
|
||||||
```
|
|
||||||
|
|
||||||
2. [Unseal] Vault
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl -n vault-system exec vault-0 -- vault operator init -key-shares=1 -key-threshold=1 -format=json > cluster-keys.json
|
|
||||||
VAULT_UNSEAL_KEY=$(cat cluster-keys.json | jq -r ".unseal_keys_b64[]")
|
|
||||||
kubectl -n vault-system exec vault-0 -- vault operator unseal $VAULT_UNSEAL_KEY
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Configure Vault with Kubernetes Auth.
|
|
||||||
|
|
||||||
In order for Vault to be able to authenticate requests based on Kubernetes
|
|
||||||
service accounts, the [Kubernetes auth method] must be enabled.
|
|
||||||
This requires logging in to Vault and configuring it with a service account
|
|
||||||
token, API server address, and certificate. Because we are running Vault in
|
|
||||||
Kubernetes, these values are already available via the container filesystem and
|
|
||||||
environment variables.
|
|
||||||
|
|
||||||
Get Vault Root Token:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cat cluster-keys.json | jq -r ".root_token"
|
|
||||||
```
|
|
||||||
|
|
||||||
Login as root and enable/configure Kubernetes Auth:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl -n vault-system exec -it vault-0 -- /bin/sh
|
|
||||||
|
|
||||||
vault login # use root token from above
|
|
||||||
|
|
||||||
vault auth enable kubernetes
|
|
||||||
vault write auth/kubernetes/config \
|
|
||||||
token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
|
|
||||||
kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" \
|
|
||||||
kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
|
|
||||||
|
|
||||||
exit # exit vault container
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Enable Vault Key Value Secret Engine
|
|
||||||
|
|
||||||
There are two different versions of [Vault KV Secrets Engine], `v1` and `v2`,
|
|
||||||
which you can find more details in the linked documentation page.
|
|
||||||
We will use `v2` in this guide as an example, however, both versions are
|
|
||||||
supported as an external secret store.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl -n vault-system exec -it vault-0 -- vault secrets enable -path=secret kv-v2
|
|
||||||
```
|
|
||||||
|
|
||||||
5. Create a Vault Policy and Role for Crossplane
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl -n vault-system exec -i vault-0 -- vault policy write crossplane - <<EOF
|
|
||||||
path "secret/data/*" {
|
|
||||||
capabilities = ["create", "read", "update", "delete"]
|
|
||||||
}
|
|
||||||
path "secret/metadata/*" {
|
|
||||||
capabilities = ["create", "read", "update", "delete"]
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
kubectl -n vault-system exec -it vault-0 -- vault write auth/kubernetes/role/crossplane \
|
|
||||||
bound_service_account_names="*" \
|
|
||||||
bound_service_account_namespaces=crossplane-system \
|
|
||||||
policies=crossplane \
|
|
||||||
ttl=24h
|
|
||||||
```
|
|
||||||
|
|
||||||
### Install and Configure Crossplane
|
|
||||||
|
|
||||||
1. Install Crossplane by:
|
|
||||||
|
|
||||||
- Enabling `External Secret Stores` feature.
|
|
||||||
- Annotating for [Vault Agent Sidecar Injection]
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl create ns crossplane-system
|
|
||||||
|
|
||||||
helm repo add crossplane-stable https://charts.crossplane.io/stable --force-update
|
|
||||||
|
|
||||||
helm upgrade --install crossplane crossplane-stable/crossplane --namespace crossplane-system \
|
|
||||||
--set 'args={--enable-external-secret-stores}' \
|
|
||||||
--set-string customAnnotations."vault\.hashicorp\.com/agent-inject"=true \
|
|
||||||
--set-string customAnnotations."vault\.hashicorp\.com/agent-inject-token"=true \
|
|
||||||
--set-string customAnnotations."vault\.hashicorp\.com/role"=crossplane \
|
|
||||||
--set-string customAnnotations."vault\.hashicorp\.com/agent-run-as-user"=65532
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Create a Secret `StoreConfig` for Crossplane to be used by
|
|
||||||
Composition types, i.e. `Composites` and `Claims`:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
echo "apiVersion: secrets.crossplane.io/v1alpha1
|
|
||||||
kind: StoreConfig
|
|
||||||
metadata:
|
|
||||||
name: vault
|
|
||||||
spec:
|
|
||||||
type: Vault
|
|
||||||
defaultScope: crossplane-system
|
|
||||||
vault:
|
|
||||||
server: http://vault.vault-system:8200
|
|
||||||
mountPath: secret/
|
|
||||||
version: v2
|
|
||||||
auth:
|
|
||||||
method: Token
|
|
||||||
token:
|
|
||||||
source: Filesystem
|
|
||||||
fs:
|
|
||||||
path: /vault/secrets/token" | kubectl apply -f -
|
|
||||||
```
|
|
||||||
|
|
||||||
### Install and Configure Provider GCP
|
|
||||||
|
|
||||||
1. Similar to Crossplane, install Provider GCP by:
|
|
||||||
|
|
||||||
- Enabling `External Secret Stores` feature.
|
|
||||||
- Annotating for [Vault Agent Sidecar Injection]
|
|
||||||
|
|
||||||
```shell
|
|
||||||
echo "apiVersion: pkg.crossplane.io/v1alpha1
|
|
||||||
kind: ControllerConfig
|
|
||||||
metadata:
|
|
||||||
name: vault-config
|
|
||||||
spec:
|
|
||||||
args:
|
|
||||||
- --enable-external-secret-stores
|
|
||||||
metadata:
|
|
||||||
annotations:
|
|
||||||
vault.hashicorp.com/agent-inject: \"true\"
|
|
||||||
vault.hashicorp.com/agent-inject-token: \"true\"
|
|
||||||
vault.hashicorp.com/role: crossplane
|
|
||||||
vault.hashicorp.com/agent-run-as-user: \"2000\"
|
|
||||||
---
|
|
||||||
apiVersion: pkg.crossplane.io/v1
|
|
||||||
kind: Provider
|
|
||||||
metadata:
|
|
||||||
name: provider-gcp
|
|
||||||
spec:
|
|
||||||
package: xpkg.upbound.io/crossplane-contrib/provider-gcp:v0.22.0
|
|
||||||
controllerConfigRef:
|
|
||||||
name: vault-config" | kubectl apply -f -
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Create a Secret `StoreConfig` for Provider GCP to be used by GCP Managed
|
|
||||||
Resources:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
echo "apiVersion: gcp.crossplane.io/v1alpha1
|
|
||||||
kind: StoreConfig
|
|
||||||
metadata:
|
|
||||||
name: vault
|
|
||||||
spec:
|
|
||||||
type: Vault
|
|
||||||
defaultScope: crossplane-system
|
|
||||||
vault:
|
|
||||||
server: http://vault.vault-system:8200
|
|
||||||
mountPath: secret/
|
|
||||||
version: v2
|
|
||||||
auth:
|
|
||||||
method: Token
|
|
||||||
token:
|
|
||||||
source: Filesystem
|
|
||||||
fs:
|
|
||||||
path: /vault/secrets/token" | kubectl apply -f -
|
|
||||||
```
|
|
||||||
|
|
||||||
### Deploy and Test
|
|
||||||
|
|
||||||
> Prerequisite: You should have a working **default** `ProviderConfig` for
|
|
||||||
> GCP available.
|
|
||||||
|
|
||||||
1. Create a `Composition` and a `CompositeResourceDefinition`:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
echo "apiVersion: apiextensions.crossplane.io/v1
|
|
||||||
kind: CompositeResourceDefinition
|
|
||||||
metadata:
|
|
||||||
name: compositeessinstances.ess.example.org
|
|
||||||
annotations:
|
|
||||||
feature: ess
|
|
||||||
spec:
|
|
||||||
group: ess.example.org
|
|
||||||
names:
|
|
||||||
kind: CompositeESSInstance
|
|
||||||
plural: compositeessinstances
|
|
||||||
claimNames:
|
|
||||||
kind: ESSInstance
|
|
||||||
plural: essinstances
|
|
||||||
connectionSecretKeys:
|
|
||||||
- publicKey
|
|
||||||
- publicKeyType
|
|
||||||
versions:
|
|
||||||
- name: v1alpha1
|
|
||||||
served: true
|
|
||||||
referenceable: true
|
|
||||||
schema:
|
|
||||||
openAPIV3Schema:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
spec:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
parameters:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
serviceAccount:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- serviceAccount
|
|
||||||
required:
|
|
||||||
- parameters" | kubectl apply -f -
|
|
||||||
|
|
||||||
echo "apiVersion: apiextensions.crossplane.io/v1
|
|
||||||
kind: Composition
|
|
||||||
metadata:
|
|
||||||
name: essinstances.ess.example.org
|
|
||||||
labels:
|
|
||||||
feature: ess
|
|
||||||
spec:
|
|
||||||
publishConnectionDetailsWithStoreConfigRef:
|
|
||||||
name: vault
|
|
||||||
compositeTypeRef:
|
|
||||||
apiVersion: ess.example.org/v1alpha1
|
|
||||||
kind: CompositeESSInstance
|
|
||||||
resources:
|
|
||||||
- name: serviceaccount
|
|
||||||
base:
|
|
||||||
apiVersion: iam.gcp.crossplane.io/v1alpha1
|
|
||||||
kind: ServiceAccount
|
|
||||||
metadata:
|
|
||||||
name: ess-test-sa
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
displayName: a service account to test ess
|
|
||||||
- name: serviceaccountkey
|
|
||||||
base:
|
|
||||||
apiVersion: iam.gcp.crossplane.io/v1alpha1
|
|
||||||
kind: ServiceAccountKey
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
serviceAccountSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
publishConnectionDetailsTo:
|
|
||||||
name: ess-mr-conn
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
environment: development
|
|
||||||
team: backend
|
|
||||||
configRef:
|
|
||||||
name: vault
|
|
||||||
connectionDetails:
|
|
||||||
- fromConnectionSecretKey: publicKey
|
|
||||||
- fromConnectionSecretKey: publicKeyType" | kubectl apply -f -
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Create a `Claim`:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
echo "apiVersion: ess.example.org/v1alpha1
|
|
||||||
kind: ESSInstance
|
|
||||||
metadata:
|
|
||||||
name: my-ess
|
|
||||||
namespace: default
|
|
||||||
spec:
|
|
||||||
parameters:
|
|
||||||
serviceAccount: ess-test-sa
|
|
||||||
compositionSelector:
|
|
||||||
matchLabels:
|
|
||||||
feature: ess
|
|
||||||
publishConnectionDetailsTo:
|
|
||||||
name: ess-claim-conn
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
environment: development
|
|
||||||
team: backend
|
|
||||||
configRef:
|
|
||||||
name: vault" | kubectl apply -f -
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Verify all resources SYNCED and READY:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl get managed
|
|
||||||
# Example output:
|
|
||||||
# NAME READY SYNCED DISPLAYNAME EMAIL DISABLED
|
|
||||||
# serviceaccount.iam.gcp.crossplane.io/my-ess-zvmkz-vhklg True True a service account to test ess my-ess-zvmkz-vhklg@testingforbugbounty.iam.gserviceaccount.com
|
|
||||||
|
|
||||||
# NAME READY SYNCED KEY_ID CREATED_AT EXPIRES_AT
|
|
||||||
# serviceaccountkey.iam.gcp.crossplane.io/my-ess-zvmkz-bq8pz True True 5cda49b7c32393254b5abb121b4adc07e140502c 2022-03-23T10:54:50Z
|
|
||||||
|
|
||||||
kubectl -n default get claim
|
|
||||||
# Example output:
|
|
||||||
# NAME READY CONNECTION-SECRET AGE
|
|
||||||
# my-ess True 19s
|
|
||||||
|
|
||||||
kubectl get composite
|
|
||||||
# Example output:
|
|
||||||
# NAME READY COMPOSITION AGE
|
|
||||||
# my-ess-zvmkz True essinstances.ess.example.org 32s
|
|
||||||
```
|
|
||||||
|
|
||||||
### Verify the Connection Secrets landed to Vault
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# Check connection secrets in the "default" scope (namespace).
|
|
||||||
kubectl -n vault-system exec -i vault-0 -- vault kv list /secret/default
|
|
||||||
# Example output:
|
|
||||||
# Keys
|
|
||||||
# ----
|
|
||||||
# ess-claim-conn
|
|
||||||
|
|
||||||
# Check connection secrets in the "crossplane-system" scope (namespace).
|
|
||||||
kubectl -n vault-system exec -i vault-0 -- vault kv list /secret/crossplane-system
|
|
||||||
# Example output:
|
|
||||||
# Keys
|
|
||||||
# ----
|
|
||||||
# d2408335-eb88-4146-927b-8025f405da86
|
|
||||||
# ess-mr-conn
|
|
||||||
|
|
||||||
# Check contents of claim connection secret
|
|
||||||
kubectl -n vault-system exec -i vault-0 -- vault kv get /secret/default/ess-claim-conn
|
|
||||||
# Example output:
|
|
||||||
# ======= Metadata =======
|
|
||||||
# Key Value
|
|
||||||
# --- -----
|
|
||||||
# created_time 2022-03-18T21:24:07.2085726Z
|
|
||||||
# custom_metadata map[environment:development secret.crossplane.io/owner-uid:881cd9a0-6cc6-418f-8e1d-b36062c1e108 team:backend]
|
|
||||||
# deletion_time n/a
|
|
||||||
# destroyed false
|
|
||||||
# version 1
|
|
||||||
#
|
|
||||||
# ======== Data ========
|
|
||||||
# Key Value
|
|
||||||
# --- -----
|
|
||||||
# publicKey -----BEGIN PUBLIC KEY-----
|
|
||||||
# MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzsEYCokmYEsZJCc9QN/8
|
|
||||||
# Fm1M/kTPp7Gat/MXLTP3zFyCTBFVNLN79MbAKdinWi6ePXEb75vzB79IdZcWj8lo
|
|
||||||
# 8trnS64QjNB9Vs4Xk5UvDALwleFN/bZeperxivDPwVPvT9Aqy/U9kohoS/LHyE8w
|
|
||||||
# uWQb5AuMeVQ1gtCTnCqQZ4d2MSVhQXYVvAWax1spJ9LT7mHub5j95xDdYIcOV3VJ
|
|
||||||
# l9CIo4VrWIT8THFN2NnjTrGq9+0TzXY0bV674bjJkfBC6v6yXs5HTetG+Uekq/xf
|
|
||||||
# FCjrrDi1+2UR9Mu2WTuvl8qn50be+mbwdJO5wE32jewxdYrVVmj19+PkaEeAwGTc
|
|
||||||
# vwIDAQAB
|
|
||||||
# -----END PUBLIC KEY-----
|
|
||||||
# publicKeyType TYPE_RAW_PUBLIC_KEY
|
|
||||||
|
|
||||||
# Check contents of managed resource connection secret
|
|
||||||
kubectl -n vault-system exec -i vault-0 -- vault kv get /secret/crossplane-system/ess-mr-conn
|
|
||||||
# Example output:
|
|
||||||
# ======= Metadata =======
|
|
||||||
# Key Value
|
|
||||||
# --- -----
|
|
||||||
# created_time 2022-03-18T21:21:07.9298076Z
|
|
||||||
# custom_metadata map[environment:development secret.crossplane.io/owner-uid:4cd973f8-76fc-45d6-ad45-0b27b5e9252a team:backend]
|
|
||||||
# deletion_time n/a
|
|
||||||
# destroyed false
|
|
||||||
# version 2
|
|
||||||
#
|
|
||||||
# ========= Data =========
|
|
||||||
# Key Value
|
|
||||||
# --- -----
|
|
||||||
# privateKey {
|
|
||||||
# "type": "service_account",
|
|
||||||
# "project_id": "REDACTED",
|
|
||||||
# "private_key_id": "REDACTED",
|
|
||||||
# "private_key": "-----BEGIN PRIVATE KEY-----\nREDACTED\n-----END PRIVATE KEY-----\n",
|
|
||||||
# "client_email": "ess-test-sa@REDACTED.iam.gserviceaccount.com",
|
|
||||||
# "client_id": "REDACTED",
|
|
||||||
# "auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
|
||||||
# "token_uri": "https://oauth2.googleapis.com/token",
|
|
||||||
# "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
|
||||||
# "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/ess-test-sa%40REDACTED.iam.gserviceaccount.com"
|
|
||||||
# }
|
|
||||||
# privateKeyType TYPE_GOOGLE_CREDENTIALS_FILE
|
|
||||||
# publicKey -----BEGIN PUBLIC KEY-----
|
|
||||||
# MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzsEYCokmYEsZJCc9QN/8
|
|
||||||
# Fm1M/kTPp7Gat/MXLTP3zFyCTBFVNLN79MbAKdinWi6ePXEb75vzB79IdZcWj8lo
|
|
||||||
# 8trnS64QjNB9Vs4Xk5UvDALwleFN/bZeperxivDPwVPvT9Aqy/U9kohoS/LHyE8w
|
|
||||||
# uWQb5AuMeVQ1gtCTnCqQZ4d2MSVhQXYVvAWax1spJ9LT7mHub5j95xDdYIcOV3VJ
|
|
||||||
# l9CIo4VrWIT8THFN2NnjTrGq9+0TzXY0bV674bjJkfBC6v6yXs5HTetG+Uekq/xf
|
|
||||||
# FCjrrDi1+2UR9Mu2WTuvl8qn50be+mbwdJO5wE32jewxdYrVVmj19+PkaEeAwGTc
|
|
||||||
# vwIDAQAB
|
|
||||||
# -----END PUBLIC KEY-----
|
|
||||||
# publicKeyType TYPE_RAW_PUBLIC_KEY
|
|
||||||
```
|
|
||||||
|
|
||||||
The commands above verifies using the cli, however, you can also connect to the
|
|
||||||
Vault UI and check secrets there.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl -n vault-system port-forward vault-0 8200:8200
|
|
||||||
```
|
|
||||||
|
|
||||||
Now, you can open http://127.0.0.1:8200/ui in browser and login with the root token.
|
|
||||||
|
|
||||||
### Cleanup
|
|
||||||
|
|
||||||
Delete the claim which should clean up all the resources created.
|
|
||||||
|
|
||||||
```
|
|
||||||
kubectl -n default delete claim my-ess
|
|
||||||
```
|
|
||||||
|
|
||||||
<!-- named links -->
|
|
||||||
|
|
||||||
[Vault]: https://www.vaultproject.io/
|
|
||||||
[External Secret Store]: https://github.com/crossplane/crossplane/blob/master/design/design-doc-external-secret-stores.md
|
|
||||||
[the previous guide]: {{<ref "vault-injection" >}}
|
|
||||||
[this issue]: https://github.com/crossplane/crossplane/issues/2985
|
|
||||||
[Kubernetes Auth Method]: https://www.vaultproject.io/docs/auth/kubernetes
|
|
||||||
[Unseal]: https://www.vaultproject.io/docs/concepts/seal
|
|
||||||
[Vault KV Secrets Engine]: https://www.vaultproject.io/docs/secrets/kv
|
|
||||||
[Vault Agent Sidecar Injection]: https://www.vaultproject.io/docs/platform/k8s/injector
|
|
|
@ -1,322 +0,0 @@
|
||||||
---
|
|
||||||
title: Vault Credential Injection
|
|
||||||
weight: 230
|
|
||||||
---
|
|
||||||
|
|
||||||
> This guide is adapted from the [Vault on Minikube] and [Vault Kubernetes
|
|
||||||
> Sidecar] guides.
|
|
||||||
|
|
||||||
Most Crossplane providers support supplying credentials from at least the
|
|
||||||
following sources:
|
|
||||||
- Kubernetes Secret
|
|
||||||
- Environment Variable
|
|
||||||
- Filesystem
|
|
||||||
|
|
||||||
A provider may optionally support additional credentials sources, but the common
|
|
||||||
sources cover a wide variety of use cases. One specific use case that is popular
|
|
||||||
among organizations that use [Vault] for secrets management is using a sidecar
|
|
||||||
to inject credentials into the filesystem. This guide will demonstrate how to
|
|
||||||
use the [Vault Kubernetes Sidecar] to provide credentials for [provider-gcp].
|
|
||||||
|
|
||||||
> Note: in this guide we will copy GCP credentials into Vault's KV secrets
|
|
||||||
> engine. This is a simple generic approach to managing secrets with Vault, but
|
|
||||||
> is not as robust as using Vault's dedicated cloud provider secrets engines for
|
|
||||||
> [AWS], [Azure], and [GCP].
|
|
||||||
|
|
||||||
## Setup
|
|
||||||
|
|
||||||
> Note: this guide walks through setting up Vault running in the same cluster as
|
|
||||||
> Crossplane. You may also choose to use an existing Vault instance that runs
|
|
||||||
> outside the cluster but has Kubernetes authentication enabled.
|
|
||||||
|
|
||||||
Before getting started, you must ensure that you have installed Crossplane and
|
|
||||||
Vault and that they are running in your cluster.
|
|
||||||
|
|
||||||
1. Install Crossplane
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl create namespace crossplane-system
|
|
||||||
|
|
||||||
helm repo add crossplane-stable https://charts.crossplane.io/stable
|
|
||||||
helm repo update
|
|
||||||
|
|
||||||
helm install crossplane --namespace crossplane-system crossplane-stable/crossplane
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Install Vault Helm Chart
|
|
||||||
|
|
||||||
```console
|
|
||||||
helm repo add hashicorp https://helm.releases.hashicorp.com
|
|
||||||
helm install vault hashicorp/vault
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Unseal Vault Instance
|
|
||||||
|
|
||||||
In order for Vault to access encrypted data from physical storage, it must be
|
|
||||||
[unsealed].
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl exec vault-0 -- vault operator init -key-shares=1 -key-threshold=1 -format=json > cluster-keys.json
|
|
||||||
VAULT_UNSEAL_KEY=$(cat cluster-keys.json | jq -r ".unseal_keys_b64[]")
|
|
||||||
kubectl exec vault-0 -- vault operator unseal $VAULT_UNSEAL_KEY
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Enable Kubernetes Authentication Method
|
|
||||||
|
|
||||||
In order for Vault to be able to authenticate requests based on Kubernetes
|
|
||||||
service accounts, the [Kubernetes authentication backend] must be enabled. This
|
|
||||||
requires logging in to Vault and configuring it with a service account token,
|
|
||||||
API server address, and certificate. Because we are running Vault in Kubernetes,
|
|
||||||
these values are already available via the container filesystem and environment
|
|
||||||
variables.
|
|
||||||
|
|
||||||
```console
|
|
||||||
cat cluster-keys.json | jq -r ".root_token" # get root token
|
|
||||||
|
|
||||||
kubectl exec -it vault-0 -- /bin/sh
|
|
||||||
vault login # use root token from above
|
|
||||||
vault auth enable kubernetes
|
|
||||||
|
|
||||||
vault write auth/kubernetes/config \
|
|
||||||
token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
|
|
||||||
kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" \
|
|
||||||
kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
|
|
||||||
```
|
|
||||||
|
|
||||||
5. Exit Vault Container
|
|
||||||
|
|
||||||
The next steps will be executed in your local environment.
|
|
||||||
|
|
||||||
```console
|
|
||||||
exit
|
|
||||||
```
|
|
||||||
|
|
||||||
## Create GCP Service Account
|
|
||||||
|
|
||||||
In order to provision infrastructure on GCP, you will need to create a service
|
|
||||||
account with appropriate permissions. In this guide we will only provision a
|
|
||||||
CloudSQL instance, so the service account will be bound to the `cloudsql.admin`
|
|
||||||
role. The following steps will setup a GCP service account, give it the
|
|
||||||
necessary permissions for Crossplane to be able to manage CloudSQL instances,
|
|
||||||
and emit the service account credentials in a JSON file.
|
|
||||||
|
|
||||||
```console
|
|
||||||
# replace this with your own gcp project id and the name of the service account
|
|
||||||
# that will be created.
|
|
||||||
PROJECT_ID=my-project
|
|
||||||
NEW_SA_NAME=test-service-account-name
|
|
||||||
|
|
||||||
# create service account
|
|
||||||
SA="${NEW_SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
|
|
||||||
gcloud iam service-accounts create $NEW_SA_NAME --project $PROJECT_ID
|
|
||||||
|
|
||||||
# enable cloud API
|
|
||||||
SERVICE="sqladmin.googleapis.com"
|
|
||||||
gcloud services enable $SERVICE --project $PROJECT_ID
|
|
||||||
|
|
||||||
# grant access to cloud API
|
|
||||||
ROLE="roles/cloudsql.admin"
|
|
||||||
gcloud projects add-iam-policy-binding --role="$ROLE" $PROJECT_ID --member "serviceAccount:$SA"
|
|
||||||
|
|
||||||
# create service account keyfile
|
|
||||||
gcloud iam service-accounts keys create creds.json --project $PROJECT_ID --iam-account $SA
|
|
||||||
```
|
|
||||||
|
|
||||||
You should now have valid service account credentials in `creds.json`.
|
|
||||||
|
|
||||||
## Store Credentials in Vault
|
|
||||||
|
|
||||||
After setting up Vault, you will need to store your credentials in the [kv
|
|
||||||
secrets engine].
|
|
||||||
|
|
||||||
> Note: the steps below involve copying credentials into the container
|
|
||||||
> filesystem before storing them in Vault. You may also choose to use Vault's
|
|
||||||
> HTTP API or UI by port-forwarding the container to your local environment
|
|
||||||
> (`kubectl port-forward vault-0 8200:8200`).
|
|
||||||
|
|
||||||
1. Copy Credentials File into Vault Container
|
|
||||||
|
|
||||||
Copy your credentials into the container filesystem so that your can store them
|
|
||||||
in Vault.
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl cp creds.json vault-0:/tmp/creds.json
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Enable KV Secrets Engine
|
|
||||||
|
|
||||||
Secrets engines must be enabled before they can be used. Enable the `kv-v2`
|
|
||||||
secrets engine a the `secret` path.
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl exec -it vault-0 -- /bin/sh
|
|
||||||
|
|
||||||
vault secrets enable -path=secret kv-v2
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Store GCP Credentials in KV Engine
|
|
||||||
|
|
||||||
The path of your GCP credentials is how the secret will be referenced when
|
|
||||||
injecting it into the `provider-gcp` controller `Pod`.
|
|
||||||
|
|
||||||
```console
|
|
||||||
vault kv put secret/provider-creds/gcp-default @tmp/creds.json
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Clean Up Credentials File
|
|
||||||
|
|
||||||
You no longer need our GCP credentials file in the container filesystem, so go
|
|
||||||
ahead and clean it up.
|
|
||||||
|
|
||||||
```console
|
|
||||||
rm tmp/creds.json
|
|
||||||
```
|
|
||||||
|
|
||||||
## Create a Vault Policy for Reading Provider Credentials
|
|
||||||
|
|
||||||
In order for our controllers to have the Vault sidecar inject the credentials
|
|
||||||
into their filesystem, you must associate the `Pod` with a [policy]. This policy
|
|
||||||
will allow for reading and listing all secrets on the `provider-creds` path in
|
|
||||||
the `kv-v2` secrets engine.
|
|
||||||
|
|
||||||
```console
|
|
||||||
vault policy write provider-creds - <<EOF
|
|
||||||
path "secret/data/provider-creds/*" {
|
|
||||||
capabilities = ["read", "list"]
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
```
|
|
||||||
|
|
||||||
## Create a Role for Crossplane Provider Pods
|
|
||||||
|
|
||||||
1. Create Role
|
|
||||||
|
|
||||||
The last step is to create a role that is bound to the policy you created and
|
|
||||||
associate it with a group of Kubernetes service accounts. This role can be
|
|
||||||
assumed by any (`*`) service account in the `crossplane-system` namespace.
|
|
||||||
|
|
||||||
```console
|
|
||||||
vault write auth/kubernetes/role/crossplane-providers \
|
|
||||||
bound_service_account_names="*" \
|
|
||||||
bound_service_account_namespaces=crossplane-system \
|
|
||||||
policies=provider-creds \
|
|
||||||
ttl=24h
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Exit Vault Container
|
|
||||||
|
|
||||||
The next steps will be executed in your local environment.
|
|
||||||
|
|
||||||
```console
|
|
||||||
exit
|
|
||||||
```
|
|
||||||
|
|
||||||
## Install provider-gcp
|
|
||||||
|
|
||||||
You are now ready to install `provider-gcp`. Crossplane provides a
|
|
||||||
`ControllerConfig` type that allows you to customize the deployment of a
|
|
||||||
provider's controller `Pod`. A `ControllerConfig` can be created and referenced
|
|
||||||
by any number of `Provider` objects that wish to use its configuration. In the
|
|
||||||
example below, the `Pod` annotations indicate to the Vault mutating webhook that
|
|
||||||
we want for the secret stored at `secret/provider-creds/gcp-default` to be
|
|
||||||
injected into the container filesystem by assuming role `crossplane-providers`.
|
|
||||||
There is also so template formatting added to make sure the secret data is
|
|
||||||
presented in a form that `provider-gcp` is expecting.
|
|
||||||
|
|
||||||
{% raw %}
|
|
||||||
```console
|
|
||||||
echo "apiVersion: pkg.crossplane.io/v1alpha1
|
|
||||||
kind: ControllerConfig
|
|
||||||
metadata:
|
|
||||||
name: vault-config
|
|
||||||
spec:
|
|
||||||
metadata:
|
|
||||||
annotations:
|
|
||||||
vault.hashicorp.com/agent-inject: \"true\"
|
|
||||||
vault.hashicorp.com/role: "crossplane-providers"
|
|
||||||
vault.hashicorp.com/agent-inject-secret-creds.txt: "secret/provider-creds/gcp-default"
|
|
||||||
vault.hashicorp.com/agent-inject-template-creds.txt: |
|
|
||||||
{{- with secret \"secret/provider-creds/gcp-default\" -}}
|
|
||||||
{{ .Data.data | toJSON }}
|
|
||||||
{{- end -}}
|
|
||||||
---
|
|
||||||
apiVersion: pkg.crossplane.io/v1
|
|
||||||
kind: Provider
|
|
||||||
metadata:
|
|
||||||
name: provider-gcp
|
|
||||||
spec:
|
|
||||||
package: xpkg.upbound.io/crossplane-contrib/provider-gcp:v0.22.0
|
|
||||||
controllerConfigRef:
|
|
||||||
name: vault-config" | kubectl apply -f -
|
|
||||||
```
|
|
||||||
{% endraw %}
|
|
||||||
|
|
||||||
## Configure provider-gcp
|
|
||||||
|
|
||||||
One `provider-gcp` is installed and running, you will want to create a
|
|
||||||
`ProviderConfig` that specifies the credentials in the filesystem that should be
|
|
||||||
used to provision managed resources that reference this `ProviderConfig`.
|
|
||||||
Because the name of this `ProviderConfig` is `default` it will be used by any
|
|
||||||
managed resources that do not explicitly reference a `ProviderConfig`.
|
|
||||||
|
|
||||||
> Note: make sure that the `PROJECT_ID` environment variable that was defined
|
|
||||||
> earlier is still set correctly.
|
|
||||||
|
|
||||||
```console
|
|
||||||
echo "apiVersion: gcp.crossplane.io/v1beta1
|
|
||||||
kind: ProviderConfig
|
|
||||||
metadata:
|
|
||||||
name: default
|
|
||||||
spec:
|
|
||||||
projectID: ${PROJECT_ID}
|
|
||||||
credentials:
|
|
||||||
source: Filesystem
|
|
||||||
fs:
|
|
||||||
path: /vault/secrets/creds.txt" | kubectl apply -f -
|
|
||||||
```
|
|
||||||
|
|
||||||
## Provision Infrastructure
|
|
||||||
|
|
||||||
The final step is to actually provision a `CloudSQLInstance`. Creating the
|
|
||||||
object below will result in the creation of a Cloud SQL Postgres database on
|
|
||||||
GCP.
|
|
||||||
|
|
||||||
```console
|
|
||||||
echo "apiVersion: database.gcp.crossplane.io/v1beta1
|
|
||||||
kind: CloudSQLInstance
|
|
||||||
metadata:
|
|
||||||
name: postgres-vault-demo
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
databaseVersion: POSTGRES_12
|
|
||||||
region: us-central1
|
|
||||||
settings:
|
|
||||||
tier: db-custom-1-3840
|
|
||||||
dataDiskType: PD_SSD
|
|
||||||
dataDiskSizeGb: 10
|
|
||||||
writeConnectionSecretToRef:
|
|
||||||
namespace: crossplane-system
|
|
||||||
name: cloudsqlpostgresql-conn" | kubectl apply -f -
|
|
||||||
```
|
|
||||||
|
|
||||||
You can monitor the progress of the database provisioning with the following
|
|
||||||
command:
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl get cloudsqlinstance -w
|
|
||||||
```
|
|
||||||
|
|
||||||
<!-- named links -->
|
|
||||||
|
|
||||||
[Vault on Minikube]: https://learn.hashicorp.com/tutorials/vault/kubernetes-minikube
|
|
||||||
[Vault Kubernetes Sidecar]: https://learn.hashicorp.com/tutorials/vault/kubernetes-sidecar
|
|
||||||
[Vault]: https://www.vaultproject.io/
|
|
||||||
[Vault Kubernetes Sidecar]: https://www.vaultproject.io/docs/platform/k8s/injector
|
|
||||||
[provider-gcp]: https://marketplace.upbound.io/providers/crossplane-contrib/provider-gcp
|
|
||||||
[AWS]: https://www.vaultproject.io/docs/secrets/aws
|
|
||||||
[Azure]: https://www.vaultproject.io/docs/secrets/azure
|
|
||||||
[GCP]: https://www.vaultproject.io/docs/secrets/gcp
|
|
||||||
[unsealed]: https://www.vaultproject.io/docs/concepts/seal
|
|
||||||
[Kubernetes authentication backend]: https://www.vaultproject.io/docs/auth/kubernetes
|
|
||||||
[kv secrets engine]: https://www.vaultproject.io/docs/secrets/kv/kv-v2
|
|
||||||
[policy]: https://www.vaultproject.io/docs/concepts/policies
|
|
|
@ -1,24 +0,0 @@
|
||||||
---
|
|
||||||
title: Reference
|
|
||||||
weight: 300
|
|
||||||
---
|
|
||||||
The reference documentation includes answers to frequently asked questions,
|
|
||||||
information about similar projects, and links to resources that can help you
|
|
||||||
learn more about Crossplane and Kubernetes. If you have additional information
|
|
||||||
that you think would be valuable for the community, please feel free to [open a
|
|
||||||
pull request] and add it.
|
|
||||||
|
|
||||||
1. [Install]
|
|
||||||
1. [Configure]
|
|
||||||
1. [Uninstall]
|
|
||||||
1. [Troubleshoot]
|
|
||||||
1. [Learn More]
|
|
||||||
|
|
||||||
<!-- Named Links -->
|
|
||||||
|
|
||||||
[open a pull request]: https://github.com/crossplane/crossplane/compare
|
|
||||||
[Install]: {{<ref "install" >}}
|
|
||||||
[Configure]: {{<ref "configure" >}}
|
|
||||||
[Uninstall]: {{<ref "uninstall" >}}
|
|
||||||
[Troubleshoot]: {{<ref "troubleshoot" >}}
|
|
||||||
[Learn More]: {{<ref "learn_more" >}}
|
|
|
@ -1,22 +0,0 @@
|
||||||
---
|
|
||||||
title: Configure Your Cloud Provider Account
|
|
||||||
weight: 302
|
|
||||||
---
|
|
||||||
|
|
||||||
In order for Crossplane to be able to manage resources in a specific cloud
|
|
||||||
provider, you will need to create an account for Crossplane to use. Use the
|
|
||||||
links below for cloud-specific instructions to create an account that can be
|
|
||||||
used throughout the guides:
|
|
||||||
|
|
||||||
* [Google Cloud Platform (GCP) Service Account]
|
|
||||||
* [Microsoft Azure Service Principal]
|
|
||||||
* [Amazon Web Services (AWS) IAM User]
|
|
||||||
|
|
||||||
Once you have configured your cloud provider account, you can get started
|
|
||||||
provisioning resources!
|
|
||||||
|
|
||||||
<!-- Named Links -->
|
|
||||||
|
|
||||||
[Google Cloud Platform (GCP) Service Account]: {{<ref "../cloud-providers/gcp/gcp-provider" >}}
|
|
||||||
[Microsoft Azure Service Principal]: {{<ref "../cloud-providers/azure/azure-provider" >}}
|
|
||||||
[Amazon Web Services (AWS) IAM User]: {{<ref "../cloud-providers/aws/aws-provider" >}}
|
|
|
@ -1,169 +0,0 @@
|
||||||
---
|
|
||||||
title: Install Crossplane
|
|
||||||
weight: 301
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Install Crossplane
|
|
||||||
|
|
||||||
Crossplane can be easily installed into any existing Kubernetes cluster using
|
|
||||||
the regularly published Helm chart. The Helm chart contains all the custom
|
|
||||||
resources and controllers needed to deploy and configure Crossplane.
|
|
||||||
|
|
||||||
## Pre-requisites
|
|
||||||
|
|
||||||
* [Kubernetes cluster], minimum version `v1.16.0+`
|
|
||||||
* [Helm], minimum version `v3.0.0+`.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
Helm charts for Crossplane are currently published to the `stable` and `master`
|
|
||||||
channels.
|
|
||||||
|
|
||||||
### Stable
|
|
||||||
|
|
||||||
The stable channel is the most recent release of Crossplane that is considered
|
|
||||||
ready for the community.
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl create namespace crossplane-system
|
|
||||||
|
|
||||||
helm repo add crossplane-stable https://charts.crossplane.io/stable
|
|
||||||
helm repo update
|
|
||||||
|
|
||||||
helm install crossplane --namespace crossplane-system crossplane-stable/crossplane
|
|
||||||
```
|
|
||||||
|
|
||||||
### Master
|
|
||||||
|
|
||||||
The `master` channel contains the latest commits, with all automated tests
|
|
||||||
passing. `master` is subject to instability, incompatibility, and features may
|
|
||||||
be added or removed without much prior notice. It is recommended to use one of
|
|
||||||
the more stable channels, but if you want the absolute newest Crossplane
|
|
||||||
installed, then you can use the `master` channel.
|
|
||||||
|
|
||||||
To install the Helm chart from master, you will need to pass the specific
|
|
||||||
version returned by the `search` command:
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl create namespace crossplane-system
|
|
||||||
helm repo add crossplane-master https://charts.crossplane.io/master/
|
|
||||||
helm repo update
|
|
||||||
helm search repo crossplane-master --devel
|
|
||||||
|
|
||||||
helm install crossplane --namespace crossplane-system crossplane-master/crossplane --devel --version <version>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Uninstalling the Chart
|
|
||||||
|
|
||||||
To uninstall/delete the `crossplane` deployment:
|
|
||||||
|
|
||||||
```console
|
|
||||||
helm delete crossplane --namespace crossplane-system
|
|
||||||
```
|
|
||||||
|
|
||||||
That command removes all Kubernetes components associated with Crossplane,
|
|
||||||
including all the custom resources and controllers.
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
The following tables lists the configurable parameters of the Crossplane chart
|
|
||||||
and their default values.
|
|
||||||
|
|
||||||
{{< expand "Select to view all configuration options" >}}
|
|
||||||
{{< table "table table-hover table-striped table-sm">}}
|
|
||||||
| Parameter | Description | Default |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `affinity` | Enable affinity for Crossplane pod | `{}` |
|
|
||||||
| `image.repository` | Image | `crossplane/crossplane` |
|
|
||||||
| `image.tag` | Image tag | `master` |
|
|
||||||
| `image.pullPolicy` | Image pull policy used in all containers | `IfNotPresent` |
|
|
||||||
| `imagePullSecrets` | Names of image pull secrets to use | `dockerhub` |
|
|
||||||
| `registryCaBundleConfig.name` | Name of ConfigMap containing additional CA bundle for fetching from package registries | `{}` |
|
|
||||||
| `registryCaBundleConfig.key` | Key to use from ConfigMap containing additional CA bundle for fetching from package registries | `{}` |
|
|
||||||
| `replicas` | The number of replicas to run for the Crossplane pods | `1` |
|
|
||||||
| `deploymentStrategy` | The deployment strategy for the Crossplane and RBAC Manager (if enabled) pods | `RollingUpdate` |
|
|
||||||
| `leaderElection` | Enable leader election for Crossplane Managers pod | `true` |
|
|
||||||
| `nodeSelector` | Enable nodeSelector for Crossplane pod | `{}` |
|
|
||||||
| `customLabels` | Custom labels to add into metadata | `{}` |
|
|
||||||
| `customAnnotations` | Custom annotations to add to the Crossplane deployment and pod | `{}` |
|
|
||||||
| `serviceAccount.customAnnotations` | Custom annotations to add to the serviceaccount of Crossplane | `{}` |
|
|
||||||
| `priorityClassName` | Priority class name for Crossplane and RBAC Manager (if enabled) pods | `""` |
|
|
||||||
| `resourcesCrossplane.limits.cpu` | CPU resource limits for Crossplane | `100m` |
|
|
||||||
| `resourcesCrossplane.limits.memory` | Memory resource limits for Crossplane | `512Mi` |
|
|
||||||
| `resourcesCrossplane.requests.cpu` | CPU resource requests for Crossplane | `100m` |
|
|
||||||
| `resourcesCrossplane.requests.memory` | Memory resource requests for Crossplane | `256Mi` |
|
|
||||||
| `securityContextCrossplane.runAsUser` | Run as user for Crossplane | `65532` |
|
|
||||||
| `securityContextCrossplane.runAsGroup` | Run as group for Crossplane | `65532` |
|
|
||||||
| `securityContextCrossplane.allowPrivilegeEscalation` | Allow privilege escalation for Crossplane | `false` |
|
|
||||||
| `securityContextCrossplane.readOnlyRootFilesystem` | ReadOnly root filesystem for Crossplane | `true` |
|
|
||||||
| `provider.packages` | The list of Provider packages to install together with Crossplane | `[]` |
|
|
||||||
| `configuration.packages` | The list of Configuration packages to install together with Crossplane | `[]` |
|
|
||||||
| `packageCache.medium` | Storage medium for package cache. `Memory` means volume will be backed by tmpfs, which can be useful for development. | `""` |
|
|
||||||
| `packageCache.sizeLimit` | Size limit for package cache. If medium is `Memory` then maximum usage would be the minimum of this value the sum of all memory limits on containers in the Crossplane pod. | `5Mi` |
|
|
||||||
| `packageCache.pvc` | Name of the PersistentVolumeClaim to be used as the package cache. Providing a value will cause the default emptyDir volume to not be mounted. | `""` |
|
|
||||||
| `tolerations` | Enable tolerations for Crossplane pod | `{}` |
|
|
||||||
| `resourcesRBACManager.limits.cpu` | CPU resource limits for RBAC Manager | `100m` |
|
|
||||||
| `resourcesRBACManager.limits.memory` | Memory resource limits for RBAC Manager | `512Mi` |
|
|
||||||
| `resourcesRBACManager.requests.cpu` | CPU resource requests for RBAC Manager | `100m` |
|
|
||||||
| `resourcesRBACManager.requests.memory` | Memory resource requests for RBAC Manager | `256Mi` |
|
|
||||||
| `securityContextRBACManager.runAsUser` | Run as user for RBAC Manager | `65532` |
|
|
||||||
| `securityContextRBACManager.runAsGroup` | Run as group for RBAC Manager | `65532` |
|
|
||||||
| `securityContextRBACManager.allowPrivilegeEscalation` | Allow privilege escalation for RBAC Manager | `false` |
|
|
||||||
| `securityContextRBACManager.readOnlyRootFilesystem` | ReadOnly root filesystem for RBAC Manager | `true` |
|
|
||||||
| `rbacManager.affinity` | Enable affinity for RBAC Managers pod | `{}` |
|
|
||||||
| `rbacManager.deploy` | Deploy RBAC Manager and its required roles | `true` |
|
|
||||||
| `rbacManager.nodeSelector` | Enable nodeSelector for RBAC Managers pod | `{}` |
|
|
||||||
| `rbacManager.replicas` | The number of replicas to run for the RBAC Manager pods | `1` |
|
|
||||||
| `rbacManager.leaderElection` | Enable leader election for RBAC Managers pod | `true` |
|
|
||||||
| `rbacManager.managementPolicy`| The extent to which the RBAC manager will manage permissions. `All` indicates to manage all Crossplane controller and user roles. `Basic` indicates to only manage Crossplane controller roles and the `crossplane-admin`, `crossplane-edit`, and `crossplane-view` user roles. | `All` |
|
|
||||||
| `rbacManager.tolerations` | Enable tolerations for RBAC Managers pod | `{}` |
|
|
||||||
| `rbacManager.skipAggregatedClusterRoles` | Opt out of deploying aggregated ClusterRoles | `false` |
|
|
||||||
| `metrics.enabled` | Expose Crossplane and RBAC Manager metrics endpoint | `false` |
|
|
||||||
| `extraEnvVarsCrossplane` | List of extra environment variables to set in the crossplane deployment. Any `.` in variable names will be replaced with `_` (example: `SAMPLE.KEY=value1` becomes `SAMPLE_KEY=value1`). | `{}` |
|
|
||||||
| `extraEnvVarsRBACManager` | List of extra environment variables to set in the crossplane rbac manager deployment. Any `.` in variable names will be replaced with `_` (example: `SAMPLE.KEY=value1` becomes `SAMPLE_KEY=value1`). | `{}` |
|
|
||||||
| `webhooks.enabled` | Enable webhook functionality for Crossplane as well as packages installed by Crossplane. | `false` |
|
|
||||||
{{< /table >}}
|
|
||||||
{{< /expand >}}
|
|
||||||
### Command Line
|
|
||||||
|
|
||||||
You can pass the settings with helm command line parameters. Specify each
|
|
||||||
parameter using the `--set key=value[,key=value]` argument to `helm install`.
|
|
||||||
For example, the following command will install Crossplane with an image pull
|
|
||||||
policy of `IfNotPresent`.
|
|
||||||
|
|
||||||
```console
|
|
||||||
helm install --namespace crossplane-system crossplane-stable/crossplane --set image.pullPolicy=IfNotPresent
|
|
||||||
```
|
|
||||||
|
|
||||||
### Settings File
|
|
||||||
|
|
||||||
Alternatively, a yaml file that specifies the values for the above parameters
|
|
||||||
(`values.yaml`) can be provided while installing the chart.
|
|
||||||
|
|
||||||
```console
|
|
||||||
helm install crossplane --namespace crossplane-system crossplane-stable/crossplane -f values.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
Here are the sample settings to get you started.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
replicas: 1
|
|
||||||
|
|
||||||
deploymentStrategy: RollingUpdate
|
|
||||||
|
|
||||||
image:
|
|
||||||
repository: crossplane/crossplane
|
|
||||||
tag: alpha
|
|
||||||
pullPolicy: Always
|
|
||||||
|
|
||||||
imagePullSecrets:
|
|
||||||
- dockerhub
|
|
||||||
```
|
|
||||||
|
|
||||||
<!-- Named Links -->
|
|
||||||
|
|
||||||
[Kubernetes cluster]: https://kubernetes.io/docs/setup/
|
|
||||||
[Minikube]: https://kubernetes.io/docs/tasks/tools/install-minikube/
|
|
||||||
[Helm]: https://docs.helm.sh/using_helm/
|
|
|
@ -1,35 +0,0 @@
|
||||||
---
|
|
||||||
title: Learn More
|
|
||||||
weight: 307
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
If you have any questions, please drop us a note on [Crossplane Slack][join-crossplane-slack] or [contact us][contact-us]!
|
|
||||||
|
|
||||||
***Learn more about using Crossplane***
|
|
||||||
- [Latest Design Docs](https://github.com/crossplane/crossplane/tree/master/design)
|
|
||||||
- [Roadmap](https://github.com/crossplane/crossplane/blob/master/ROADMAP.md)
|
|
||||||
- [Crossplane Architecture](https://docs.google.com/document/d/1whncqdUeU2cATGEJhHvzXWC9xdK29Er45NJeoemxebo/edit?usp=sharing)
|
|
||||||
- [GitLab deploys into multiple clouds from kubectl using Crossplane](https://about.gitlab.com/2019/05/20/gitlab-first-deployed-kubernetes-api-to-multiple-clouds/)
|
|
||||||
- [CNCF Talks & Community Presentations](https://www.youtube.com/playlist?list=PL510POnNVaaZJj9OG6PbgsZvgYbhwJRyE)
|
|
||||||
- [Software Engineering Daily - Intro Podcast](https://softwareengineeringdaily.com/2019/01/02/crossplane-multicloud-control-plane-with-bassam-tabbara/)
|
|
||||||
|
|
||||||
***Writing Kubernetes controllers to extend Crossplane***
|
|
||||||
- [Keep the Space Shuttle Flying: Writing Robust Operators](https://www.youtube.com/watch?v=uf97lOApOv8)
|
|
||||||
- [Best practices for building Kubernetes Operators](https://cloud.google.com/blog/products/containers-kubernetes/best-practices-for-building-kubernetes-operators-and-stateful-apps)
|
|
||||||
- [Programming Kubernetes Book](https://www.oreilly.com/library/view/programming-kubernetes/9781492047094/)
|
|
||||||
- [Contributor Guide](https://github.com/crossplane/crossplane/blob/master/CONTRIBUTING.md)
|
|
||||||
|
|
||||||
***Join the growing Crossplane community and get involved!***
|
|
||||||
- Join our [Community Slack](https://slack.crossplane.io/)!
|
|
||||||
- Submit an issue on [GitHub](https://github.com/crossplane/crossplane)
|
|
||||||
- Attend our bi-weekly [Community Meeting](https://github.com/crossplane/crossplane#get-involved)
|
|
||||||
- Join our bi-weekly live stream: [The Binding Status](https://github.com/crossplane/tbs)
|
|
||||||
- Subscribe to our [YouTube Channel](https://www.youtube.com/channel/UC19FgzMBMqBro361HbE46Fw)
|
|
||||||
- Drop us a note on Twitter: [@crossplane_io](https://twitter.com/crossplane_io)
|
|
||||||
- Email us: [info@crossplane.io](mailto:info@crossplane.io)
|
|
||||||
|
|
||||||
<!-- Named links -->
|
|
||||||
|
|
||||||
[join-crossplane-slack]: https://slack.crossplane.io
|
|
||||||
[contact-us]: https://github.com/crossplane/crossplane#contact
|
|
|
@ -1,91 +0,0 @@
|
||||||
---
|
|
||||||
title: Release Cycle
|
|
||||||
weight: 308
|
|
||||||
---
|
|
||||||
|
|
||||||
Starting with the v1.0.0 release, Crossplane is released on an eight week
|
|
||||||
cadence. A cycle is comprised of three general stages:
|
|
||||||
|
|
||||||
- Weeks 1-6: [Active Development]
|
|
||||||
- Week 7: [Feature Freeze]
|
|
||||||
- Week 8: [Code Freeze]
|
|
||||||
|
|
||||||
This results in six releases per year, with the most recent three releases being
|
|
||||||
maintained at any given time. When a new release is cut, the fourth most recent
|
|
||||||
release reaches end of life (EOL). Users can expect any given release to be
|
|
||||||
maintained for six months.
|
|
||||||
|
|
||||||
### Definition of Maintenance
|
|
||||||
|
|
||||||
The Crossplane community defines maintenance in that relevant bug fixes that are
|
|
||||||
merged to the main development branch will be eligible to be back-ported to the
|
|
||||||
release branch of any currently maintained version, and patch releases will be
|
|
||||||
cut appropriately. It is also possible that a fix may be merged directly to the
|
|
||||||
release branch if no longer applicable on the main development branch.
|
|
||||||
Maintenance does not indicate any SLA on response time for user support in the
|
|
||||||
form of Slack messages or issues, but problems will be addressed on a best
|
|
||||||
effort basis by maintainers and contributors for currently maintained releases.
|
|
||||||
|
|
||||||
### Patch Releases
|
|
||||||
|
|
||||||
_This policy is subject to change in the future._
|
|
||||||
|
|
||||||
Patch releases are cut for currently maintained minor versions on an as-needed
|
|
||||||
basis. Any critical back-ported fixes will be included in a patch release as
|
|
||||||
soon as possible after merge.
|
|
||||||
|
|
||||||
### Pre-Releases
|
|
||||||
|
|
||||||
_This policy is subject to change in the future._
|
|
||||||
|
|
||||||
Alpha, Beta, and RC releases are cut for an upcoming release on an as-needed
|
|
||||||
basis. As a policy, at least one pre-release will be cut prior to any minor
|
|
||||||
release. Pre-releases will not be made on release branches.
|
|
||||||
|
|
||||||
### Provider Releases
|
|
||||||
|
|
||||||
The Crossplane release cycle is not required to be adhered to by any other
|
|
||||||
Crossplane projects, but a similar cadence is encouraged. Maintainers listed in
|
|
||||||
each repository's `OWNERS.md` file are responsible for determining and
|
|
||||||
publishing the release cycle for their project.
|
|
||||||
|
|
||||||
## Release Stages
|
|
||||||
|
|
||||||
The following stages are the main milestones in a Crossplane release.
|
|
||||||
|
|
||||||
### Active Development
|
|
||||||
|
|
||||||
During active development, any code that meets the requisite criteria (i.e.
|
|
||||||
passing appropriate tests, approved by a maintainer, etc.) will be merged into
|
|
||||||
the main development branch. At present, there is no requirement to formally
|
|
||||||
submit an enhancement proposal prior to the start of the release cycle, but
|
|
||||||
contributors are encouraged to open an issue and gather feedback before starting
|
|
||||||
work on a major implementation (see [CONTRIBUTING.md] for more information).
|
|
||||||
|
|
||||||
### Feature Freeze
|
|
||||||
|
|
||||||
During feature freeze, no new functionality should be merged into the main
|
|
||||||
development branch. Bug fixes, documentation changes, and non-critical changes
|
|
||||||
may be made. In the case that a new feature is deemed absolutely necessary for a
|
|
||||||
release, the Crossplane maintainers will weigh the impact of the change and make
|
|
||||||
a decision on whether it should be included.
|
|
||||||
|
|
||||||
### Code Freeze
|
|
||||||
|
|
||||||
During code freeze, there should be no changes merged to the main development
|
|
||||||
branch with the following exceptions:
|
|
||||||
- Fixes to a failing test that is deemed to be incorrectly testing
|
|
||||||
functionality.
|
|
||||||
- Documentation only changes. It is possible that a documentation freeze will be
|
|
||||||
implemented in the future, but it is not currently enforced.
|
|
||||||
- Fixes to a critical bug that was not previously identified. Merging a bug fix
|
|
||||||
during code freeze requires application for and approval of an exception by
|
|
||||||
Crossplane maintainers. This process is currently informal, but may be
|
|
||||||
formalized in the future.
|
|
||||||
|
|
||||||
<!-- Named links -->
|
|
||||||
|
|
||||||
[Active Development]: #active-development
|
|
||||||
[Feature Freeze]: #feature-freeze
|
|
||||||
[Code Freeze]: #code-freeze
|
|
||||||
[CONTRIBUTING.md]: https://github.com/crossplane/crossplane/blob/master/CONTRIBUTING.md
|
|
|
@ -1,292 +0,0 @@
|
||||||
---
|
|
||||||
title: Troubleshoot
|
|
||||||
weight: 306
|
|
||||||
---
|
|
||||||
|
|
||||||
* [Requested Resource Not Found]
|
|
||||||
* [Resource Status and Conditions]
|
|
||||||
* [Resource Events]
|
|
||||||
* [Crossplane Logs]
|
|
||||||
* [Provider Logs]
|
|
||||||
* [Pausing Crossplane]
|
|
||||||
* [Pausing Providers]
|
|
||||||
* [Deleting When a Resource Hangs]
|
|
||||||
* [Installing Crossplane Package]
|
|
||||||
* [Handling Crossplane Package Dependency]
|
|
||||||
|
|
||||||
## Requested Resource Not Found
|
|
||||||
|
|
||||||
If you use the kubectl Crossplane plugin to install a `Provider` or
|
|
||||||
`Configuration` (e.g. `kubectl crossplane install provider
|
|
||||||
xpkg.upbound.io/crossplane-contrib/provider-aws:v0.33.0`) and get `the server
|
|
||||||
could not find the requested resource` error, more often than not, that is an
|
|
||||||
indicator that the kubectl Crossplane you're using is outdated. In other words
|
|
||||||
some Crossplane API has been graduated from alpha to beta or stable and the old
|
|
||||||
plugin is not aware of this change.
|
|
||||||
|
|
||||||
You can follow the [install Crossplane CLI] instructions to upgrade the plugin.
|
|
||||||
|
|
||||||
## Resource Status and Conditions
|
|
||||||
|
|
||||||
Most Crossplane resources have a `status` section that can represent the current
|
|
||||||
state of that particular resource. Running `kubectl describe` against a
|
|
||||||
Crossplane resource will frequently give insightful information about its
|
|
||||||
condition. For example, to determine the status of a GCP `CloudSQLInstance`
|
|
||||||
managed resource, run:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl describe cloudsqlinstance my-db
|
|
||||||
```
|
|
||||||
|
|
||||||
This should produce output that includes:
|
|
||||||
|
|
||||||
```console
|
|
||||||
Status:
|
|
||||||
Conditions:
|
|
||||||
Last Transition Time: 2019-09-16T13:46:42Z
|
|
||||||
Reason: Creating
|
|
||||||
Status: False
|
|
||||||
Type: Ready
|
|
||||||
```
|
|
||||||
|
|
||||||
Most Crossplane resources set the `Ready` condition. `Ready` represents the
|
|
||||||
availability of the resource - whether it is creating, deleting, available,
|
|
||||||
unavailable, binding, etc.
|
|
||||||
|
|
||||||
## Resource Events
|
|
||||||
|
|
||||||
Most Crossplane resources emit _events_ when something interesting happens. You
|
|
||||||
can see the events associated with a resource by running `kubectl describe` -
|
|
||||||
e.g. `kubectl describe cloudsqlinstance my-db`. You can also see all events in a
|
|
||||||
particular namespace by running `kubectl get events`.
|
|
||||||
|
|
||||||
```console
|
|
||||||
Events:
|
|
||||||
Type Reason Age From Message
|
|
||||||
---- ------ ---- ---- -------
|
|
||||||
Warning CannotConnectToProvider 16s (x4 over 46s) managed/postgresqlserver.database.azure.crossplane.io cannot get referenced ProviderConfig: ProviderConfig.azure.crossplane.io "default" not found
|
|
||||||
```
|
|
||||||
|
|
||||||
> Note that events are namespaced, while many Crossplane resources (XRs, etc)
|
|
||||||
> are cluster scoped. Crossplane emits events for cluster scoped resources to
|
|
||||||
> the 'default' namespace.
|
|
||||||
|
|
||||||
## Crossplane Logs
|
|
||||||
|
|
||||||
The next place to look to get more information or investigate a failure would be
|
|
||||||
in the Crossplane pod logs, which should be running in the `crossplane-system`
|
|
||||||
namespace. To get the current Crossplane logs, run the following:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl -n crossplane-system logs -lapp=crossplane
|
|
||||||
```
|
|
||||||
|
|
||||||
> Note that Crossplane emits few logs by default - events are typically the best
|
|
||||||
> place to look for information about what Crossplane is doing. You may need to
|
|
||||||
> restart Crossplane with the `--debug` flag if you can't find what you're
|
|
||||||
> looking for.
|
|
||||||
|
|
||||||
## Provider Logs
|
|
||||||
|
|
||||||
Remember that much of Crossplane's functionality is provided by providers. You
|
|
||||||
can use `kubectl logs` to view provider logs too. By convention, they also emit
|
|
||||||
few logs by default.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
kubectl -n crossplane-system logs <name-of-provider-pod>
|
|
||||||
```
|
|
||||||
|
|
||||||
All providers maintained by the Crossplane community mirror Crossplane's support
|
|
||||||
of the `--debug` flag. The easiest way to set flags on a provider is to create a
|
|
||||||
`ControllerConfig` and reference it from the `Provider`:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: pkg.crossplane.io/v1alpha1
|
|
||||||
kind: ControllerConfig
|
|
||||||
metadata:
|
|
||||||
name: debug-config
|
|
||||||
spec:
|
|
||||||
args:
|
|
||||||
- --debug
|
|
||||||
---
|
|
||||||
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: debug-config
|
|
||||||
```
|
|
||||||
|
|
||||||
> Note that a reference to a `ControllerConfig` can be added to an already
|
|
||||||
> installed `Provider` and it will update its `Deployment` accordingly.
|
|
||||||
|
|
||||||
## Pausing Crossplane
|
|
||||||
|
|
||||||
Sometimes, for example when you encounter a bug, it can be useful to pause
|
|
||||||
Crossplane if you want to stop it from actively attempting to manage your
|
|
||||||
resources. To pause Crossplane without deleting all of its resources, run the
|
|
||||||
following command to simply scale down its deployment:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl -n crossplane-system scale --replicas=0 deployment/crossplane
|
|
||||||
```
|
|
||||||
|
|
||||||
Once you have been able to rectify the problem or smooth things out, you can
|
|
||||||
unpause Crossplane simply by scaling its deployment back up:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
kubectl -n crossplane-system scale --replicas=1 deployment/crossplane
|
|
||||||
```
|
|
||||||
|
|
||||||
## Pausing Providers
|
|
||||||
|
|
||||||
Providers can also be paused when troubleshooting an issue or orchestrating a
|
|
||||||
complex migration of resources. Creating and referencing a `ControllerConfig` is
|
|
||||||
the easiest way to scale down a provider, and the `ControllerConfig` can be
|
|
||||||
modified or the reference can be removed to scale it back up:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: pkg.crossplane.io/v1alpha1
|
|
||||||
kind: ControllerConfig
|
|
||||||
metadata:
|
|
||||||
name: scale-config
|
|
||||||
spec:
|
|
||||||
replicas: 0
|
|
||||||
---
|
|
||||||
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: scale-config
|
|
||||||
```
|
|
||||||
|
|
||||||
> Note that a reference to a `ControllerConfig` can be added to an already
|
|
||||||
> installed `Provider` and it will update its `Deployment` accordingly.
|
|
||||||
|
|
||||||
## Deleting When a Resource Hangs
|
|
||||||
|
|
||||||
The resources that Crossplane manages will automatically be cleaned up so as not
|
|
||||||
to leave anything running behind. This is accomplished by using finalizers, but
|
|
||||||
in certain scenarios the finalizer can prevent the Kubernetes object from
|
|
||||||
getting deleted.
|
|
||||||
|
|
||||||
To deal with this, we essentially want to patch the object to remove its
|
|
||||||
finalizer, which will then allow it to be deleted completely. Note that this
|
|
||||||
won't necessarily delete the external resource that Crossplane was managing, so
|
|
||||||
you will want to go to your cloud provider's console and look there for any
|
|
||||||
lingering resources to clean up.
|
|
||||||
|
|
||||||
In general, a finalizer can be removed from an object with this command:
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl patch <resource-type> <resource-name> -p '{"metadata":{"finalizers": []}}' --type=merge
|
|
||||||
```
|
|
||||||
|
|
||||||
For example, for a `CloudSQLInstance` managed resource (`database.gcp.crossplane.io`) named
|
|
||||||
`my-db`, you can remove its finalizer with:
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl patch cloudsqlinstance my-db -p '{"metadata":{"finalizers": []}}' --type=merge
|
|
||||||
```
|
|
||||||
|
|
||||||
## Installing Crossplane Package
|
|
||||||
|
|
||||||
After installing [Crossplane package], to verify the install results or
|
|
||||||
troubleshoot any issue spotted during the installation, there are a few things
|
|
||||||
you can do.
|
|
||||||
|
|
||||||
Run below command to list all Crossplane resources available on your cluster:
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl get crossplane
|
|
||||||
```
|
|
||||||
|
|
||||||
If you installed a Provider package, pay attention to the `Provider` and
|
|
||||||
`ProviderRevision` resource. Especially the `INSTALLED` and `HEALTHY` column.
|
|
||||||
They all need to be `TRUE`. Otherwise, there must be some errors that occurred
|
|
||||||
during the installation.
|
|
||||||
|
|
||||||
If you installed a Configuration package, pay attention to the `Configuration`
|
|
||||||
and `ConfigurationRevision` resource. Again, the `INSTALLED` and `HEALTHY`
|
|
||||||
column for these resources need to be `TRUE`. Besides that, you should also see
|
|
||||||
the `CompositeResourceDefinition` and `Composition` resources included in this
|
|
||||||
package are listed if the package is installed successfully.
|
|
||||||
|
|
||||||
If you only care about the installed packages, you can also run below command
|
|
||||||
which will show you all installed Configuration and Provider packages:
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl get pkg
|
|
||||||
```
|
|
||||||
|
|
||||||
When there are errors, you can run below command to check detailed information
|
|
||||||
for the packages that are getting installed.
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl get lock -o yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
To inspect a particular package for troubleshooting, you can run
|
|
||||||
`kubectl describe` against the corresponding resources, e.g. the `Provider` and
|
|
||||||
`ProviderRevision` resource for Provider package, or the `Configuration` and
|
|
||||||
`ConfigurationRevision` resource for Configuration package. Usually, you should
|
|
||||||
be able to know the error reason by checking the `Status` and `Events` field for
|
|
||||||
these resources.
|
|
||||||
|
|
||||||
## Handling Crossplane Package Dependency
|
|
||||||
|
|
||||||
When using `crossplane.yaml` to define a Crossplane Configuration package, you
|
|
||||||
can specify packages that it depends on by including `spec.dependsOn`. You can
|
|
||||||
also specify version constraints for dependency packages.
|
|
||||||
|
|
||||||
When you define a dependency package, please make sure you provide the fully
|
|
||||||
qualified address to the dependency package, but do not append the package
|
|
||||||
version (i.e. the OCI image tag) after the package name. This may lead to the
|
|
||||||
missing dependency error when Crossplane tries to install the dependency.
|
|
||||||
|
|
||||||
When specifying the version constraint, you should strictly follow the
|
|
||||||
[semver spec]. Otherwise, it may not be able to find the appropriate version for
|
|
||||||
the dependency package even it says the dependency is found. This may lead to an
|
|
||||||
incompatible dependency error during the installation.
|
|
||||||
|
|
||||||
Below is an example where a Configuration package depends on a provider pulled
|
|
||||||
from `xpkg.upbound.io/crossplane-contrib/provider-aws`. It defines `">=v0.18.2`
|
|
||||||
as the version constraint which means all versions after `v0.16.0` including all
|
|
||||||
prerelease versions, in the form of `-xyz` after the normal version string, will
|
|
||||||
be considered when Crossplane tries to find the best match.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
apiVersion: meta.pkg.crossplane.io/v1
|
|
||||||
kind: Configuration
|
|
||||||
metadata:
|
|
||||||
name: test-configuration
|
|
||||||
annotations:
|
|
||||||
provider: aws
|
|
||||||
spec:
|
|
||||||
crossplane:
|
|
||||||
version: ">=v1.4.0-0"
|
|
||||||
dependsOn:
|
|
||||||
- provider: xpkg.upbound.io/crossplane-contrib/provider-aws
|
|
||||||
version: ">=v0.18.2"
|
|
||||||
```
|
|
||||||
|
|
||||||
<!-- Named Links -->
|
|
||||||
|
|
||||||
[Requested Resource Not Found]: #requested-resource-not-found
|
|
||||||
[install Crossplane CLI]: {{<ref "../getting-started/install-configure" >}}#install-crossplane-cli
|
|
||||||
[Resource Status and Conditions]: #resource-status-and-conditions
|
|
||||||
[Resource Events]: #resource-events
|
|
||||||
[Crossplane Logs]: #crossplane-logs
|
|
||||||
[Provider Logs]: #provider-logs
|
|
||||||
[Pausing Crossplane]: #pausing-crossplane
|
|
||||||
[Pausing Providers]: #pausing-providers
|
|
||||||
[Deleting When a Resource Hangs]: #deleting-when-a-resource-hangs
|
|
||||||
[Installing Crossplane Package]: #installing-crossplane-package
|
|
||||||
[Crossplane package]: {{<ref "../concepts/packages" >}}
|
|
||||||
[Handling Crossplane Package Dependency]: #handling-crossplane-package-dependency
|
|
||||||
[semver spec]: https://github.com/Masterminds/semver#basic-comparisons
|
|
|
@ -1,87 +0,0 @@
|
||||||
---
|
|
||||||
title: Uninstall
|
|
||||||
weight: 303
|
|
||||||
---
|
|
||||||
|
|
||||||
Crossplane has a number of components that must be cleaned up in order to
|
|
||||||
guarantee proper removal from the cluster. When deleting objects, it is best to
|
|
||||||
consider parent-child relationships and clean up the children first to ensure
|
|
||||||
the proper action is taken externally. For instance, cleaning up `provider-aws`
|
|
||||||
before deleting an `RDSInstance` will result in the RDS instance remaining
|
|
||||||
provisioned on AWS as the controller responsible for cleaning it up will have
|
|
||||||
already been deleted. It will also result in the `RDSInstance` CRD remaining in
|
|
||||||
the cluster, which could make it difficult to re-install the same provider at a
|
|
||||||
future time.
|
|
||||||
|
|
||||||
## Deleting Resources
|
|
||||||
|
|
||||||
If you wish for all claims (XRC), composite resources (XR), and managed
|
|
||||||
resources to have deletion handled properly both in the cluster in externally,
|
|
||||||
they should be deleted and no longer exist in cluster before the package that
|
|
||||||
extended the Kubernetes API to include them is uninstalled. You can use the
|
|
||||||
following logic to clean up resources effectively:
|
|
||||||
|
|
||||||
- If an XRC exists for a given XR and set of managed resources, delete the XRC
|
|
||||||
and both the XR and managed resources will be cleaned up.
|
|
||||||
- If only an XR exists for a given set of managed resources, delete the XR and
|
|
||||||
each of the managed resources will be cleaned up.
|
|
||||||
- If a managed resource was provisioned directly, delete it directly.
|
|
||||||
|
|
||||||
The following commands can be used to identify existing XRC, XR, and managed
|
|
||||||
resources:
|
|
||||||
|
|
||||||
- XRC: `kubectl get claim`
|
|
||||||
- XR: `kubectl get composite`
|
|
||||||
- Managed Resources: `kubectl get managed`
|
|
||||||
|
|
||||||
Crossplane controllers add [finalizers] to resources to ensure they are handled
|
|
||||||
externally before they are fully removed from the cluster. If resource deletion
|
|
||||||
hangs it is likely due to a delay in the resource being handled externally,
|
|
||||||
causing the controller to wait to remove the finalizer. If this persists for a
|
|
||||||
long period of time, use the [troubleshooting guide] to fix the issue.
|
|
||||||
|
|
||||||
## Uninstall Packages
|
|
||||||
|
|
||||||
Once all resources are cleaned up, it is safe to uninstall packages.
|
|
||||||
`Configuration` packages can typically be deleted safely with the following
|
|
||||||
command:
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl delete configuration.pkg <configuration-name>
|
|
||||||
```
|
|
||||||
|
|
||||||
Before deleting `Provider` packages, you will want to make sure you have deleted
|
|
||||||
all `ProviderConfig`s you created. An example command if you used AWS Provider:
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl delete providerconfig.aws --all
|
|
||||||
```
|
|
||||||
|
|
||||||
Now you are safe to delete the `Provider` package:
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl delete provider.pkg <provider-name>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Uninstall Crossplane
|
|
||||||
|
|
||||||
When all resources and packages have been cleaned up, you are safe to uninstall
|
|
||||||
Crossplane:
|
|
||||||
|
|
||||||
```console
|
|
||||||
helm delete crossplane --namespace crossplane-system
|
|
||||||
|
|
||||||
kubectl delete namespace crossplane-system
|
|
||||||
```
|
|
||||||
|
|
||||||
Helm does not delete CRD objects. You can delete the ones Crossplane created
|
|
||||||
with the following commands:
|
|
||||||
|
|
||||||
```console
|
|
||||||
kubectl get crd -o name | grep crossplane.io | xargs kubectl delete
|
|
||||||
```
|
|
||||||
|
|
||||||
<!-- Named Links -->
|
|
||||||
|
|
||||||
[finalizers]: https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#finalizers
|
|
||||||
[troubleshooting guide]: {{<ref "troubleshoot" >}}
|
|
|
@ -1,211 +0,0 @@
|
||||||
---
|
|
||||||
title: xpkg Specification
|
|
||||||
weight: 305
|
|
||||||
---
|
|
||||||
|
|
||||||
Crossplane supports two types of [packages]: Providers and Configurations. These
|
|
||||||
packages are distributed as generic [OCI images], which contain [YAML] content
|
|
||||||
informing the Crossplane package manager how to alter the state of a cluster by
|
|
||||||
installing objects that configure new resource types, and starting controllers
|
|
||||||
to reconcile them. An OCI image that contains valid Crossplane package content
|
|
||||||
is commonly referred to as an `xpkg` ("ex-package"). This document provides the
|
|
||||||
specification for a valid `xpkg`, which can be considered a superset of the
|
|
||||||
requirements detailed in the [OCI image specification]. It is divided into two
|
|
||||||
broad sections: requirements related to OCI image format and requirements
|
|
||||||
related to Crossplane `package.yaml` contents.
|
|
||||||
|
|
||||||
- [OCI Image Format](#oci-image-format)
|
|
||||||
- [Indexes](#indexes)
|
|
||||||
- [Manifests](#manifests)
|
|
||||||
- [Configuration](#configuration)
|
|
||||||
- [Layers](#layers)
|
|
||||||
- [package.yaml Contents](#packageyaml-contents)
|
|
||||||
- [Configuration Package Requirements](#configuration-package-requirements)
|
|
||||||
- [Provider Package Requirements](#provider-package-requirements)
|
|
||||||
- [Object Annotations](#object-annotations)
|
|
||||||
|
|
||||||
## OCI Image Format
|
|
||||||
|
|
||||||
OCI images are comprised of [manifests], [configuration], and [layers].
|
|
||||||
Additionally, an image reference could refer to an image [index], which may
|
|
||||||
reference multiple image manifests and is frequently used for multi-platform
|
|
||||||
images. A valid Crossplane `xpkg` imposes various requirements on the components
|
|
||||||
of an OCI, each of which are described in the following sections.
|
|
||||||
|
|
||||||
### Indexes
|
|
||||||
|
|
||||||
The components of an `xpkg` that Crossplane interacts with do not contain any
|
|
||||||
platform-specific information, so Crossplane is broadly agnostic to the
|
|
||||||
formatting of an image index. Crossplane does impose the following requirements
|
|
||||||
on an image index:
|
|
||||||
|
|
||||||
- At least one (1) manifest MUST be referenced in the manifest descriptor array
|
|
||||||
for a package to be successfully fetched and processed.
|
|
||||||
|
|
||||||
> The OCI image specification allows for zero-length manifest descriptor arrays
|
|
||||||
> in an index.
|
|
||||||
|
|
||||||
The following default behavior when interacting with image indexes is
|
|
||||||
implemented in the Crossplane package manager:
|
|
||||||
|
|
||||||
- If one manifest is referenced in the image index, the image it points to will
|
|
||||||
be used.
|
|
||||||
- If multiple manifests are referenced in the image index, Crossplane will use
|
|
||||||
the `linux/amd64` variant by default.
|
|
||||||
|
|
||||||
> It is important to note that the platform of the package image that is used by
|
|
||||||
> Crossplane does not necessarily mean that the same platform will be used for
|
|
||||||
> the controller if the package is a Provider. The decision of selecting a
|
|
||||||
> platform for a Provider controller image is deferred to the configured
|
|
||||||
> container runtime.
|
|
||||||
|
|
||||||
### Manifests
|
|
||||||
|
|
||||||
A manifest defines the layers and configuration of a specific image. Crossplane
|
|
||||||
is only concerned with the layer descriptors array in an image manifest and does
|
|
||||||
not impose additional requirements on any other portions of the manifest. The
|
|
||||||
following requirements are imposed on the layer descriptors array:
|
|
||||||
|
|
||||||
- One (1) layer descriptor in the array MAY have an [annotation] with key
|
|
||||||
`io.crossplane.xpkg` and value `base`.
|
|
||||||
- Any number of layer descriptors in the array MAY have an annotation with key
|
|
||||||
`io.crossplane.xpkg` and arbitrary value. Whether multiple layer descriptors
|
|
||||||
may have the same value is left to the specification of the consumer of those
|
|
||||||
layers.
|
|
||||||
|
|
||||||
> As evidenced by the fact that annotations are provided as a map of
|
|
||||||
> _string-string_, no single descriptor will contain multiple
|
|
||||||
> `io.crossplane.xpkg` annotations.
|
|
||||||
|
|
||||||
Crossplane is only concerned with the layer with the `base` annotation, and any
|
|
||||||
other layers with the `io.crossplane.xpkg` key are used to signify to
|
|
||||||
third-party consumers that a layer contains content related to the `xpkg` that
|
|
||||||
may be specific to a given consumer.
|
|
||||||
|
|
||||||
If no layer descriptors have an annotation in the form `io.crossplane.xpkg:
|
|
||||||
base`, the resultant filesystem from [applying changesets] from all layers will
|
|
||||||
be used. It is preferred to use layer descriptor annotations.
|
|
||||||
|
|
||||||
**Motivation**
|
|
||||||
|
|
||||||
Crossplane prefers the usage of annotated layer descriptors because it allows
|
|
||||||
for fetching and processing individual layers, rather than all layers in the
|
|
||||||
image. In the event that the image contains a single layer, this overhead is
|
|
||||||
minimal. However, larger images with many layers, whether they contain
|
|
||||||
third-party `xpkg` content or unrelated data, will result in multiple network
|
|
||||||
calls and more data to process.
|
|
||||||
|
|
||||||
Crossplane also prefers the usage of annotated layer descriptors to define
|
|
||||||
additive package content (i.e. third-party `xpkg` content) as it provides a
|
|
||||||
clean mechanism to build an `xpkg` through a series of stages. A valid `xpkg`
|
|
||||||
can be produced and later modified while verifying that the integrity of the
|
|
||||||
existing content is not violated, which ensures that Crossplane's package
|
|
||||||
manager will process the resulting `xpkg` in the same manner as the it would
|
|
||||||
prior to modification.
|
|
||||||
|
|
||||||
While not explicitly forbidden, modifying content from a preceding layer with
|
|
||||||
the `io.crossplane.xpkg` annotation in any subsequent layers is discouraged, as
|
|
||||||
it may lead to confusion if a third-party is consuming content from the
|
|
||||||
flattened filesystem.
|
|
||||||
|
|
||||||
### Configuration
|
|
||||||
|
|
||||||
Crossplane imposes no additional requirements on image configuration and does
|
|
||||||
not consider its contents when processing a package.
|
|
||||||
|
|
||||||
### Layers
|
|
||||||
|
|
||||||
As described above, Crossplane is only concerned with the single layer
|
|
||||||
referenced by the descriptor containing `io.crossplane.xpkg: base` if
|
|
||||||
distinguished. Crossplane imposes no additional restrictions on any other
|
|
||||||
layers, including those with a `io.crossplane.xpkg` annotation but a value other
|
|
||||||
than `base`, but does require the following of the `xpkg` base layer:
|
|
||||||
|
|
||||||
- A single file with name `package.yaml` MUST exist in the root directory of the
|
|
||||||
`xpkg` base layer if distinguished, or in the root of the image filesystem
|
|
||||||
after all layer changesets are applied.
|
|
||||||
- The `package.yaml` file MUST contain a valid [YAML stream].
|
|
||||||
- All other content in either the `xpkg` base layer, or the full image
|
|
||||||
filesystem is ignored by Crossplane.
|
|
||||||
|
|
||||||
> The ability to use the image's flattened filesystem is primarily for backwards
|
|
||||||
> compatibility and is not encouraged, especially in the event that an image
|
|
||||||
> contains more than just `xpkg` related content, due to the fact that
|
|
||||||
> accidentally overwriting or modifying the `xpkg` layer contents in subsequent
|
|
||||||
> layers when constructing an image could cause the package to be invalid.
|
|
||||||
|
|
||||||
## package.yaml Contents
|
|
||||||
|
|
||||||
Depending on the type of package, the YAML stream in the `xpkg` base layer
|
|
||||||
`package.yaml` may contain different content. Additionally, the objects in the
|
|
||||||
YAML stream may contain common annotations that are suitable for the given
|
|
||||||
object type.
|
|
||||||
|
|
||||||
### Configuration Package Requirements
|
|
||||||
|
|
||||||
The `package.yaml` for Configuration packages must adhere to the following
|
|
||||||
requirements:
|
|
||||||
|
|
||||||
- One (1) and only one `Configuration.meta.pkg.crossplane.io` object MUST be
|
|
||||||
defined in the YAML stream.
|
|
||||||
- Zero (0) or more `CompositeResourceDefinition.apiextensions.crossplane.io`
|
|
||||||
objects MAY be defined in the YAML stream.
|
|
||||||
- Zero (0) or more `Composition.apiextensions.crossplane.io` objects MAY be
|
|
||||||
defined in the YAML stream.
|
|
||||||
- Zero (0) other object types may be defined in the YAML stream.
|
|
||||||
|
|
||||||
### Provider Package Requirements
|
|
||||||
|
|
||||||
The `package.yaml` for Provider packages must adhere to the following
|
|
||||||
requirements:
|
|
||||||
|
|
||||||
- One (1) and only one `Provider.meta.pkg.crossplane.io` object MUST be defined
|
|
||||||
in the YAML stream.
|
|
||||||
- Zero (0) or more `CustomResourceDefinition.apiextensions.k8s.io` objects MAY
|
|
||||||
be defined in the YAML stream.
|
|
||||||
- Zero (0) or more `AdmissionWebhookConfiguration.admissionregistration.k8s.io`
|
|
||||||
objects MAY be defined in the YAML stream.
|
|
||||||
- Zero (0) or more `MutatingWebhookConfiguration.admissionregistration.k8s.io`
|
|
||||||
objects MAY be defined in the YAML stream.
|
|
||||||
- Zero (0) other object types may be defined in the YAML stream.
|
|
||||||
|
|
||||||
### Object Annotations
|
|
||||||
|
|
||||||
Though not used directly by Crossplane, the following object metadata
|
|
||||||
annotations (not to be confused with descriptor annotations in an OCI image
|
|
||||||
manifest) are defined for `Configuration.meta.pkg.crossplane.io` and
|
|
||||||
`Provider.meta.pkg.crossplane.io` and should be honored over any competing
|
|
||||||
annotations by third-party consumers of Crossplane packages:
|
|
||||||
|
|
||||||
- `meta.crossplane.io/maintainer`: The package's maintainers, as a short opaque
|
|
||||||
text string.
|
|
||||||
- `meta.crossplane.io/source`: The URL at which the package's source can be
|
|
||||||
found.
|
|
||||||
- `meta.crossplane.io/license`: The license under which the package's source is
|
|
||||||
released. This should be a valid [SPDX License Identifier].
|
|
||||||
- `meta.crossplane.io/description`: A one sentence description of the package.
|
|
||||||
- `meta.crossplane.io/readme`: A longer description, documentation, etc.
|
|
||||||
|
|
||||||
Third party consumers may define additional arbitrary annotations with any key
|
|
||||||
and value on any object in a package. All annotations on "meta" types (i.e.
|
|
||||||
`Configuration.meta.pkg.crossplane.io` and `Provider.meta.pkg.crossplane.io`)
|
|
||||||
are propagated to the respective package revision (i.e.
|
|
||||||
`ConfigurationRevision.pkg.crossplane.io` and
|
|
||||||
`ProviderRevision.pkg.crossplane.io`) on package install. Annotations on all
|
|
||||||
other objects in a package are propagated to their in-cluster representation
|
|
||||||
unmodified.
|
|
||||||
|
|
||||||
<!-- Named Links -->
|
|
||||||
|
|
||||||
[packages]: {{<ref "../concepts/packages" >}}
|
|
||||||
[OCI images]: https://github.com/opencontainers/image-spec
|
|
||||||
[OCI image specification]: https://github.com/opencontainers/image-spec/blob/main/spec.md
|
|
||||||
[YAML]: https://yaml.org/spec/1.2.2/
|
|
||||||
[YAML stream]: https://yaml.org/spec/1.2.2/#92-streams
|
|
||||||
[manifests]: https://github.com/opencontainers/image-spec/blob/main/manifest.md
|
|
||||||
[configuration]: https://github.com/opencontainers/image-spec/blob/main/config.md
|
|
||||||
[layers]: https://github.com/opencontainers/image-spec/blob/main/layer.md
|
|
||||||
[index]: https://github.com/opencontainers/image-spec/blob/main/image-index.md
|
|
||||||
[annotation]: https://github.com/opencontainers/image-spec/blob/main/annotations.md
|
|
||||||
[applying changesets]: https://github.com/opencontainers/image-spec/blob/main/layer.md#applying-changesets
|
|
||||||
[SPDX License Identifier]: https://spdx.org/licenses/
|
|
|
@ -1,13 +0,0 @@
|
||||||
apiVersion: database.example.org/v1alpha1
|
|
||||||
kind: PostgreSQLInstance
|
|
||||||
metadata:
|
|
||||||
name: my-db
|
|
||||||
namespace: default
|
|
||||||
spec:
|
|
||||||
parameters:
|
|
||||||
storageGB: 20
|
|
||||||
compositionSelector:
|
|
||||||
matchLabels:
|
|
||||||
provider: aws
|
|
||||||
writeConnectionSecretToRef:
|
|
||||||
name: db-conn
|
|
|
@ -1,13 +0,0 @@
|
||||||
apiVersion: database.example.org/v1alpha1
|
|
||||||
kind: PostgreSQLInstance
|
|
||||||
metadata:
|
|
||||||
name: my-db
|
|
||||||
namespace: default
|
|
||||||
spec:
|
|
||||||
parameters:
|
|
||||||
storageGB: 20
|
|
||||||
compositionSelector:
|
|
||||||
matchLabels:
|
|
||||||
provider: azure
|
|
||||||
writeConnectionSecretToRef:
|
|
||||||
name: db-conn
|
|
|
@ -1,13 +0,0 @@
|
||||||
apiVersion: database.example.org/v1alpha1
|
|
||||||
kind: PostgreSQLInstance
|
|
||||||
metadata:
|
|
||||||
name: my-db
|
|
||||||
namespace: default
|
|
||||||
spec:
|
|
||||||
parameters:
|
|
||||||
storageGB: 20
|
|
||||||
compositionSelector:
|
|
||||||
matchLabels:
|
|
||||||
provider: gcp
|
|
||||||
writeConnectionSecretToRef:
|
|
||||||
name: db-conn
|
|
|
@ -1,34 +0,0 @@
|
||||||
apiVersion: v1
|
|
||||||
kind: Pod
|
|
||||||
metadata:
|
|
||||||
name: see-db
|
|
||||||
namespace: default
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: see-db
|
|
||||||
image: postgres:12
|
|
||||||
command: ['psql']
|
|
||||||
args: ['-c', 'SELECT current_database();']
|
|
||||||
env:
|
|
||||||
- name: PGDATABASE
|
|
||||||
value: postgres
|
|
||||||
- name: PGHOST
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: db-conn
|
|
||||||
key: endpoint
|
|
||||||
- name: PGUSER
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: db-conn
|
|
||||||
key: username
|
|
||||||
- name: PGPASSWORD
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: db-conn
|
|
||||||
key: password
|
|
||||||
- name: PGPORT
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: db-conn
|
|
||||||
key: port
|
|
|
@ -1,12 +0,0 @@
|
||||||
---
|
|
||||||
apiVersion: aws.crossplane.io/v1beta1
|
|
||||||
kind: ProviderConfig
|
|
||||||
metadata:
|
|
||||||
name: default
|
|
||||||
spec:
|
|
||||||
credentials:
|
|
||||||
source: Secret
|
|
||||||
secretRef:
|
|
||||||
namespace: crossplane-system
|
|
||||||
name: aws-creds
|
|
||||||
key: creds
|
|
|
@ -1,53 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
#
|
|
||||||
# This is a helper script that uses ~/.aws/credentials and ~/.aws/config
|
|
||||||
# to build an aws provider object
|
|
||||||
#
|
|
||||||
# aws configuration (credentials and default region) is required for this
|
|
||||||
# script
|
|
||||||
|
|
||||||
set -e -o pipefail
|
|
||||||
|
|
||||||
# change to script directory
|
|
||||||
cd "$( cd "$( dirname "${BASH_SOURCE[0]}")" && pwd )"
|
|
||||||
|
|
||||||
aws_profile=
|
|
||||||
|
|
||||||
while (( "$#" )); do
|
|
||||||
if test -z "$2"; then
|
|
||||||
echo "invalid value for $1 option"
|
|
||||||
exit -1
|
|
||||||
fi
|
|
||||||
case "$1" in
|
|
||||||
-p|--profile)
|
|
||||||
aws_profile=$2
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# make sure kubectl is configured
|
|
||||||
kubectl cluster-info > /dev/null || echo "KUBECONFIG is not configured properly"
|
|
||||||
|
|
||||||
# if aws_profile is not provided, use default
|
|
||||||
aws_profile="${aws_profile:-default}"
|
|
||||||
|
|
||||||
# retrieve aws profile credentials, save it under 'default' profile, and base64 encode it
|
|
||||||
AWS_CREDS_BASE64=$(echo -e "[default]\naws_access_key_id = $(aws configure get aws_access_key_id --profile $aws_profile)\naws_secret_access_key = $(aws configure get aws_secret_access_key --profile $aws_profile)" | base64 | tr -d "\n")
|
|
||||||
|
|
||||||
if test -z "$AWS_CREDS_BASE64"; then
|
|
||||||
echo "error reading credentials from aws config"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "apiVersion: v1
|
|
||||||
data:
|
|
||||||
creds: $AWS_CREDS_BASE64
|
|
||||||
kind: Secret
|
|
||||||
metadata:
|
|
||||||
name: aws-creds
|
|
||||||
namespace: crossplane-system
|
|
||||||
type: Opaque" | kubectl apply -f -
|
|
|
@ -1,12 +0,0 @@
|
||||||
---
|
|
||||||
apiVersion: azure.crossplane.io/v1beta1
|
|
||||||
kind: ProviderConfig
|
|
||||||
metadata:
|
|
||||||
name: default
|
|
||||||
spec:
|
|
||||||
credentials:
|
|
||||||
source: Secret
|
|
||||||
secretRef:
|
|
||||||
namespace: crossplane-system
|
|
||||||
name: azure-creds
|
|
||||||
key: creds
|
|
|
@ -1,84 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
#
|
|
||||||
# This is a helper script to create a project, service account, and credentials.json
|
|
||||||
# file for use in Crossplane GCP examples
|
|
||||||
#
|
|
||||||
# gcloud is required for use and must be configured with privileges to perform these tasks
|
|
||||||
#
|
|
||||||
set -e -o pipefail
|
|
||||||
ROLES=(roles/iam.serviceAccountUser roles/cloudsql.admin roles/container.admin roles/redis.admin roles/compute.networkAdmin roles/storage.admin)
|
|
||||||
SERVICES=(container.googleapis.com sqladmin.googleapis.com redis.googleapis.com compute.googleapis.com servicenetworking.googleapis.com)
|
|
||||||
KEYFILE=crossplane-gcp-provider-key.json
|
|
||||||
RAND=$RANDOM
|
|
||||||
|
|
||||||
if ! command -v gcloud > /dev/null; then
|
|
||||||
echo "Please install gcloud: https://cloud.google.com/sdk/install"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
tab () { sed 's/^/ /' ; }
|
|
||||||
# list your organizations (if applicable), take note of the specific organization ID you want to use
|
|
||||||
# if you have more than one organization (not common)
|
|
||||||
gcloud organizations list --format '[box]' 2>&1 | tab
|
|
||||||
|
|
||||||
ORGANIZATION_ID=$(gcloud organizations list --format 'value(ID)' --limit 1)
|
|
||||||
read -e -p "Choose an Organization ID [$ORGANIZATION_ID]: " PROMPT_ORGANIZATION_ID
|
|
||||||
ORGANIZATION_ID=${PROMPT_ORGANIZATION_ID:-$ORGANIZATION_ID}
|
|
||||||
|
|
||||||
gcloud projects list --format '[box]' 2>&1 | tab
|
|
||||||
|
|
||||||
# create a new id
|
|
||||||
EXAMPLE_PROJECT_ID="crossplane-example-$RAND"
|
|
||||||
read -e -p "Choose or create a Project ID [$EXAMPLE_PROJECT_ID]: " PROMPT_EXAMPLE_PROJECT_ID
|
|
||||||
EXAMPLE_PROJECT_ID=${PROMPT_EXAMPLE_PROJECT_ID:-$EXAMPLE_PROJECT_ID}
|
|
||||||
|
|
||||||
EXAMPLE_PROJECT_ID_FOUND=$(gcloud projects list --filter PROJECT_ID="$EXAMPLE_PROJECT_ID" --format="value(PROJECT_ID)")
|
|
||||||
|
|
||||||
if [[ -z $EXAMPLE_PROJECT_ID_FOUND ]]; then
|
|
||||||
ACCOUNT_ID=$(gcloud beta billing accounts list --format 'value(ACCOUNT_ID)' --limit 1)
|
|
||||||
gcloud beta billing accounts list --format '[box]' 2>&1 | tab
|
|
||||||
read -e -p "Choose a Billing Account ID [$ACCOUNT_ID]: " PROMPT_ACCOUNT_ID
|
|
||||||
ACCOUNT_ID=${PROMPT_ACCOUNT_ID:-$ACCOUNT_ID}
|
|
||||||
|
|
||||||
echo -e "\n* Creating Project $EXAMPLE_PROJECT_ID ... "
|
|
||||||
gcloud projects create $EXAMPLE_PROJECT_ID --enable-cloud-apis --organization $ORGANIZATION_ID 2>&1 | tab
|
|
||||||
|
|
||||||
echo "* Linking Billing Account $ACCOUNT_ID with Project $EXAMPLE_PROJECT_ID ... "
|
|
||||||
gcloud beta billing projects link $EXAMPLE_PROJECT_ID --billing-account=$ACCOUNT_ID 2>&1 | tab
|
|
||||||
else
|
|
||||||
echo -n "\n* Using Project $EXAMPLE_PROJECT_NAME ... $EXAMPLE_PROJECT_ID"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# enable Kubernetes API
|
|
||||||
for service in "${SERVICES[@]}"; do
|
|
||||||
# enable Google API
|
|
||||||
echo "* Enabling Service $service on $EXAMPLE_PROJECT_ID"
|
|
||||||
gcloud --project $EXAMPLE_PROJECT_ID services enable $service 2>&1 | tab
|
|
||||||
done
|
|
||||||
|
|
||||||
# create service account
|
|
||||||
SA_NAME="example-$RAND"
|
|
||||||
echo " * Creating a Service Account"
|
|
||||||
gcloud --project $EXAMPLE_PROJECT_ID iam service-accounts create $SA_NAME --display-name "Crossplane Example" 2>&1 | tab
|
|
||||||
# export service account email
|
|
||||||
EXAMPLE_SA="${SA_NAME}@${EXAMPLE_PROJECT_ID}.iam.gserviceaccount.com"
|
|
||||||
|
|
||||||
# assign roles
|
|
||||||
for role in "${ROLES[@]}"; do
|
|
||||||
echo "* Adding Role $role to $EXAMPLE_SA on $EXAMPLE_PROJECT_ID"
|
|
||||||
gcloud projects add-iam-policy-binding $EXAMPLE_PROJECT_ID --member "serviceAccount:$EXAMPLE_SA" --role="$role" 2>&1 | tab
|
|
||||||
done
|
|
||||||
|
|
||||||
# create service account key (this will create a `crossplane-gcp-provider-key.json` file in your current working directory)
|
|
||||||
echo " * Creating $EXAMPLE_SA Key File $KEYFILE"
|
|
||||||
gcloud --project $EXAMPLE_PROJECT_ID iam service-accounts keys create --iam-account $EXAMPLE_SA $KEYFILE 2>&1 | tab
|
|
||||||
|
|
||||||
cat <<EOS
|
|
||||||
#
|
|
||||||
# Run the following for the variables that are used throughout the GCP example projects
|
|
||||||
#
|
|
||||||
export ORGANIZATION_ID=$ORGANIZATION_ID
|
|
||||||
export PROJECT_ID=$EXAMPLE_PROJECT_ID
|
|
||||||
export EXAMPLE_SA=$EXAMPLE_SA
|
|
||||||
export BASE64ENCODED_GCP_PROVIDER_CREDS=\$(base64 $KEYFILE | tr -d "\n")
|
|
||||||
EOS
|
|
|
@ -1,160 +0,0 @@
|
||||||
---
|
|
||||||
apiVersion: apiextensions.crossplane.io/v1
|
|
||||||
kind: Composition
|
|
||||||
metadata:
|
|
||||||
name: vpcpostgresqlinstances.aws.database.example.org
|
|
||||||
labels:
|
|
||||||
provider: aws
|
|
||||||
guide: quickstart
|
|
||||||
vpc: new
|
|
||||||
spec:
|
|
||||||
writeConnectionSecretsToNamespace: crossplane-system
|
|
||||||
compositeTypeRef:
|
|
||||||
apiVersion: database.example.org/v1alpha1
|
|
||||||
kind: XPostgreSQLInstance
|
|
||||||
resources:
|
|
||||||
- name: vpc
|
|
||||||
base:
|
|
||||||
apiVersion: ec2.aws.crossplane.io/v1beta1
|
|
||||||
kind: VPC
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
region: us-east-1
|
|
||||||
cidrBlock: 192.168.0.0/16
|
|
||||||
enableDnsSupport: true
|
|
||||||
enableDnsHostNames: true
|
|
||||||
- name: subnet-a
|
|
||||||
base:
|
|
||||||
apiVersion: ec2.aws.crossplane.io/v1beta1
|
|
||||||
kind: Subnet
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
zone: us-east-1a
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
region: us-east-1
|
|
||||||
cidrBlock: 192.168.64.0/18
|
|
||||||
vpcIdSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
availabilityZone: us-east-1a
|
|
||||||
- name: subnet-b
|
|
||||||
base:
|
|
||||||
apiVersion: ec2.aws.crossplane.io/v1beta1
|
|
||||||
kind: Subnet
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
zone: us-east-1b
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
region: us-east-1
|
|
||||||
cidrBlock: 192.168.128.0/18
|
|
||||||
vpcIdSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
availabilityZone: us-east-1b
|
|
||||||
- name: subnet-c
|
|
||||||
base:
|
|
||||||
apiVersion: ec2.aws.crossplane.io/v1beta1
|
|
||||||
kind: Subnet
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
zone: us-east-1c
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
region: us-east-1
|
|
||||||
cidrBlock: 192.168.192.0/18
|
|
||||||
vpcIdSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
availabilityZone: us-east-1c
|
|
||||||
- name: dbsubnetgroup
|
|
||||||
base:
|
|
||||||
apiVersion: database.aws.crossplane.io/v1beta1
|
|
||||||
kind: DBSubnetGroup
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
region: us-east-1
|
|
||||||
description: An excellent formation of subnetworks.
|
|
||||||
subnetIdSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
- name: internetgateway
|
|
||||||
base:
|
|
||||||
apiVersion: ec2.aws.crossplane.io/v1beta1
|
|
||||||
kind: InternetGateway
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
region: us-east-1
|
|
||||||
vpcIdSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
- name: routetable
|
|
||||||
base:
|
|
||||||
apiVersion: ec2.aws.crossplane.io/v1beta1
|
|
||||||
kind: RouteTable
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
region: us-east-1
|
|
||||||
vpcIdSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
routes:
|
|
||||||
- destinationCidrBlock: 0.0.0.0/0
|
|
||||||
gatewayIdSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
associations:
|
|
||||||
- subnetIdSelector:
|
|
||||||
matchLabels:
|
|
||||||
zone: us-east-1a
|
|
||||||
- subnetIdSelector:
|
|
||||||
matchLabels:
|
|
||||||
zone: us-east-1b
|
|
||||||
- subnetIdSelector:
|
|
||||||
matchLabels:
|
|
||||||
zone: us-east-1c
|
|
||||||
- name: securitygroup
|
|
||||||
base:
|
|
||||||
apiVersion: ec2.aws.crossplane.io/v1beta1
|
|
||||||
kind: SecurityGroup
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
region: us-east-1
|
|
||||||
vpcIdSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
groupName: crossplane-getting-started
|
|
||||||
description: Allow access to PostgreSQL
|
|
||||||
ingress:
|
|
||||||
- fromPort: 5432
|
|
||||||
toPort: 5432
|
|
||||||
ipProtocol: tcp
|
|
||||||
ipRanges:
|
|
||||||
- cidrIp: 0.0.0.0/0
|
|
||||||
description: Everywhere
|
|
||||||
- name: rdsinstance
|
|
||||||
base:
|
|
||||||
apiVersion: database.aws.crossplane.io/v1beta1
|
|
||||||
kind: RDSInstance
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
region: us-east-1
|
|
||||||
dbSubnetGroupNameSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
vpcSecurityGroupIDSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
dbInstanceClass: db.t2.small
|
|
||||||
masterUsername: masteruser
|
|
||||||
engine: postgres
|
|
||||||
engineVersion: "12"
|
|
||||||
skipFinalSnapshotBeforeDeletion: true
|
|
||||||
publiclyAccessible: true
|
|
||||||
writeConnectionSecretToRef:
|
|
||||||
namespace: crossplane-system
|
|
||||||
patches:
|
|
||||||
- fromFieldPath: "metadata.uid"
|
|
||||||
toFieldPath: "spec.writeConnectionSecretToRef.name"
|
|
||||||
transforms:
|
|
||||||
- type: string
|
|
||||||
string:
|
|
||||||
fmt: "%s-postgresql"
|
|
||||||
- fromFieldPath: "spec.parameters.storageGB"
|
|
||||||
toFieldPath: "spec.forProvider.allocatedStorage"
|
|
||||||
connectionDetails:
|
|
||||||
- fromConnectionSecretKey: username
|
|
||||||
- fromConnectionSecretKey: password
|
|
||||||
- fromConnectionSecretKey: endpoint
|
|
||||||
- fromConnectionSecretKey: port
|
|
|
@ -1,29 +0,0 @@
|
||||||
apiVersion: meta.pkg.crossplane.io/v1alpha1
|
|
||||||
kind: Configuration
|
|
||||||
metadata:
|
|
||||||
name: getting-started-with-aws-with-vpc
|
|
||||||
annotations:
|
|
||||||
meta.crossplane.io/maintainer: Crossplane Maintainers <info@crossplane.io>
|
|
||||||
meta.crossplane.io/source: github.com/crossplane/crossplane
|
|
||||||
meta.crossplane.io/license: Apache-2.0
|
|
||||||
meta.crossplane.io/description: |
|
|
||||||
An introductory example to Crossplane and Composition for AWS.
|
|
||||||
meta.crossplane.io/readme: |
|
|
||||||
An introductory example to Crossplane and Composition for AWS.
|
|
||||||
This will enable provisioning of an RDS database instance.
|
|
||||||
The example also illustrates how to specify a non-default VPC.
|
|
||||||
|
|
||||||
[Install &
|
|
||||||
Configure](https://crossplane.io/docs/master/getting-started/install-configure.html)
|
|
||||||
|
|
||||||
[Provision a PostgreSQL RDS
|
|
||||||
Database](https://crossplane.io/docs/master/getting-started/provision-infrastructure.html)
|
|
||||||
guide: quickstart
|
|
||||||
provider: aws
|
|
||||||
vpc: new
|
|
||||||
spec:
|
|
||||||
crossplane:
|
|
||||||
version: ">=v1.4.0-0"
|
|
||||||
dependsOn:
|
|
||||||
- provider: xpkg.upbound.io/crossplane-contrib/provider-aws
|
|
||||||
version: ">=v0.24.1"
|
|
|
@ -1,40 +0,0 @@
|
||||||
---
|
|
||||||
apiVersion: apiextensions.crossplane.io/v1
|
|
||||||
kind: CompositeResourceDefinition
|
|
||||||
metadata:
|
|
||||||
name: xpostgresqlinstances.database.example.org
|
|
||||||
spec:
|
|
||||||
group: database.example.org
|
|
||||||
names:
|
|
||||||
kind: XPostgreSQLInstance
|
|
||||||
plural: xpostgresqlinstances
|
|
||||||
claimNames:
|
|
||||||
kind: PostgreSQLInstance
|
|
||||||
plural: postgresqlinstances
|
|
||||||
connectionSecretKeys:
|
|
||||||
- username
|
|
||||||
- password
|
|
||||||
- endpoint
|
|
||||||
- port
|
|
||||||
versions:
|
|
||||||
- name: v1alpha1
|
|
||||||
served: true
|
|
||||||
referenceable: true
|
|
||||||
schema:
|
|
||||||
openAPIV3Schema:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
spec:
|
|
||||||
type: object
|
|
||||||
description: "The OpenAPIV3Schema of this Composite Resource Definition."
|
|
||||||
properties:
|
|
||||||
parameters:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
storageGB:
|
|
||||||
type: integer
|
|
||||||
description: "The desired storage capacity of the database, in GB."
|
|
||||||
required:
|
|
||||||
- storageGB
|
|
||||||
required:
|
|
||||||
- parameters
|
|
|
@ -1,44 +0,0 @@
|
||||||
---
|
|
||||||
apiVersion: apiextensions.crossplane.io/v1
|
|
||||||
kind: Composition
|
|
||||||
metadata:
|
|
||||||
name: xpostgresqlinstances.aws.database.example.org
|
|
||||||
labels:
|
|
||||||
provider: aws
|
|
||||||
guide: quickstart
|
|
||||||
vpc: default
|
|
||||||
spec:
|
|
||||||
writeConnectionSecretsToNamespace: crossplane-system
|
|
||||||
compositeTypeRef:
|
|
||||||
apiVersion: database.example.org/v1alpha1
|
|
||||||
kind: XPostgreSQLInstance
|
|
||||||
resources:
|
|
||||||
- name: rdsinstance
|
|
||||||
base:
|
|
||||||
apiVersion: database.aws.crossplane.io/v1beta1
|
|
||||||
kind: RDSInstance
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
region: us-east-1
|
|
||||||
dbInstanceClass: db.t2.small
|
|
||||||
masterUsername: masteruser
|
|
||||||
engine: postgres
|
|
||||||
engineVersion: "12"
|
|
||||||
skipFinalSnapshotBeforeDeletion: true
|
|
||||||
publiclyAccessible: true
|
|
||||||
writeConnectionSecretToRef:
|
|
||||||
namespace: crossplane-system
|
|
||||||
patches:
|
|
||||||
- fromFieldPath: "metadata.uid"
|
|
||||||
toFieldPath: "spec.writeConnectionSecretToRef.name"
|
|
||||||
transforms:
|
|
||||||
- type: string
|
|
||||||
string:
|
|
||||||
fmt: "%s-postgresql"
|
|
||||||
- fromFieldPath: "spec.parameters.storageGB"
|
|
||||||
toFieldPath: "spec.forProvider.allocatedStorage"
|
|
||||||
connectionDetails:
|
|
||||||
- fromConnectionSecretKey: username
|
|
||||||
- fromConnectionSecretKey: password
|
|
||||||
- fromConnectionSecretKey: endpoint
|
|
||||||
- fromConnectionSecretKey: port
|
|
|
@ -1,29 +0,0 @@
|
||||||
apiVersion: meta.pkg.crossplane.io/v1alpha1
|
|
||||||
kind: Configuration
|
|
||||||
metadata:
|
|
||||||
name: getting-started-with-aws
|
|
||||||
annotations:
|
|
||||||
meta.crossplane.io/maintainer: Crossplane Maintainers <info@crossplane.io>
|
|
||||||
meta.crossplane.io/source: github.com/crossplane/crossplane
|
|
||||||
meta.crossplane.io/license: Apache-2.0
|
|
||||||
meta.crossplane.io/description: |
|
|
||||||
An introductory example to Crossplane and Composition for AWS.
|
|
||||||
meta.crossplane.io/readme: |
|
|
||||||
An introductory example to Crossplane and Composition for AWS.
|
|
||||||
This will enable provisioning of an RDS database instance.
|
|
||||||
|
|
||||||
[Install &
|
|
||||||
Configure](https://crossplane.io/docs/master/getting-started/install-configure.html)
|
|
||||||
|
|
||||||
[Provision a PostgreSQL RDS
|
|
||||||
Database](https://crossplane.io/docs/master/getting-started/provision-infrastructure.html)
|
|
||||||
labels:
|
|
||||||
guide: quickstart
|
|
||||||
provider: aws
|
|
||||||
vpc: default
|
|
||||||
spec:
|
|
||||||
crossplane:
|
|
||||||
version: ">=v1.4.0-0"
|
|
||||||
dependsOn:
|
|
||||||
- provider: xpkg.upbound.io/crossplane-contrib/provider-aws
|
|
||||||
version: ">=v0.24.1"
|
|
|
@ -1,40 +0,0 @@
|
||||||
---
|
|
||||||
apiVersion: apiextensions.crossplane.io/v1
|
|
||||||
kind: CompositeResourceDefinition
|
|
||||||
metadata:
|
|
||||||
name: xpostgresqlinstances.database.example.org
|
|
||||||
spec:
|
|
||||||
group: database.example.org
|
|
||||||
names:
|
|
||||||
kind: XPostgreSQLInstance
|
|
||||||
plural: xpostgresqlinstances
|
|
||||||
claimNames:
|
|
||||||
kind: PostgreSQLInstance
|
|
||||||
plural: postgresqlinstances
|
|
||||||
connectionSecretKeys:
|
|
||||||
- username
|
|
||||||
- password
|
|
||||||
- endpoint
|
|
||||||
- port
|
|
||||||
versions:
|
|
||||||
- name: v1alpha1
|
|
||||||
served: true
|
|
||||||
referenceable: true
|
|
||||||
schema:
|
|
||||||
openAPIV3Schema:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
spec:
|
|
||||||
type: object
|
|
||||||
description: "The OpenAPIV3Schema of this Composite Resource Definition."
|
|
||||||
properties:
|
|
||||||
parameters:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
storageGB:
|
|
||||||
type: integer
|
|
||||||
description: "The desired storage capacity of the database, in GB."
|
|
||||||
required:
|
|
||||||
- storageGB
|
|
||||||
required:
|
|
||||||
- parameters
|
|
|
@ -1,73 +0,0 @@
|
||||||
---
|
|
||||||
apiVersion: apiextensions.crossplane.io/v1
|
|
||||||
kind: Composition
|
|
||||||
metadata:
|
|
||||||
name: xpostgresqlinstances.azure.database.example.org
|
|
||||||
labels:
|
|
||||||
provider: azure
|
|
||||||
guide: quickstart
|
|
||||||
spec:
|
|
||||||
writeConnectionSecretsToNamespace: crossplane-system
|
|
||||||
compositeTypeRef:
|
|
||||||
apiVersion: database.example.org/v1alpha1
|
|
||||||
kind: XPostgreSQLInstance
|
|
||||||
resources:
|
|
||||||
- name: resourcegroup
|
|
||||||
base:
|
|
||||||
apiVersion: azure.crossplane.io/v1alpha3
|
|
||||||
kind: ResourceGroup
|
|
||||||
spec:
|
|
||||||
location: West US 2
|
|
||||||
- name: postgresqlserver
|
|
||||||
base:
|
|
||||||
apiVersion: database.azure.crossplane.io/v1beta1
|
|
||||||
kind: PostgreSQLServer
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
administratorLogin: myadmin
|
|
||||||
resourceGroupNameSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
location: West US 2
|
|
||||||
sslEnforcement: Disabled
|
|
||||||
version: "11"
|
|
||||||
storageProfile:
|
|
||||||
storageMB: 5120
|
|
||||||
sku:
|
|
||||||
tier: GeneralPurpose
|
|
||||||
capacity: 2
|
|
||||||
family: Gen5
|
|
||||||
writeConnectionSecretToRef:
|
|
||||||
namespace: crossplane-system
|
|
||||||
patches:
|
|
||||||
- fromFieldPath: "metadata.uid"
|
|
||||||
toFieldPath: "spec.writeConnectionSecretToRef.name"
|
|
||||||
transforms:
|
|
||||||
- type: string
|
|
||||||
string:
|
|
||||||
fmt: "%s-postgresql"
|
|
||||||
- fromFieldPath: "spec.parameters.storageGB"
|
|
||||||
toFieldPath: "spec.forProvider.storageProfile.storageMB"
|
|
||||||
transforms:
|
|
||||||
- type: math
|
|
||||||
math:
|
|
||||||
multiply: 1024
|
|
||||||
connectionDetails:
|
|
||||||
- fromConnectionSecretKey: username
|
|
||||||
- fromConnectionSecretKey: password
|
|
||||||
- fromConnectionSecretKey: endpoint
|
|
||||||
- type: FromValue
|
|
||||||
name: port
|
|
||||||
value: "5432"
|
|
||||||
- name: firewallrule
|
|
||||||
base:
|
|
||||||
apiVersion: database.azure.crossplane.io/v1alpha3
|
|
||||||
kind: PostgreSQLServerFirewallRule
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
serverNameSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
resourceGroupNameSelector:
|
|
||||||
matchControllerRef: true
|
|
||||||
properties:
|
|
||||||
startIpAddress: 0.0.0.0
|
|
||||||
endIpAddress: 255.255.255.254
|
|
|
@ -1,27 +0,0 @@
|
||||||
apiVersion: meta.pkg.crossplane.io/v1alpha1
|
|
||||||
kind: Configuration
|
|
||||||
metadata:
|
|
||||||
name: getting-started-with-azure
|
|
||||||
annotations:
|
|
||||||
meta.crossplane.io/maintainer: Crossplane Maintainers <info@crossplane.io>
|
|
||||||
meta.crossplane.io/source: github.com/crossplane/crossplane
|
|
||||||
meta.crossplane.io/license: Apache-2.0
|
|
||||||
meta.crossplane.io/description: |
|
|
||||||
An introductory example to Crossplane and Composition for Azure.
|
|
||||||
meta.crossplane.io/readme: |
|
|
||||||
An introductory example to Crossplane and Composition for Azure.
|
|
||||||
This will enable provisioning of an Azure SQL database instance.
|
|
||||||
|
|
||||||
[Install &
|
|
||||||
Configure](https://crossplane.io/docs/master/getting-started/install-configure.html)
|
|
||||||
|
|
||||||
[Provision a PostgreSQL Azure SQL
|
|
||||||
Database](https://crossplane.io/docs/master/getting-started/provision-infrastructure.html)
|
|
||||||
guide: quickstart
|
|
||||||
provider: azure
|
|
||||||
spec:
|
|
||||||
crossplane:
|
|
||||||
version: ">=v1.4.0-0"
|
|
||||||
dependsOn:
|
|
||||||
- provider: xpkg.upbound.io/crossplane-contrib/provider-azure
|
|
||||||
version: ">=v0.18.1"
|
|
|
@ -1,40 +0,0 @@
|
||||||
---
|
|
||||||
apiVersion: apiextensions.crossplane.io/v1
|
|
||||||
kind: CompositeResourceDefinition
|
|
||||||
metadata:
|
|
||||||
name: xpostgresqlinstances.database.example.org
|
|
||||||
spec:
|
|
||||||
group: database.example.org
|
|
||||||
names:
|
|
||||||
kind: XPostgreSQLInstance
|
|
||||||
plural: xpostgresqlinstances
|
|
||||||
claimNames:
|
|
||||||
kind: PostgreSQLInstance
|
|
||||||
plural: postgresqlinstances
|
|
||||||
connectionSecretKeys:
|
|
||||||
- username
|
|
||||||
- password
|
|
||||||
- endpoint
|
|
||||||
- port
|
|
||||||
versions:
|
|
||||||
- name: v1alpha1
|
|
||||||
served: true
|
|
||||||
referenceable: true
|
|
||||||
schema:
|
|
||||||
openAPIV3Schema:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
spec:
|
|
||||||
type: object
|
|
||||||
description: "The OpenAPIV3Schema of this Composite Resource Definition."
|
|
||||||
properties:
|
|
||||||
parameters:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
storageGB:
|
|
||||||
type: integer
|
|
||||||
description: "The desired storage capacity of the database, in GB."
|
|
||||||
required:
|
|
||||||
- storageGB
|
|
||||||
required:
|
|
||||||
- parameters
|
|
|
@ -1,38 +0,0 @@
|
||||||
---
|
|
||||||
apiVersion: apiextensions.crossplane.io/v1
|
|
||||||
kind: CompositeResourceDefinition
|
|
||||||
metadata:
|
|
||||||
name: xpostgresqlinstances.database.example.org
|
|
||||||
spec:
|
|
||||||
group: database.example.org
|
|
||||||
names:
|
|
||||||
kind: XPostgreSQLInstance
|
|
||||||
plural: xpostgresqlinstances
|
|
||||||
claimNames:
|
|
||||||
kind: PostgreSQLInstance
|
|
||||||
plural: postgresqlinstances
|
|
||||||
connectionSecretKeys:
|
|
||||||
- username
|
|
||||||
- password
|
|
||||||
- endpoint
|
|
||||||
- port
|
|
||||||
versions:
|
|
||||||
- name: v1alpha1
|
|
||||||
served: true
|
|
||||||
referenceable: true
|
|
||||||
schema:
|
|
||||||
openAPIV3Schema:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
spec:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
parameters:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
storageGB:
|
|
||||||
type: integer
|
|
||||||
required:
|
|
||||||
- storageGB
|
|
||||||
required:
|
|
||||||
- parameters
|
|
|
@ -1,47 +0,0 @@
|
||||||
---
|
|
||||||
apiVersion: apiextensions.crossplane.io/v1
|
|
||||||
kind: Composition
|
|
||||||
metadata:
|
|
||||||
name: xpostgresqlinstances.gcp.database.example.org
|
|
||||||
labels:
|
|
||||||
provider: gcp
|
|
||||||
guide: quickstart
|
|
||||||
spec:
|
|
||||||
writeConnectionSecretsToNamespace: crossplane-system
|
|
||||||
compositeTypeRef:
|
|
||||||
apiVersion: database.example.org/v1alpha1
|
|
||||||
kind: XPostgreSQLInstance
|
|
||||||
resources:
|
|
||||||
- name: cloudsqlinstance
|
|
||||||
base:
|
|
||||||
apiVersion: database.gcp.crossplane.io/v1beta1
|
|
||||||
kind: CloudSQLInstance
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
databaseVersion: POSTGRES_12
|
|
||||||
region: us-central1
|
|
||||||
settings:
|
|
||||||
tier: db-custom-1-3840
|
|
||||||
dataDiskType: PD_SSD
|
|
||||||
ipConfiguration:
|
|
||||||
ipv4Enabled: true
|
|
||||||
authorizedNetworks:
|
|
||||||
- value: "0.0.0.0/0"
|
|
||||||
writeConnectionSecretToRef:
|
|
||||||
namespace: crossplane-system
|
|
||||||
patches:
|
|
||||||
- fromFieldPath: "metadata.uid"
|
|
||||||
toFieldPath: "spec.writeConnectionSecretToRef.name"
|
|
||||||
transforms:
|
|
||||||
- type: string
|
|
||||||
string:
|
|
||||||
fmt: "%s-postgresql"
|
|
||||||
- fromFieldPath: "spec.parameters.storageGB"
|
|
||||||
toFieldPath: "spec.forProvider.settings.dataDiskSizeGb"
|
|
||||||
connectionDetails:
|
|
||||||
- fromConnectionSecretKey: username
|
|
||||||
- fromConnectionSecretKey: password
|
|
||||||
- fromConnectionSecretKey: endpoint
|
|
||||||
- type: FromValue
|
|
||||||
name: port
|
|
||||||
value: "5432"
|
|
|
@ -1,27 +0,0 @@
|
||||||
apiVersion: meta.pkg.crossplane.io/v1alpha1
|
|
||||||
kind: Configuration
|
|
||||||
metadata:
|
|
||||||
name: getting-started-with-gcp
|
|
||||||
annotations:
|
|
||||||
meta.crossplane.io/maintainer: Crossplane Maintainers <info@crossplane.io>
|
|
||||||
meta.crossplane.io/source: github.com/crossplane/crossplane
|
|
||||||
meta.crossplane.io/license: Apache-2.0
|
|
||||||
meta.crossplane.io/description: |
|
|
||||||
An introductory example to Crossplane and Composition for GCP.
|
|
||||||
meta.crossplane.io/readme: |
|
|
||||||
An introductory example to Crossplane and Composition for GCP.
|
|
||||||
This will enable provisioning of a Cloud SQL database instance.
|
|
||||||
|
|
||||||
[Install &
|
|
||||||
Configure](https://crossplane.io/docs/master/getting-started/install-configure.html)
|
|
||||||
|
|
||||||
[Provision a PostgreSQL Cloud SQL
|
|
||||||
Database](https://crossplane.io/docs/master/getting-started/provision-infrastructure.html)
|
|
||||||
guide: quickstart
|
|
||||||
provider: gcp
|
|
||||||
spec:
|
|
||||||
crossplane:
|
|
||||||
version: ">=v1.4.0-0"
|
|
||||||
dependsOn:
|
|
||||||
- provider: xpkg.upbound.io/crossplane-contrib/provider-gcp
|
|
||||||
version: ">=v0.20.0"
|
|
|
@ -1,40 +0,0 @@
|
||||||
---
|
|
||||||
apiVersion: apiextensions.crossplane.io/v1
|
|
||||||
kind: CompositeResourceDefinition
|
|
||||||
metadata:
|
|
||||||
name: xpostgresqlinstances.database.example.org
|
|
||||||
spec:
|
|
||||||
group: database.example.org
|
|
||||||
names:
|
|
||||||
kind: XPostgreSQLInstance
|
|
||||||
plural: xpostgresqlinstances
|
|
||||||
claimNames:
|
|
||||||
kind: PostgreSQLInstance
|
|
||||||
plural: postgresqlinstances
|
|
||||||
connectionSecretKeys:
|
|
||||||
- username
|
|
||||||
- password
|
|
||||||
- endpoint
|
|
||||||
- port
|
|
||||||
versions:
|
|
||||||
- name: v1alpha1
|
|
||||||
served: true
|
|
||||||
referenceable: true
|
|
||||||
schema:
|
|
||||||
openAPIV3Schema:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
spec:
|
|
||||||
type: object
|
|
||||||
description: "The OpenAPIV3Schema of this Composite Resource Definition."
|
|
||||||
properties:
|
|
||||||
parameters:
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
storageGB:
|
|
||||||
type: integer
|
|
||||||
description: "The desired storage capacity of the database, in GB."
|
|
||||||
required:
|
|
||||||
- storageGB
|
|
||||||
required:
|
|
||||||
- parameters
|
|
|
@ -1,16 +0,0 @@
|
||||||
apiVersion: database.aws.crossplane.io/v1beta1
|
|
||||||
kind: RDSInstance
|
|
||||||
metadata:
|
|
||||||
name: rdspostgresql
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
region: us-east-1
|
|
||||||
dbInstanceClass: db.t2.small
|
|
||||||
masterUsername: masteruser
|
|
||||||
allocatedStorage: 20
|
|
||||||
engine: postgres
|
|
||||||
engineVersion: "12"
|
|
||||||
skipFinalSnapshotBeforeDeletion: true
|
|
||||||
writeConnectionSecretToRef:
|
|
||||||
namespace: crossplane-system
|
|
||||||
name: aws-rdspostgresql-conn
|
|
|
@ -1,28 +0,0 @@
|
||||||
apiVersion: azure.crossplane.io/v1alpha3
|
|
||||||
kind: ResourceGroup
|
|
||||||
metadata:
|
|
||||||
name: sqlserverpostgresql-rg
|
|
||||||
spec:
|
|
||||||
location: West US 2
|
|
||||||
---
|
|
||||||
apiVersion: database.azure.crossplane.io/v1beta1
|
|
||||||
kind: PostgreSQLServer
|
|
||||||
metadata:
|
|
||||||
name: sqlserverpostgresql
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
administratorLogin: myadmin
|
|
||||||
resourceGroupNameRef:
|
|
||||||
name: sqlserverpostgresql-rg
|
|
||||||
location: West US 2
|
|
||||||
sslEnforcement: Disabled
|
|
||||||
version: "11"
|
|
||||||
sku:
|
|
||||||
tier: GeneralPurpose
|
|
||||||
capacity: 2
|
|
||||||
family: Gen5
|
|
||||||
storageProfile:
|
|
||||||
storageMB: 20480
|
|
||||||
writeConnectionSecretToRef:
|
|
||||||
namespace: crossplane-system
|
|
||||||
name: sqlserverpostgresql-conn
|
|
|
@ -1,15 +0,0 @@
|
||||||
apiVersion: database.gcp.crossplane.io/v1beta1
|
|
||||||
kind: CloudSQLInstance
|
|
||||||
metadata:
|
|
||||||
name: cloudsqlpostgresql
|
|
||||||
spec:
|
|
||||||
forProvider:
|
|
||||||
databaseVersion: POSTGRES_12
|
|
||||||
region: us-central1
|
|
||||||
settings:
|
|
||||||
tier: db-custom-1-3840
|
|
||||||
dataDiskType: PD_SSD
|
|
||||||
dataDiskSizeGb: 10
|
|
||||||
writeConnectionSecretToRef:
|
|
||||||
namespace: crossplane-system
|
|
||||||
name: cloudsqlpostgresql-conn
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
[[redirects]]
|
[[redirects]]
|
||||||
from = "/latest/*"
|
from = "/latest/*"
|
||||||
to = "/v1.11/:splat"
|
to = "/v1.12/:splat"
|
||||||
status = 302
|
status = 302
|
||||||
|
|
||||||
[[redirects]]
|
[[redirects]]
|
||||||
|
|
Loading…
Reference in New Issue