mirror of https://github.com/crossplane/docs.git
Remove EOL v1.10 docs
Signed-off-by: Pete Lumbis <pete@upbound.io>
This commit is contained in:
parent
0968bbe309
commit
7f443f319d
|
@ -1,24 +0,0 @@
|
|||
---
|
||||
tocHidden: true
|
||||
---
|
||||
# Overview
|
||||
|
||||

|
||||
|
||||
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] into any
|
||||
Kubernetes cluster to get started.
|
||||
|
||||
Crossplane is a [Cloud Native Compute Foundation][cncf] project.
|
||||
|
||||
<!-- Named Links -->
|
||||
|
||||
[Install Crossplane]: getting-started/install-configure.md
|
||||
[cncf]: https://www.cncf.io/
|
|
@ -1,27 +0,0 @@
|
|||
---
|
||||
title: "Overview"
|
||||
weight: -1
|
||||
cascade:
|
||||
version: "1.10"
|
||||
---
|
||||
|
||||
{{< img src="media/banner.png" alt="Crossplane Popsicle Truck" eager=true >}}
|
||||
|
||||
|
||||
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,5 +0,0 @@
|
|||
---
|
||||
title: Crossplane
|
||||
layout: redirect
|
||||
to: "https://doc.crds.dev/github.com/crossplane/crossplane"
|
||||
---
|
|
@ -1,154 +0,0 @@
|
|||
---
|
||||
title: Adding Amazon Web Services (AWS) to Crossplane
|
||||
tocHidden: true
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved in recent versions of Crossplane documentation.
|
||||
|
||||
View the latest
|
||||
[AWS quickstart guide]({{<ref "/v1.11/getting-started/provider-aws" >}}).
|
||||
{{</hint >}}
|
||||
|
||||
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.10/docs/snippets/configure/aws/providerconfig.yaml
|
||||
curl -O https://raw.githubusercontent.com/crossplane/crossplane/release-1.10/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,139 +0,0 @@
|
|||
---
|
||||
title: Adding Microsoft Azure to Crossplane
|
||||
tocHidden: true
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved in recent versions of Crossplane documentation.
|
||||
|
||||
View the latest
|
||||
[Azure quickstart guide]({{<ref "/v1.11/getting-started/provider-azure" >}}).
|
||||
{{</hint >}}
|
||||
|
||||
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 --scopes="/subscriptions/<azure subscription id>" > 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,274 +0,0 @@
|
|||
---
|
||||
title: Adding Google Cloud Platform (GCP) to Crossplane
|
||||
tocHidden: true
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved in recent versions of Crossplane documentation.
|
||||
|
||||
View the latest
|
||||
[GCP quickstart guide]({{<ref "/v1.11/getting-started/provider-gcp" >}}).
|
||||
{{</hint >}}
|
||||
|
||||
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.10/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,55 +0,0 @@
|
|||
---
|
||||
title: Concepts
|
||||
weight: 100
|
||||
---
|
||||
|
||||
Crossplane introduces multiple building blocks that enable you to provision,
|
||||
compose, and consume infrastructure using the Kubernetes API. These individual
|
||||
concepts work together to allow for powerful separation of concern between
|
||||
different personas in an organization, meaning that each member of a team
|
||||
interacts with Crossplane at an appropriate level of abstraction.
|
||||
|
||||
## Packages
|
||||
|
||||
[Packages] allow Crossplane to be extended to include new functionality. This
|
||||
typically looks like bundling a set of Kubernetes [CRDs] and [controllers] that
|
||||
represent and manage external infrastructure (i.e. a provider), then installing
|
||||
them into a cluster where Crossplane is running. Crossplane handles making sure
|
||||
any new CRDs do not conflict with existing ones, as well as manages the RBAC and
|
||||
security of new packages. Packages are not strictly required to be providers,
|
||||
but it is the most common use-case for packages at this time.
|
||||
|
||||
## Providers
|
||||
|
||||
Providers are packages that enable Crossplane to provision infrastructure on an
|
||||
external service. They bring CRDs (i.e. managed resources) that map one-to-one
|
||||
to external infrastructure resources, as well as controllers to manage the
|
||||
life-cycle of those resources. You can read more about providers, including how
|
||||
to install and configure them, in the [providers documentation].
|
||||
|
||||
## Managed Resources
|
||||
|
||||
Managed resources are Kubernetes custom resources that represent infrastructure
|
||||
primitives. Managed resources with an API version of `v1beta1` or higher support
|
||||
every field that the cloud provider does for the given resource. You can find
|
||||
the Managed Resources and their API specifications for each provider on
|
||||
the [Upbound Marketplace] and learn more in the [managed resources documentation].
|
||||
|
||||
## Composite Resources
|
||||
|
||||
A composite resource (XR) is a special kind of custom resource that is defined
|
||||
by a `CompositeResourceDefinition`. It composes one or more managed resources
|
||||
into a higher level infrastructure unit. Composite resources are infrastructure
|
||||
operator facing, but may optionally offer an application developer facing
|
||||
composite resource claim that acts as a proxy for a composite resource. You can
|
||||
learn more about all of these concepts in the [composition documentation].
|
||||
|
||||
<!-- Named Links -->
|
||||
|
||||
[Packages]: {{<ref "packages" >}}
|
||||
[CRDs]: https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/
|
||||
[controllers]: https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#custom-controllers
|
||||
[providers documentation]: {{<ref "providers" >}}
|
||||
[Upbound Marketplace]: https://marketplace.upbound.io
|
||||
[managed resources documentation]: {{<ref "managed-resources" >}}
|
||||
[composition documentation]: {{<ref "composition" >}}
|
|
@ -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,478 +0,0 @@
|
|||
---
|
||||
title: Managed Resources
|
||||
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].
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
## Syntax
|
||||
|
||||
Crossplane API conventions extend the Kubernetes API conventions for the schema
|
||||
of Crossplane managed resources. Following is an example of a managed resource:
|
||||
|
||||
{{< tabs >}}
|
||||
{{< tab "AWS" >}}
|
||||
|
||||
The AWS provider supports provisioning an [RDS][rds] instance via the `RDSInstance`
|
||||
managed resource it adds to Crossplane.
|
||||
|
||||
```yaml
|
||||
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
|
||||
```
|
||||
|
||||
```console
|
||||
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
|
||||
on AWS. You can view the progress with the following command:
|
||||
|
||||
```console
|
||||
kubectl get rdsinstance rdspostgresql
|
||||
```
|
||||
|
||||
When provisioning is complete, you should see `READY: True` in the output. You
|
||||
can take a look at its connection secret that is referenced under
|
||||
`spec.writeConnectionSecretToRef`:
|
||||
|
||||
```console
|
||||
kubectl describe secret aws-rdspostgresql-conn -n crossplane-system
|
||||
```
|
||||
|
||||
You can then delete the `RDSInstance`:
|
||||
|
||||
```console
|
||||
kubectl delete rdsinstance rdspostgresql
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
{{< tab "GCP" >}}
|
||||
|
||||
The GCP provider supports provisioning a [CloudSQL][cloudsql] instance with the
|
||||
`CloudSQLInstance` managed resource it adds to Crossplane.
|
||||
|
||||
```yaml
|
||||
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
|
||||
```
|
||||
|
||||
```console
|
||||
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
|
||||
instance on GCP. You can view the progress with the following command:
|
||||
|
||||
```console
|
||||
kubectl get cloudsqlinstance cloudsqlpostgresql
|
||||
```
|
||||
|
||||
When provisioning is complete, you should see `READY: True` in the output. You
|
||||
can take a look at its connection secret that is referenced under
|
||||
`spec.writeConnectionSecretToRef`:
|
||||
|
||||
```console
|
||||
kubectl describe secret cloudsqlpostgresql-conn -n crossplane-system
|
||||
```
|
||||
|
||||
You can then delete the `CloudSQLInstance`:
|
||||
|
||||
```console
|
||||
kubectl delete cloudsqlinstance cloudsqlpostgresql
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
{{< tab "Azure" >}}
|
||||
|
||||
The Azure provider supports provisioning an [Azure Database for PostgreSQL]
|
||||
instance with the `PostgreSQLServer` managed resource it adds to Crossplane.
|
||||
|
||||
> Note: provisioning an Azure Database for PostgreSQL requires the presence of a
|
||||
> [Resource Group] in your Azure account. We go ahead and provision a new
|
||||
> `ResourceGroup` here in case you do not already have a suitable one in your
|
||||
> account.
|
||||
|
||||
```yaml
|
||||
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: "9.6"
|
||||
sku:
|
||||
tier: GeneralPurpose
|
||||
capacity: 2
|
||||
family: Gen5
|
||||
storageProfile:
|
||||
storageMB: 20480
|
||||
writeConnectionSecretToRef:
|
||||
namespace: crossplane-system
|
||||
name: sqlserverpostgresql-conn
|
||||
```
|
||||
|
||||
```console
|
||||
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
|
||||
database instance on Azure. You can view the progress with the following
|
||||
command:
|
||||
|
||||
```console
|
||||
kubectl get postgresqlserver sqlserverpostgresql
|
||||
```
|
||||
|
||||
When provisioning is complete, you should see `READY: True` in the output. You
|
||||
can take a look at its connection secret that is referenced under
|
||||
`spec.writeConnectionSecretToRef`:
|
||||
|
||||
```console
|
||||
kubectl describe secret sqlserverpostgresql-conn -n crossplane-system
|
||||
```
|
||||
|
||||
You can then delete the `PostgreSQLServer`:
|
||||
|
||||
```console
|
||||
kubectl delete postgresqlserver sqlserverpostgresql
|
||||
kubectl delete resourcegroup sqlserverpostgresql-rg
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
In Kubernetes, `spec` top field represents the desired state of the user.
|
||||
Crossplane adheres to that and has its own conventions about how the fields
|
||||
under `spec` should look like.
|
||||
|
||||
* `writeConnectionSecretToRef`: A reference to the secret that you want this
|
||||
managed resource to write its connection secret that you'd be able to mount to
|
||||
your pods in the same namespace. For `RDSInstance`, this secret would contain
|
||||
`endpoint`, `username` and `password`.
|
||||
|
||||
* `providerConfigRef`: Reference to the `ProviderConfig` resource that will
|
||||
provide information regarding authentication of Crossplane to the provider.
|
||||
`ProviderConfig` resources refer to `Secret` and potentially contain other
|
||||
information regarding authentication. The `providerConfigRef` is defaulted to
|
||||
a `ProviderConfig` named `default` if omitted.
|
||||
|
||||
* `deletionPolicy`: Enum to specify whether the actual cloud resource should be
|
||||
deleted when this managed resource is deleted in Kubernetes API server.
|
||||
Possible values are `Delete` (the default) and `Orphan`.
|
||||
|
||||
* `forProvider`: While the rest of the fields relate to how Crossplane should
|
||||
behave, the fields under `forProvider` are solely used to configure the actual
|
||||
external resource. In most of the cases, the field names correspond to the
|
||||
what exists in provider's API Reference.
|
||||
|
||||
The objects under `forProvider` field can get huge depending on the provider
|
||||
API. For example, GCP `ServiceAccount` has only a few fields while GCP
|
||||
`CloudSQLInstance` has over 100 fields that you can configure.
|
||||
|
||||
### Versioning
|
||||
|
||||
Crossplane closely follows the [Kubernetes API versioning
|
||||
conventions][api-versioning] for the CRDs that it deploys. In short, for
|
||||
`vXbeta` and `vX` versions, you can expect that either automatic migration or
|
||||
instructions for manual migration will be provided when a new version of that
|
||||
CRD schema is released.
|
||||
|
||||
In practice, we suggest the following guidelines to provider developers:
|
||||
* Every new kind has to be introduced as `v1alpha1` with no exception.
|
||||
* Breaking changes require a version change, i.e. `v1alpha1` needs to become
|
||||
`v1alpha2`.
|
||||
* Alpha resources don't require automatic conversions or manual instructions
|
||||
but it's recommended that manual instructions are provided.
|
||||
* Beta resources require at least manual instructions but it's recommended
|
||||
that conversion webhooks are used so that users can upgrade without any
|
||||
hands-on operation.
|
||||
* Stable resources require conversion webhooks.
|
||||
* As long as the developer feels comfortable with the guarantees above, they can
|
||||
bump the version to beta or stable given that the CRD shape adheres to the
|
||||
Crossplane Resource Model (XRM) specifications for managed resources
|
||||
[here][managed-api-patterns].
|
||||
* It's suggested that the bump from Alpha to Beta or from Beta to Stable happen
|
||||
after a bake period which includes at least one release.
|
||||
|
||||
### Grouping
|
||||
|
||||
In general, managed resources are high fidelity resources meaning they will
|
||||
provide parameters and behaviors that are provided by the external resource API.
|
||||
This applies to grouping of resources, too. For example, `Queue` appears under
|
||||
`sqs` API group in AWS,so, its `APIVersion` and `Kind` look like the following:
|
||||
|
||||
```yaml
|
||||
apiVersion: sqs.aws.crossplane.io/v1beta1
|
||||
kind: Queue
|
||||
```
|
||||
|
||||
## Behavior
|
||||
|
||||
As a general rule, managed resource controllers try not to make any decision
|
||||
that is not specified by the user in the desired state since managed resources
|
||||
are the lowest level primitives that operate directly on the cloud provider
|
||||
APIs.
|
||||
|
||||
### Continuous Reconciliation
|
||||
|
||||
Crossplane providers continuously reconcile the managed resource to achieve the
|
||||
desired state. The parameters under `spec` are considered the one and only
|
||||
source of truth for the external resource. This means that if someone changed a
|
||||
configuration in the UI of the provider, like AWS Console, Crossplane will
|
||||
change it back to what's given under `spec`.
|
||||
|
||||
#### Connection Details
|
||||
|
||||
Some Crossplane resources support writing connection details - things like URLs,
|
||||
usernames, endpoints, and passwords to a Kubernetes `Secret`. You can specify
|
||||
the secret to write by setting the `spec.writeConnectionSecretToRef` field. Note
|
||||
that while all managed resources have a `writeConnectionSecretToRef` field, not
|
||||
all managed resources actually have connection details to write - many will
|
||||
write an empty `Secret`.
|
||||
|
||||
> Which managed resources have connection details and what connection details
|
||||
> they have is currently undocumented. This is tracked in [this
|
||||
> issue][issue-1143].
|
||||
|
||||
#### Immutable Properties
|
||||
|
||||
There are configuration parameters in external resources that cloud providers do
|
||||
not allow to be changed. For example, in AWS, you cannot change the region of an
|
||||
`RDSInstance`.
|
||||
|
||||
Some infrastructure tools such as Terraform delete and recreate the resource to
|
||||
accommodate those changes but Crossplane does not take that route. Unless the
|
||||
managed resource is deleted and its `deletionPolicy` is `Delete`, its controller
|
||||
never deletes the external resource in the provider.
|
||||
|
||||
> Kubernetes does not yet support immutable fields for custom resources. This
|
||||
> 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
|
||||
cloud resource that will show up in your cloud console. To specify a different
|
||||
external name, Crossplane has a special annotation to represent the name of the
|
||||
external resource. For example, I would like to have a `CloudSQLInstance` with
|
||||
an external name that is different than its managed resource name:
|
||||
|
||||
```yaml
|
||||
apiVersion: database.gcp.crossplane.io/v1beta1
|
||||
kind: CloudSQLInstance
|
||||
metadata:
|
||||
name: foodb
|
||||
annotations:
|
||||
crossplane.io/external-name: my-special-db
|
||||
spec:
|
||||
...
|
||||
```
|
||||
|
||||
When you create this managed resource, you will see that the name of
|
||||
`CloudSQLInstance` in GCP console will be `my-special-db`.
|
||||
|
||||
If the annotation is not given, Crossplane will fill it with the name of the
|
||||
managed resource by default. In cases where provider doesn't allow you to name
|
||||
the resource, like AWS VPC, the controller creates the resource and sets
|
||||
external annotation to be the name that the cloud provider chose. So, you would
|
||||
see something like `vpc-28dsnh3` as the value of `crossplane.io/external-name`
|
||||
annotation of your AWS `VPC` resource even if you added your own custom external
|
||||
name during creation.
|
||||
|
||||
### Late Initialization
|
||||
|
||||
For some of the optional fields, users rely on the default that the cloud
|
||||
provider chooses for them. Since Crossplane treats the managed resource as the
|
||||
source of the truth, values of those fields need to exist in `spec` of the
|
||||
managed resource. So, in each reconciliation, Crossplane will fill the value of
|
||||
a field that is left empty by the user but is assigned a value by the provider.
|
||||
For example, there could be two fields like `region` and `availabilityZone` and
|
||||
you might want to give only `region` and leave the availability zone to be
|
||||
chosen by the cloud provider. In that case, if the provider assigns an
|
||||
availability zone, Crossplane gets that value and fills `availabilityZone`. Note
|
||||
that if the field is already filled, the controller won't override its value.
|
||||
|
||||
### Deletion
|
||||
|
||||
When a deletion request is made for a managed resource, its controller starts
|
||||
the deletion process immediately. However, the managed resource is kept in the
|
||||
Kubernetes API (via a finalizer) until the controller confirms the external
|
||||
resource in the cloud is gone. So you can be sure that if the managed resource
|
||||
is deleted, then the external cloud resource is also deleted. Any errors that
|
||||
happen during deletion will be added to the `status` of the managed resource, so
|
||||
you can troubleshoot any issues.
|
||||
|
||||
## Dependencies
|
||||
|
||||
In many cases, an external resource refers to another one for a specific
|
||||
configuration. For example, you could want your Azure Kubernetes cluster in a
|
||||
specific Virtual Network. External resources have specific fields for these
|
||||
relations, however, they usually require the information to be supplied in
|
||||
different formats. In Azure MySQL, you might be required to enter only the name
|
||||
of the Virtual Network while in Azure Kubernetes, it could be required to enter
|
||||
a string in a specific format that includes other information such as resource
|
||||
group name.
|
||||
|
||||
In Crossplane, users have 3 fields to refer to another resource. Here is an
|
||||
example from Azure MySQL managed resource referring to an Azure Resource Group:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
forProvider:
|
||||
resourceGroupName: foo-res-group
|
||||
resourceGroupNameRef:
|
||||
name: resourcegroup
|
||||
resourceGroupNameSelector:
|
||||
matchLabels:
|
||||
app: prod
|
||||
```
|
||||
|
||||
In this example, the user provided only a set of labels to select a
|
||||
`ResourceGroup` managed resource that already exists in the cluster via
|
||||
`resourceGroupNameSelector`. Then after a specific `ResourceGroup` is selected,
|
||||
`resourceGroupNameRef` is filled with the name of that `ResourceGroup` managed
|
||||
resource. Then in the last step, Crossplane fills the actual `resourceGroupName`
|
||||
field with whatever format Azure accepts it. Once a dependency is resolved, the
|
||||
controller never changes it.
|
||||
|
||||
Users are able to specify any of these three fields:
|
||||
|
||||
- Selector to select via labels
|
||||
- Reference to point to a determined managed resource
|
||||
- Actual value that will be submitted to the provider
|
||||
|
||||
It's important to note that in case a reference exists, the managed resource
|
||||
does not create the external resource until the referenced object is ready. In
|
||||
this example, creation call of Azure MySQL Server will not be made until
|
||||
referenced `ResourceGroup` has its `status.condition` named `Ready` to be true.
|
||||
|
||||
## Importing Existing Resources
|
||||
|
||||
If you have some resources that are already provisioned in the cloud provider,
|
||||
you can import them as managed resources and let Crossplane manage them. What
|
||||
you need to do is to enter the name of the external resource as well as the
|
||||
required fields on the managed resource. For example, let's say I have a GCP
|
||||
Network provisioned from GCP console and I would like to migrate it to
|
||||
Crossplane. Here is the YAML that I need to create:
|
||||
|
||||
```yaml
|
||||
apiVersion: compute.gcp.crossplane.io/v1beta1
|
||||
kind: Network
|
||||
metadata:
|
||||
name: foo-network
|
||||
annotations:
|
||||
crossplane.io/external-name: existing-network
|
||||
spec:
|
||||
forProvider: {}
|
||||
providerConfigRef:
|
||||
name: default
|
||||
```
|
||||
|
||||
Crossplane will check whether a GCP Network called `existing-network` exists,
|
||||
and if it does, then the optional fields under `forProvider` will be filled with
|
||||
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.
|
||||
|
||||
## Backup and Restore
|
||||
|
||||
Crossplane adheres to Kubernetes conventions as much as possible and one of the
|
||||
advantages we gain is backup & restore ability with tools that work with native
|
||||
Kubernetes types, like [Velero][velero].
|
||||
|
||||
If you'd like to backup and restore manually, you can simply export them and
|
||||
save YAMLs in your file system. When you reload them, as we've discovered in
|
||||
import section, their `crossplane.io/external-name` annotation and required
|
||||
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/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
|
|
@ -1,507 +0,0 @@
|
|||
---
|
||||
title: Crossplane Packages
|
||||
weight: 104
|
||||
---
|
||||
|
||||
Crossplane packages are opinionated [OCI images] that contain a stream of YAML
|
||||
that can be parsed by the Crossplane package manager. Crossplane packages come
|
||||
in two varieties: [Providers] and Configurations. Ultimately, the primary
|
||||
purposes of Crossplane packages are as follows:
|
||||
|
||||
- **Convenient Distribution**: Crossplane packages can be pushed to or installed
|
||||
from any OCI-compatible registry.
|
||||
- **Version Upgrade**: Crossplane can update packages in-place, meaning that you
|
||||
can pick up support for new resource types or controller bug-fixes without
|
||||
modifying your existing infrastructure.
|
||||
- **Permissions**: Crossplane allocates permissions to packaged controllers in a
|
||||
manner that ensures they will not maliciously take over control of existing
|
||||
resources owned by other packages. Installing CRDs via packages also allows
|
||||
Crossplane itself to manage those resources, allowing for powerful
|
||||
[composition] features to be enabled.
|
||||
- **Dependency Management**: Crossplane resolves dependencies between packages,
|
||||
automatically installing a package's dependencies if they are not present in
|
||||
the cluster, and checking if dependency versions are valid if they are already
|
||||
installed.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
The following packaging operations are covered in detail below:
|
||||
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Building a Package](#building-a-package)
|
||||
- [Provider Packages](#provider-packages)
|
||||
- [Configuration Packages](#configuration-packages)
|
||||
- [Pushing a Package](#pushing-a-package)
|
||||
- [Installing a Package](#installing-a-package)
|
||||
- [spec.package](#specpackage)
|
||||
- [spec.packagePullPolicy](#specpackagepullpolicy)
|
||||
- [spec.revisionActivationPolicy](#specrevisionactivationpolicy)
|
||||
- [spec.revisionHistoryLimit](#specrevisionhistorylimit)
|
||||
- [spec.packagePullSecrets](#specpackagepullsecrets)
|
||||
- [spec.skipDependencyResolution](#specskipdependencyresolution)
|
||||
- [spec.ignoreCrossplaneConstraints](#specignorecrossplaneconstraints)
|
||||
- [spec.controllerConfigRef](#speccontrollerconfigref)
|
||||
- [Upgrading a Package](#upgrading-a-package)
|
||||
- [Package Upgrade Issues](#package-upgrade-issues)
|
||||
- [The Package Cache](#the-package-cache)
|
||||
- [Pre-Populating the Package Cache](#pre-populating-the-package-cache)
|
||||
|
||||
## Building a Package
|
||||
|
||||
As stated above, Crossplane packages are just opinionated OCI images, meaning
|
||||
they can be constructed using any tool that outputs files that comply the the
|
||||
OCI specification. However, constructing packages using the Crossplane CLI is a
|
||||
more streamlined experience, as it will perform build-time checks on your
|
||||
packages to ensure that they are compliant with the Crossplane [package format].
|
||||
|
||||
Providers and Configurations vary in the types of resources they may contain in
|
||||
their packages. All packages must have a `crossplane.yaml` file in the root
|
||||
directory with package contents. The `crossplane.yaml` contains the package's
|
||||
metadata, which governs how Crossplane will install the package.
|
||||
|
||||
### Provider Packages
|
||||
|
||||
A Provider package contains a `crossplane.yaml` with the following format:
|
||||
|
||||
```yaml
|
||||
apiVersion: meta.pkg.crossplane.io/v1
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: provider-gcp
|
||||
spec:
|
||||
crossplane:
|
||||
version: ">=v1.0.0"
|
||||
controller:
|
||||
image: crossplane/provider-gcp-controller:v0.14.0
|
||||
permissionRequests:
|
||||
- apiGroups:
|
||||
- apiextensions.crossplane.io
|
||||
resources:
|
||||
- compositions
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- create
|
||||
- update
|
||||
- patch
|
||||
- watch
|
||||
```
|
||||
|
||||
See all available fields in the [official documentation][provider-docs].
|
||||
|
||||
> Note: The `meta.pkg.crossplane.io` group does not contain custom resources
|
||||
> that may be installed into the cluster. They are strictly used as metadata in
|
||||
> a Crossplane package.
|
||||
|
||||
A Provider package may optionally contain one or more CRDs. These CRDs will be
|
||||
installed prior to the creation of the Provider's `Deployment`. Crossplane will
|
||||
not install _any_ CRDs for a package unless it can determine that _all_ CRDs can
|
||||
be installed. This guards against multiple Providers attempting to reconcile the
|
||||
same CRDs. Crossplane will also create a `ServiceAccount` with permissions to
|
||||
reconcile these CRDs and it will be assigned to the controller `Deployment`.
|
||||
|
||||
The `spec.controller.image` fields specifies that the `Provider` desires for the
|
||||
controller `Deployment` to be created with the provided image. It is important
|
||||
to note that this image is separate from the package image itself. In the case
|
||||
above, it is an image containing the `provider-gcp` controller binary.
|
||||
|
||||
The `spec.controller.permissionRequests` field allows a package author to
|
||||
request additional RBAC for the packaged controller. The controller's
|
||||
`ServiceAccount` will automatically give the controller permission to reconcile
|
||||
all types that its package installs, as well as `Secrets`, `ConfigMaps`, and
|
||||
`Events`. Any additional permissions must be explicitly requested.
|
||||
|
||||
> Note that the Crossplane RBAC manager can be configured to reject permissions
|
||||
> for certain API groups. If a package requests permissions that Crossplane is
|
||||
> configured to reject, the package will fail to be installed.
|
||||
> Authorized permissions should be aggregated to the rbac manager clusterrole
|
||||
> (the cluster role defined by the provider-clusterrole flag in the rbac manager)
|
||||
> by using the label `rbac.crossplane.io/aggregate-to-allowed-provider-permissions: "true"`
|
||||
|
||||
The `spec.crossplane.version` field specifies the version constraints for core
|
||||
Crossplane that the `Provider` is compatible with. It is advisable to use this
|
||||
field if a package relies on specific features in a minimum version of
|
||||
Crossplane.
|
||||
|
||||
> All version constraints used in packages follow the [specification] outlined
|
||||
> in the `Masterminds/semver` repository.
|
||||
|
||||
For an example Provider package, see [provider-gcp].
|
||||
|
||||
To build a Provider package, navigate to the package root directory and execute
|
||||
the following command:
|
||||
|
||||
```
|
||||
kubectl crossplane build provider
|
||||
```
|
||||
|
||||
If the Provider package is valid, you will see a file with the `.xpkg`
|
||||
extension.
|
||||
|
||||
> Note that the Crossplane CLI will not follow symbolic links for files in the
|
||||
> root package directory.
|
||||
|
||||
### Configuration Packages
|
||||
|
||||
A Configuration package contains a `crossplane.yaml` with the following format:
|
||||
|
||||
```yaml
|
||||
apiVersion: meta.pkg.crossplane.io/v1
|
||||
kind: Configuration
|
||||
metadata:
|
||||
name: my-org-infra
|
||||
spec:
|
||||
crossplane:
|
||||
version: ">=v1.0.0"
|
||||
dependsOn:
|
||||
- provider: xpkg.upbound.io/crossplane-contrib/provider-gcp
|
||||
version: ">=v0.14.0"
|
||||
```
|
||||
|
||||
See all available fields in the [official documentation][configuration-docs].
|
||||
|
||||
A Configuration package may also specify one or more of
|
||||
`CompositeResourceDefinition` and `Composition` types. These resources will be
|
||||
installed and will be solely owned by the Configuration package. No other
|
||||
package will be able to modify them.
|
||||
|
||||
The `spec.crossplane.version` field serves the same purpose that it does in a
|
||||
`Provider` package.
|
||||
|
||||
The `spec.dependsOn` field specifies packages that this package depends on. When
|
||||
installed, the package manager will ensure that all dependencies are present and
|
||||
have a valid version given the constraint. If a dependency is not installed, the
|
||||
package manager will install it at the latest version that fits within the
|
||||
provided constraints.
|
||||
|
||||
> Dependency resolution is a `beta` feature and depends on the `v1beta1`
|
||||
> [`Lock` API][lock-api].
|
||||
|
||||
For an example Configuration package, see [getting-started-with-gcp](https://github.com/crossplane/docs/tree/master/content/v1.10/snippets/package/gcp).
|
||||
|
||||
To build a Configuration package, navigate to the package root directory and
|
||||
execute the following command:
|
||||
|
||||
```
|
||||
kubectl crossplane build configuration
|
||||
```
|
||||
|
||||
If the Provider package is valid, you will see a file with the `.xpkg`
|
||||
extension.
|
||||
|
||||
## Pushing a Package
|
||||
|
||||
Crossplane packages can be pushed to any OCI-compatible registry. If a specific
|
||||
registry is not specified they will be pushed to Docker Hub.
|
||||
|
||||
To push a Provider package, execute the following command:
|
||||
|
||||
```
|
||||
kubectl crossplane push provider xpkg.upbound.io/crossplane-contrib/provider-gcp:v0.22.0
|
||||
```
|
||||
|
||||
To push a Configuration package, execute the following command:
|
||||
|
||||
```
|
||||
kubectl crossplane push configuration xpkg.upbound.io/crossplane-contrib/my-org-infra:v0.1.0
|
||||
```
|
||||
|
||||
> Note: Both of the above commands assume a single `.xpkg` file exists in the
|
||||
> directory. If multiple exist or you would like to specify a package in a
|
||||
> different directory, you can supply the `-f` flag with the path to the
|
||||
> package.
|
||||
|
||||
## Installing a Package
|
||||
|
||||
Packages can be installed into a Crossplane cluster using the Crossplane CLI.
|
||||
|
||||
To install a Provider package, execute the following command:
|
||||
|
||||
```
|
||||
kubectl crossplane install provider xpkg.upbound.io/crossplane-contrib/provider-gcp:v0.22.0
|
||||
```
|
||||
|
||||
To install a Configuration package, execute the following command:
|
||||
|
||||
```
|
||||
kubectl crossplane install configuration xpkg.upbound.io/crossplane-contrib/my-org-infra:v0.1.0
|
||||
```
|
||||
|
||||
Packages can also be installed manually by creating a `Provider` or
|
||||
`Configuration` object directly. The preceding commands would result in the
|
||||
creation of the following two resources, which could have been authored by hand:
|
||||
|
||||
```yaml
|
||||
apiVersion: pkg.crossplane.io/v1
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: provider-gcp
|
||||
spec:
|
||||
package: xpkg.upbound.io/crossplane-contrib/provider-gcp:v0.22.0
|
||||
packagePullPolicy: IfNotPresent
|
||||
revisionActivationPolicy: Automatic
|
||||
revisionHistoryLimit: 1
|
||||
```
|
||||
|
||||
```yaml
|
||||
apiVersion: pkg.crossplane.io/v1
|
||||
kind: Configuration
|
||||
metadata:
|
||||
name: my-org-infra
|
||||
spec:
|
||||
package: xpkg.upbound.io/crossplane-contrib/my-org-infra:v0.1.0
|
||||
packagePullPolicy: IfNotPresent
|
||||
revisionActivationPolicy: Automatic
|
||||
revisionHistoryLimit: 1
|
||||
```
|
||||
|
||||
> Note: These types differ from the `Provider` and `Configuration` types we saw
|
||||
> earlier. They exist in the `pkg.crossplane.io` group rather than the
|
||||
> `meta.pkg.crossplane.io` group and are actual custom resources created in the
|
||||
> cluster.
|
||||
|
||||
The default fields specified above can be configured with different values to
|
||||
modify the installation and upgrade behavior of a package. In addition, there
|
||||
are multiple other fields which can further customize how the package manager
|
||||
handles a specific revision.
|
||||
|
||||
### spec.package
|
||||
|
||||
This is the package image that we built, pushed, and are asking Crossplane to
|
||||
install. The tag we specify here is important. Crossplane will periodically
|
||||
check if the installed image matches the digest of the image in the remote
|
||||
registry. If it does not, Crossplane will create a new _Revision_ (either
|
||||
`ProviderRevision` or `ConfigurationRevision`). If you do not wish Crossplane to
|
||||
ever update your packages without explicitly instructing it to do so, you should
|
||||
consider specifying a tag which you know will not have the underlying contents
|
||||
change unexpectedly (e.g. a specific semantic version, such as `v0.1.0`) or, for
|
||||
an even stronger guarantee, providing the image with a `@sha256` extension
|
||||
instead of a tag.
|
||||
|
||||
### spec.packagePullPolicy
|
||||
|
||||
Valid values: `IfNotPresent`, `Always`, or `Never` (default: `IfNotPresent`)
|
||||
|
||||
When a package is installed, Crossplane downloads the image contents into a
|
||||
cache. Depending on the image identifier (tag or digest) and the
|
||||
`packagePullPolicy`, the Crossplane package manager will decide if and when to
|
||||
check and see if newer package contents are available. The following table
|
||||
describes expected behavior based on the supplied fields:
|
||||
|
||||
| | `IfNotPresent` | `Always` | `Never` |
|
||||
|---------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------|
|
||||
| Semver Tag (e.g. `v1.3.0`) | Package is downloaded when initially installed, and as long as it is present in the cache, it will not be downloaded again. If the cache is lost and the a new version of the package image has been pushed for the same tag, package could inadvertently be upgraded. <br><br> **Upgrade Safety: Strong** | Package is downloaded when initially installed, but Crossplane will check every minute if new content is available. New content would have to be pushed for the same semver tag for upgrade to take place. <br><br> **Upgrade Safety: Weak** | Crossplane will never download content. Must manually load package image in cache. <br><br> **Upgrade Safety: Strongest** |
|
||||
| Digest (e.g. `@sha256:28b6...`) | Package is downloaded when initially installed, and as long as it is present in the cache, it will not be downloaded again. If the cache is lost but an image with this digest is still available, it will be downloaded again. The package will never be upgraded without a user changing the digest. <br><br> **Upgrade Safety: Very Strong** | Package is downloaded when initially installed, but Crossplane will check every minute if new content is available. Because image digest is used, new content will never be downloaded. <br><br> **Upgrade Safety: Strong** | Crossplane will never download content. Must manually load package image in cache. <br><br> **Upgrade Safety: Strongest** |
|
||||
| Channel Tag (e.g. `latest`) | Package is downloaded when initially installed, and as long as it is present in the cache, it will not be downloaded again. If the cache is lost, the latest version of this package image will be downloaded again, which will frequently have different contents. <br><br> **Upgrade Safety: Weak** | Package is downloaded when initially installed, but Crossplane will check every minute if new content is available. When the image content is new, Crossplane will download the new contents and create a new revision. <br><br> **Upgrade Safety: Very Weak** | Crossplane will never download content. Must manually load package image in cache. <br><br> **Upgrade Safety: Strongest** |
|
||||
|
||||
### spec.revisionActivationPolicy
|
||||
|
||||
Valid values: `Automatic` or `Manual` (default: `Automatic`)
|
||||
|
||||
When Crossplane downloads new contents for a package, regardless of whether it
|
||||
was a manual upgrade (i.e. user updating package image tag), or an automatic one
|
||||
(enabled by the `packagePullPolicy`), it will create a new package revision.
|
||||
However, the new objects and / or controllers will not be installed until the
|
||||
new revision is marked as `Active`. This activation process is configured by the
|
||||
`revisionActivationPolicy` field.
|
||||
|
||||
An `Active` package revision attempts to become the _controller_ of all
|
||||
resources it installs. There can only be one controller of a resource, so if two
|
||||
`Active` revisions both install the same resource, one will fail to install
|
||||
until the other cedes control.
|
||||
|
||||
An `Inactive` package revision attempts to become the _owner_ of all resources
|
||||
it installs. There can be an arbitrary number of owners of a resource, so
|
||||
multiple `Inactive` revisions and a single `Active` revision can exist for a
|
||||
resource. Importantly, an `Inactive` package revision will not perform any
|
||||
auxiliary actions (such as creating a `Deployment` in the case of a `Provider`),
|
||||
meaning we will not encounter a situation where two revisions are fighting over
|
||||
reconciling a resource.
|
||||
|
||||
With `revisionActivationPolicy: Automatic`, Crossplane will mark any new
|
||||
revision as `Active` when it is created, as well as transition any old revisions
|
||||
to `Inactive`. When `revisionActivationPolicy: Manual`, the user must manually
|
||||
edit a new revision and mark it as `Active`. This can be useful if you are using
|
||||
a `packagePullPolicy: Automatic` with a channel tag (e.g. `latest`) and you want
|
||||
Crossplane to create new revisions when a new version is available, but you
|
||||
don't want to automatically update to that newer revision.
|
||||
|
||||
It is recommended for most users to use semver tags or image digests and
|
||||
manually update their packages, but use a `revisionActivationPolicy: Automatic`
|
||||
to avoid having to manually activate new versions. However, each user should
|
||||
consider their specific environment and choose a combination that makes sense
|
||||
for them.
|
||||
|
||||
For security reasons, it's suggested using image digests instead or alongside
|
||||
tags (`vx.y.z@sha256:...`), to ensure that the package content wasn't tampered
|
||||
with.
|
||||
|
||||
### spec.revisionHistoryLimit
|
||||
|
||||
Valid values: any integer, disabled by explicitly setting to `0` (default `1`)
|
||||
|
||||
When a revision transitions from `Inactive` to `Active`, its revision number
|
||||
gets set to one greater than the largest revision number of all revisions for
|
||||
its package. Therefore, as the number of revisions increases, the least recently
|
||||
`Active` revision will have the lowest revision number. Crossplane will garbage
|
||||
collect old `Inactive` revisions if they fall outside the
|
||||
`spec.revisionHistoryLimit`. For instance, if my revision history limit is `3`
|
||||
and I currently have three old `Inactive` revisions and one `Active` revision,
|
||||
when I upgrade the next time, the new revision will be given the highest
|
||||
revision number when it becomes `Active`, the previously `Active` revision will
|
||||
become `Inactive`, and the oldest `Inactive` revision will be garbage collected.
|
||||
|
||||
> Note: In the case that `spec.revisionActivationPolicy: Manual` and you upgrade
|
||||
> enough times (but do not make `Active` the new revisions), it is possible that
|
||||
> activating a newer revision could cause the previously `Active` revision to
|
||||
> immediately be garbage collected if it is outside the
|
||||
> `spec.revisionHistoryLimit`.
|
||||
|
||||
### spec.packagePullSecrets
|
||||
|
||||
Valid values: slice of `Secret` names (secrets must exist in `namespace`
|
||||
Crossplane was installed in, typically `crossplane-system`)
|
||||
|
||||
This field allows a user to provide credentials required to pull a package from
|
||||
a private repository on a registry. The credentials are passed along to a
|
||||
packaged controller if the package is a `Provider`, but are not passed along to
|
||||
any dependencies.
|
||||
|
||||
### spec.skipDependencyResolution
|
||||
|
||||
Valid values: `true` or `false` (default: `false`)
|
||||
|
||||
If `skipDependencyResolution: true`, the package manager will install a package
|
||||
without considering its dependencies.
|
||||
|
||||
### spec.ignoreCrossplaneConstraints
|
||||
|
||||
Valid values: `true` or `false` (default: `false`)
|
||||
|
||||
If `ignoreCrossplaneConstraints: true`, the package manager will install a
|
||||
package without considering the version of Crossplane that is installed.
|
||||
|
||||
### spec.controllerConfigRef
|
||||
|
||||
> This field is only available when installing a `Provider` and is an `alpha`
|
||||
> feature that depends on the `v1alpha1` [`ControllerConfig` API][controller-config-docs].
|
||||
|
||||
Valid values: name of a `ControllerConfig` object
|
||||
|
||||
Packaged `Provider` controllers are installed in the form of a `Deployment`.
|
||||
Crossplane populates the `Deployment` with default values that may not be
|
||||
appropriate for every use-case. In the event that a user wants to override some
|
||||
of the defaults that Crossplane has set, they may create and reference a
|
||||
`ControllerConfig`.
|
||||
|
||||
An example of when this may be useful is when a user is running Crossplane on
|
||||
EKS and wants to take advantage of [IAM Roles for Service Accounts]. This
|
||||
requires setting an `fsGroup` and annotating the `ServiceAccount` that
|
||||
Crossplane creates for the controller. This could be accomplished with the
|
||||
following `ControllerConfig` and `Provider`:
|
||||
|
||||
```yaml
|
||||
apiVersion: pkg.crossplane.io/v1alpha1
|
||||
kind: ControllerConfig
|
||||
metadata:
|
||||
name: aws-config
|
||||
annotations:
|
||||
eks.amazonaws.com/role-arn: arn:aws:iam::$AWS_ACCOUNT_ID\:role/$IAM_ROLE_NAME
|
||||
spec:
|
||||
podSecurityContext:
|
||||
fsGroup: 2000
|
||||
---
|
||||
apiVersion: pkg.crossplane.io/v1
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: provider-aws
|
||||
spec:
|
||||
package: xpkg.upbound.io/crossplane-contrib/provider-aws:v0.33.0
|
||||
controllerConfigRef:
|
||||
name: aws-config
|
||||
```
|
||||
|
||||
You can find all configurable values in the [official `ControllerConfig`
|
||||
documentation][controller-config-docs].
|
||||
|
||||
## Upgrading a Package
|
||||
|
||||
Upgrading a `Provider` or `Configuration` to a new version can be accomplished
|
||||
by editing the existing manifest and applying it with a new version tag in
|
||||
`spec.package`. Crossplane will observe the updated manifest and create a new
|
||||
`ProviderRevision` or `ConfigurationRevision` for the specified version. The new
|
||||
revision will be activated in accordance with `spec.revisionActivationPolicy`.
|
||||
|
||||
### Package Upgrade Issues
|
||||
|
||||
Upgrading a package can require manual intervention in the event that the
|
||||
previous version of the package supported a version of a custom resource that
|
||||
has been dropped and replaced by a new version in the new package revision.
|
||||
Kubernetes does not allow for applying a `CustomResourceDefinition` (CRD) that
|
||||
drops a version in the `spec` that is in the current `status.storedVersions`
|
||||
list, meaning that a revision cannot update and become the _controller_ of all
|
||||
of its resources.
|
||||
|
||||
This situation can be remedied by manually deleting the offending CRD and
|
||||
letting the new revision re-create it. In the event that custom resources exist
|
||||
for the given CRD, they must be deleted before the CRD can be removed.
|
||||
|
||||
## The Package Cache
|
||||
|
||||
When a package is installed into a cluster, Crossplane fetches the package image
|
||||
and stores its contents in a dedicated package cache. By default, this cache is
|
||||
backed by an [`emptyDir` Volume][emptyDir-volume], meaning that all cached data
|
||||
is lost when a `Pod` restarts. Users who wish for cache contents to be persisted
|
||||
between `Pod` restarts may opt to instead use a [`persistentVolumeClaim`
|
||||
(PVC)][pvc] by setting the `packageCache.pvc` Helm chart parameter to the name
|
||||
of the PVC.
|
||||
|
||||
### Pre-Populating the Package Cache
|
||||
|
||||
Because the package cache can be backed by any storage medium, users are able to
|
||||
optionally to pre-populate the cache with images that are not present on an
|
||||
external [OCI registry]. To utilize a package that has been manually stored in
|
||||
the cache, users must specify the name of the package in `spec.package` and use
|
||||
`packagePullPolicy: Never`. For instance, if a user built a `Configuration`
|
||||
package named `mycoolpkg.xpkg` and loaded it into the volume that was to be used
|
||||
for the package cache (i.e. copied the `.xpkg` file into the storage medium
|
||||
backing the PVC), the package could be utilized with the following manifest:
|
||||
|
||||
```yaml
|
||||
apiVersion: pkg.crossplane.io/v1
|
||||
kind: Configuration
|
||||
metadata:
|
||||
name: my-cool-pkg
|
||||
spec:
|
||||
package: mycoolpkg
|
||||
packagePullPolicy: Never
|
||||
```
|
||||
|
||||
Importantly, as long as a package is being used as the `spec.package` of a
|
||||
`Configuration` or `Provider`, it must remain in the cache. For this reason, it
|
||||
is recommended that users opt for a durable storage medium when manually loading
|
||||
packages into the cache.
|
||||
|
||||
In addition, if manually loading a `Provider` package into the cache, users must
|
||||
ensure that the controller image that it references is able to be pulled by the
|
||||
cluster nodes. This can be accomplished either by pushing it to a registry, or
|
||||
by [pre-pulling images] onto nodes in the cluster.
|
||||
|
||||
|
||||
<!-- Named Links -->
|
||||
|
||||
[OCI images]: https://github.com/opencontainers/image-spec
|
||||
[Providers]: {{<ref "providers" >}}
|
||||
[provider-docs]: https://doc.crds.dev/github.com/crossplane/crossplane/meta.pkg.crossplane.io/Provider/v1
|
||||
[configuration-docs]: https://doc.crds.dev/github.com/crossplane/crossplane/meta.pkg.crossplane.io/Configuration/v1
|
||||
[lock-api]: https://doc.crds.dev/github.com/crossplane/crossplane/pkg.crossplane.io/Lock/v1beta1
|
||||
[specification]: https://github.com/Masterminds/semver#basic-comparisons
|
||||
[composition]: {{<ref "composition" >}}
|
||||
[IAM Roles for Service Accounts]: https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html
|
||||
[controller-config-docs]: https://doc.crds.dev/github.com/crossplane/crossplane/pkg.crossplane.io/ControllerConfig/v1alpha1
|
||||
[package format]: https://github.com/crossplane/crossplane/blob/1aa83092172bdf0d2ed64754d33517c612ff7368/design/one-pager-package-format-v2.md
|
||||
[provider-gcp]: https://doc.crds.dev/github.com/crossplane/crossplane/meta.pkg.crossplane.io/Provider/v1
|
||||
[emptyDir-volume]: https://kubernetes.io/docs/concepts/storage/volumes/#emptydir
|
||||
[pvc]: https://kubernetes.io/docs/concepts/storage/volumes/#persistentvolumeclaim
|
||||
[OCI registry]: https://github.com/opencontainers/distribution-spec
|
||||
[pre-pulling images]: https://kubernetes.io/docs/concepts/containers/images/#pre-pulled-images
|
|
@ -1,407 +0,0 @@
|
|||
---
|
||||
title: Providers
|
||||
weight: 101
|
||||
---
|
||||
|
||||
Providers enable Crossplane to provision infrastructure on an
|
||||
external service. Providers create new Kubernetes APIs and map them to external
|
||||
APIs.
|
||||
|
||||
Providers are responsible for all aspects of connecting to non-Kubernetes
|
||||
resources. This includes authentication, making external API calls and
|
||||
providing
|
||||
[Kubernetes Controller](https://kubernetes.io/docs/concepts/architecture/controller/)
|
||||
logic for any external resources.
|
||||
|
||||
Examples of providers include:
|
||||
* [Provider AWS](https://github.com/upbound/provider-aws)
|
||||
* [Provider Azure](https://github.com/upbound/provider-azure)
|
||||
* [Provider GCP](https://github.com/upbound/provider-gcp)
|
||||
* [Provider Kubernetes](https://github.com/crossplane-contrib/provider-kubernetes)
|
||||
|
||||
{{< hint "tip" >}}
|
||||
Find more providers in the [Upbound Marketplace](https://marketplace.upbound.io).
|
||||
{{< /hint >}}
|
||||
|
||||
<!-- vale write-good.Passive = NO -->
|
||||
<!-- "are Managed" isn't passive in this context -->
|
||||
Providers define every external resource they can create in Kubernetes as a
|
||||
Kubernetes API endpoint. These endpoints are
|
||||
[_Managed Resources_]({{<ref "managed-resources" >}}).
|
||||
<!-- vale write-good.Passive = YES -->
|
||||
|
||||
{{< hint "note" >}}
|
||||
Instructions on building your own Provider are outside of the scope of this
|
||||
document. Read the Crossplane contributing [Provider Development
|
||||
Guide](https://github.com/crossplane/crossplane/blob/master/contributing/guide-provider-development.md)
|
||||
for more information.
|
||||
{{< /hint >}}
|
||||
|
||||
## Install a Provider
|
||||
|
||||
Installing a provider creates a Provider pod that's responsible for installing
|
||||
the Provider's APIs into the Kubernetes cluster. Providers constantly watch the
|
||||
state of the desired managed resources and create any external resources that
|
||||
are missing.
|
||||
|
||||
Install a Provider with a Crossplane
|
||||
{{<hover label="install" line="2">}}Provider{{</hover >}} object setting the
|
||||
{{<hover label="install" line="6">}}spec.package{{</hover >}} value to the
|
||||
location of the provider package.
|
||||
|
||||
For example, to install the
|
||||
[AWS Community Provider](https://github.com/crossplane-contrib/provider-aws),
|
||||
|
||||
```yaml {label="install"}
|
||||
apiVersion: pkg.crossplane.io/v1
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: provider-aws
|
||||
spec:
|
||||
package: xpkg.upbound.io/crossplane-contrib/provider-aws:v0.39.0
|
||||
```
|
||||
|
||||
{{< hint "tip" >}}
|
||||
Providers are Crossplane Packages. Read more about Packages in the
|
||||
[Packages documentation]({{<ref "packages" >}}).
|
||||
{{< /hint >}}
|
||||
|
||||
By default, the Provider pod installs in the same namespace as Crossplane
|
||||
(`crossplane-system`).
|
||||
|
||||
### Install with Helm
|
||||
|
||||
Crossplane supports installing Providers during an initial Crossplane
|
||||
installation with the Crossplane Helm chart.
|
||||
|
||||
Use the
|
||||
{{<hover label="helm" line="5" >}}--set provider.packages{{</hover >}}
|
||||
argument with `helm install`.
|
||||
|
||||
For example, to install the AWS Community Provider,
|
||||
|
||||
```shell {label="helm"}
|
||||
helm install crossplane \
|
||||
crossplane-stable/crossplane \
|
||||
--namespace crossplane-system \
|
||||
--create-namespace \
|
||||
--set provider.packages={xpkg.upbound.io/crossplane-contrib/provider-aws:v0.39.0}
|
||||
```
|
||||
|
||||
### Install from a private repository
|
||||
|
||||
Installing a Provider from a private package repository requires a
|
||||
Kubernetes secret object. The Provider uses the secret with the
|
||||
{{<hover label="pps" line="7" >}}packagePullSecrets{{</hover>}} option.
|
||||
|
||||
```yaml {label="pps"}
|
||||
apiVersion: pkg.crossplane.io/v1
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: private-provider
|
||||
spec:
|
||||
package: private-repo.example.org/providers/my-provider
|
||||
packagePullSecrets:
|
||||
- name: my-secret
|
||||
```
|
||||
|
||||
{{< hint "note" >}}
|
||||
The Kubernetes secret object the Provider uses must be in the same namespace as
|
||||
the Crossplane pod.
|
||||
{{< /hint >}}
|
||||
|
||||
## Upgrade a Provider
|
||||
|
||||
To upgrade an existing Provider edit the installed Provider Package by either
|
||||
applying a new Provider manifest or with `kubectl edit providers`.
|
||||
|
||||
Update the version number in the Provider's `spec.package` and apply the change.
|
||||
Crossplane installs the new image and creates a new `ProviderRevision`.
|
||||
|
||||
## Remove a Provider
|
||||
|
||||
Remove a Provider by deleting the Provider object with `kubectl delete
|
||||
provider`.
|
||||
|
||||
{{< hint "warning" >}}
|
||||
Removing a Provider without first removing the Provider's managed resources
|
||||
may abandon the resources. The external resources aren't deleted.
|
||||
|
||||
If you remove the Provider first, you must manually delete external resources
|
||||
through your cloud provider. Managed resources must be manually deleted by
|
||||
removing their finalizers.
|
||||
|
||||
For more information on deleting abandoned resources read the [Crossplane
|
||||
troubleshooting guide]({{<ref "/knowledge-base/guides/troubleshoot#deleting-when-a-resource-hangs" >}}).
|
||||
{{< /hint >}}
|
||||
|
||||
## Verify a Provider
|
||||
|
||||
Providers install their own APIs representing the managed resources they support.
|
||||
Providers may also create Deployments, Service Accounts or RBAC configuration.
|
||||
|
||||
View the status of a Provider with
|
||||
|
||||
`kubectl get providers`
|
||||
|
||||
During the install a Provider report `INSTALLED` as `True` and `HEALTHY` as
|
||||
`Unknown`.
|
||||
|
||||
```shell
|
||||
kubectl get providers
|
||||
NAME INSTALLED HEALTHY PACKAGE AGE
|
||||
crossplane-contrib-provider-aws True Unknown xpkg.upbound.io/crossplane-contrib/provider-aws:v0.39.0 63s
|
||||
```
|
||||
|
||||
After the Provider install completes and it's ready for use the `HEALTHY` status
|
||||
reports `True`.
|
||||
|
||||
```shell
|
||||
kubectl get providers
|
||||
NAME INSTALLED HEALTHY PACKAGE AGE
|
||||
crossplane-contrib-provider-aws True True xpkg.upbound.io/crossplane-contrib/provider-aws:v0.39.0 88s
|
||||
```
|
||||
|
||||
{{<hint "important" >}}
|
||||
Some Providers install hundreds of Kubernetes Custom Resource Definitions (`CRDs`).
|
||||
This can create significant strain on undersized API Servers, impacting Provider
|
||||
install times.
|
||||
|
||||
The Crossplane community has more
|
||||
[details on scaling CRDs](https://github.com/crossplane/crossplane/blob/master/design/one-pager-crd-scaling.md).
|
||||
{{< /hint >}}
|
||||
### Provider conditions
|
||||
|
||||
View the conditions of a provider under their `Status` with
|
||||
`kubectl describe provider`.
|
||||
|
||||
Providers have the following possible conditions:
|
||||
|
||||
<!-- vale Google.Headings = NO -->
|
||||
#### InactivePackageRevision
|
||||
<!-- vale Google.Headings = YES -->
|
||||
```yaml
|
||||
Type: Installed
|
||||
Status: False
|
||||
Reason: InactivePackageRevision
|
||||
```
|
||||
|
||||
The Provider Package is using an inactive Provider Package Revision.
|
||||
|
||||
<!-- vale Google.Headings = NO -->
|
||||
#### ActivePackageRevision
|
||||
<!-- vale Google.Headings = YES -->
|
||||
```yaml
|
||||
Type: Installed
|
||||
Status: True
|
||||
Reason: ActivePackageRevision
|
||||
```
|
||||
|
||||
The Provider Package is the current Package Revision, but Crossplane hasn't
|
||||
finished installing the Package Revision yet.
|
||||
|
||||
{{< hint "tip" >}}
|
||||
Providers stuck in this state are because of a problem with Package Revisions.
|
||||
|
||||
Use `kubectl describe providerrevisions` for more details.
|
||||
{{< /hint >}}
|
||||
|
||||
<!-- vale Google.Headings = NO -->
|
||||
#### HealthyPackageRevision
|
||||
<!-- vale Google.Headings = YES -->
|
||||
```yaml
|
||||
Type: Healthy
|
||||
Status: True
|
||||
Reason: HealthyPackageRevision
|
||||
```
|
||||
|
||||
The Provider is fully installed and ready to use.
|
||||
|
||||
|
||||
<!-- vale Google.Headings = NO -->
|
||||
#### UnhealthyPackageRevision
|
||||
<!-- vale Google.Headings = YES -->
|
||||
|
||||
```yaml
|
||||
Type: Healthy
|
||||
Status: False
|
||||
Reason: UnhealthyPackageRevision
|
||||
```
|
||||
|
||||
There was an error installing the Provider Package Revision, preventing
|
||||
Crossplane from installing the Provider Package.
|
||||
|
||||
{{<hint "tip" >}}
|
||||
Use `kubectl describe providerrevisions` for more details on why the Package
|
||||
Revision failed.
|
||||
{{< /hint >}}
|
||||
|
||||
<!-- vale Google.Headings = NO -->
|
||||
#### UnknownPackageRevisionHealth
|
||||
<!-- vale Google.Headings = YES -->
|
||||
```yaml
|
||||
Type: Healthy
|
||||
Status: Unknown
|
||||
Reason: UnknownPackageRevisionHealth
|
||||
```
|
||||
|
||||
The status of the Provider Package Revision is `Unknown`. The Provider Package
|
||||
Revision may be installing or has an issue.
|
||||
|
||||
{{<hint "tip" >}}
|
||||
Use `kubectl describe providerrevisions` for more details on why the Package
|
||||
Revision failed.
|
||||
{{< /hint >}}
|
||||
|
||||
## Configure a Provider
|
||||
|
||||
Providers have two different types of configurations:
|
||||
* _Controller configurations_ that change the settings of the Provider pod
|
||||
running inside the Kubernetes cluster. For example, Pod `toleration`.
|
||||
* _Provider configurations_ that change settings used when communicating with
|
||||
an external provider. For example, cloud provider authentication.
|
||||
|
||||
{{<hint "important" >}}
|
||||
Apply `ControllerConfig` objects to Providers.
|
||||
|
||||
Apply `ProviderConfig` objects to managed resources.
|
||||
{{< /hint >}}
|
||||
|
||||
### Controller configuration
|
||||
{{< hint "important" >}}
|
||||
The Crossplane community deprecated the `ControllerConfig` type in v1.11.
|
||||
Applying a Controller configuration generates a deprecation warning.
|
||||
|
||||
Controller configurations are still supported until there is a replacement type
|
||||
in a future Crossplane version.
|
||||
{{< /hint >}}
|
||||
|
||||
Applying a Crossplane `ControllerConfig` to a Provider changes the settings of
|
||||
the Provider's pod. The
|
||||
[Crossplane ControllerConfig schema](https://doc.crds.dev/github.com/crossplane/crossplane/pkg.crossplane.io/ControllerConfig/v1alpha1)
|
||||
defines the supported set of ControllerConfig settings.
|
||||
|
||||
The most common use-case for ControllerConfigs are providing `args` to a
|
||||
Provider's pod enabling optional services. For example, enabling
|
||||
[external secret stores](https://docs.crossplane.io/knowledge-base/integrations/vault-as-secret-store/#enable-external-secret-stores-in-the-provider)
|
||||
for a Provider.
|
||||
|
||||
Each Provider determines their supported set of `args`.
|
||||
|
||||
### Provider configuration
|
||||
|
||||
The `ProviderConfig` determines settings the Provider uses communicating to the
|
||||
external provider. Each Provider determines available settings of their
|
||||
`ProviderConfig`.
|
||||
|
||||
<!-- vale write-good.Weasel = NO -->
|
||||
<!-- allow "usually" -->
|
||||
Provider authentication is usually configured with a `ProviderConfig`. For
|
||||
example, to use basic key-pair authentication with Provider AWS a
|
||||
{{<hover label="providerconfig" line="2" >}}ProviderConfig{{</hover >}}
|
||||
{{<hover label="providerconfig" line="5" >}}spec{{</hover >}}
|
||||
defines the
|
||||
{{<hover label="providerconfig" line="6" >}}credentials{{</hover >}} and that
|
||||
the Provider pod should look in the Kubernetes
|
||||
{{<hover label="providerconfig" line="7" >}}Secrets{{</hover >}} objects and use
|
||||
the key named
|
||||
{{<hover label="providerconfig" line="10" >}}aws-creds{{</hover >}}.
|
||||
<!-- vale write-good.Weasel = YES -->
|
||||
```yaml {label="providerconfig"}
|
||||
apiVersion: aws.crossplane.io/v1beta1
|
||||
kind: ProviderConfig
|
||||
metadata:
|
||||
name: aws-provider
|
||||
spec:
|
||||
credentials:
|
||||
source: Secret
|
||||
secretRef:
|
||||
namespace: crossplane-system
|
||||
name: aws-creds
|
||||
key: creds
|
||||
```
|
||||
|
||||
{{< hint "important" >}}
|
||||
Authentication configuration may be different across Providers.
|
||||
|
||||
Read the documentation on a specific Provider for instructions on configuring
|
||||
authentication for that Provider.
|
||||
{{< /hint >}}
|
||||
|
||||
<!-- vale write-good.TooWordy = NO -->
|
||||
<!-- allow multiple -->
|
||||
ProviderConfig objects apply to individual Managed Resources. A single
|
||||
Provider can authenticate with multiple users or accounts through
|
||||
ProviderConfigs.
|
||||
<!-- vale write-good.TooWordy = YES -->
|
||||
|
||||
Each account's credentials tie to a unique ProviderConfig. When creating a
|
||||
managed resource, attach the desired ProviderConfig.
|
||||
|
||||
For example, two AWS ProviderConfigs, named
|
||||
{{<hover label="user" line="4">}}user-keys{{</hover >}} and
|
||||
{{<hover label="admin" line="4">}}admin-keys{{</hover >}}
|
||||
use different Kubernetes secrets.
|
||||
|
||||
```yaml {label="user"}
|
||||
apiVersion: aws.crossplane.io/v1beta1
|
||||
kind: ProviderConfig
|
||||
metadata:
|
||||
name: user-keys
|
||||
spec:
|
||||
credentials:
|
||||
source: Secret
|
||||
secretRef:
|
||||
namespace: crossplane-system
|
||||
name: my-key
|
||||
key: secret-key
|
||||
```
|
||||
|
||||
```yaml {label="admin"}
|
||||
apiVersion: aws.crossplane.io/v1beta1
|
||||
kind: ProviderConfig
|
||||
metadata:
|
||||
name: admin-keys
|
||||
spec:
|
||||
credentials:
|
||||
source: Secret
|
||||
secretRef:
|
||||
namespace: crossplane-system
|
||||
name: admin-key
|
||||
key: admin-secret-key
|
||||
```
|
||||
|
||||
Apply the ProviderConfig when creating a managed resource.
|
||||
|
||||
This creates an AWS {{<hover label="user-bucket" line="2" >}}Bucket{{< /hover >}}
|
||||
resource using the
|
||||
{{<hover label="user-bucket" line="9" >}}user-keys{{< /hover >}} ProviderConfig.
|
||||
|
||||
```yaml {label="user-bucket"}
|
||||
apiVersion: s3.aws.upbound.io/v1beta1
|
||||
kind: Bucket
|
||||
metadata:
|
||||
name: user-bucket
|
||||
spec:
|
||||
forProvider:
|
||||
region: us-east-2
|
||||
providerConfigRef:
|
||||
name: user-keys
|
||||
```
|
||||
|
||||
This creates a second {{<hover label="admin-bucket" line="2" >}}Bucket{{< /hover >}}
|
||||
resource using the
|
||||
{{<hover label="admin-bucket" line="9" >}}admin-keys{{< /hover >}} ProviderConfig.
|
||||
|
||||
```yaml {label="admin-bucket"}
|
||||
apiVersion: s3.aws.upbound.io/v1beta1
|
||||
kind: Bucket
|
||||
metadata:
|
||||
name: user-bucket
|
||||
spec:
|
||||
forProvider:
|
||||
region: us-east-2
|
||||
providerConfigRef:
|
||||
name: admin-keys
|
||||
```
|
||||
|
|
@ -1,211 +0,0 @@
|
|||
---
|
||||
title: Terminology
|
||||
weight: 110
|
||||
---
|
||||
## A Note on Style
|
||||
|
||||
Each type of Kubernetes resource has a ‘Pascal case’ name - i.e. a title case
|
||||
name with no spaces between each word. Examples include ‘DaemonSet’ and
|
||||
‘PersistentVolumeClaim’. Often these names are written using fixed width fonts
|
||||
to draw attention to the fact that they’re a concrete type of resource within
|
||||
the API - e.g. `PersistentVolumeClaim`.
|
||||
|
||||
Crossplane follows this convention. We often use names like RDSInstance or
|
||||
CompositeResourceDefinition when discussing Crossplane types. Crossplane also
|
||||
has “classes of types” - i.e. concepts that aren’t a distinct type of API
|
||||
resource, but rather describe a group of conceptually similar types. For example
|
||||
there is no ManagedResource type in Crossplane - instead types like RDSInstance
|
||||
and GKECluster are said to be “a managed resource”.
|
||||
|
||||
Use your discretion as to whether you use pascal case when writing about a
|
||||
distinct type - e.g. “RDS Instance” and “RDSInstance” are both fine. The pascal
|
||||
case form makes more sense in contexts like documentation where you’re referring
|
||||
to Crossplane’s RDSInstance managed resource rather than the general concept of
|
||||
“an RDS instance”. Avoid using Pascal case when talking about classes of types -
|
||||
i.e. always write “managed resource”, not “ManagedResource”. Each of the below
|
||||
terms clarify whether they correspond to a single type, or a class of types.
|
||||
|
||||
### Why 'X'?
|
||||
|
||||
You may notice that Crossplane uses “X” as shorthand for “Crossplane” and/or
|
||||
“Composite”. This is because some of our concepts - specifically Composite
|
||||
Resources (XRs) and Composite Resource Definitions (XRDs) are modelled on
|
||||
similar Kubernetes concepts - Custom Resources (CRs) and Custom Resource
|
||||
Definitions (CRDs). We chose to abbreviate to (e.g.) XRD instead of CRD to avoid
|
||||
confusion.
|
||||
|
||||
## Crossplane Terms
|
||||
|
||||
The below terms are commonly used in the Crossplane ecosystem.
|
||||
|
||||
### Composition
|
||||
|
||||
The term Composition has two related but distinct meanings.
|
||||
|
||||
“Composition” refers broadly to the feature of Crossplane that allows teams to
|
||||
define their own opinionated platform APIs.
|
||||
|
||||
“A Composition” or `Composition` (fixed width) refers to the key Crossplane API
|
||||
type that configures how Crossplane should compose resources into a higher level
|
||||
“composite resource”. A Composition tells Crossplane “when someone creates
|
||||
composite resource X, you should respond by creating resources Y and Z”.
|
||||
|
||||
The latter use of Composition represents a distinct Crossplane API type so
|
||||
Pascal case and fixed width fonts are appropriate. We also tend to capitalise
|
||||
the former use, representing the feature in general, but fixed width fonts are
|
||||
not appropriate in that context.
|
||||
|
||||
> Folks accustomed to Terraform might think of a Composition as a Terraform
|
||||
> module; the HCL code that describes how to take input variables and use them
|
||||
> to create resources in some cloud API. Folks accustomed to Helm might think of
|
||||
> a Composition as a Helm chart’s templates; the moustache templated YAML files
|
||||
> that describe how to take Helm chart values and render Kubernetes resources.
|
||||
|
||||
### Composite Resource
|
||||
|
||||
A “Composite Resource” or “XR” is an API type defined using Crossplane. A
|
||||
composite resource’s API type is arbitrary - dictated by the concept the author
|
||||
wishes to expose as an API, for example an “AcmeCoDB”. A common convention is
|
||||
for types to start with "X" - e.g. "XAcmeCoDB".
|
||||
|
||||
We talk about Crossplane being a tool teams can use to define their own
|
||||
opinionated platform APIs. Those APIs are made up of composite resources; when
|
||||
you are interacting with an API that your platform team has defined, you’re
|
||||
interacting with composite resources.
|
||||
|
||||
A composite resource can be thought of as the interface to a Composition. It
|
||||
provides the inputs a Composition uses to compose resources into a higher level
|
||||
concept. In fact, the composite resource _is_ the high level concept.
|
||||
|
||||
The term “Composite Resource” refers to a class of types, so avoid using Pascal
|
||||
case - “Composite Resource” not CompositeResource. Use pascal case when
|
||||
referring to a distinct type of composite resource - e.g. a XAcmeCoDB.
|
||||
|
||||
> Folks accustomed to Terraform might think of a composite resource as a
|
||||
> `tfvars` file that supplies values for the variables a Terraform module uses
|
||||
> to create resources in some cloud API. Folks accustomed to Helm might think of
|
||||
> a composite resource as the `values.yaml` file that supplies inputs to a Helm
|
||||
> chart’s templates.
|
||||
|
||||
### Composite Resource Claim
|
||||
|
||||
A “Composite Resource Claim”, “XRC”, or just “a claim” is also an API type
|
||||
defined using Crossplane. Each type of claim corresponds to a type of composite
|
||||
resource, and the pair have nearly identical schemas. Like composite resources,
|
||||
the type of a claim is arbitrary.
|
||||
|
||||
We talk about Crossplane being a tool platform teams can use to offer
|
||||
opinionated platform APIs to the application teams they support. The platform
|
||||
team offers those APIs using claims. It helps to think of the claim as an
|
||||
application team’s interface to a composite resource. You could also think of
|
||||
claims as the public (app team) facing part of the opinionated platform API,
|
||||
while composite resources are the private (platform team) facing part.
|
||||
|
||||
A common convention is for a claim to be of the same type as its corresponding
|
||||
composite resource, but without the "X" prefix. So an "AcmeCoDB" would be a type
|
||||
of claim, and a "XAcmeCoDB" would be the corresponding type of composite
|
||||
resource. This allows claim consumers to be relatively ignorant of Crossplane
|
||||
and composition, and to instead simply think about managing “an AcmeCo DB” while
|
||||
the platform team worries about the implementation details.
|
||||
|
||||
The term “Composite Resource Claim” refers to a class of types, so avoid using
|
||||
Pascal case - “Composite Resource Claim” not CompositeResourceClaim. Use Pascal
|
||||
case when referring to a distinct type of composite resource claim - e.g. an
|
||||
AcmeCoDB.
|
||||
|
||||
> Claims map to the same concepts as described above under the composite
|
||||
> resource heading; i.e. `tfvars` files and Helm `values.yaml` files. Imagine
|
||||
> that some `tfvars` files and some `values.yaml` files were only accessible to
|
||||
> the platform team while others were offered to application teams; that’s the
|
||||
> difference between a composite resource and a claim.
|
||||
|
||||
### Composite Resource Definition
|
||||
|
||||
A “Composite Resource Definition” or “XRD” is the API type used to define new
|
||||
types of composite resources and claims. Types of composite resources and types
|
||||
of claims exist because they were defined into existence by an XRD. The XRD
|
||||
configures Crossplane with support for the composite resources and claims that
|
||||
make up a platform API.
|
||||
|
||||
XRDs are often conflated with composite resources (XRs) - try to avoid this.
|
||||
When someone uses the platform API to create infrastructure they’re not creating
|
||||
XRDs but rather creating composite resources (XRs). It may help to think of a
|
||||
composite resource as a database entry, while an XRD is a database schema. For
|
||||
those familiar with Kubernetes, the relationship is very similar to that between
|
||||
a Custom Resource Definition (CRD) and a Custom Resource (CR).
|
||||
|
||||
A `CompositeResourceDefinition` is a distinct Crossplane API type, so Pascal
|
||||
case and fixed width fonts are appropriate.
|
||||
|
||||
> There isn’t a direct analog to XRDs in the Helm ecosystem, but they’re a
|
||||
> little bit like the variable blocks in a Terraform module that define which
|
||||
> variables exist, whether those variables are strings or integers, whether
|
||||
> they’re required or optional, etc.
|
||||
|
||||
### Managed Resource
|
||||
|
||||
Managed resources are granular, high fidelity Crossplane representations of a
|
||||
resource in an external system - i.e. resources that are managed by Crossplane.
|
||||
Managed resources are what Crossplane enables platform teams to compose into
|
||||
higher level composite resources, forming an opinionated platform API. They're
|
||||
the building blocks of Crossplane.
|
||||
|
||||
You’ll often hear three related terms used in the Crossplane ecosystem; composed
|
||||
resource, managed resource, and external resource. While there are some subtle
|
||||
contextual differences, these all broadly refer to the same thing. Take an
|
||||
RDSInstance for example; it is a managed resource. A distinct resource within
|
||||
the Crossplane API that represents an AWS RDS instance. When we make a
|
||||
distinction between the managed resource and an external resource we’re simply
|
||||
making the distinction between Crossplane’s representation of the thing (the
|
||||
`RDSInstance` in the Kubernetes API), and the actual thing in whatever external
|
||||
system Crossplane is orchestrating (the RDS instance in AWS's API). When we
|
||||
mention composed resources, we mean a managed resource of which a composite
|
||||
resource is composed.
|
||||
|
||||
Managed resources are a class of resource, so avoid using Pascal case - “managed
|
||||
resource” not “ManagedResource”.
|
||||
|
||||
> Managed resources are similar to Terraform resource blocks, or a distinct
|
||||
> Kubernetes resource within a Helm chart.
|
||||
|
||||
### Package
|
||||
|
||||
Packages extend Crossplane, either with support for new kinds of composite
|
||||
resources and claims, or support for new kinds of managed resources. There are
|
||||
two types of Crossplane package; configurations and providers.
|
||||
|
||||
A package is not a distinct type in the Crossplane API, but rather a class of
|
||||
types. Therefore Pascal case is not appropriate.
|
||||
|
||||
### Configuration
|
||||
|
||||
A configuration extends Crossplane by installing conceptually related groups of
|
||||
XRDs and Compositions, as well as dependencies like providers or further
|
||||
configurations. Put otherwise, it configures the opinionated platform API
|
||||
that Crossplane exposes.
|
||||
|
||||
A `Configuration` is a distinct type in the Crossplane API, therefore Pascal
|
||||
case and fixed width fonts are appropriate.
|
||||
|
||||
### Provider
|
||||
|
||||
A provider extends Crossplane by installing controllers for new kinds of managed
|
||||
resources. Providers typically group conceptually related managed resources; for
|
||||
example the AWS provider installs support for AWS managed resources like
|
||||
RDSInstance and S3Bucket.
|
||||
|
||||
A `Provider` is a distinct type in the Crossplane API, therefore Pascal case and
|
||||
fixed width fonts are appropriate. Note that each Provider package has its own
|
||||
configuration type, called a `ProviderConfig`. Don’t confuse the two; the former
|
||||
installs the provider while the latter specifies configuration that is relevant
|
||||
to all of its managed resources.
|
||||
|
||||
> Providers are directly analogous to Terraform providers.
|
||||
|
||||
### Crossplane Resource Model
|
||||
|
||||
The Crossplane Resource Model or XRM is neither a distinct Crossplane API type,
|
||||
or a class of types. Rather it represents the fact that Crossplane has a
|
||||
consistent, opinionated API. The strict definition of the XRM is currently
|
||||
somewhat vague, but it could broadly be interpreted as a catchall term referring
|
||||
to all of the concepts mentioned on this page.
|
|
@ -1,26 +0,0 @@
|
|||
---
|
||||
title: Contributing
|
||||
weight: 1000
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved in recent versions of Crossplane documentation.
|
||||
|
||||
Contributing to the Crossplane project and provider development is now in the
|
||||
[Crossplane contributing repository](https://github.com/crossplane/crossplane/tree/master/contributing).
|
||||
|
||||
Contributing to Crossplane documentation is in the docs
|
||||
[Contributing]({{<ref "contribute" >}}) section.
|
||||
{{</hint >}}
|
||||
|
||||
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,136 +0,0 @@
|
|||
---
|
||||
title: Adding Secret Store Support
|
||||
weight: 1004
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved in recent versions of Crossplane documentation.
|
||||
|
||||
The [Crossplane contributing repository](https://github.com/crossplane/crossplane/blob/master/contributing/guide-adding-external-secret-stores.md)
|
||||
contains any future revisions to this document.
|
||||
{{</hint >}}
|
||||
|
||||
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.
|
||||
1. Add a new Type and CRD for Secret StoreConfig.
|
||||
2. Add feature flag for enabling External Secret Store support.
|
||||
3. 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,515 +0,0 @@
|
|||
---
|
||||
title: "Crossplane Documentation"
|
||||
weight: 2000
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved in recent versions of Crossplane documentation.
|
||||
|
||||
The
|
||||
[Crossplane docs contributing guide]({{<ref "contribute">}})
|
||||
contains any future revisions to this document.
|
||||
{{</hint >}}
|
||||
|
||||
|
||||
## Code of conduct
|
||||
Crossplane follows the [CNCF Code of
|
||||
Conduct](https://github.com/cncf/foundation/blob/main/code-of-conduct.md).
|
||||
|
||||
Taken directly from the code:
|
||||
<!-- vale off -->
|
||||
>As contributors and maintainers in the CNCF community, and in the interest of
|
||||
>fostering an open and welcoming community, we pledge to respect all people who
|
||||
>contribute through reporting issues, posting feature requests, updating
|
||||
>documentation, submitting pull requests or patches, and other activities.
|
||||
>
|
||||
>We are committed to making participation in the CNCF community a
|
||||
>harassment-free experience for everyone, regardless of level of experience,
|
||||
>gender, gender identity and expression, sexual orientation, disability,
|
||||
>personal appearance, body size, race, ethnicity, age, religion, or nationality.
|
||||
<!-- vale on -->
|
||||
|
||||
### Reporting violations
|
||||
To report violations contact the Crossplane maintainers at `info@crossplane.io`
|
||||
or the CNCF at `conduct@cncf.io`.
|
||||
|
||||
## Docs source
|
||||
Crossplane documentation lives in two repositories:
|
||||
|
||||
* Crossplane documentation source is in the [Crossplane
|
||||
repository](https://github.com/crossplane/crossplane) `/docs` directory.
|
||||
|
||||
* The Crossplane docs website is in the
|
||||
[docs](https://github.com/crossplane/docs)
|
||||
repository.
|
||||
|
||||
Use `crossplane/crossplane` for documentation contributions.
|
||||
Use `crossplane/docs` for local development or updates involving
|
||||
HTML, CSS or Hugo.
|
||||
|
||||
### Licensing
|
||||
The Crossplane documentation is under the [Creative Commons
|
||||
Attribution](https://creativecommons.org/licenses/by/4.0/) license. CC-BY allows
|
||||
reuse, remixing and republishing of Crossplane documentation with attribution to
|
||||
the Crossplane organization.
|
||||
|
||||
### Issues and feature requests
|
||||
Open an [issue](https://github.com/crossplane/crossplane/issues)
|
||||
to report a problem or request documentation content.
|
||||
|
||||
## Contributing
|
||||
|
||||
Documentation content contributions are always welcome.
|
||||
|
||||
The Crossplane documentation source is in the [Crossplane
|
||||
repository](https://github.com/crossplane/crossplane) `/docs` directory.
|
||||
|
||||
Crossplane recommends using the [website
|
||||
repository](https://github.com/crossplane/crossplane.github.io) for local development.
|
||||
When a contribution is ready, submit a pull request to the [Crossplane
|
||||
repository](https://github.com/crossplane/crossplane).
|
||||
|
||||
|
||||
### Local development
|
||||
Build the Crossplane documentation site locally for development and
|
||||
testing.
|
||||
|
||||
#### Clone the documentation site
|
||||
Clone the [documentation
|
||||
repository](https://github.com/crossplane/crossplane.github.io) with
|
||||
|
||||
```command
|
||||
git clone https://github.com/crossplane/crossplane.github.io.git
|
||||
```
|
||||
|
||||
#### Download the Hugo static site generator
|
||||
Crossplane uses [Hugo](https://github.com/gohugoio/hugo), a static site
|
||||
generator.
|
||||
|
||||
Download a Hugo v0.101.0 or later from the [Hugo
|
||||
releases](https://github.com/gohugoio/hugo/releases/tag/v0.106.0).
|
||||
|
||||
#### Build the Crossplane documentation
|
||||
From the `crossplane.github.io` folder run
|
||||
|
||||
```command
|
||||
hugo server
|
||||
```
|
||||
|
||||
Hugo builds the website and launch a local web server on
|
||||
<a href="http://localhost:1313" data-proofer-ignore>http://localhost:1313</a>.
|
||||
|
||||
Any changes made are instantly reflected on the local web server. You
|
||||
don't need to restart Hugo.
|
||||
|
||||
### Contribute to a specific version
|
||||
The documentation location for the various Crossplane versions are different
|
||||
for the Crossplane source and docs website.
|
||||
|
||||
#### Crossplane repository
|
||||
In the [crossplane/crossplane](https://github.com/crossplane/crossplane)
|
||||
repository documentation is in the `/docs` directory.
|
||||
|
||||
Each active release has a `/docs` folder in a branch called
|
||||
`release-<version>`. For example, v1.10 docs are in the branch
|
||||
[release-1.10](https://github.com/crossplane/crossplane/tree/release-1.10).
|
||||
|
||||
To contribute to a specific release submit a pull-request to the
|
||||
`release-<version>` or `master` branch.
|
||||
|
||||
The next Crossplane release uses `master` as the starting documentation.
|
||||
|
||||
#### Website repository
|
||||
The [docs website
|
||||
repository](https://github.com/crossplane/crossplane.github.io) combines all
|
||||
active versions in the `/content` directory.
|
||||
|
||||
## Style guidelines
|
||||
The official Crossplane documentation style guide is still under construction.
|
||||
Guiding principals for the documentation include:
|
||||
<!-- vale off -->
|
||||
* Avoid [passive voice](https://www.grammarly.com/blog/passive-voice/).
|
||||
* Use [sentence-case headings](https://apastyle.apa.org/style-grammar-guidelines/capitalization/sentence-case).
|
||||
* Wrap lines at 80 characters.
|
||||
* Use [present tense](https://www.grammarly.com/blog/simple-present/).
|
||||
* Spell out numbers less than 10, except for percentages, time and versions.
|
||||
* Capitalize "Crossplane" and "Kubernetes."
|
||||
* Spell out the first use of an acronym unless it's common to new Crossplane
|
||||
users. When in doubt, spell it out first.
|
||||
* Don't use [cliches](https://www.topcreativewritingcourses.com/blog/common-cliches-in-writing-and-how-to-avoid-them).
|
||||
* Use contractions for phrases like "do not", "cannot", "is not" and related terms.
|
||||
* Don't use Latin terms (i.e., e.g., etc.).
|
||||
* Don't use [gerund](https://owl.purdue.edu/owl/general_writing/mechanics/gerunds_participles_and_infinitives/index.html) headings (-ing words).
|
||||
* Try and limit sentences to 25 words or fewer.
|
||||
* [Be descriptive in link text](https://usability.yale.edu/web-accessibility/articles/links#link-text). Don't use "click here" or "read more".
|
||||
<!-- vale on -->
|
||||
|
||||
Crossplane documentation is adopting
|
||||
[Vale](https://github.com/errata-ai/vale) and relies on the [Upbound Vale
|
||||
definitions](https://github.com/upbound/vale) for style guidelines.
|
||||
|
||||
Beyond Vale, Crossplane recommends [Grammarly](https://www.grammarly.com/) and [Hemingway
|
||||
Editor](https://hemingwayapp.com/) to improve writing quality.
|
||||
|
||||
## Docs site styling features
|
||||
The Crossplane documentation supports multiple styling features to improve
|
||||
readability.
|
||||
|
||||
### Images
|
||||
Crossplane supports standard [Markdown image
|
||||
syntax](https://www.markdownguide.org/basic-syntax/#images-1) but using the
|
||||
`img` shortcode is strongly recommended.
|
||||
|
||||
Images using the shortcode are automatically converted to `webp` image format,
|
||||
compressed and use responsive image sizing.
|
||||
|
||||
{{<hint "note">}}
|
||||
The `img` shortcode doesn't support .SVG files.
|
||||
{{< /hint >}}
|
||||
|
||||
The shortcode requires a `src` (relative to the file using the shortcode), an
|
||||
`alt` text and an optional `size`.
|
||||
|
||||
The `size` can be one of:
|
||||
* `xtiny` - Resizes the image to 150px.
|
||||
* `tiny` - Resizes the image to 320px.
|
||||
* `small` - Resizes the image to 600px.
|
||||
* `medium` - Resizes the image to 1200px.
|
||||
* `large` - Resizes the image to 1800px.
|
||||
|
||||
By default the image isn't resized.
|
||||
|
||||
An example of using the `img` shortcode:
|
||||
```html
|
||||
{{</* img src="/media/banner.png" alt="Crossplane Popsicle Truck" size="small" */>}}
|
||||
```
|
||||
|
||||
Which generates this responsive image (change your browser size to see it change):
|
||||
{{<img src="/media/banner.png" alt="Crossplane Popsicle Truck" size="small" >}}
|
||||
|
||||
### Links
|
||||
Crossplane docs support standard [Markdown
|
||||
links](https://www.markdownguide.org/basic-syntax/#links) but Crossplane prefers link shortcodes
|
||||
for links between docs pages. Using shortcodes prevents incorrect link creation
|
||||
and notifies which links to change after moving a page.
|
||||
|
||||
#### Between docs pages
|
||||
For links between pages use a standard Markdown link in the form:
|
||||
|
||||
`[Link text](link)`
|
||||
|
||||
Crossplane recommends using the [Hugo ref
|
||||
shortcode](https://gohugo.io/content-management/shortcodes/#ref-and-relref)
|
||||
with the path of the file relative to `/content` for the link location.
|
||||
|
||||
For example, to link to the `master` release index page use
|
||||
```markdown
|
||||
[master branch documentation]({{</* ref "master/_index.md" */>}})
|
||||
```
|
||||
|
||||
<!-- [master branch documentation]({{<ref "master/_index.md" >}}) -->
|
||||
|
||||
The `ref` value is of the markdown file, including `.md` extension.
|
||||
|
||||
If the `ref` value points to a page that doesn't exist, Hugo fails to start.
|
||||
|
||||
#### Linking to external sites
|
||||
Minimize linking to external sites. When linking to any page outside of
|
||||
`crossplane.io` use standard [markdown link
|
||||
syntax](https://www.markdownguide.org/basic-syntax/#links) without using the
|
||||
`ref` shortcode.
|
||||
|
||||
For example,
|
||||
```markdown
|
||||
[Go to Upbound](http://upbound.io)
|
||||
```
|
||||
|
||||
### Tabs
|
||||
Use tabs to present information about a single topic with multiple exclusive
|
||||
options. For example, creating a resource via command-line or GUI.
|
||||
|
||||
To create a tab set, first create a `tabs` shortcode and use multiple `tab`
|
||||
shortcodes inside for each tab.
|
||||
|
||||
```html
|
||||
{{</* tabs */>}}
|
||||
|
||||
{{</* tab "First tab title" */>}}
|
||||
An example tab. Place anything inside a tab.
|
||||
{{</* /tab */>}}
|
||||
|
||||
{{</* tab "Second tab title" */>}}
|
||||
A second example tab.
|
||||
{{</* /tab */>}}
|
||||
|
||||
{{</* /tabs */>}}
|
||||
```
|
||||
|
||||
This code block renders the following tabs
|
||||
{{< tabs >}}
|
||||
|
||||
{{< tab "First tab title" >}}
|
||||
An example tab. Place anything inside a tab.
|
||||
{{< /tab >}}
|
||||
|
||||
{{< tab "Second tab title" >}}
|
||||
A second example tab.
|
||||
{{< /tab >}}
|
||||
|
||||
{{< /tabs >}}
|
||||
|
||||
Both `tab` and `tabs` require opening and closing tags. Unclosed tags causes
|
||||
Hugo to fail.
|
||||
|
||||
### Hints and alert boxes
|
||||
Hint and alert boxes provide call-outs to important information to the reader. Crossplane docs support four different hint box styles.
|
||||
|
||||
{{< hint "note" >}}
|
||||
Notes are useful for calling out optional information.
|
||||
{{< /hint >}}
|
||||
|
||||
{{< hint "tip" >}}
|
||||
Use tips to provide context or a best practice.
|
||||
{{< /hint >}}
|
||||
|
||||
{{< hint "important" >}}
|
||||
Important hints are for drawing extra attention to something.
|
||||
{{< /hint >}}
|
||||
|
||||
{{< hint "warning" >}}
|
||||
Use warning boxes to alert users of things that may cause outages, lose data or
|
||||
are irreversible changes.
|
||||
{{< /hint >}}
|
||||
|
||||
|
||||
Create a hint by using a shortcode in your markdown file:
|
||||
```html
|
||||
{{</* hint "note" */>}}
|
||||
Your box content. This hint box is a note.
|
||||
{{</* /hint */>}}
|
||||
```
|
||||
|
||||
Use `note`, `tip`, `important`, or `warning` as the `hint` value.
|
||||
|
||||
The `hint` shortcode requires opening and closing tags. Unclosed tags causes
|
||||
Hugo to fail.
|
||||
|
||||
|
||||
### Hide long outputs
|
||||
Some outputs may be verbose or only relevant for
|
||||
a small audience. Use the `expand` shortcode to hide blocks of text by default.
|
||||
|
||||
{{<expand "A large XRD" >}}
|
||||
```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
|
||||
```
|
||||
{{< /expand >}}
|
||||
|
||||
The `expand` shortcode can have a title, the default is "Expand."
|
||||
````yaml
|
||||
{{</* expand "A large XRD" */>}}
|
||||
```yaml
|
||||
apiVersion: apiextensions.crossplane.io/v1
|
||||
kind: CompositeResourceDefinition
|
||||
metadata:
|
||||
name: xpostgresqlinstances.database.example.org
|
||||
```
|
||||
{{</* /expand */>}}
|
||||
````
|
||||
|
||||
The `expand` shortcode requires opening and closing tags. Unclosed tags causes
|
||||
Hugo to fail.
|
||||
|
||||
## Adding new content
|
||||
|
||||
To create new content create a new markdown file in the appropriate location.
|
||||
|
||||
To create a new section, create a new directory and an `_index.md` file in the
|
||||
root.
|
||||
|
||||
### Front matter
|
||||
Each page contains metadata called [front matter](https://gohugo.io/content-management/front-matter/). Each page requires front matter to render.
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: "A New Page"
|
||||
weight: 610
|
||||
---
|
||||
```
|
||||
|
||||
`title` defines the name of the page.
|
||||
`weight` determines the ordering of the page in the table of contents. Lower weight pages come before higher weights in the table of contents. The value of `weight` is otherwise arbitrary.
|
||||
|
||||
|
||||
### Hiding pages
|
||||
To hide a page from the left-hand navigation use `tocHidden: true` in the front
|
||||
matter of the page. The docs website skips pages with `tocHidden:true` when building the menu.
|
||||
|
||||
## Docs website
|
||||
The Crossplane document website is in a unique [website GitHub
|
||||
repository](https://github.com/crossplane/docs).
|
||||
|
||||
Crossplane uses [Hugo](https://gohugo.io/), a static site generator. Hugo
|
||||
influences the directory structure of the website repository.
|
||||
|
||||
The `/content` directory is the root directory for all documentation content.
|
||||
|
||||
The `/themes/geekboot` directory is the root directory for all website related
|
||||
files, like HTML templates, shortcodes and global media files.
|
||||
|
||||
The `/utils/` directory is for JavaScript source code used in the website.
|
||||
|
||||
The `/themes/geekboot/assets` folder contains all (S)CSS and compiled JavaScript
|
||||
for the website.
|
||||
|
||||
### CSS
|
||||
Crossplane documentation uses [Bootstrap
|
||||
5.2](https://getbootstrap.com/docs/5.2/getting-started/introduction/).
|
||||
Unmodified Bootstrap SCSS files are in
|
||||
`/themes/geekboot/assets/scss/bootstrap/`. Any docs-specific overrides are in
|
||||
per-element SCSS files located one directory higher in
|
||||
`/themes/geekboot/assets/scss/`.
|
||||
|
||||
{{<hint "important" >}}
|
||||
Don't edit the original Bootstrap stylesheets. It makes the ability to
|
||||
upgrade to future Bootstrap versions difficult or impossible.
|
||||
{{< /hint >}}
|
||||
|
||||
#### Color themes
|
||||
Crossplane docs support a light and dark color theme that's applied via CSS
|
||||
variables.
|
||||
|
||||
Universal and default variables are defined in
|
||||
`/themes/geekboot/assets/scss/_variables.scss`.
|
||||
|
||||
Provide theme specific color overrides in
|
||||
`/themes/geekboot/assets/scss/light-mode.scss` or
|
||||
`/themes/geekboot/assets/scss/light-mode.scss`.
|
||||
|
||||
{{<hint "note" >}}
|
||||
When creating new styles rely on variables for any color function, even if both
|
||||
themes share the color.
|
||||
{{< /hint >}}
|
||||
|
||||
#### SCSS compilation
|
||||
Hugo compiles the SCSS to CSS. Local development doesn't require SCSS installed.
|
||||
|
||||
For local development (when using `hugo server`) Hugo compiles SCSS without
|
||||
any optimizations.
|
||||
|
||||
For production (publishing on Netlify or using `hugo server
|
||||
--environment production`) Hugo compiles SCSS and optimizes the CSS with
|
||||
[PostCSS](https://postcss.org/). The PostCSS configuration is in
|
||||
`/postcss.config.js`. The optimizations includes:
|
||||
* [postcss-lightningcss](https://github.com/onigoetz/postcss-lightningcss) - for
|
||||
building, minimizing and generating a source map.
|
||||
* [PurgeCSS](https://purgecss.com/plugins/postcss.html) - removes unused styles
|
||||
to reduce the CSS file size.
|
||||
* [postcss-sort-media-queries](https://github.com/yunusga/postcss-sort-media-queries)-
|
||||
to organize and reduce CSS media queries to remove duplicate and unused
|
||||
CSS.
|
||||
|
||||
Optimizing CSS locally with PostCSS requires installing extra packages.
|
||||
* [Sass](https://sass-lang.com/install)
|
||||
* [NPM](https://www.npmjs.com/)
|
||||
* NPM packages defined in `/package.json` with `npm install`.
|
||||
|
||||
|
||||
### JavaScript
|
||||
A goal of the documentation website is to use as little JavaScript as possible. Unless
|
||||
the script provides a significant improvement in performance, capability or user
|
||||
experience.
|
||||
|
||||
To make local development there are no run-time dependencies for
|
||||
JavaScript.
|
||||
|
||||
Runtime JavaScript is in `/themes/geekboot/assets/js/`. [Webpack](https://webpack.js.org/)
|
||||
has bundled, minified and compressed the JavaScript.
|
||||
|
||||
The source JavaScript is in `/utils/webpack/src/js` and
|
||||
requires [Webpack](https://webpack.js.org/) to bundle and optimize the code.
|
||||
|
||||
* `colorMode.js` provides the ability to change the light/dark mode color theme.
|
||||
* `tabDeepAnchor.js` rewrites anchor links inside tabs to open a tab and present
|
||||
the anchor.
|
||||
* `globalScripts.js` is the point of entry for Webpack to determine all
|
||||
dependencies. This bundles [instant.page](https://instant.page/) and
|
||||
[Bootstrap's
|
||||
JavaScript](https://getbootstrap.com/docs/5.2/getting-started/javascript/).
|
||||
|
||||
#### Bootstrap JavaScript
|
||||
The entire [Bootstap JavaScript
|
||||
source](https://github.com/twbs/bootstrap/tree/main/js/src) is in
|
||||
`/utils/webpack/src/js/bootstrap`.
|
||||
|
||||
Adding a new Bootstrap feature requires importing it in `globalScripts.js`.
|
||||
|
||||
By importing only the necessary Bootstrap JavaScript features, reduces the
|
||||
bundle size.
|
||||
## Annotated website tree
|
||||
Expand the tab below to see an annotated `tree` output of the website repo.
|
||||
|
||||
{{<expand >}}
|
||||
```console
|
||||
├── content # Root for all page content
|
||||
│ ├── master
|
||||
│ ├── v1.10
|
||||
│ ├── v1.8
|
||||
│ └── v1.9
|
||||
├── themes # Entry point for theme-specific designs
|
||||
│ └── geekboot
|
||||
│ ├── assets # JS and stylesheets
|
||||
│ │ ├── js # Bundled and optmized Javascript
|
||||
│ │ └── scss # Bootstrap SCSS overrides
|
||||
│ │ └── bootstrap # Bootstrap original SCSS files
|
||||
│ ├── data
|
||||
│ ├── layouts # HTML layouts and shortcodes
|
||||
│ │ ├── _default # HTML layouts for page types
|
||||
│ │ │ └── _markup # Hugo render hooks
|
||||
│ │ ├── partials # HTML Template elements
|
||||
│ │ │ ├── icons
|
||||
│ │ │ └── utils
|
||||
│ │ └── shortcodes # Shortcode features
|
||||
│ └── static # Static files across the theme.
|
||||
│ ├── fonts # Font files
|
||||
│ └── img # Global images
|
||||
└── utils # Files unrelated to Hugo
|
||||
└── webpack # Files managed or related to webpack
|
||||
└── src
|
||||
└── js
|
||||
└── bootstrap/ # Original Bootstrap JavaScript
|
||||
└── colorMode.js # Color theme switcher
|
||||
└── tabDeepAnchor.js # Enable anchors inside tabs
|
||||
```
|
||||
{{</expand>}}
|
|
@ -1,202 +0,0 @@
|
|||
---
|
||||
title: Observability Developer Guide
|
||||
weight: 1002
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved in recent versions of Crossplane documentation.
|
||||
|
||||
The [Crossplane contributing repository](https://github.com/crossplane/crossplane/blob/master/contributing/guide-observability.md)
|
||||
contains any future revisions to this document.
|
||||
{{</hint >}}
|
||||
|
||||
|
||||
## 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/kubernetes-api/cluster-resources/event-v1/
|
||||
[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://kubernetes.io/docs/reference/kubernetes-api/cluster-resources/event-v1/
|
||||
[`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,664 +0,0 @@
|
|||
---
|
||||
title: Provider Development Guide
|
||||
weight: 1001
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved in recent versions of Crossplane documentation.
|
||||
|
||||
The [Crossplane contributing repository](https://github.com/crossplane/crossplane/blob/master/contributing/guide-provider-development.md)
|
||||
contains any future revisions to this document.
|
||||
{{</hint >}}
|
||||
|
||||
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,273 +0,0 @@
|
|||
---
|
||||
title: Release Process
|
||||
weight: 1003
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved in recent versions of Crossplane documentation.
|
||||
|
||||
The [Crossplane contributing repository](https://github.com/crossplane/crossplane/blob/master/contributing/release-process.md)
|
||||
contains any future revisions to this document.
|
||||
{{</hint >}}
|
||||
|
||||
|
||||
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,24 +0,0 @@
|
|||
---
|
||||
title: FAQ
|
||||
weight: 1200
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
Recent versions of Crossplane documentation removed this document.
|
||||
{{</hint >}}
|
||||
|
||||
### 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,87 +0,0 @@
|
|||
---
|
||||
title: Related Projects
|
||||
weight: 1201
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
Recent versions of Crossplane documentation removed this document.
|
||||
{{</hint >}}
|
||||
|
||||
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,24 +0,0 @@
|
|||
---
|
||||
title: Getting Started
|
||||
weight: 4
|
||||
---
|
||||
|
||||
{{< 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,680 +0,0 @@
|
|||
---
|
||||
title: Create a Configuration
|
||||
weight: 4
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved in recent versions of Crossplane documentation.
|
||||
|
||||
Current Crossplane documentation versions introduce configurations as part of
|
||||
the [Getting Started]({{<ref "/v1.11/getting-started" >}}) guides.
|
||||
{{</hint >}}
|
||||
|
||||
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.10/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.10/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.10/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.10/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.10/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.10/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.10.2
|
||||
```
|
||||
|
||||
> Note that the Crossplane CLI will not follow symbolic links for files in the
|
||||
> root package directory.
|
||||
|
||||
{{< /tab >}}
|
||||
{{< tab "AWS (New 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.10/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.10.2
|
||||
```
|
||||
|
||||
> 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.10/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.10.2
|
||||
```
|
||||
|
||||
> 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.10/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.10.2
|
||||
```
|
||||
|
||||
> 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,476 +0,0 @@
|
|||
---
|
||||
title: Install & Configure
|
||||
weight: 2
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved in recent versions of Crossplane documentation.
|
||||
|
||||
Read the current [Install and Upgrade]({{<ref "/v1.11/software" >}}) guide.
|
||||
{{</hint >}}
|
||||
|
||||
|
||||
## 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](https://kubernetes.io/docs/setup/)
|
||||
* [Kind](https://kind.sigs.k8s.io/docs/user/quick-start/)
|
||||
* [Minikube](https://minikube.sigs.k8s.io/docs/start/), minimum version `v0.28+`
|
||||
* etc.
|
||||
* [Helm](https://helm.sh/docs/intro/using_helm/), minimum version `v3.0.0+`.
|
||||
|
||||
<!-- close "macOS / Linux" -->
|
||||
{{% /tab %}}
|
||||
|
||||
{{% tab "Windows" %}}
|
||||
For Windows use the following:
|
||||
|
||||
* [Kubernetes cluster](https://kubernetes.io/docs/setup/)
|
||||
* [Kind](https://kind.sigs.k8s.io/docs/user/quick-start/)
|
||||
* [Minikube](https://minikube.sigs.k8s.io/docs/start/), minimum version `v0.28+`
|
||||
* etc.
|
||||
* [Helm](https://helm.sh/docs/intro/using_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]({{<ref "../concepts/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]({{<ref "../concepts/packages" >}}) 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]({{<ref "create-configuration" >}})
|
||||
> section.
|
||||
|
||||
```bash
|
||||
kubectl crossplane install configuration registry.upbound.io/xp/getting-started-with-aws:v1.10.2
|
||||
```
|
||||
|
||||
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
|
||||
```
|
||||
```bash
|
||||
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-1.10/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]({{<ref "create-configuration" >}})
|
||||
> section.
|
||||
|
||||
```bash
|
||||
kubectl crossplane install configuration registry.upbound.io/xp/getting-started-with-aws-with-vpc:v1.10.2
|
||||
```
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
```bash
|
||||
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-1.10/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]({{<ref "create-configuration" >}})
|
||||
> section.
|
||||
|
||||
```bash
|
||||
kubectl crossplane install configuration registry.upbound.io/xp/getting-started-with-gcp:v1.10.2
|
||||
```
|
||||
|
||||
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]({{<ref "create-configuration" >}})
|
||||
> section.
|
||||
|
||||
```bash
|
||||
kubectl crossplane install configuration registry.upbound.io/xp/getting-started-with-azure:v1.10.2
|
||||
```
|
||||
|
||||
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.10/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]({{<ref "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](https://docs.upbound.io/uxp/install) on the Upbound Documentation site.
|
||||
|
||||
<i>Want see another hosted Crossplane service listed? Please reach out on
|
||||
[Slack](http://slack.crossplane.io/) 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 -->
|
||||
[Install]: {{<ref "../reference/install" >}}
|
||||
[Configure]: {{<ref "../reference/configure" >}}
|
||||
[Uninstall]: {{<ref "../reference/uninstall" >}}
|
||||
[Providers]: {{<ref "../concepts/providers" >}}
|
||||
[certified by the CNCF]: https://github.com/cncf/crossplane-conformance
|
||||
[Crossplane GitHub]: https://github.com/crossplane/crossplane
|
|
@ -1,279 +0,0 @@
|
|||
---
|
||||
title: Provision Infrastructure
|
||||
weight: 3
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved in recent versions of Crossplane documentation.
|
||||
|
||||
Current Crossplane documentation versions introduce configurations as part of
|
||||
the [Getting Started]({{<ref "/v1.11/getting-started" >}}) guides.
|
||||
{{</hint >}}
|
||||
|
||||
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.10/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.10/docs/snippets/compose/claim-aws-new.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.10/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.10/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.10/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,31 +0,0 @@
|
|||
---
|
||||
title: Guides
|
||||
weight: 200
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
Recent versions of Crossplane documentation removed this document.
|
||||
{{</hint >}}
|
||||
|
||||
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,44 +0,0 @@
|
|||
---
|
||||
title: Configuring Crossplane with Argo CD
|
||||
weight: 270
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved.
|
||||
Read the recent version in the
|
||||
[Crossplane Knowledge Base]({{< ref "knowledge-base/integrations/argo-cd-crossplane" >}}).
|
||||
{{</hint >}}
|
||||
|
||||
[Argo CD](https://argoproj.github.io/cd/) and [Crossplane](https://crossplane.io)
|
||||
are a great combination. Argo CD provides GitOps while Crossplane turns any Kubernetes
|
||||
cluster into a Universal Control Plane for all of your resources. There are
|
||||
configuration details required in order for the two to work together properly.
|
||||
This doc will help you understand these requirements. It is recommended to use
|
||||
|
||||
Argo CD version 2.4.8 or later with Crossplane.
|
||||
|
||||
Argo CD synchronizes Kubernetes resource manifests stored in a Git repository
|
||||
with those running in a Kubernetes cluster (GitOps). There are different ways to configure
|
||||
|
||||
how Argo CD tracks resources. With Crossplane, you need to configure Argo CD
|
||||
to use Annotation based resource tracking. See the [Argo CD docs](https://argo-cd.readthedocs.io/en/latest/user-guide/resource_tracking/) for additional detail.
|
||||
|
||||
### Configuring Argo CD with Crossplane
|
||||
|
||||
To configure Argo CD for Annotation resource tracking, edit the `argocd-cm`
|
||||
|
||||
`ConfigMap` in the `argocd` `Namespace`. Add `application.resourceTrackingMethod: annotation`
|
||||
|
||||
to the data section as below:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: v1
|
||||
data:
|
||||
application.resourceTrackingMethod: annotation
|
||||
kind: ConfigMap
|
||||
```
|
||||
|
||||
On the next Argo CD sync, Crossplane `Claims` and `Composite Resources` will
|
||||
|
||||
be considered synchronized and will not trigger auto-pruning.
|
|
@ -1,159 +0,0 @@
|
|||
---
|
||||
title: Composition Revisions
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved.
|
||||
Read the recent version in the
|
||||
[Crossplane Knowledge Base]({{< ref "knowledge-base/guides/composition-revisions" >}}).
|
||||
{{</hint >}}
|
||||
|
||||
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,345 +0,0 @@
|
|||
---
|
||||
title: Multi-Tenant Crossplane
|
||||
weight: 240
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved.
|
||||
Read the recent version in the
|
||||
[Crossplane Knowledge Base]({{< ref "knowledge-base/guides/multi-tenant" >}}).
|
||||
{{</hint >}}
|
||||
|
||||
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,55 +0,0 @@
|
|||
---
|
||||
title: Self-Signed CA Certs
|
||||
weight: 270
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved.
|
||||
Read the recent version in the
|
||||
[Crossplane Knowledge Base]({{< ref "knowledge-base/guides/self-signed-ca-certs" >}}).
|
||||
{{</hint >}}
|
||||
|
||||
> 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,166 +0,0 @@
|
|||
---
|
||||
title: Upgrading to v0.14
|
||||
weight: 210
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
Recent versions of Crossplane documentation removed this document.
|
||||
{{</hint >}}
|
||||
|
||||
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,51 +0,0 @@
|
|||
---
|
||||
title: Upgrading to v1.x
|
||||
weight: 220
|
||||
---
|
||||
|
||||
|
||||
{{<hint "important" >}}
|
||||
Recent versions of Crossplane documentation removed this document.
|
||||
{{</hint >}}
|
||||
|
||||
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,499 +0,0 @@
|
|||
---
|
||||
title: Vault as an External Secret Store
|
||||
weight: 230
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved.
|
||||
Read the recent version in the
|
||||
[Crossplane Knowledge Base]({{< ref "knowledge-base/integrations/vault-as-secret-store" >}}).
|
||||
{{</hint >}}
|
||||
|
||||
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
|
||||
|
||||
Add the Helm repo.
|
||||
```shell
|
||||
helm repo add hashicorp https://helm.releases.hashicorp.com --force-update
|
||||
```
|
||||
|
||||
Install the Helm chart.
|
||||
```shell
|
||||
helm -n vault-system upgrade --install vault hashicorp/vault --create-namespace
|
||||
```
|
||||
|
||||
2. [Unseal] Vault
|
||||
|
||||
Get the Vault keys.
|
||||
```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[]")
|
||||
```
|
||||
|
||||
Unseal the vault with the keys.
|
||||
```shell
|
||||
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
|
||||
|
||||
|
||||
cat << EOF > values.yaml
|
||||
args:
|
||||
- --enable-external-secret-stores
|
||||
customAnnotations:
|
||||
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: "65532"
|
||||
EOF
|
||||
|
||||
|
||||
helm upgrade --install crossplane crossplane-stable/crossplane --namespace crossplane-system -f values.yaml
|
||||
```
|
||||
|
||||
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.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 -
|
||||
```
|
||||
|
||||
### 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,511 +0,0 @@
|
|||
---
|
||||
title: Vault Credential Injection
|
||||
weight: 230
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved.
|
||||
Read the recent version in the
|
||||
[Crossplane Knowledge Base]({{< ref "knowledge-base/integrations/vault-injection" >}}).
|
||||
{{</hint >}}
|
||||
|
||||
> 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]
|
||||
and [provider-aws].
|
||||
|
||||
> Note: in this guide we will copy GCP credentials and AWS access keys
|
||||
> 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
|
||||
```
|
||||
|
||||
{{< tabs >}}
|
||||
{{< tab "GCP" >}}
|
||||
|
||||
## 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 at 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
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
{{< tab "AWS" >}}
|
||||
|
||||
## Create AWS IAM User
|
||||
|
||||
In order to provision infrastructure on AWS, you will need to use an existing or create a new IAM
|
||||
user with appropriate permissions. The following steps will create an AWS IAM user and give it the necessary
|
||||
permissions.
|
||||
|
||||
> Note: if you have an existing IAM user with appropriate permissions, you can skip this step but you will
|
||||
> still need to provide the values for the `ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables.
|
||||
|
||||
```console
|
||||
# create a new IAM user
|
||||
IAM_USER=test-user
|
||||
aws iam create-user --user-name $IAM_USER
|
||||
|
||||
# grant the IAM user the necessary permissions
|
||||
aws iam attach-user-policy --user-name $IAM_USER --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess
|
||||
|
||||
# create a new IAM access key for the user
|
||||
aws iam create-access-key --user-name $IAM_USER > creds.json
|
||||
# assign the access key values to environment variables
|
||||
ACCESS_KEY_ID=$(jq -r .AccessKey.AccessKeyId creds.json)
|
||||
AWS_SECRET_ACCESS_KEY=$(jq -r .AccessKey.SecretAccessKey creds.json)
|
||||
```
|
||||
|
||||
## Store Credentials in Vault
|
||||
|
||||
After setting up Vault, you will need to store your credentials in the [kv
|
||||
secrets engine].
|
||||
|
||||
1. Enable KV Secrets Engine
|
||||
|
||||
Secrets engines must be enabled before they can be used. Enable the `kv-v2`
|
||||
secrets engine at the `secret` path.
|
||||
|
||||
```console
|
||||
kubectl exec -it vault-0 -- env \
|
||||
ACCESS_KEY_ID=${ACCESS_KEY_ID} \
|
||||
AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} \
|
||||
/bin/sh
|
||||
|
||||
vault secrets enable -path=secret kv-v2
|
||||
```
|
||||
|
||||
2. Store AWS Credentials in KV Engine
|
||||
|
||||
The path of your AWS credentials is how the secret will be referenced when
|
||||
injecting it into the `provider-aws` controller `Pod`.
|
||||
|
||||
```
|
||||
vault kv put secret/provider-creds/aws-default access_key="$ACCESS_KEY_ID" secret_key="$AWS_SECRET_ACCESS_KEY"
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
## 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
|
||||
```
|
||||
|
||||
{{< tabs >}}
|
||||
{{< tab "GCP" >}}
|
||||
|
||||
## 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 -
|
||||
```
|
||||
|
||||
To verify that the GCP credentials are being injected into the container run the
|
||||
following command:
|
||||
|
||||
```console
|
||||
PROVIDER_CONTROLLER_POD=$(kubectl -n crossplane-system get pod -l pkg.crossplane.io/provider=provider-gcp -o name --no-headers=true)
|
||||
kubectl -n crossplane-system exec -it $PROVIDER_CONTROLLER_POD -c provider-gcp -- cat /vault/secrets/creds.txt
|
||||
```
|
||||
|
||||
## 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
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
{{< tab "AWS" >}}
|
||||
|
||||
## Install provider-aws
|
||||
|
||||
You are now ready to install `provider-aws`. 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/aws-default` to be
|
||||
injected into the container filesystem by assuming role `crossplane-providers`.
|
||||
There is also some template formatting added to make sure the secret data is
|
||||
presented in a form that `provider-aws` is expecting.
|
||||
|
||||
{% raw %}
|
||||
```console
|
||||
echo "apiVersion: pkg.crossplane.io/v1alpha1
|
||||
kind: ControllerConfig
|
||||
metadata:
|
||||
name: aws-vault-config
|
||||
spec:
|
||||
args:
|
||||
- --debug
|
||||
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/aws-default\"
|
||||
vault.hashicorp.com/agent-inject-template-creds.txt: |
|
||||
{{- with secret \"secret/provider-creds/aws-default\" -}}
|
||||
[default]
|
||||
aws_access_key_id="{{ .Data.data.access_key }}"
|
||||
aws_secret_access_key="{{ .Data.data.secret_key }}"
|
||||
{{- end -}}
|
||||
---
|
||||
apiVersion: pkg.crossplane.io/v1
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: provider-aws
|
||||
spec:
|
||||
package: xpkg.upbound.io/crossplane-contrib/provider-aws:v0.33.0
|
||||
controllerConfigRef:
|
||||
name: aws-vault-config" | kubectl apply -f -
|
||||
```
|
||||
{% endraw %}
|
||||
|
||||
## Configure provider-aws
|
||||
|
||||
Once `provider-aws` 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`.
|
||||
|
||||
```console
|
||||
echo "apiVersion: aws.crossplane.io/v1beta1
|
||||
kind: ProviderConfig
|
||||
metadata:
|
||||
name: default
|
||||
spec:
|
||||
credentials:
|
||||
source: Filesystem
|
||||
fs:
|
||||
path: /vault/secrets/creds.txt" | kubectl apply -f -
|
||||
```
|
||||
|
||||
To verify that the AWS credentials are being injected into the container run the
|
||||
following command:
|
||||
|
||||
```console
|
||||
PROVIDER_CONTROLLER_POD=$(kubectl -n crossplane-system get pod -l pkg.crossplane.io/provider=provider-aws -o name --no-headers=true)
|
||||
kubectl -n crossplane-system exec -it $PROVIDER_CONTROLLER_POD -c provider-aws -- cat /vault/secrets/creds.txt
|
||||
```
|
||||
|
||||
## Provision Infrastructure
|
||||
|
||||
The final step is to actually provision a `Bucket`. Creating the
|
||||
object below will result in the creation of a S3 bucket on AWS.
|
||||
|
||||
```console
|
||||
echo "apiVersion: s3.aws.crossplane.io/v1beta1
|
||||
kind: Bucket
|
||||
metadata:
|
||||
name: s3-vault-demo
|
||||
spec:
|
||||
forProvider:
|
||||
acl: private
|
||||
locationConstraint: us-east-1
|
||||
publicAccessBlockConfiguration:
|
||||
blockPublicPolicy: true
|
||||
tagging:
|
||||
tagSet:
|
||||
- key: Name
|
||||
value: s3-vault-demo
|
||||
providerConfigRef:
|
||||
name: default" | kubectl apply -f -
|
||||
```
|
||||
|
||||
You can monitor the progress of the bucket provisioning with the following
|
||||
command:
|
||||
|
||||
```console
|
||||
kubectl get bucket -w
|
||||
```
|
||||
|
||||
{{< /tab >}}
|
||||
{{< /tabs >}}
|
||||
|
||||
<!-- 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
|
||||
[provider-aws]: https://marketplace.upbound.io/providers/crossplane-contrib/provider-aws
|
||||
[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,29 +0,0 @@
|
|||
---
|
||||
title: Reference
|
||||
weight: 300
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
Recent versions of Crossplane documentation removed this document.
|
||||
{{</hint >}}
|
||||
|
||||
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]
|
||||
2. [Configure]
|
||||
3. [Uninstall]
|
||||
4. [Troubleshoot]
|
||||
5. [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,907 +0,0 @@
|
|||
---
|
||||
title: Composition
|
||||
weight: 304
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document moved in recent versions of Crossplane documentation.
|
||||
|
||||
Read the new
|
||||
[Crossplane Introduction]({{<ref "/v1.11/getting-started/introduction">}}).
|
||||
{{</hint >}}
|
||||
|
||||
|
||||
This reference provides detailed examples of defining, configuring, and using
|
||||
Composite Resources in Crossplane. You can also refer to Crossplane's [API
|
||||
documentation][api-docs] for more details. If you're looking for a more general
|
||||
overview of Composite Resources and Composition in Crossplane, try the
|
||||
[Composite Resources][xr-concepts] page under Concepts.
|
||||
|
||||
## Composite Resources and Claims
|
||||
|
||||
The type and most of the schema of Composite Resources and claims are largely of
|
||||
your own choosing, but there is some common 'machinery' injected into them.
|
||||
Here's a hypothetical XR that doesn't have any user-defined fields and thus only
|
||||
includes the automatically injected Crossplane machinery:
|
||||
|
||||
```yaml
|
||||
apiVersion: database.example.org/v1alpha1
|
||||
kind: XPostgreSQLInstance
|
||||
metadata:
|
||||
# This XR was created automatically by a claim, so its name is derived from
|
||||
# the claim's name.
|
||||
name: my-db-mfd1b
|
||||
annotations:
|
||||
# The external name annotation has special meaning in Crossplane. When a
|
||||
# claim creates an XR its external name will automatically be propagated to
|
||||
# the XR. Whether and how the external name is propagated to the resources
|
||||
# the XR composes is up to its Composition.
|
||||
crossplane.io/external-name: production-db-0
|
||||
spec:
|
||||
# XRs have a reference to the claim that created them (or, if the XR was
|
||||
# pre-provisioned, to the claim that later claimed them).
|
||||
claimRef:
|
||||
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
|
||||
# reference, or if the below composition selector is set.
|
||||
compositionRef:
|
||||
name: production-us-east
|
||||
# The compositionSelector allows you to match a Composition by labels rather
|
||||
# than naming one explicitly. It is used to set the compositionRef if none is
|
||||
# specified explicitly.
|
||||
compositionSelector:
|
||||
matchLabels:
|
||||
environment: production
|
||||
region: us-east
|
||||
provider: 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.
|
||||
resourceRefs:
|
||||
- apiVersion: database.gcp.crossplane.io/v1beta1
|
||||
kind: CloudSQLInstance
|
||||
name: my-db-mfd1b-md9ab
|
||||
# The writeConnectionSecretToRef field specifies a Kubernetes Secret that this
|
||||
# XR should write its connection details (if any) to.
|
||||
writeConnectionSecretToRef:
|
||||
namespace: crossplane-system
|
||||
name: my-db-connection-details
|
||||
status:
|
||||
# An XR's 'Ready' condition will become True when all of the resources it
|
||||
# composes are deemed ready. Refer to the Composition 'readinessChecks' field
|
||||
# for more information.
|
||||
conditions:
|
||||
- type: Ready
|
||||
statue: "True"
|
||||
reason: Available
|
||||
lastTransitionTime: 2021-10-02T07:20:50.52Z
|
||||
# The last time the XR published its connection details to a Secret.
|
||||
connectionDetails:
|
||||
lastPublishedTime: 2021-10-02T07:20:51.24Z
|
||||
```
|
||||
|
||||
Similarly, here's an example of the claim that corresponds to the above XR:
|
||||
|
||||
```yaml
|
||||
apiVersion: database.example.org/v1alpha1
|
||||
kind: PostgreSQLInstance
|
||||
metadata:
|
||||
# Claims are namespaced, unlike XRs.
|
||||
namespace: default
|
||||
name: my-db
|
||||
annotations:
|
||||
# The external name annotation has special meaning in Crossplane. When a
|
||||
# claim creates an XR its external name will automatically be propagated to
|
||||
# the XR. Whether and how the external name is propagated to the resources
|
||||
# the XR composes is up to its Composition.
|
||||
crossplane.io/external-name: production-db-0
|
||||
spec:
|
||||
# The resourceRef field references the XR this claim corresponds to. You can
|
||||
# either set it to an existing (compatible) XR that you'd like to claim or
|
||||
# (the more common approach) leave it blank and let Crossplane automatically
|
||||
# create and reference an XR for you.
|
||||
resourceRef:
|
||||
apiVersion: database.example.org/v1alpha1
|
||||
kind: XPostgreSQLInstance
|
||||
name: my-db-mfd1b
|
||||
# A claim's compositionRef and compositionSelector work the same way as an XR.
|
||||
compositionRef:
|
||||
name: production-us-east
|
||||
compositionSelector:
|
||||
matchLabels:
|
||||
environment: production
|
||||
region: us-east
|
||||
provider: gcp
|
||||
# A claim's writeConnectionSecretToRef mostly works the same way as an XR's.
|
||||
# The one difference is that the Secret is always written to the namespace of
|
||||
# the claim.
|
||||
writeConnectionSecretToRef:
|
||||
name: my-db-connection-details
|
||||
status:
|
||||
# A claim's 'Ready' condition will become True when its XR's 'Ready' condition
|
||||
# becomes True.
|
||||
conditions:
|
||||
- type: Ready
|
||||
statue: "True"
|
||||
reason: Available
|
||||
lastTransitionTime: 2021-10-02T07:20:50.52Z
|
||||
# The last time the claim published its connection details to a Secret.
|
||||
connectionDetails:
|
||||
lastPublishedTime: 2021-10-02T07:20:51.24Z
|
||||
```
|
||||
|
||||
> If your XR or claim isn't working as you'd expect you can try running `kubectl
|
||||
> describe` against it for details - pay particular attention to any events and
|
||||
> status conditions. You may need to follow the references from claim to XR to
|
||||
> composed resources to find out what's happening.
|
||||
|
||||
## CompositeResourceDefinitions
|
||||
|
||||
Below is an example `CompositeResourceDefinition` that includes all configurable
|
||||
fields.
|
||||
|
||||
```yaml
|
||||
apiVersion: apiextensions.crossplane.io/v1
|
||||
kind: CompositeResourceDefinition
|
||||
metadata:
|
||||
# XRDs must be named '<plural>.<group>', per the plural and group names below.
|
||||
name: xpostgresqlinstances.example.org
|
||||
spec:
|
||||
# This XRD defines an XR in the 'example.org' API group.
|
||||
group: example.org
|
||||
# The kind of this XR will be 'XPostgreSQLInstance`. You may also optionally
|
||||
# specify a singular name and a listKind.
|
||||
names:
|
||||
kind: XPostgreSQLInstance
|
||||
plural: xpostgresqlinstances
|
||||
# This type of XR offers a claim. Omit claimNames if you don't want to do so.
|
||||
# The claimNames must be different from the names above - a common convention
|
||||
# is that names are prefixed with 'X' while claim names are not. This lets app
|
||||
# team members think of creating a claim as (e.g.) 'creating a
|
||||
# PostgreSQLInstance'.
|
||||
claimNames:
|
||||
kind: PostgreSQLInstance
|
||||
plural: postgresqlinstances
|
||||
# Each type of XR can declare any keys they write to their connection secret
|
||||
# which will act as a filter during aggregation of the connection secret from
|
||||
# composed resources. It's recommended to provide the set of keys here so that
|
||||
# consumers of claims and XRs can see what to expect in the connection secret.
|
||||
# If no key is given, then all keys in the aggregated connection secret will
|
||||
# be written to the connection secret of the XR.
|
||||
connectionSecretKeys:
|
||||
- hostname
|
||||
# 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 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
|
||||
# from alpha to beta to production ready.
|
||||
versions:
|
||||
- name: v1alpha1
|
||||
# Served specifies that XRs should be served at this version. It can be set
|
||||
# to false to temporarily disable a version, for example to test whether
|
||||
# doing so breaks anything before a version is removed wholesale.
|
||||
served: true
|
||||
# Referenceable denotes the version of a type of XR that Compositions may
|
||||
# use. Only one version may be referenceable.
|
||||
referenceable: true
|
||||
# Schema is an OpenAPI schema just like the one used by Kubernetes CRDs. It
|
||||
# determines what fields your XR and claim will have. Note that Crossplane
|
||||
# will automatically extend with some additional Crossplane machinery.
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
type: object
|
||||
properties:
|
||||
spec:
|
||||
type: object
|
||||
properties:
|
||||
parameters:
|
||||
type: object
|
||||
properties:
|
||||
storageGB:
|
||||
type: integer
|
||||
required:
|
||||
- storageGB
|
||||
required:
|
||||
- parameters
|
||||
status:
|
||||
type: object
|
||||
properties:
|
||||
address:
|
||||
description: Address of this MySQL server.
|
||||
type: string
|
||||
```
|
||||
|
||||
Take a look at the Kubernetes [CRD documentation][crd-docs] for a more detailed
|
||||
guide to writing OpenAPI schemas. Note that the following fields are reserved
|
||||
for Crossplane machinery, and will be ignored if your schema includes them:
|
||||
|
||||
* `spec.resourceRef`
|
||||
* `spec.resourceRefs`
|
||||
* `spec.claimRef`
|
||||
* `spec.writeConnectionSecretToRef`
|
||||
* `status.conditions`
|
||||
* `status.connectionDetails`
|
||||
|
||||
> If your `CompositeResourceDefinition` isn't working as you'd expect you can
|
||||
> try running `kubectl describe xrd` for details - pay particular attention to
|
||||
> any events and status conditions.
|
||||
|
||||
## Compositions
|
||||
|
||||
You'll encounter a lot of 'field paths' when reading or writing a `Composition`.
|
||||
Field paths reference a field within a Kubernetes object via a simple string
|
||||
'path'. [API conventions][field-paths] describe the syntax as:
|
||||
|
||||
> Standard JavaScript syntax for accessing that field, assuming the JSON object
|
||||
> was transformed into a JavaScript object, without the leading dot, such as
|
||||
> `metadata.name`.
|
||||
|
||||
Valid field paths include:
|
||||
|
||||
* `metadata.name` - The `name` field of the `metadata` object.
|
||||
* `spec.containers[0].name` - The `name` field of the 0th `containers` element.
|
||||
* `data[.config.yml]` - The `.config.yml` field of the `data` object.
|
||||
* `apiVersion` - The `apiVersion` field of the root object.
|
||||
|
||||
While the following are invalid:
|
||||
|
||||
* `.metadata.name` - Leading period.
|
||||
* `metadata..name` - Double period.
|
||||
* `metadata.name.` - Trailing period.
|
||||
* `spec.containers[]` - Empty brackets.
|
||||
* `spec.containers.[0].name` - Period before open bracket.
|
||||
|
||||
Below is a detailed example of a `Composition`. While detailed, this example
|
||||
doesn't include every patch, transform, connection detail, and readiness check
|
||||
type. Keep reading below to discover those.
|
||||
|
||||
```yaml
|
||||
apiVersion: apiextensions.crossplane.io/v1
|
||||
kind: Composition
|
||||
metadata:
|
||||
name: example
|
||||
labels:
|
||||
# An optional convention is to include a label of the XRD. This allows
|
||||
# easy discovery of compatible Compositions.
|
||||
crossplane.io/xrd: xpostgresqlinstances.database.example.org
|
||||
# The following label marks this Composition for GCP. This label can
|
||||
# be used in 'compositionSelector' in an XR or Claim.
|
||||
provider: gcp
|
||||
spec:
|
||||
|
||||
# Each Composition must declare that it is compatible with a particular type
|
||||
# of Composite Resource using its 'compositeTypeRef' field. The referenced
|
||||
# version must be marked 'referenceable' in the XRD that defines the XR.
|
||||
compositeTypeRef:
|
||||
apiVersion: database.example.org/v1alpha1
|
||||
kind: XPostgreSQLInstance
|
||||
|
||||
# When an XR is created in response to a claim Crossplane needs to know where
|
||||
# it should create the XR's connection secret. This is configured using the
|
||||
# 'writeConnectionSecretsToNamespace' field.
|
||||
writeConnectionSecretsToNamespace: crossplane-system
|
||||
|
||||
# Each Composition must specify at least one composed resource template. In
|
||||
# this case the Composition tells Crossplane that it should create, update, or
|
||||
# delete a CloudSQLInstance whenever someone creates, updates, or deletes an
|
||||
# XPostgresSQLInstance.
|
||||
resources:
|
||||
|
||||
# It's good practice to provide a unique name for each entry. Note that
|
||||
# this identifies the resources entry within the Composition - it's not
|
||||
# the name the CloudSQLInstance. The 'name' field will be required in a
|
||||
# future version of this API.
|
||||
- name: cloudsqlinstance
|
||||
|
||||
# The 'base' template for the CloudSQLInstance Crossplane will create.
|
||||
# You can use the base template to specify fields that never change, or
|
||||
# default values for fields that may optionally be patched over. Bases must
|
||||
# be a valid Crossplane resource - a Managed Resource, Composite Resource,
|
||||
# or a ProviderConfig.
|
||||
base:
|
||||
apiVersion: database.gcp.crossplane.io/v1beta1
|
||||
kind: CloudSQLInstance
|
||||
spec:
|
||||
forProvider:
|
||||
databaseVersion: POSTGRES_12
|
||||
region: us-central1
|
||||
settings:
|
||||
dataDiskType: PD_SSD
|
||||
ipConfiguration:
|
||||
ipv4Enabled: true
|
||||
authorizedNetworks:
|
||||
- value: "0.0.0.0/0"
|
||||
|
||||
# Each resource can optionally specify a set of 'patches' that copy fields
|
||||
# from (or to) the XR.
|
||||
patches:
|
||||
# FromCompositeFieldPath is the default when 'type' is omitted, but it's
|
||||
# good practice to always include the type for readability.
|
||||
- type: FromCompositeFieldPath
|
||||
fromFieldPath: spec.parameters.size
|
||||
toFieldPath: spec.forProvider.settings.tier
|
||||
|
||||
# Each patch can optionally specify one or more 'transforms', which
|
||||
# transform the 'from' field's value before applying it to the 'to' field.
|
||||
# Transforms are applied in the order they are specified; each transform's
|
||||
# output is passed to the following transform's input.
|
||||
transforms:
|
||||
- type: map
|
||||
map:
|
||||
medium: db-custom-1-3840
|
||||
|
||||
policy:
|
||||
# By default a patch from a field path that does not exist is simply
|
||||
# skipped until it does. Use the 'Required' policy to instead block and
|
||||
# return an error when the field path does not exist.
|
||||
fromFieldPath: Required
|
||||
|
||||
# You can patch entire objects or arrays from one resource to another.
|
||||
# By default the 'to' object or array will be overwritten, not merged.
|
||||
# Use the 'mergeOptions' field to override this behaviour. Note that
|
||||
# these fields accidentally leak Go terminology - 'slice' means 'array'.
|
||||
# 'map' means 'map' in YAML or 'object' in JSON.
|
||||
mergeOptions:
|
||||
appendSlice: true
|
||||
keepMapValues: true
|
||||
|
||||
# You can include connection details to propagate from this CloudSQLInstance
|
||||
# up to the XPostgreSQLInstance XR (and then on to the PostgreSQLInstance
|
||||
# claim). Remember that your XRD must declare which connection secret keys
|
||||
# it supports.
|
||||
connectionDetails:
|
||||
- name: hostname
|
||||
fromConnectionSecretKey: hostname
|
||||
|
||||
# By default an XR's 'Ready' status condition will become True when the
|
||||
# 'Ready' status conditions of all of its composed resources become true.
|
||||
# You can optionally specify custom readiness checks to override this.
|
||||
readinessChecks:
|
||||
- type: None
|
||||
|
||||
|
||||
# If you find yourself repeating patches a lot you can group them as a named
|
||||
# 'patch set' then use a PatchSet type patch to reference them.
|
||||
patchSets:
|
||||
- name: metadata
|
||||
patches:
|
||||
- type: FromCompositeFieldPath
|
||||
# When both field paths are the same you can omit the 'toFieldPath' and it
|
||||
# will default to the 'fromFieldPath'.
|
||||
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`:
|
||||
|
||||
`FromCompositeFieldPath`. The default if the `type` is omitted. This type
|
||||
patches from a field within the XR to a field within the composed resource. It's
|
||||
commonly used to expose a composed resource spec field as an XR spec field.
|
||||
|
||||
```yaml
|
||||
# Patch from the XR's spec.parameters.size field to the composed resource's
|
||||
# spec.forProvider.settings.tier field.
|
||||
- type: FromCompositeFieldPath
|
||||
fromFieldPath: spec.parameters.size
|
||||
toFieldPath: spec.forProvider.settings.tier
|
||||
```
|
||||
|
||||
`ToCompositeFieldPath`. The inverse of `FromCompositeFieldPath`. This type
|
||||
patches from a field within the composed resource to a field within the XR. It's
|
||||
commonly used to derive an XR status field from a composed resource status
|
||||
field.
|
||||
|
||||
```yaml
|
||||
# Patch from the composed resource's status.atProvider.zone field to the XR's
|
||||
# status.zone field.
|
||||
- type: ToCompositeFieldPath
|
||||
fromFieldPath: status.atProvider.zone
|
||||
toFieldPath: status.zone
|
||||
```
|
||||
|
||||
`FromCompositeFieldPath` and `ToCompositeFieldPath` patches can also take a wildcarded
|
||||
field path in the `toFieldPath` parameter and patch each array element in the `toFieldPath`
|
||||
with the singular value provided in the `fromFieldPath`.
|
||||
|
||||
```yaml
|
||||
# Patch from the XR's spec.parameters.allowedIPs to the CIDRBlock elements
|
||||
# inside the array spec.forProvider.firewallRules on the composed resource.
|
||||
resources:
|
||||
- name: exampleFirewall
|
||||
base:
|
||||
apiVersion: firewall.example.crossplane.io/v1beta1
|
||||
kind: Firewall
|
||||
spec:
|
||||
forProvider:
|
||||
firewallRules:
|
||||
- Action: "Allow"
|
||||
Destination: "example1"
|
||||
CIDRBlock: ""
|
||||
- Action: "Allow"
|
||||
Destination: "example2"
|
||||
CIDRBlock: ""
|
||||
- type: FromCompositeFieldPath
|
||||
fromFieldPath: spec.parameters.allowedIP
|
||||
toFieldPath: spec.forProvider.firewallRules[*].CIDRBlock
|
||||
```
|
||||
|
||||
Note that the field to be patched requires some initial value to be set.
|
||||
|
||||
`CombineFromComposite`. Combines multiple fields from the XR to produce one
|
||||
composed resource field.
|
||||
|
||||
```yaml
|
||||
# Patch from the XR's spec.parameters.location field and the
|
||||
# metadata.labels[crossplane.io/claim-name] label to the composed
|
||||
# resource's spec.forProvider.administratorLogin field.
|
||||
- type: CombineFromComposite
|
||||
combine:
|
||||
# The patch will only be applied when all variables have non-zero values.
|
||||
variables:
|
||||
- fromFieldPath: spec.parameters.location
|
||||
- fromFieldPath: metadata.labels[crossplane.io/claim-name]
|
||||
strategy: string
|
||||
string:
|
||||
fmt: "%s-%s"
|
||||
toFieldPath: spec.forProvider.administratorLogin
|
||||
# By default Crossplane will skip the patch until all of the variables to be
|
||||
# combined have values. Set the fromFieldPath policy to 'Required' to instead
|
||||
# abort composition and return an error if a variable has no value.
|
||||
policy:
|
||||
fromFieldPath: Required
|
||||
```
|
||||
|
||||
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
|
||||
would be set to `us-west-db`.
|
||||
|
||||
`CombineToComposite` is the inverse of `CombineFromComposite`.
|
||||
|
||||
```yaml
|
||||
# Patch from the composed resource's spec.parameters.administratorLogin and
|
||||
# status.atProvider.fullyQualifiedDomainName fields back to the XR's
|
||||
# status.adminDSN field.
|
||||
- type: CombineToComposite
|
||||
combine:
|
||||
variables:
|
||||
- fromFieldPath: spec.parameters.administratorLogin
|
||||
- fromFieldPath: status.atProvider.fullyQualifiedDomainName
|
||||
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: status.adminDSN
|
||||
```
|
||||
|
||||
`PatchSet`. References a named set of patches defined in the `spec.patchSets`
|
||||
array of a `Composition`.
|
||||
|
||||
```yaml
|
||||
# This is equivalent to specifying all of the patches included in the 'metadata'
|
||||
# PatchSet.
|
||||
- type: PatchSet
|
||||
patchSetName: metadata
|
||||
```
|
||||
|
||||
The `patchSets` array may not contain patches of `type: PatchSet`. The
|
||||
`transforms` and `patchPolicy` fields are ignored by `type: PatchSet`.
|
||||
|
||||
### Transform Types
|
||||
|
||||
You can use the following types of transform on a value being patched:
|
||||
|
||||
`map`. Transforms values using a map.
|
||||
|
||||
```yaml
|
||||
# If the value of the 'from' field is 'us-west', the value of the 'to' field
|
||||
# will be set to 'West US'.
|
||||
- type: map
|
||||
map:
|
||||
us-west: West US
|
||||
us-east: East US
|
||||
au-east: Australia East
|
||||
```
|
||||
|
||||
`math`. Transforms values using math. The input value must be an integer.
|
||||
Currently only `multiply` is supported.
|
||||
|
||||
```yaml
|
||||
# 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
|
||||
```
|
||||
|
||||
`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 `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.
|
||||
|
||||
```yaml
|
||||
# If you omit the field type, by default type is set to `Format`
|
||||
# If the value of the 'from' field is 'hello', the value of the 'to' field will
|
||||
# be set to 'hello-world'.
|
||||
- type: string
|
||||
string:
|
||||
fmt: "%s-world"
|
||||
|
||||
# This is the same as above
|
||||
# the value of the 'to' field will be set to 'hello-world'.
|
||||
- type: string
|
||||
string:
|
||||
type: Format
|
||||
fmt: "%s-world"
|
||||
|
||||
# If the value of the 'from' field is 'hello', the value of the 'to' field will
|
||||
# be set to 'HELLO'.
|
||||
- type: string
|
||||
string:
|
||||
type: Convert
|
||||
convert: ToUpper
|
||||
|
||||
# If the value of the 'from' field is 'Hello', the value of the 'to' field will
|
||||
# be set to 'hello'.
|
||||
- type: string
|
||||
string:
|
||||
type: Convert
|
||||
convert: ToLower
|
||||
|
||||
# If the value of the 'from' field is 'Hello', the value of the 'to' field will
|
||||
# be set to 'SGVsbG8='.
|
||||
- type: string
|
||||
string:
|
||||
type: Convert
|
||||
convert: ToBase64
|
||||
|
||||
# If the value of the 'from' field is 'SGVsbG8=', the value of the 'to' field will
|
||||
# be set to 'Hello'.
|
||||
- type: string
|
||||
string:
|
||||
type: Convert
|
||||
convert: FromBase64
|
||||
|
||||
# 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
|
||||
string:
|
||||
type: TrimPrefix
|
||||
trim: 'https://'
|
||||
|
||||
# If the value of the 'from' field is my-string-test, the value of the 'to' field will
|
||||
# be set to my-string
|
||||
- type: string
|
||||
string:
|
||||
type: TrimSuffix
|
||||
trim: '-test'
|
||||
|
||||
# If the value of the 'from' field is 'arn:aws:iam::42:example, the value of the
|
||||
# 'to' field will be set to "42". Note that the 'to' field is always a string.
|
||||
- type: string
|
||||
string:
|
||||
type: Regexp
|
||||
regexp:
|
||||
match: 'arn:aws:iam::(\d+):.*'
|
||||
group: 1 # Optional capture group. Omit to match the entire regexp.
|
||||
```
|
||||
|
||||
`convert`. Transforms values of one type to another, for example from a string
|
||||
to an integer. The following values are supported by the `from` and `to` fields:
|
||||
|
||||
* `string`
|
||||
* `bool`
|
||||
* `int`
|
||||
* `int64`
|
||||
* `float64`
|
||||
|
||||
The strings 1, t, T, TRUE, true, and True are considered 'true', while 0, f, F,
|
||||
FALSE, false, and False are considered 'false'. The integer 1 and float 1.0 are
|
||||
considered true, while all other values are considered false. Similarly, boolean
|
||||
true converts to integer 1 and float 1.0, while false converts to 0 and 0.0.
|
||||
|
||||
```yaml
|
||||
# If the value to be converted is "1" (a string), the value of the 'toType'
|
||||
# field will be set to 1 (an integer).
|
||||
- type: convert
|
||||
convert:
|
||||
toType: int
|
||||
```
|
||||
|
||||
### Connection Details
|
||||
|
||||
Connection details secret of XR is an aggregated sum of the connection details
|
||||
of the composed resources. It's recommended that the author of XRD specify
|
||||
exactly which keys will be allowed in the XR connection secret by listing them
|
||||
in `spec.connectionSecretKeys` so that consumers of claims and XRs can see what
|
||||
they can expect in the connection details secret.
|
||||
|
||||
If `spec.connectionSecretKeys` is empty, then all keys of the aggregated connection
|
||||
details secret will be propagated.
|
||||
|
||||
You can derive the following types of connection details from a composed
|
||||
resource to be aggregated:
|
||||
|
||||
`FromConnectionSecretKey`. Derives an XR connection detail from a connection
|
||||
secret key of a composed resource.
|
||||
|
||||
```yaml
|
||||
# Derive the XR's 'user' connection detail from the 'username' key of the
|
||||
# composed resource's connection secret.
|
||||
- type: FromConnectionSecretKey
|
||||
name: user
|
||||
fromConnectionSecretKey: username
|
||||
```
|
||||
|
||||
`FromFieldPath`. Derives an XR connection detail from a field path within the
|
||||
composed resource.
|
||||
|
||||
```yaml
|
||||
# Derive the XR's 'user' connection detail from the 'adminUser' status field of
|
||||
# the composed resource.
|
||||
- type: FromFieldPath
|
||||
name: user
|
||||
fromFieldPath: status.atProvider.adminUser
|
||||
```
|
||||
|
||||
`FromValue`. Derives an XR connection detail from a fixed value.
|
||||
|
||||
```yaml
|
||||
# Always sets the XR's 'user' connection detail to 'admin'.
|
||||
- type: FromValue
|
||||
name: user
|
||||
value: admin
|
||||
```
|
||||
|
||||
### Readiness Checks
|
||||
|
||||
Crossplane can use the following types of readiness check to determine whether a
|
||||
composed resource is ready (and therefore whether the XR and claim should be
|
||||
considered ready). Specify multiple readiness checks if multiple conditions must
|
||||
be met for a composed resource to be considered ready.
|
||||
|
||||
> Note that if you don't specify any readiness checks Crossplane will consider
|
||||
> the composed resource to be ready when its 'Ready' status condition becomes
|
||||
> 'True'.
|
||||
|
||||
`MatchString`. Considers the composed resource to be ready when the value of a
|
||||
field within that resource matches a specified string.
|
||||
|
||||
```yaml
|
||||
# The composed resource will be considered ready when the 'state' status field
|
||||
# matches the string 'Online'.
|
||||
- type: MatchString
|
||||
fieldPath: status.atProvider.state
|
||||
matchString: "Online"
|
||||
```
|
||||
|
||||
`MatchInteger`. Considers the composed resource to be ready when the value of a
|
||||
field within that resource matches a specified integer.
|
||||
|
||||
```yaml
|
||||
# The composed resource will be considered ready when the 'state' status field
|
||||
# matches the integer 4.
|
||||
- type: MatchInteger
|
||||
fieldPath: status.atProvider.state
|
||||
matchInteger: 4
|
||||
```
|
||||
|
||||
`NonEmpty`. Considers the composed resource to be ready when a field exists in
|
||||
the composed resource. The name of this check can be a little confusing in that
|
||||
a field that exists with a zero value (e.g. an empty string or zero integer) is
|
||||
not considered to be 'empty', and thus will pass the readiness check.
|
||||
|
||||
```yaml
|
||||
# The composed resource will be considered ready if and when 'online' status
|
||||
# field exists.
|
||||
- type: NonEmpty
|
||||
fieldPath: status.atProvider.online
|
||||
```
|
||||
|
||||
`None`. Considers the composed resource to be ready as soon as it exists.
|
||||
|
||||
### Missing Functionality
|
||||
|
||||
You might find while reading through this reference that Crossplane is missing
|
||||
some functionality you need to compose resources. If that's the case, please
|
||||
[raise an issue] with as much detail **about your use case** as possible. Please
|
||||
understand that the Crossplane maintainers are growing the feature set of the
|
||||
`Composition` type conservatively. We highly value the input of our users and
|
||||
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
|
||||
[this proposal][issue-2524].
|
||||
|
||||
## Tips, Tricks, and Troubleshooting
|
||||
|
||||
In this section we'll cover some common tips, tricks, and troubleshooting steps
|
||||
for working with Composite Resources. If you're trying to track down why your
|
||||
Composite Resources aren't working the [Troubleshooting][trouble-ref] page also
|
||||
has some useful information.
|
||||
|
||||
### Troubleshooting Claims and XRs
|
||||
|
||||
Crossplane relies heavily on status conditions and events for troubleshooting.
|
||||
You can see both using `kubectl describe` - for example:
|
||||
|
||||
```console
|
||||
# Describe the PostgreSQLInstance claim named my-db
|
||||
kubectl describe postgresqlinstance.database.example.org my-db
|
||||
```
|
||||
|
||||
Per Kubernetes convention, Crossplane keeps errors close to the place they
|
||||
happen. This means that if your claim is not becoming ready due to an issue with
|
||||
your `Composition` or with a composed resource you'll need to "follow the
|
||||
references" to find out why. Your claim will only tell you that the XR is not
|
||||
yet ready.
|
||||
|
||||
To follow the references:
|
||||
|
||||
1. Find your XR by running `kubectl describe` on your claim and looking for its
|
||||
"Resource Ref" (aka `spec.resourceRef`).
|
||||
1. Run `kubectl describe` on your XR. This is where you'll find out about issues
|
||||
with the `Composition` you're using, if any.
|
||||
1. If there are no issues but your XR doesn't seem to be becoming ready, take a
|
||||
look for the "Resource Refs" (or `spec.resourceRefs`) to find your composed
|
||||
resources.
|
||||
1. Run `kubectl describe` on each referenced composed resource to determine
|
||||
whether it is ready and what issues, if any, it is encountering.
|
||||
|
||||
### Composite Resource Connection Secrets
|
||||
|
||||
Claim and Composite Resource connection secrets are often derived from the
|
||||
connection secrets of the managed resources they compose. This is a common
|
||||
source of confusion because several things need to align for it to work:
|
||||
|
||||
1. The **claim** must specify the secret where the aggregated connection details
|
||||
should be written
|
||||
* This is the `spec.writeConnectionSecretToRef` field in a claim
|
||||
* If creating a composite resource directly (without a claim) then this same
|
||||
field must be set on your composite resource instead
|
||||
1. The **composite resource definition** must state which connection details to
|
||||
aggregate from its children to publish to the claim
|
||||
* This is the `spec.connectionSecretKeys` field in a
|
||||
`CompositeResourceDefinition`
|
||||
1. The **composition** must define where to write its aggregated connection
|
||||
details
|
||||
* This is the `spec.writeConnectionSecretsToNamespace` field in the
|
||||
`Composition`
|
||||
1. Each child **composed resource** must define the connection details it
|
||||
publishes and where to write them
|
||||
* These are the `connectionDetails` and
|
||||
`base.spec.writeConnectionSecretToRef` fields of the composed resources
|
||||
|
||||
Finally, you can't currently edit a XRD's supported connection details. The
|
||||
XRD's `spec.connectionSecretKeys` is effectively immutable. This may change in
|
||||
future per [this issue][issue-2024]
|
||||
|
||||
### Claiming an Existing Composite Resource
|
||||
|
||||
Most people create Composite Resources using a claim, but you can actually claim
|
||||
an existing Composite Resource as long as its a type of XR that offers a claim
|
||||
and no one else has already claimed it. To do so:
|
||||
|
||||
1. Set the `spec.resourceRef` of your claim to reference the existing XR.
|
||||
1. Make sure the rest of your claim's spec fields match the XR's.
|
||||
|
||||
If your claim's spec fields don't match the XR's Crossplane will still claim it
|
||||
but will then try to update the XR's spec fields to match the claim's.
|
||||
|
||||
### Influencing External Names
|
||||
|
||||
The `crossplane.io/external-name` annotation has special meaning to Crossplane
|
||||
managed resources - it specifies the name (or identifier) of the resource in the
|
||||
external system, for example the actual name of a `CloudSQLInstance` in the GCP
|
||||
API. Some managed resources don't let you specify an external name - in those
|
||||
cases Crossplane will set it for you to whatever the external system requires.
|
||||
|
||||
If you add the `crossplane.io/external-name` annotation to a claim Crossplane
|
||||
will automatically propagate it when it creates an XR. It's good practice to
|
||||
have your `Composition` further propagate the annotation to one or more composed
|
||||
resources, but it's not required.
|
||||
|
||||
### Mixing and Matching Providers
|
||||
|
||||
Crossplane has providers for many things in addition to the big clouds. Take a
|
||||
look at the [Upbound Marketplace][upbound-marketplace] to find many of them.
|
||||
Keep in mind that you can mix and match managed resources from different
|
||||
providers within a `Composition` to create Composite Resources. For example you
|
||||
might use provider-aws and provider-sql to create an XR that provisions an
|
||||
`RDSInstance` then creates an SQL `Database` and `User`, or provider-gcp and
|
||||
provider-helm to create a `GKECluster` and deploy a Helm Chart `Release` to it.
|
||||
|
||||
Often when mixing and matching providers you'll need to compose a
|
||||
`ProviderConfig` for one provider that loads credentials from the connection
|
||||
secret of a managed resource from another provider. Sometimes you may need to
|
||||
use an intermediary XR to mutate the connection details to suit your needs.
|
||||
[This example][helm-and-gcp] from provider-helm demonstrates using a GKE cluster
|
||||
connection secret as Helm `ProviderConfig` credentials.
|
||||
|
||||
### Patching From One Composed Resource to Another
|
||||
|
||||
It's not possible to patch _directly_ from one composed resource to another -
|
||||
i.e. from one entry in the `spec.resources` array of a `Composition` to another.
|
||||
It is however possible to achieve this by using the XR as an intermediary. To do
|
||||
so:
|
||||
|
||||
1. Use a `ToCompositeFieldPath` patch to patch from your source composed
|
||||
resource to the XR. Typically you'll want to patch to a status field or an
|
||||
annotation.
|
||||
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
|
|
@ -1,29 +0,0 @@
|
|||
---
|
||||
title: Configure Your Cloud Provider Account
|
||||
weight: 302
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved in recent versions of Crossplane documentation.
|
||||
|
||||
Current Crossplane documentation versions introduce configurations as part of
|
||||
the [Getting Started]({{<ref "/v1.11/getting-started" >}}) guides.
|
||||
{{</hint >}}
|
||||
|
||||
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,61 +0,0 @@
|
|||
---
|
||||
title: Feature Lifecycle
|
||||
toc: true
|
||||
weight: 309
|
||||
indent: true
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved.
|
||||
Read the recent version in the
|
||||
[Crossplane Knowledge Base]({{< ref "knowledge-base/guides/feature-lifecycle" >}}).
|
||||
{{</hint >}}
|
||||
# Feature Lifecycle
|
||||
|
||||
Crossplane follows a similar feature lifecycle to [upstream
|
||||
Kubernetes][kube-features]. All major new features must be added in alpha. Alpha
|
||||
features are expected to eventually graduate to beta, and then to general
|
||||
availability (GA). Features that languish at alpha or beta may be subject to
|
||||
deprecation.
|
||||
|
||||
## Alpha Features
|
||||
|
||||
Alpha are off by default, and must be enabled by a feature flag, for example
|
||||
`--enable-composition-revisions`. API types pertaining to alpha features use a
|
||||
`vNalphaN` style API version, like `v1alpha`. **Alpha features are subject to
|
||||
removal or breaking changes without notice**, and generally not considered ready
|
||||
for use in production.
|
||||
|
||||
In some cases alpha features require fields be added to existing beta or GA
|
||||
API types. In these cases fields must clearly be marked (i.e in their OpenAPI
|
||||
schema) as alpha and subject to alpha API constraints (or lack thereof).
|
||||
|
||||
All alpha features should have an issue tracking their graduation to beta.
|
||||
|
||||
## Beta Features
|
||||
|
||||
Beta features are on by default, but may be disabled by a feature flag. API
|
||||
types pertaining to beta features use a `vNbetaN` style API version, like
|
||||
`v1beta1`. Beta features are considered to be well tested, and will not be
|
||||
removed completely without being marked deprecated for at least two releases.
|
||||
|
||||
The schema and/or semantics of objects may change in incompatible ways in a
|
||||
subsequent beta or stable release. When this happens, we will provide
|
||||
instructions for migrating to the next version. This may require deleting,
|
||||
editing, and re-creating API objects. The editing process may require some
|
||||
thought. This may require downtime for applications that rely on the feature.
|
||||
|
||||
In some cases beta features require fields be added to existing GA API types. In
|
||||
these cases fields must clearly be marked (i.e in their OpenAPI schema) as beta
|
||||
and subject to beta API constraints (or lack thereof).
|
||||
|
||||
All beta features should have an issue tracking their graduation to GA.
|
||||
|
||||
## GA Features
|
||||
|
||||
GA features are always enabled - they cannot be disabled. API types pertaining
|
||||
to GA features use `vN` style API versions, like `v1`. GA features are widely
|
||||
used and thoroughly tested. They guarantee API stability - only backward
|
||||
compatible changes are allowed.
|
||||
|
||||
[kube-features]: https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/#feature-stages
|
|
@ -1,165 +0,0 @@
|
|||
---
|
||||
title: Install Crossplane
|
||||
weight: 301
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved in recent versions of Crossplane documentation.
|
||||
|
||||
Read the current [Install and Upgrade]({{<ref "/v1.11/software" >}}) guide.
|
||||
{{</hint >}}
|
||||
|
||||
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
|
||||
|
||||
{{< 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 | `{}` |
|
||||
| `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
|
||||
```
|
||||
|
||||
<!-- 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,38 +0,0 @@
|
|||
---
|
||||
title: Learn More
|
||||
weight: 307
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
Recent versions of Crossplane documentation removed this document.
|
||||
{{</hint >}}
|
||||
|
||||
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,97 +0,0 @@
|
|||
---
|
||||
title: Release Cycle
|
||||
weight: 308
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved.
|
||||
Read the recent version in the
|
||||
[Crossplane Knowledge Base]({{< ref "knowledge-base/guides/release-cycle" >}}).
|
||||
{{</hint >}}
|
||||
|
||||
Starting with the v1.10.0 release, Crossplane is released on a quarterly (13
|
||||
week) cadence. A cycle is comprised of three general stages:
|
||||
|
||||
- Weeks 1-11: [Active Development]
|
||||
- Week 12: [Feature Freeze]
|
||||
- Week 13: [Code Freeze]
|
||||
|
||||
This results in four 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 nine 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,281 +0,0 @@
|
|||
---
|
||||
title: Troubleshoot
|
||||
weight: 306
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved.
|
||||
Read the recent version in the
|
||||
[Crossplane Knowledge Base]({{< ref "knowledge-base/guides/troubleshoot" >}}).
|
||||
{{</hint >}}
|
||||
|
||||
## 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]({{<ref "../getting-started/install-configure" >}})
|
||||
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 use `kubectl describe` for the resource.
|
||||
|
||||
```shell {copy-lines="1"}
|
||||
kubectl describe cloudsqlinstance my-db
|
||||
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:
|
||||
|
||||
```shell
|
||||
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:
|
||||
|
||||
```shell
|
||||
kubectl patch cloudsqlinstance my-db -p '{"metadata":{"finalizers": []}}' --type=merge
|
||||
```
|
||||
|
||||
## Installing Crossplane Package
|
||||
|
||||
After installing [Crossplane package]({{<ref "../concepts/packages" >}}), 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:
|
||||
|
||||
```shell
|
||||
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:
|
||||
|
||||
```shell
|
||||
kubectl get pkg
|
||||
```
|
||||
|
||||
When there are errors, you can run below command to check detailed information
|
||||
for the packages that are getting installed.
|
||||
|
||||
```shell
|
||||
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
|
||||
[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
|
||||
[Handling Crossplane Package Dependency]: #handling-crossplane-package-dependency
|
||||
[semver spec]: https://github.com/Masterminds/semver#basic-comparisons
|
|
@ -1,93 +0,0 @@
|
|||
---
|
||||
title: Uninstall Crossplane
|
||||
weight: 303
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved in recent versions of Crossplane documentation.
|
||||
|
||||
Read the current [Install and Upgrade]({{<ref "/v1.11/software" >}}) guide.
|
||||
{{</hint >}}
|
||||
|
||||
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,217 +0,0 @@
|
|||
---
|
||||
title: xpkg Specification
|
||||
weight: 305
|
||||
---
|
||||
|
||||
{{<hint "important" >}}
|
||||
This document has moved in recent versions of Crossplane documentation.
|
||||
|
||||
Read the current [Crossplane Packages]({{<ref "/v1.11/concepts/packages" >}}) guide.
|
||||
{{</hint >}}
|
||||
|
||||
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,14 +0,0 @@
|
|||
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
|
|
@ -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/v1
|
||||
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.8.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/v1
|
||||
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.8.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/v1
|
||||
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.8.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/v1
|
||||
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.8.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
|
Loading…
Reference in New Issue