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 `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.
|
||||
- [ ] Remove EOL'd docs version from "/content" directory and run `hugo` locally to check for broken links.
|
|
@ -51,7 +51,7 @@ security:
|
|||
- ^REVIEW_ID
|
||||
|
||||
params:
|
||||
latest: "1.11"
|
||||
latest: "1.12"
|
||||
upboundLink: "https://www.upbound.io/"
|
||||
slackLink: "https://slack.crossplane.io/"
|
||||
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
|
||||
weight: 100
|
||||
description: Understand Crossplane's core components
|
||||
---
|
||||
|
||||
Crossplane introduces multiple building blocks that enable you to provision,
|
|
@ -1,8 +1,245 @@
|
|||
---
|
||||
title: Composition
|
||||
weight: 304
|
||||
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.
|
||||
|
||||
|
||||
This reference provides detailed examples of defining, configuring, and using
|
||||
Composite Resources in Crossplane. You can also refer to Crossplane's [API
|
||||
|
@ -37,6 +274,17 @@ spec:
|
|||
apiVersion: database.example.org/v1alpha1
|
||||
kind: PostgreSQLInstance
|
||||
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
|
||||
# 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
|
||||
|
@ -51,6 +299,27 @@ spec:
|
|||
environment: production
|
||||
region: us-east
|
||||
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
|
||||
# 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.
|
||||
|
@ -167,12 +436,21 @@ spec:
|
|||
# be written to the connection secret of the XR.
|
||||
connectionSecretKeys:
|
||||
- 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
|
||||
# specified (e.g. when the XR has no compositionRef or selector). A similar
|
||||
# enforceCompositionRef field also exists to allow XRs to enforce a specific
|
||||
# Composition that should always be used.
|
||||
defaultCompositionRef:
|
||||
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
|
||||
# and v1 - simultaneously. Currently Crossplane requires that all versions
|
||||
# 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]
|
||||
```
|
||||
|
||||
### 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
|
||||
|
||||
You can use the following types of patch in a `Composition`:
|
||||
|
@ -428,6 +745,35 @@ resources:
|
|||
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.
|
||||
|
||||
`CombineFromComposite`. Combines multiple fields from the XR to produce one
|
||||
|
@ -454,6 +800,26 @@ composed resource field.
|
|||
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
|
||||
[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
|
||||
|
@ -478,6 +844,26 @@ would be set to `us-west-db`.
|
|||
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`
|
||||
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
|
||||
```
|
||||
|
||||
`math`. Transforms values using math. The input value must be an integer.
|
||||
Currently only `multiply` is supported.
|
||||
`match`. A more complex version of `map` that can match different kinds of
|
||||
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
|
||||
# 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
|
||||
# to 4.
|
||||
- type: math
|
||||
math:
|
||||
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 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 `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.
|
||||
|
@ -568,6 +1022,19 @@ Currently only `multiply` is supported.
|
|||
type: Convert
|
||||
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
|
||||
# be set to crossplane.io
|
||||
- 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
|
||||
```
|
||||
|
||||
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 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.
|
||||
|
||||
### 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
|
||||
|
||||
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
|
||||
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
|
||||
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].
|
||||
|
||||
## Tips, Tricks, and Troubleshooting
|
||||
|
@ -826,14 +1336,19 @@ so:
|
|||
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.
|
||||
|
||||
[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/
|
||||
[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
|
||||
[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
|
||||
[trouble-ref]: {{<ref "troubleshoot" >}}
|
||||
[upbound-marketplace]: https://marketplace.upbound.io
|
||||
[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
|
||||
[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
|
||||
external system - most commonly a cloud provider. Managed Resources are
|
||||
opinionated, Crossplane Resource Model ([XRM][term-xrm]) compliant Kubernetes
|
||||
Custom Resources that are installed by a Crossplane [provider].
|
||||
opinionated, Crossplane Resource Model ([XRM]({{<ref "../concepts/terminology">}})) compliant Kubernetes
|
||||
Custom Resources that are installed by a Crossplane [provider]({{<ref "providers" >}}).
|
||||
|
||||
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
|
||||
resources are reflected directly on the corresponding resource in the provider.
|
||||
Similarly, the `Database` types in the SQL provider represent a PostgreSQL or
|
||||
MySQL database. You can browse [API Reference][api-reference] to discover all
|
||||
available managed resources.
|
||||
MySQL database.
|
||||
|
||||
Managed Resources are the building blocks of Crossplane. They're designed to be
|
||||
_composed_ into higher level, opinionated Custom Resources that Crossplane calls
|
||||
Composite Resources or XRs - not used directly. See the
|
||||
[Composition][composition] documentation for more information.
|
||||
[Composition]({{<ref "composition" >}}) documentation for more information.
|
||||
|
||||
## Syntax
|
||||
|
||||
|
@ -51,7 +50,7 @@ spec:
|
|||
```
|
||||
|
||||
```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
|
||||
|
@ -100,7 +99,7 @@ spec:
|
|||
```
|
||||
|
||||
```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
|
||||
|
@ -167,7 +166,7 @@ spec:
|
|||
```
|
||||
|
||||
```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
|
||||
|
@ -304,6 +303,25 @@ never deletes the external resource in the provider.
|
|||
> 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].
|
||||
|
||||
#### 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
|
||||
|
||||
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
|
||||
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
|
||||
indicated in the [API Reference][api-reference] documentation.
|
||||
need to enter the name of the resource as well as the required fields.
|
||||
|
||||
## 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
|
||||
including Velero.
|
||||
|
||||
[term-xrm]: {{<ref "terminology" >}}#crossplane-resource-model
|
||||
[rds]: https://aws.amazon.com/rds/
|
||||
[cloudsql]: https://cloud.google.com/sql
|
||||
[composition]: {{<ref "composition" >}}
|
||||
[api-versioning]: https://kubernetes.io/docs/reference/using-api/#api-versioning#api-versioning
|
||||
[velero]: https://velero.io/
|
||||
[api-reference]: {{<ref "../api-docs" >}}
|
||||
[provider]: {{<ref "providers" >}}
|
||||
[issue-727]: https://github.com/crossplane/crossplane/issues/727
|
||||
[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`
|
||||
> [`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
|
||||
execute the following command:
|
||||
|
@ -379,8 +379,10 @@ package without considering the version of Crossplane that is installed.
|
|||
|
||||
### spec.controllerConfigRef
|
||||
|
||||
> This field is only available when installing a `Provider` and is an `alpha`
|
||||
> feature that depends on the `v1alpha1` [`ControllerConfig` API][controller-config-docs].
|
||||
{{< hint "warning" >}}
|
||||
The `ControllerConfig` API has been deprecated and will be removed in a future
|
||||
release when a comparable alternative is available.
|
||||
{{< /hint >}}
|
||||
|
||||
Valid values: name of a `ControllerConfig` object
|
||||
|
||||
|
@ -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
|
||||
[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
|
||||
[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
|
||||
[composition]: {{<ref "composition" >}}
|
||||
[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
|
||||
---
|
||||
|
||||
Providers are Crossplane packages that bundle a set of [Managed
|
||||
Resources][managed-resources] and their respective controllers to allow
|
||||
Providers are Crossplane packages that bundle a set of
|
||||
[Managed Resources]({{<ref "managed-resources" >}}) and their respective controllers to allow
|
||||
Crossplane to provision the respective infrastructure resource.
|
||||
|
||||
## Installing Providers
|
||||
|
@ -65,8 +65,7 @@ spec:
|
|||
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
|
||||
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
|
||||
details.
|
||||
blob should look like.
|
||||
|
||||
The following is an example usage of AWS `ProviderConfig`, referenced by a
|
||||
`RDSInstance`:
|
||||
|
@ -90,8 +89,7 @@ will attempt to use a `ProviderConfig` named `default`.
|
|||
|
||||
<!-- Named Links -->
|
||||
|
||||
[getting-started]: {{<ref "../getting-started/install-configure" >}}
|
||||
[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" >}}
|
||||
[managed-resources]: {{<ref "managed-resources" >}}
|
||||
|
||||
[Google Cloud Platform (GCP) Service Account]: "../cloud-providers/gcp/gcp-provider"
|
||||
[Microsoft Azure Service Principal]: "../cloud-providers/azure/azure-provider"
|
||||
[Amazon Web Services (AWS) IAM User]: "../cloud-providers/aws/aws-provider"
|
|
@ -2,7 +2,6 @@
|
|||
title: Terminology
|
||||
weight: 110
|
||||
---
|
||||
|
||||
## A Note on Style
|
||||
|
||||
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]]
|
||||
from = "/latest/*"
|
||||
to = "/v1.11/:splat"
|
||||
to = "/v1.12/:splat"
|
||||
status = 302
|
||||
|
||||
[[redirects]]
|
||||
|
|
Loading…
Reference in New Issue