docs snapshot for crossplane version `v1.2`

This commit is contained in:
Crossplane 2021-04-27 23:10:18 +00:00
parent 720d39fbf8
commit dac345a31c
82 changed files with 9355 additions and 1 deletions

View File

@ -1 +1 @@
[{"version":"v1.1","path":"/docs/v1.1"},{"version":"v1.0","path":"/docs/v1.0"},{"version":"v0.14","path":"/docs/v0.14"},{"version":"v0.13","path":"/docs/v0.13"},{"version":"v0.12","path":"/docs/v0.12"},{"version":"v0.11","path":"/docs/v0.11"},{"version":"v0.10","path":"/docs/v0.10"},{"version":"v0.9","path":"/docs/v0.9"},{"version":"v0.8","path":"/docs/v0.8"},{"version":"v0.7","path":"/docs/v0.7"},{"version":"v0.6","path":"/docs/v0.6"},{"version":"v0.5","path":"/docs/v0.5"},{"version":"v0.4","path":"/docs/v0.4"},{"version":"v0.3","path":"/docs/v0.3"},{"version":"v0.2","path":"/docs/v0.2"},{"version":"v0.1","path":"/docs/v0.1"},{"version":"master","path":"/docs/master"}]
[{"version":"v1.2","path":"/docs/v1.2"},{"version":"v1.1","path":"/docs/v1.1"},{"version":"v1.0","path":"/docs/v1.0"},{"version":"v0.14","path":"/docs/v0.14"},{"version":"v0.13","path":"/docs/v0.13"},{"version":"v0.12","path":"/docs/v0.12"},{"version":"v0.11","path":"/docs/v0.11"},{"version":"v0.10","path":"/docs/v0.10"},{"version":"v0.9","path":"/docs/v0.9"},{"version":"v0.8","path":"/docs/v0.8"},{"version":"v0.7","path":"/docs/v0.7"},{"version":"v0.6","path":"/docs/v0.6"},{"version":"v0.5","path":"/docs/v0.5"},{"version":"v0.4","path":"/docs/v0.4"},{"version":"v0.3","path":"/docs/v0.3"},{"version":"v0.2","path":"/docs/v0.2"},{"version":"v0.1","path":"/docs/v0.1"},{"version":"master","path":"/docs/master"}]

52
docs/v1.2/README.md Normal file
View File

@ -0,0 +1,52 @@
# Overview
![Crossplane](media/banner.png)
Crossplane is an open source Kubernetes add-on that enables platform teams to
assemble infrastructure from multiple vendors, and expose higher level
self-service APIs for application teams to consume. Crossplane effectively
enables platform teams to quickly put together their own opinionated platform
declaratively without having to write any code, and offer it to their
application teams as a self-service Kubernetes-style declarative API.
Both the higher level abstractions as well as the granular resources they are
composed of are represented simply as objects in the Kubernetes API, meaning
they can all be provisioned and managed by kubectl, GitOps, or any tools that
can talk with the Kubernetes API. To facilitate reuse and sharing of these APIs,
Crossplane supports packaging them in a standard OCI image and distributing via
any compliant registry.
Platform engineers are able to define organizational policies and guardrails
behind these self-service API abstractions. The developer is presented with the
limited set of configuration that they need to tune for their use-case and is
not exposed to any of the complexities of the low-level infrastructure below the
API. Access to these APIs is managed with Kubernetes-native RBAC, thus enabling
the level of permissioning to be at the level of abstraction.
While extending the Kubernetes control plane with a diverse set of vendors,
resources, and abstractions, Crossplane recognized the need for a single
consistent API across all of them. To this end, we have created the Crossplane
Resource Model (XRM). XRM extends the Kubernetes Resource Model (KRM) in an
opinionated way, resulting in a universal experience for managing resources,
regardless of where they reside. When interacting with the XRM, things like
credentials, workload identity, connection secrets, status conditions, deletion
policies, and references to other resources work the same no matter what
provider or level of abstraction they are a part of.
The functionality and value of the Crossplane project can be summarized at a
very high level by these two main areas:
1. Enabling infrastructure owners to build custom platform abstractions (APIs)
composed of granular resources that allow developer self-service and service
catalog use cases
2. Providing a universal experience for managing infrastructure, resources, and
abstractions consistently across all vendors and environments in a uniform
way, called the Crossplane Resource Model (XRM)
## Getting Started
[Install Crossplane] into any Kubernetes cluster to get started.
<!-- Named Links -->
[Install Crossplane]: getting-started/install-configure.md

View File

@ -0,0 +1,142 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.3.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: []

View File

@ -0,0 +1,268 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.3.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. ResourceAll represents all resources.
items:
type: string
type: array
verbs:
description: Verbs is a list of Verbs that apply to ALL
the ResourceKinds and AttributeRestrictions contained
in this rule. VerbAll represents all kinds.
items:
type: string
type: array
required:
- verbs
type: object
type: array
required:
- image
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. ResourceAll represents all resources.
items:
type: string
type: array
verbs:
description: Verbs is a list of Verbs that apply to ALL
the ResourceKinds and AttributeRestrictions contained
in this rule. VerbAll represents all kinds.
items:
type: string
type: array
required:
- verbs
type: object
type: array
required:
- image
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: []

View File

@ -0,0 +1,7 @@
---
title: crossplane
toc: true
weight: 401
indent: true
redirect_to: https://doc.crds.dev/github.com/crossplane/crossplane
---

View File

@ -0,0 +1,7 @@
---
title: oam-kubernetes-runtime
toc: true
weight: 408
indent: true
redirect_to: https://doc.crds.dev/github.com/crossplane/oam-kubernetes-runtime
---

View File

@ -0,0 +1,39 @@
---
title: API Documentation
toc: true
weight: 400
---
# API Documentation
The Crossplane ecosystem contains many CRDs that map to API types represented by
external infrastructure providers. The documentation for these CRDs are
auto-generated on [doc.crds.dev]. To find the CRDs available for providers
maintained by the Crossplane organization, you can search for the Github URL, or
append it in the [doc.crds.dev] URL path.
For instance, to find the CRDs available for [provider-azure], you would go to:
[doc.crds.dev/github.com/crossplane/provider/azure]
By default, you will be served the latest CRDs on the `master` branch for the
repository. If you prefer to see the CRDs for a specific version, you can append
the git tag for the release:
[doc.crds.dev/github.com/crossplane/provider-azure@v0.8.0]
Crossplane repositories that are not providers but do publish CRDs are also
served on [doc.crds.dev]. For instance, the [crossplane/crossplane] repository.
Bugs and feature requests for API documentation should be [opened as issues] on
the open source [doc.crds.dev repo].
<!-- Named Links -->
[doc.crds.dev]: https://doc.crds.dev/
[provider-azure]: https://github.com/crossplane/provider-azure
[doc.crds.dev/github.com/crossplane/provider/azure]: https://doc.crds.dev/github.com/crossplane/provider-azure
[doc.crds.dev/github.com/crossplane/provider-azure@v0.8.0]: https://doc.crds.dev/github.com/crossplane/provider-azure@v0.8.0
[crossplane/crossplane]: https://doc.crds.dev/github.com/crossplane/crossplane
[opened as issues]: https://github.com/crdsdev/doc/issues/new
[doc.crds.dev repo]: https://github.com/crdsdev/doc

View File

@ -0,0 +1,7 @@
---
title: provider-alibaba
toc: true
weight: 402
indent: true
redirect_to: https://doc.crds.dev/github.com/crossplane/provider-alibaba
---

View File

@ -0,0 +1,7 @@
---
title: provider-aws
toc: true
weight: 403
indent: true
redirect_to: https://doc.crds.dev/github.com/crossplane/provider-aws
---

View File

@ -0,0 +1,7 @@
---
title: provider-azure
toc: true
weight: 404
indent: true
redirect_to: https://doc.crds.dev/github.com/crossplane/provider-azure
---

View File

@ -0,0 +1,7 @@
---
title: provider-gcp
toc: true
weight: 405
indent: true
redirect_to: https://doc.crds.dev/github.com/crossplane/provider-gcp
---

View File

@ -0,0 +1,7 @@
---
title: provider-helm
toc: true
weight: 407
indent: true
redirect_to: https://doc.crds.dev/github.com/crossplane-contrib/provider-helm
---

View File

@ -0,0 +1,7 @@
---
title: provider-rook
toc: true
weight: 406
indent: true
redirect_to: https://doc.crds.dev/github.com/crossplane/provider-rook
---

View File

@ -0,0 +1,143 @@
# Adding Amazon Web Services (AWS) to Crossplane
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/master/docs/snippets/configure/aws/providerconfig.yaml
curl -O https://raw.githubusercontent.com/crossplane/crossplane/master/docs/snippets/configure/aws/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:
credentials: ${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: credentials
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/cli-chap-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/cli-chap-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

View File

@ -0,0 +1,129 @@
# Adding Microsoft Azure to Crossplane
In this guide, we will walk through the steps necessary to configure your Azure
account to be ready for integration with Crossplane. The general steps we will
take are summarized below:
* Create a new service principal (account) that Crossplane will use to create
and manage Azure resources
* Add the required permissions to the account
* Consent to the permissions using an administrator account
## Preparing your Microsoft Azure Account
In order to manage resources in Azure, you must provide credentials for a Azure
service principal that Crossplane can use to authenticate. This assumes that you
have already [set up the Azure CLI
client](https://docs.microsoft.com/en-us/cli/azure/authenticate-azure-cli?view=azure-cli-latest)
with your credentials.
Create a JSON file that contains all the information needed to connect and
authenticate to Azure:
```bash
# create service principal with Owner role
az ad sp create-for-rbac --sdk-auth --role Owner > crossplane-azure-provider-key.json
```
Take note of the `clientID` value from the JSON file that we just created, and
save it to an environment variable:
```bash
export AZURE_CLIENT_ID=<clientId value from json file>
```
Now add the required permissions to the service principal that will allow it to
manage the necessary resources in Azure:
```bash
# add required Azure Active Directory permissions
az ad app permission add --id ${AZURE_CLIENT_ID} --api 00000002-0000-0000-c000-000000000000 --api-permissions 1cda74f2-2616-4834-b122-5cb1b07f8a59=Role 78c8a3c8-a07e-4b9e-af1b-b5ccab50a175=Role
# grant (activate) the permissions
az ad app permission grant --id ${AZURE_CLIENT_ID} --api 00000002-0000-0000-c000-000000000000 --expires never
```
You might see an error similar to the following, but that is OK, the permissions
should have gone through still:
```console
Operation failed with status: 'Conflict'. Details: 409 Client Error: Conflict for url: https://graph.windows.net/e7985bc4-a3b3-4f37-b9d2-fa256023b1ae/oauth2PermissionGrants?api-version=1.6
```
Finally, you need to grant admin permissions on the Azure Active Directory to
the service principal because it will need to create other service principals
for your `AKSCluster`:
```bash
# grant admin consent to the service princinpal you created
az ad app permission admin-consent --id "${AZURE_CLIENT_ID}"
```
Note: You might need `Global Administrator` role to `Grant admin consent for
Default Directory`. Please contact the administrator of your Azure subscription.
To check your role, go to `Azure Active Directory` -> `Roles and
administrators`. You can find your role(s) by clicking on `Your Role (Preview)`
After these steps are completed, you should have the following file on your
local filesystem:
* `crossplane-azure-provider-key.json`
## Setup Azure ProviderConfig
Before creating any resources, we need to create and configure an Azure cloud
provider resource in Crossplane, which stores the cloud account information in
it. All the requests from Crossplane to Azure Cloud will use the credentials
attached to this provider resource. The following command assumes that you have
a `crossplane-azure-provider-key.json` file that belongs to the account youd
like Crossplane to use.
```bash
BASE64ENCODED_AZURE_ACCOUNT_CREDS=$(base64 crossplane-azure-provider-key.json | tr -d "\n")
```
Now well 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.

View File

@ -0,0 +1,264 @@
# Adding Google Cloud Platform (GCP) to Crossplane
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/master/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` button
- This should advance to the next section `2 Grant this service account to
project (optional)`
- We will assign this account 3 roles:
- `Service Account User`
- `Cloud SQL Admin`
- `Kubernetes Engine Admin`
- `Compute Network Admin`
- Click `Create` 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 well 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:
credentials: ${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: credentials
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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View File

@ -0,0 +1,901 @@
---
title: Composing Infrastructure
toc: true
weight: 103
indent: true
---
# Composing Infrastructure
## Composition
Providers extend Crossplane with custom resources that can be used to
declaratively configure a system. The AWS provider for example, adds custom
resources for AWS services like RDS and S3. We call these 'managed resources'.
Managed resources match the APIs of the system they represent as closely as
possible, but theyre also opinionated. Common functionality like status
conditions and references work the same no matter which provider you're using -
all managed resources comply with the Crossplane Resource Model, or XRM. Despite
the name, 'provider' doesnt necessarily mean 'cloud provider'. The Crossplane
community has built providers that add support for managing databases on a SQL
server, managing Helm releases, and ordering pizza.
Composition allows platform builders to define new custom resources that are
composed of managed resources. We call these composite resources, or XRs. An XR
typically groups together a handful of managed resources into one logical
resource, exposing only the settings that the platform builer deems useful and
deferring the rest to an API-server-side template we call a 'Composition'.
Composition can be used to build a catalogue of custom resources and classes of
configuration that fit the needs and opinions of your organisation. A platform
team might define their own `MySQLInstance` XR, for example. This XR would allow
the platform customers they support to self-service their database needs by
ensuring they can configure only the settings that _your_ organisation needs -
perhaps engine version and storage size. All other settings are deferred to a
selectable composition representing a configuration class like "production" or
"staging". Compositions can hide infrastructure complexity and include policy
guardrails so that applications can easily and safely consume the infrastructure
they need, while conforming to your organisational best-practices.
## Concepts
![Infrastructure Composition Concepts]
A _Composite Resource_ (XR) is a special kind of custom resource that is
composed of other resources. Its schema is user-defined. The
`CompositeMySQLInstance` in the above diagram is a composite resource. The kind
of a composite resource is configurable - the `Composite` prefix is not
required.
A `Composition` specifies how Crossplane should reconcile a composite
infrastructure resource - i.e. what infrastructure resources it should compose.
For example the Azure `Composition` configures Crossplane to reconcile a
`CompositeMySQLInstance` by creating and managing the lifecycle of an Azure
`MySQLServer` and `MySQLServerFirewallRule`.
A _Composite Resource Claim_ (XRC) for an resource declares that an application
requires particular kind of infrastructure, as well as specifying how to
configure it. The `MySQLInstance` resources in the above diagram declare that
the application pods each require a `CompositeMySQLInstance`. As with composite
resources, the kind of the claim is configurable. Offering a claim is optional.
A `CompositeResourceDefinition` (XRD) defines a new kind of composite resource,
and optionally the claim it offers. The `CompositeResourceDefinition` in the
above diagram defines the `CompositeMySQLInstance` composite resource, and its
corresponding `MySQLInstance` claim.
> Note that composite resources and compositions are _cluster scoped_ - they
> exist outside of any Kubernetes namespace. A claim is a namespaced proxy for a
> composite resource. This enables Crossplane to model complex relationships
> between XRs that may span namespace boundaries - for example MySQLInstances
> spread across multiple namespaces can all share a VPC that exists above any
> namespace.
## Creating A New Kind of Composite Resource
New kinds of composite resource are defined by a platform builder. There are
two steps to this process:
1. Define your composite resource, and optionally the claim it offers.
1. Specify one or more possible ways your composite resource may be composed.
### Define your Composite Resource
Composite resources are defined by a `CompositeResourceDefinition`:
```yaml
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
# XRDs follow the constraints of CRD names. They must be named
# <plural>.<group>, per the plural and group names configured by the
# crdSpecTemplate below.
name: compositemysqlinstances.example.org
spec:
# Composite resources may optionally expose a connection secret - a Kubernetes
# Secret containing all of the details a pod might need to connect to the
# resource. Resources that wish to expose a connection secret must declare
# what keys they support. These keys form a 'contract' - any composition that
# intends to be compatible with this resource must compose resources that
# supply these connection secret keys.
connectionSecretKeys:
- username
- password
- hostname
- port
# You can specify a default Composition resource to be selected if there is
# no composition selector or reference was supplied on the Custom Resource.
defaultCompositionRef:
name: example-azure
# An enforced composition will be selected for all instances of this type and
# will override any selectors and references.
# enforcedCompositionRef:
# name: securemysql.acme.org
group: example.org
# The defined kind of composite resource.
names:
kind: CompositeMySQLInstance
plural: compositemysqlinstances
# The kind of claim this composite resource offers. Optional - omit the claim
# names if you don't wish to offer a claim for this composite resource. Must
# be different from the composite resource's kind. The established convention
# is for the claim kind to represent what the resource is, conceptually. e.g.
# 'MySQLInstance', not `MySQLInstanceClaim`.
claimNames:
kind: MySQLInstance
plural: mysqlinstances
# A composite resource may be served at multiple versions simultaneously, but
# all versions must have identical schemas; Crossplane does not yet support
# conversion between different version schemas.
versions:
- name: v1alpha1
# Served specifies whether this version should be exposed via the API
# server's REST API.
served: true
# Referenceable specifies whether this version may be referenced by a
# Composition. Exactly one version may be referenceable by Compositions, and
# that version must be served. The referenceable version will always be the
# storage version of the underlying CRD.
referenceable: true
# This schema defines the configuration fields that the composite resource
# supports. It uses the same structural OpenAPI schema as a Kubernetes CRD
# - for example, this resource supports a spec.parameters.version enum.
# The following fields are reserved for Crossplane's use, and will be
# overwritten if included in this validation schema:
#
# - spec.resourceRef
# - spec.resourceRefs
# - spec.claimRef
# - spec.writeConnectionSecretToRef
# - status.conditions
# - status.connectionDetails
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
parameters:
type: object
properties:
version:
description: MySQL engine version
type: string
enum: ["5.6", "5.7"]
storageGB:
type: integer
location:
description: Geographic location of this MySQL server.
type: string
required:
- version
- storageGB
- location
required:
- parameters
# The status subresource can be optionally defined in the XRD
# schema to allow observed fields from the composed resources
# to be set in the composite resource and claim.
status:
type: object
properties:
address:
description: Address of this MySQL server.
type: string
```
Refer to the Kubernetes documentation on [structural schemas] for full details
on how to configure the `openAPIV3Schema` for your composite resource.
`kubectl describe` can be used to confirm that a new composite
resource was successfully defined. Note the `Established` condition and events,
which indicate the process was successful.
```console
$ kubectl describe xrd compositemysqlinstances.example.org
Name: compositemysqlinstances.example.org
Namespace:
Labels: <none>
Annotations: <none>
API Version: apiextensions.crossplane.io/v1
Kind: CompositeResourceDefinition
Metadata:
Creation Timestamp: 2020-05-15T05:30:44Z
Finalizers:
offered.apiextensions.crossplane.io
defined.apiextensions.crossplane.io
Generation: 1
Resource Version: 1418120
UID: f8fedfaf-4dfd-4b8a-8228-6af0f4abd7a0
Spec:
Connection Secret Keys:
username
password
hostname
port
Default Composition Ref:
Name: example-azure
Group: example.org
Names:
Kind: CompositeMySQLInstance
List Kind: CompositeMySQLInstanceList
Plural: compositemysqlinstances
Singular: compositemysqlinstance
Claim Names:
Kind: MySQLInstance
List Kind: MySQLInstanceList
Plural: mysqlinstances
Singular: mysqlinstance
Versions:
Name: v1alpha1
Served: true
Referenceable: true
Schema:
openAPIV3Schema:
Properties:
Spec:
Properties:
Parameters:
Properties:
Location:
Description: Geographic location of this MySQL server.
Type: string
Storage GB:
Type: integer
Version:
Description: MySQL engine version
Enum:
5.6
5.7
Type: string
Required:
version
storageGB
location
Type: object
Required:
parameters
Type: object
Status:
Properties:
Address:
Description: Address of this MySQL server.
Type: string
Type: object
Type: object
Status:
Conditions:
Last Transition Time: 2020-05-15T05:30:45Z
Reason: WatchingCompositeResource
Status: True
Type: Established
Last Transition Time: 2020-05-15T05:30:45Z
Reason: WatchingCompositeResourceClaim
Status: True
Type: Offered
Controllers:
Composite Resource Claim Type:
API Version: example.org/v1alpha1
Kind: MySQLInstance
Composite Resource Type:
API Version: example.org/v1alpha1
Kind: CompositeMySQLInstance
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal EstablishComposite 4m10s defined/compositeresourcedefinition.apiextensions.crossplane.io waiting for composite resource CustomResourceDefinition to be established
Normal OfferClaim 4m10s offered/compositeresourcedefinition.apiextensions.crossplane.io waiting for composite resource claim CustomResourceDefinition to be established
Normal ApplyClusterRoles 4m9s (x4 over 4m10s) rbac/compositeresourcedefinition.apiextensions.crossplane.io Applied RBAC ClusterRoles
Normal RenderCRD 4m7s (x8 over 4m10s) defined/compositeresourcedefinition.apiextensions.crossplane.io Rendered composite resource CustomResourceDefinition
Normal EstablishComposite 4m7s (x6 over 4m10s) defined/compositeresourcedefinition.apiextensions.crossplane.io Applied composite resource CustomResourceDefinition
Normal EstablishComposite 4m7s (x5 over 4m10s) defined/compositeresourcedefinition.apiextensions.crossplane.io (Re)started composite resource controller
Normal RenderCRD 4m7s (x6 over 4m10s) offered/compositeresourcedefinition.apiextensions.crossplane.io Rendered composite resource claim CustomResourceDefinition
Normal OfferClaim 4m7s (x4 over 4m10s) offered/compositeresourcedefinition.apiextensions.crossplane.io Applied composite resource claim CustomResourceDefinition
Normal OfferClaim 4m7s (x3 over 4m10s) offered/compositeresourcedefinition.apiextensions.crossplane.io (Re)started composite resource claim controller
```
### Specify How Your Resource May Be Composed
Once a new kind of composite resource is defined Crossplane must be instructed
how to reconcile that kind of resource. This is done by authoring a
`Composition`.
A `Composition`:
* Declares one kind of composite resource that it satisfies.
* Specifies a "base" configuration for one or more composed resources.
* Specifies "patches" that overlay configuration values from an instance of the
composite resource onto each "base".
Multiple compositions may satisfy a particular kind of composite resource, and
the author of a composite resource (or resource claim) may select which
composition will be used. This allows a platform builder to expose a subset of
configuration to their customers in a granular fashion, and defer the rest to
fixed classes of configuration. A platform builder may offer their customers the
choice between an "Azure" and a "GCP" composition, or they may offer a choice
between a "production" and a "staging" composition. They can also offer a
default composition in case their customers do not supply a composition selector
or enforce a specific composition in order to override the composition choice of
users for all instances. In all cases, the customer may configure any value
supported by the composite resource's schema, with all other values being
deferred to the composition.
The below `Composition` satisfies the `CompositeMySQLInstance` defined in the
previous section by composing an Azure SQL server, firewall rule, and resource
group:
```yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: example-azure
labels:
purpose: example
provider: azure
spec:
# This Composition declares that it satisfies the CompositeMySQLInstance
# resource defined above - i.e. it patches "from" a CompositeMySQLInstance.
# Note that the version in apiVersion must be the referenceable version of the
# XRD.
compositeTypeRef:
apiVersion: example.org/v1alpha1
kind: CompositeMySQLInstance
# This Composition defines a patch set with the name "metadata", which consists
# of 2 individual patches. Patch sets can be referenced from any of the base
# resources within the Composition to avoid having to repeat patch definitions.
# A PatchSet can contain any of the other patch types, except another PatchSet.
patchSets:
- name: metadata
patches:
# When toFieldPath is omitted it defaults to fromFieldPath.
- fromFieldPath: metadata.labels
# Exercise caution when patching labels and annotations. Crossplane replaces
# patched objects - it does not merge them. This means that patching from
# the 'metadata.annotations' field path will _replace_ all of a composed
# resource's annotations, including annotations prefixed with crossplane.io/
# that control Crossplane's behaviour. Patching the entire annotations
# object can therefore have unexpected consquences and is not recommended.
# Instead patch specific annotations by specifying their keys.
- fromFieldPath: metadata.annotations[example.org/app-name]
- name: external-name
patches:
# FromCompositeFieldPath is the default patch type and is thus often
# omitted for brevity.
- type: FromCompositeFieldPath
fromFieldPath: metadata.annotations[crossplane.io/external-name]
# By default a patch from a field path that does not exist is a no-op. Use
# the 'Required' policy to instead block and return an error when the
# field path does not exist.
policy:
fromFieldPath: Required
# This Composition reconciles a CompositeMySQLInstance by patching from
# the CompositeMySQLInstance "to" new instances of the infrastructure
# resources below. These resources may be the managed resources of an
# infrastructure provider such as provider-azure, or other composite
# resources.
resources:
# A CompositeMySQLInstance that uses this Composition will be composed of an
# Azure ResourceGroup. Note that the 'name' is the name of this entry in the
# resources array - it does not affect the name of any ResourceGroup that is
# composed using this Composition. Specifying a name is optional but is
# *strongly* recommended. When all entries in the resources array are named
# entries may be added, deleted, and reordered as long as their names do not
# change. When entries are not named the length and order of the resources
# array should be treated as immutable. Either all or no entries must be
# named.
- name: resourcegroup
# The "base" for this ResourceGroup specifies the base
# configuration that may be extended or mutated by the patches below.
base:
apiVersion: azure.crossplane.io/v1alpha3
kind: ResourceGroup
spec: {}
# Patches copy or "overlay" the value of a field path within the composite
# resource (the CompositeMySQLInstance) to a field path within the composed
# resource (the ResourceGroup). In the below example any labels and
# annotations will be propagated from the CompositeMySQLInstance to the
# ResourceGroup (referencing the "metadata" patch set defined on the
# Composition), as will the location, using the default patch type
# FromCompositeFieldPath.
patches:
- type: PatchSet
patchSetName: metadata
- fromFieldPath: "spec.parameters.location"
toFieldPath: "spec.location"
# Sometimes it is necessary to "transform" the value from the composite
# resource into a value suitable for the composed resource, for example an
# Azure based composition may represent geographical locations differently
# from a GCP based composition that satisfies the same composite resource.
# This can be done by providing an optional array of transforms, such as
# the below that will transform the MySQLInstance spec.parameters.location
# value "us-west" into the ResourceGroup spec.location value "West US".
transforms:
- type: map
map:
us-west: West US
us-east: East US
au-east: Australia East
# A MySQLInstance that uses this Composition will also be composed of an
# Azure MySQLServer.
- name: mysqlserver
base:
apiVersion: database.azure.crossplane.io/v1beta1
kind: MySQLServer
spec:
forProvider:
# When this MySQLServer is created it must specify a ResourceGroup in
# which it will exist. The below resourceGroupNameSelector corresponds
# to the spec.forProvider.resourceGroupName field of the MySQLServer.
# It selects a ResourceGroup with a matching controller reference.
# Two resources that are part of the same composite resource will have
# matching controller references, so this MySQLServer will always
# select the ResourceGroup above. If this Composition included more
# than one ResourceGroup they could be differentiated by matchLabels.
resourceGroupNameSelector:
matchControllerRef: true
administratorLogin: notadmin
sslEnforcement: Disabled
sku:
tier: GeneralPurpose
capacity: 8
family: Gen5
storageProfile:
backupRetentionDays: 7
geoRedundantBackup: Disabled
writeConnectionSecretToRef:
namespace: crossplane-system
patches:
# This resource also uses the "metadata" patch set defined on the
# Composition.
- type: PatchSet
patchSetName: metadata
- fromFieldPath: "metadata.uid"
toFieldPath: "spec.writeConnectionSecretToRef.name"
transforms:
# Transform the value from the CompositeMySQLInstance using Go string
# formatting. This can be used to prefix or suffix a string, or to
# convert a number to a string. See https://golang.org/pkg/fmt/ for more
# detail.
- type: string
string:
fmt: "%s-mysqlserver"
- fromFieldPath: "spec.parameters.version"
toFieldPath: "spec.forProvider.version"
- fromFieldPath: "spec.parameters.location"
toFieldPath: "spec.forProvider.location"
transforms:
- type: map
map:
us-west: West US
us-east: East US
au-east: Australia East
- fromFieldPath: "spec.parameters.storageGB"
toFieldPath: "spec.forProvider.storageProfile.storageMB"
# Transform the value from the CompositeMySQLInstance by multiplying it by
# 1024 to convert Gigabytes to Megabytes.
transforms:
- type: math
math:
multiply: 1024
# Patches can also be applied from the composed resource (MySQLServer)
# to the composite resource (CompositeMySQLInstance). This MySQLServer
# will patch the FQDN generated by the provider back to the status
# subresource of the CompositeMySQLInstance. If a claim is referenced
# by the composite resource, the claim will also be patched. The
# "ToCompositeFieldPath" patch may be desirable in cases where a provider
# generated value is needed by other composed resources. The composite
# field that is patched back can then be patched forward into other resources.
- type: ToCompositeFieldPath
fromFieldPath: "status.atProvider.fullyQualifiedDomainName"
toFieldPath: "status.address"
# In addition to a base and patches, this composed MySQLServer declares that
# it can fulfil the connectionSecretKeys contract required by the definition
# of the CompositeMySQLInstance. This MySQLServer writes a connection secret
# with a username, password, and endpoint that may be used to connect to it.
# These connection details will also be exposed via the composite resource's
# connection secret. Exactly one composed resource must provide each secret
# key, but different composed resources may provide different keys.
connectionDetails:
- fromConnectionSecretKey: username
- fromConnectionSecretKey: password
# The name of the required CompositeMySQLInstance connection secret key
# can be supplied if it is different from the connection secret key
# exposed by the MySQLServer.
- name: hostname
fromConnectionSecretKey: endpoint
# In some cases it may be desirable to inject a fixed connection secret
# value, for example to expose fixed, non-sensitive connection details
# like standard ports that are not published to the composed resource's
# connection secret.
- type: FromValue
name: port
value: "3306"
# Readiness checks allow you to define custom readiness checks. All checks
# have to return true in order for resource to be considered ready. The
# default readiness check is to have the "Ready" condition to be "True".
# Currently Crossplane supports the MatchString, MatchInteger, and None
# readiness checks.
readinessChecks:
- type: MatchString
fieldPath: "status.atProvider.userVisibleState"
matchString: "Ready"
# A CompositeMySQLInstance that uses this Composition will also be composed
# of an Azure MySQLServerFirewallRule.
- name: firewallrule
base:
apiVersion: database.azure.crossplane.io/v1alpha3
kind: MySQLServerFirewallRule
spec:
forProvider:
resourceGroupNameSelector:
matchControllerRef: true
serverNameSelector:
matchControllerRef: true
properties:
startIpAddress: 10.10.0.0
endIpAddress: 10.10.255.254
virtualNetworkSubnetIdSelector:
name: sample-subnet
patches:
- type: PatchSet
patchSetName: metadata
# Some composite resources may be "dynamically provisioned" - i.e. provisioned
# on-demand to satisfy an application's claim for infrastructure. The
# writeConnectionSecretsToNamespace field configures the default value used
# when dynamically provisioning a composite resource; it is explained in more
# detail below.
writeConnectionSecretsToNamespace: crossplane-system
```
Field paths reference a field within a Kubernetes object via a simple string.
API conventions 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". Array indices are specified via
square braces while object fields may be specified via a period or via square
braces.Kubernetes field paths do not support advanced features of JSON paths,
such as `@`, `$`, or `*`. For example given the below `Pod`:
```yaml
apiVersion: v1
kind: Pod
metadata:
name: example-pod
annotations:
example.org/a: example-annotation
spec:
containers:
- name: example-container
image: example:latest
command:
- example
args:
- "--debug"
- "--example"
```
* `metadata.name` would contain "example-pod"
* `metadata.annotations['example.org/a']` would contain "example-annotation"
* `spec.containers[0].name` would contain "example-container"
* `spec.containers[0].args[1]` would contain "--example"
> Note that Compositions provide _intentionally_ limited functionality when
> compared to powerful templating and composition tools like Helm or Kustomize.
> This allows a Composition to be a schemafied Kubernetes-native resource that
> can be stored in and validated by the Kubernetes API server at authoring time
> rather than invocation time.
## Using Composite Resources
![Infrastructure Composition Provisioning]
Crossplane is designed to allow platform builders to expose XRs in several ways:
1. Platform builders can create or manage an XR that does not offer a composite
resource claim. This XR exists at the cluster scope, which Crossplane
considers the domain of the platform builder.
1. Platform builders can create an XR of _a kind that offers a claim_ without
claiming it (i.e. without authoring a claim). This allows their customers to
claim an existing XR at a future point in time.
1. Platform customers can create a composite resource claim (if the XRD offers
one), and a composite resource will be provisioned on-demand.
Options one and two are frequently referred to as "static provisioning", while
option three is known as "dynamic provisioning".
> Note that platform builder focused Crossplane concepts are cluster scoped -
> they exist outside any namespace. Crossplane assumes platform builders will
> have similar RBAC permissions to cluster administrators, and will thus be
> permitted to manage cluster scoped resources. Platform customer focused
> Crossplane concepts are namespaced. Crossplane assumes customers will be
> permitted access to the namespace(s) in which their applications run, and not
> to cluster scoped resources.
### Creating and Managing Composite Resources
A platform builder may wish to author a composite resource of a kind that offers
a claim so that a platform customer may later author a claim for that exact
resource. This pattern is useful for resources that may take several minutes to
provision - the platform builder can keep a pool of resources available in
advance in order to ensure claims may be instantly satisfied.
In some cases a platform builder may wish to use Crossplane to model an XR that
they do not wish to allow platform customers to provision. Consider a `VPC` XR
that creates an AWS VPC network with an internet gateway, route table, and
several subnets. Defining this resource as an XR allows the platform builder to
easily reuse their configuration, but it does not make sense to allow platform
customers to create "supporting infrastructure" like a VPC network.
In both of the above scenarios the platform builder may statically provision a
composite resource; i.e. author it directly rather than via its corresponding
resource claim. The `CompositeMySQLInstance` composite resource defined above
could be authored as follows:
```yaml
apiVersion: example.org/v1alpha1
kind: CompositeMySQLInstance
metadata:
# Composite resources are cluster scoped, so there's no need for a namespace.
name: example
spec:
# The schema of the spec.parameters object is defined by the earlier example
# of an CompositeResourceDefinition. The location, storageGB, and version fields
# are patched onto the ResourceGroup, MySQLServer, and MySQLServerFirewallRule
# that this MySQLInstance composes.
parameters:
location: au-east
storageGB: 20
version: "5.7"
# Support for a compositionRef is automatically injected into the schema of
# all defined composite resources. This allows the resource
# author to explicitly reference a Composition that this composite resource
# should use - in this case the earlier example-azure Composition. Note that
# it is also possible to select a composition by labels - see the below
# MySQLInstance for an example of this approach.
compositionRef:
name: example-azure
# Support for a writeConnectionSecretToRef is automatically injected into the
# schema of all defined composite resources. This allows the
# resource to write a connection secret containing any details required to
# connect to it - in this case the hostname, username, and password. Composite
# resource authors may omit this reference if they do not need or wish to
# write these details.
writeConnectionSecretToRef:
namespace: infra-secrets
name: example-mysqlinstance
```
Any updates to the `CompositeMySQLInstance` will be immediately reconciled with
the resources it composes. For example if more storage were needed an update to
the `spec.parameters.storageGB` field would immediately be propagated to the
`spec.forProvider.storageProfile.storageMB` field of the composed `MySQLServer`
due to the relationship established between these two fields by the patches
configured in the `example-azure` `Composition`.
`kubectl describe` may be used to examine a composite resource. Note the `Ready`
condition below. It indicates that all composed resources are indicating they
are 'ready', and therefore the composite resource should be online and ready to
use.
More detail about the health and configuration of the composite resource can be
determined by describing each composed resource. The kinds and names of each
composed resource are exposed as "Resource Refs" - for example `kubectl describe
mysqlserver example-zrpgr` will describe the detailed state of the composed
Azure `MySQLServer`.
```console
$ kubectl describe compositemysqlinstance.example.org
Name: example
Namespace:
Labels: crossplane.io/composite=example
Annotations: <none>
API Version: example.org/v1alpha1
Kind: CompositeMySQLInstance
Metadata:
Creation Timestamp: 2020-05-15T06:53:16Z
Generation: 4
Resource Version: 1425809
UID: f654dd52-fe0e-47c8-aa9b-235c77505674
Spec:
Composition Ref:
Name: example-azure
Parameters:
Location: au-east
Storage GB: 20
Version: 5.7
Resource Refs:
API Version: azure.crossplane.io/v1alpha3
Kind: ResourceGroup
Name: example-wspmk
UID: 4909ab46-95ef-4ba7-8f7a-e1d9ee1a6b23
API Version: database.azure.crossplane.io/v1beta1
Kind: MySQLServer
Name: example-zrpgr
UID: 3afb903e-32db-4834-a6e7-31249212dca0
API Version: database.azure.crossplane.io/v1alpha3
Kind: MySQLServerFirewallRule
Name: example-h4zjn
UID: 602c8412-7c33-4338-a3af-78166c17b1a0
Write Connection Secret To Ref:
Name: example-mysqlinstance
Namespace: infra-secrets
Status:
Address: example.mysql.database.azure.com
Conditions:
Last Transition Time: 2020-05-15T06:56:46Z
Reason: Resource is available for use
Status: True
Type: Ready
Last Transition Time: 2020-05-15T06:53:16Z
Reason: Successfully reconciled resource
Status: True
Type: Synced
Connection Details:
Last Published Time: 2020-05-15T06:53:16Z
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SelectComposition 10s (x7 over 3m40s) composite/compositemysqlinstances.example.org Successfully selected composition
Normal PublishConnectionSecret 10s (x7 over 3m40s) composite/compositemysqlinstances.example.org Successfully published connection details
Normal ComposeResources 10s (x7 over 3m40s) composite/compositemysqlinstances.example.org Successfully composed resources
```
### Creating a Composite Resource Claim
Composite resource claims represent a need for a particular kind of composite
resource, for example the above `MySQLInstance`. Claims are a proxy for the kind
of resource they claim, allowing platform customers to provision and consume an
XR. An claim may request a pre-existing, statically provisioned XR or it may
dynamically provision one on-demand.
The below claim explicitly requests the `CompositeMySQLInstance` authored in the
previous example:
```yaml
# The MySQLInstance always has the same API group and version as the
# resource it requires. Its kind is always suffixed with .
apiVersion: example.org/v1alpha1
kind: MySQLInstance
metadata:
# Infrastructure claims are namespaced.
namespace: default
name: example
spec:
# The schema of the spec.parameters object is defined by the earlier example
# of an CompositeResourceDefinition. The location, storageGB, and version fields
# are patched onto the ResourceGroup, MySQLServer, and MySQLServerFirewallRule
# composed by the required MySQLInstance.
parameters:
location: au-east
storageGB: 20
version: "5.7"
# Support for a resourceRef is automatically injected into the schema of all
# resource claims. The resourceRef requests a CompositeMySQLInstance
# explicitly.
resourceRef:
apiVersion: example.org/v1alpha1
kind: CompositeMySQLInstance
name: example
# Support for a writeConnectionSecretToRef is automatically injected into the
# schema of all published infrastructure claim resources. This allows
# the resource to write a connection secret containing any details required to
# connect to it - in this case the hostname, username, and password.
writeConnectionSecretToRef:
name: example-mysqlinstance
```
A claim may omit the `resourceRef` and instead include a `compositionRef` (as in
the previous `CompositeMySQLInstance` example) or a `compositionSelector` in
order to trigger dynamic provisioning. A claim that does not include a reference
to an existing composite resource will have a suitable composite resource
provisioned on demand:
```yaml
apiVersion: example.org/v1alpha1
kind: MySQLInstance
metadata:
namespace: default
name: example
spec:
parameters:
location: au-east
storageGB: 20
version: "5.7"
# Support for a compositionSelector is automatically injected into the schema
# of all published infrastructure claim resources. This selector selects
# the example-azure composition by its labels.
compositionSelector:
matchLabels:
purpose: example
provider: azure
writeConnectionSecretToRef:
name: example-mysqlinstance
```
> Note that compositionSelector labels can form a shared language between the
> platform builders who define compositions and their platform customers.
> Compositions could be labelled by zone, size, or purpose in order to allow
> platform customers to request a class of composite resource by describing
> their needs such as "east coast, production".
Like composite resources, claims can be examined using `kubectl describe`. The
`Ready` condition has the same meaning as the `MySQLInstance` above. The
"Resource Ref" indicates the name of the composite resource that was either
explicitly claimed, or in the case of the below claim dynamically provisioned.
```console
$ kubectl describe mysqlinstanceclaim.example.org example
Name: example
Namespace: default
Labels: <none>
Annotations: crossplane.io/external-name:
API Version: example.org/v1alpha1
Kind: MySQLInstance
Metadata:
Creation Timestamp: 2020-05-15T07:08:11Z
Finalizers:
finalizer.apiextensions.crossplane.io
Generation: 3
Resource Version: 1428420
UID: d87e9580-9d2e-41a7-a198-a39851815840
Spec:
Composition Selector:
Match Labels:
Provider: azure
Purpose: example
Parameters:
Location: au-east
Storage GB: 20
Version: 5.7
Resource Ref:
API Version: example.org/v1alpha1
Kind: CompositeMySQLInstance
Name: default-example-8t4tb
Write Connection Secret To Ref:
Name: example-mysqlinstance
Status:
Address: example.mysql.database.azure.com
Conditions:
Last Transition Time: 2020-05-15T07:26:49Z
Reason: Resource is available for use
Status: True
Type: Ready
Last Transition Time: 2020-05-15T07:08:11Z
Reason: Successfully reconciled resource
Status: True
Type: Synced
Connection Details:
Last Published Time: 2020-05-15T07:08:11Z
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ConfigureCompositeResource 8m23s claim/compositemysqlinstances.example.org Successfully configured composite resource
Normal BindCompositeResource 8m23s (x7 over 8m23s) claim/compositemysqlinstances.example.org Composite resource is not yet ready
Normal BindCompositeResource 4m53s (x4 over 23m) claim/compositemysqlinstances.example.org Successfully bound composite resource
Normal PropagateConnectionSecret 4m53s (x4 over 23m) claim/compositemysqlinstances.example.org Successfully propagated connection details from composite resource
```
## Current Limitations
At present the below functionality is planned but not yet implemented:
* Compositions are mutable, and updating a composition causes all composite
resources that use that composition to be updated accordingly. Revision
support is planned per issue [#1481].
Refer to the list of [composition related issues] for an up-to-date list of
known issues and proposed improvements.
[Current Limitations]: #current-limitations
[Infrastructure Composition Concepts]: composition-concepts.png
[structural schemas]: https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#specifying-a-structural-schema
[Infrastructure Composition Provisioning]: composition-provisioning.png
[composition related issues]: https://github.com/crossplane/crossplane/labels/composition
[#1481]: https://github.com/crossplane/crossplane/issues/1481

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@ -0,0 +1,270 @@
---
title: Managed Resources
toc: true
weight: 102
indent: true
---
# Managed Resources
## Overview
Managed resources are the Crossplane representation of the cloud
[provider][provider] resources and they are considered primitive low level
custom resources that can be used directly to provision external cloud resources
for an application or as part of an infrastructure composition.
For example, `RDSInstance` in 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.
You can browse [API Reference][api-reference] to discover all available managed
resources.
## Syntax
Crossplane API conventions extend the Kubernetes API conventions for the schema
of Crossplane managed resources. Following is an example of `RDSInstance`:
```yaml
apiVersion: database.aws.crossplane.io/v1beta1
kind: RDSInstance
metadata:
name: foodb
spec:
forProvider:
dbInstanceClass: db.t2.small
masterUsername: root
allocatedStorage: 20
engine: mysql
writeConnectionSecretToRef:
name: mysql-secret
namespace: crossplane-system
providerConfigRef:
name: default
deletionPolicy: Delete
```
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.
### 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`.
#### Immutable Properties
There are configuration parameters in external resources that cloud providers do
not allow to be changed. If the corresponding field in the managed resource is
changed by the user, Crossplane submits the new desired state to the provider
and returns the error, if any. 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.
> Immutable fields are marked as `immutable` in Crossplane codebase but
Kubernetes does not yet have immutable field notation in CRDs.
### 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 a 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:
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.
[api-versioning]: https://kubernetes.io/docs/reference/using-api/api-overview/#api-versioning
[velero]: https://velero.io/
[api-reference]: ../api-docs/overview.md
[provider]: providers.md

View File

@ -0,0 +1,58 @@
---
title: Concepts
toc: true
weight: 100
---
# Overview
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
[doc.crds.dev] 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]: packages.md
[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]: providers.md
[doc.crds.dev]: https://doc.crds.dev
[managed resources documentation]: managed-resources.md
[composition documentation]: composition.md

View File

@ -0,0 +1,415 @@
---
title: Packages
toc: true
weight: 104
indent: true
---
# Crossplane Packages
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.
## 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 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.
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: crossplane/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 an `alpha` feature and depends on the `v1alpha`
> [`Lock` API][lock-api].
For an example Configuration package, see [getting-started-with-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 crossplane/provider-gcp:v0.14.0
```
To push a Configuration package, execute the following command:
```
kubectl crossplane push configuration crossplane/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 crossplane/provider-gcp:v0.12.0
```
To install a Configuration package, execute the following command:
```
kubectl crossplane install configuration crossplane/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: crossplane/provider-gcp:master
packagePullPolicy: IfNotPresent
revisionActivationPolicy: Automatic
revisionHistoryLimit: 1
```
```yaml
apiVersion: pkg.crossplane.io/v1
kind: Configuration
metadata:
name: my-org-infra
spec:
package: crossplane/provider-gcp:master
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.
### 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: crossplane/provider-aws:v0.15.0
controllerConfigRef:
name: aws-config
```
You can find all configurable values in the [official `ControllerConfig`
documentation][controller-config-docs].
<!-- Named Links -->
[OCI images]: https://github.com/opencontainers/image-spec
[Providers]: providers.md
[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/v1alpha1
[getting-started-with-gcp]: https://github.com/crossplane/crossplane/tree/master/docs/snippets/package/gcp
[specification]: https://github.com/Masterminds/semver#basic-comparisons
[composition]: composition.md
[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://github.com/crossplane/provider-gcp/tree/master/package

View File

@ -0,0 +1,136 @@
---
title: Providers
toc: true
weight: 101
indent: true
---
# Providers
Providers extend Crossplane to enable infrastructure resource provisioning. In
order to provision a resource, a Custom Resource Definition (CRD) needs to be
registered in your Kubernetes cluster and its controller should be watching the
Custom Resources those CRDs define. Provider packages contain many Custom
Resource Definitions and their controllers.
Here is the list of current providers:
### AWS Provider
* [GitHub][provider-aws]
* [API Reference][aws-reference]
### GCP Provider
* [GitHub][provider-gcp]
* [API Reference][gcp-reference]
### Azure Provider
* [GitHub][provider-azure]
* [API Reference][azure-reference]
### Rook Provider
* [GitHub][provider-rook]
* [API Reference][rook-reference]
### Alibaba Cloud Provider
* [GitHub][provider-alibaba]
* [API Reference][alibaba-reference]
## Installing Providers
The core Crossplane controller can install provider controllers and CRDs for you
through its own provider packaging mechanism, which is triggered by the
application of a `Provider` resource. For example, in order to request
installation of the `provider-aws` package, apply the following resource to the
cluster where Crossplane is running:
```yaml
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws
spec:
package: "crossplane/provider-aws:master"
```
The field `spec.package` is where you refer to the container image of the
provider. Crossplane Package Manager will unpack that container, register CRDs
and set up necessary RBAC rules and then start the controllers.
There are a few other ways to to trigger the installation of provider packages:
* As part of Crossplane Helm chart by adding the following statement to your
`helm install` command: `--set
provider.packages={crossplane/provider-aws:master}`.
* Using the Crossplane CLI: `kubectl crossplane install provider
crossplane/provider-aws:master`
You can uninstall a provider by deleting the `Provider` resource
you've created.
## Configuring Providers
In order to authenticate with the external provider API, the provider
controllers need to have access to credentials. It could be an IAM User for AWS,
a Service Account for GCP or a Service Principal for Azure. Every provider has a
type called `ProviderConfig` that has information about how to authenticate to
the provider API. An example `ProviderConfig` resource for AWS looks like the
following:
```yaml
apiVersion: aws.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: aws-provider
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: aws-creds
key: key
```
You can see that there is a reference to a key in a specific `Secret`. The value
of that key should contain the credentials that the controller will use. The
documentation of each provider should give you an idea of how that credentials
blob should look like. See [Getting Started][getting-started] guide for more
details.
The following is an example usage of AWS `ProviderConfig`, referenced by a
`RDSInstance`:
```yaml
apiVersion: database.aws.crossplane.io/v1beta1
kind: RDSInstance
metadata:
name: prod-sql
spec:
providerConfigRef:
name: prod-acc
...
```
The AWS provider controller will use that provider for this instance of
`RDSInstance`. Since every resource has its own reference to a `ProviderConfig`,
you can have multiple `ProviderConfig` resources in your cluster referenced by
different resources. When no `providerConfigRef` is specified, the `RDSInstance`
will attempt to use a `ProviderConfig` named `default`.
<!-- Named Links -->
[provider-aws]: https://github.com/crossplane/provider-aws
[aws-reference]: https://doc.crds.dev/github.com/crossplane/provider-aws
[provider-gcp]: https://github.com/crossplane/provider-gcp
[gcp-reference]: https://doc.crds.dev/github.com/crossplane/provider-gcp
[provider-azure]: https://github.com/crossplane/provider-azure
[azure-reference]: https://doc.crds.dev/github.com/crossplane/provider-azure
[provider-rook]: https://github.com/crossplane/provider-rook
[rook-reference]: https://doc.crds.dev/github.com/crossplane/provider-rook
[provider-alibaba]: https://github.com/crossplane/provider-alibaba
[alibaba-reference]: https://doc.crds.dev/github.com/crossplane/provider-alibaba
[getting-started]: ../getting-started/install-configure.md

View File

@ -0,0 +1,198 @@
---
title: Observability Developer Guide
toc: true
weight: 1002
indent: true
---
# Observability Developer Guide
## Introduction
Observability is crucial to Crossplane users; both those operating Crossplane
and those using Crossplane to operate their infrastructure. Crossplane currently
approaches observability via Kubernetes events and structured logs.
## Goals
In short, a non-admin user and an admin user should both be able to debug any
issues only by inspecting logs and events. There should be no need to rebuild
the Crossplane binary or to reach out to a Crossplane developer.
A user should be able to:
* Debug an issue without rebuilding the Crossplane binary
* Understand an issue without contacting a cluster admin
* Ask a cluster admin to check the logs for more details about the reason the
issue happened, if the details are not part of the error message
A cluster admin should be able to:
* Debug an issue without rebuilding the Crossplane binary
* Debug an issue only by looking at the logs
* Debug an issue without needing to contact a Crossplane developer
## Error reporting in the logs
Error reporting in the logs is mostly intended for consumption by Crossplane
cluster admins. A cluster admin should be able to debug any issue by inspecting
the logs, without needing to add more logs themselves or contact a Crossplane
developer. This means that logs should contain:
* Error messages, at either the info or debug level as contextually appropriate
* Any context leading up to an error, typically at debug level, so that the
errors can be debugged
## Error reporting as events
Error reporting as Kubernetes events is primarily aimed toward end-users of
Crossplane who are not cluster admins. Crossplane typically runs as a Kubernetes
pod, and thus it is unlikely that most users of Crossplane will have access to
its logs. [Events], on the other hand, are available as top-level Kubernetes
objects, and show up the objects they relate to when running `kubectl describe`.
Events should be recorded in the following cases:
* A significant operation is taken on a resource
* The state of a resource is changed
* An error occurs
The events recorded in these cases can be thought of as forming an event log of
things that happen for the resources that Crossplane manages. Each event should
refer back to the relevant controller and resource, and use other fields of the
Event kind as appropriate.
More details about examples of how to interact with events can be found in the
guide to [debugging an application cluster].
## Choosing between methods of error reporting
There are many ways to report errors, such as:
* Metrics
* Events
* Logging
* Tracing
It can be confusing to figure out which one is appropriate in a given situation.
This section will try to offer advice and a mindset that can be used to help
make this decision.
Let's set the context by listing the different user scenarios where error
reporting may be consumed. Here are the typical scenarios as we imagine them:
1. A person **using** a system needs to figure out why things aren't working as
expected, and whether they made a mistake that they can correct.
2. A person **operating** a service needs to monitor the service's **health**,
both now and historically.
3. A person **debugging** a problem which happened in a **live environment**
(often an **operator** of the system) needs information to figure out what
happened.
4. A person **developing** the software wants to **observe** what is happening.
5. A person **debugging** the software in a **development environment**
(typically a **developer** of the system) wants to debug a problem (there is
a lot of overlap between this and the live environment debugging scenario).
The goal is to satisfy the users in all of the scenarios. We'll refer to the
scenarios by number.
The short version is: we should do whatever satisfies all of the scenarios.
Logging and events are the recommendations for satisfying the scenarios,
although they don't cover scenario 2.
The longer version is:
* Scenario 1 is best served by events in the context of Crossplane, since the
users may not have access to read logs or metrics, and even if they did, it
would be hard to relate them back to the event the user is trying to
understand.
* Scenario 2 is best served by metrics, because they can be aggregated and
understood as a whole. And because they can be used to track things over time.
* Scenario 3 is best served by either logging that contains all the information
about and leading up to the event. Request-tracing systems are also useful for
this scenario.
* Scenario 4 is usually logs, maybe at a more verbose level than normal. But it
could be an attached debugger or some other type of tool. It could also be a
test suite.
* Scenario 5 is usually either logs, up to the highest imaginable verbosity, or
an attached debugging session. If there's a gap in reporting, it could involve
adding some print statements to get more logging.
As for the question of how to decide whether to log or not, we believe it helps
to try to visualize which of the scenarios the error or information in question
will be used for. We recommend starting with reporting as much information as
possible, but with configurable runtime behavior so that, for example, debugging
logs don't show up in production normally.
For the question of what constitutes an error, errors should be actionable by a
human. See the [Dave Cheney article] on this topic for some more discussion.
## In Practice
Crossplane provides two observability libraries as part of crossplane-runtime:
* [`event`] emits Kubernetes events.
* [`logging`] produces structured logs. Refer to its package documentation for
additional context on its API choices.
Keep the following in mind when using the above libraries:
* [Do] [not] use package level loggers or event recorders. Instantiate them in
`main()` and plumb them down to where they're needed.
* Each [`Reconciler`] implementation should use its own `logging.Logger` and
`event.Recorder`. Implementations are strongly encouraged to default to using
`logging.NewNopLogger()` and `event.NewNopRecorder()`, and accept a functional
loggers and recorder via variadic options. See for example the [managed
resource reconciler].
* Each controller should use its name as its event recorder's name, and include
its name under the `controller` structured logging key. The controllers name
should be of the form `controllertype/resourcekind`, for example
`managed/cloudsqlinstance` or `stacks/stackdefinition`. Controller names
should always be lowercase.
* Logs and events should typically be emitted by the `Reconcile` method of the
`Reconciler` implementation; not by functions called by `Reconcile`. Author
the methods orchestrated by `Reconcile` as if they were a library; prefer
surfacing useful information for the `Reconciler` to log (for example by
[wrapping errors]) over plumbing loggers and event recorders down to
increasingly deeper layers of code.
* Almost nothing is worth logging at info level. When deciding which logging
level to use, consider a production deployment of Crossplane reconciling tens
or hundreds of managed resources. If in doubt, pick debug. You can easily
increase the log level later if it proves warranted.
* The above is true even for errors; consider the audience. Is this an error
only the Crossplane cluster operator can fix? Does it indicate a significant
degradation of Crossplane's functionality? If so, log it at info. If the error
pertains to a single Crossplane resource emit an event instead.
* Always log errors under the structured logging key `error` (e.g.
`log.Debug("boom!, "error", err)`). Many logging implementations (including
Crossplane's) add context like stack traces for this key.
* Emit events liberally; they're rate limited and deduplicated.
* Follow [API conventions] when emitting events; ensure event reasons are unique
and `CamelCase`.
* Consider emitting events and logs when a terminal condition is encountered
(e.g. `Reconcile` returns) over logging logic flow. i.e. Prefer one log line
that reads "encountered an error fooing the bar" over two log lines that read
"about to foo the bar" and "encountered an error". Recall that if the audience
is a developer debugging Crossplane they will be provided a stack trace with
file and line context when an error is logged.
* Consider including the `reconcile.Request`, and the resource's UID and
resource version (not API version) under the keys `request`, `uid`, and
`version`. Doing so allows log readers to determine what specific version of a
resource the log pertains to.
Finally, when in doubt, aim for consistency with existing Crossplane controller
implementations.
<!-- Named Links -->
[Events]: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.16/#event-v1-core
[debugging an application cluster]: https://kubernetes.io/docs/tasks/debug-application-cluster/
[Dave Cheney article]: https://dave.cheney.net/2015/11/05/lets-talk-about-logging
[`event`]: https://godoc.org/github.com/crossplane/crossplane-runtime/pkg/event
[`logging`]: https://godoc.org/github.com/crossplane/crossplane-runtime/pkg/logging
[Do]: https://peter.bourgon.org/go-best-practices-2016/#logging-and-instrumentation
[not]: https://dave.cheney.net/2017/01/23/the-package-level-logger-anti-pattern
[`Reconciler`]: https://godoc.org/sigs.k8s.io/controller-runtime/pkg/reconcile#Reconciler
[managed resource reconciler]: https://github.com/crossplane/crossplane-runtime/blob/a6bb0/pkg/reconciler/managed/reconciler.go#L436
[wrapping errors]: https://godoc.org/github.com/pkg/errors#Wrap
[API conventions]: https://github.com/kubernetes/community/blob/09f55c6/contributors/devel/sig-architecture/api-conventions.md#events

View File

@ -0,0 +1,62 @@
---
title: Community On-Duty
toc: true
weight: 1004
indent: true
---
# Community On-Duty
Community on-duty is a weekly rotation of Crossplane community members who have
volunteered to help the Crossplane community. Volunteers are on-duty for a week
at a time. The goals of the on-duty rotation are to:
1. Ensure the Crossplane community feels heard and supported.
1. Prevent issues and pull requests (PRs) from falling through the cracks.
1. Make it easier for the next person on-duty to achieve the above goals.
Volunteers should be able to commit to focus on being on-duty for the majority
of their typical working day (e.g. ~7 hours a day). On-duty is expected to
respond to questions, issues and pull requests at their earliest convenience,
within 24 hours.
> Don't hesitate to reach out to the current person on-duty if you're interested
> in volunteering but can't commit to so much time - we may be able to work out
> smaller shifts.
When on-duty, you should:
* Make sure the title of #general in Crossplane Slack indicates that you are the
person folks should ping with questions.
* Monitor Crossplane Slack - particularly #general and #dev - for questions from
the community. Encourage folks to raise issues for more involved queries, bug
reports, or feature requests.
* Monitor GitHub for new issues and PRs within the Crossplane org. Perform
initial triage - e.g. thank the person for their contribution, update the PR
or issue with any appropriate labels. Use your discretion as to whether you
should attempt to address the issue or review the PR during your on-duty
shift. On-duty is a great time to learn new things and address low hanging
fruit, but you're not responsible for resolving everything that comes up
during your shift.
* If there's a release happening during your on-duty week consider volunteering
to run (or help with) the release.
* If there's a release happening the week after your on-duty week please take a
pass over any open pull requests and ask the folks working on them whether
they're release blockers and whether they expect to have them merged in time
for a one week feature freeze before the release.
> You can use this [issues query] and this [PRs query] to quickly find new
> issues and PRs in the Crossplane GitHub org.
If it's a quiet on-duty week and the above isn't keeping you busy enough:
* Remember that part of on-duty is making life easier for the next community
member on-duty. Is there something you can automate to make their life easier?
* Groom the issue and PR backlog. Close any that are obviously no longer
relevant. Ask for updates on any that are stagnating.
* Look for low hanging improvements to community and contributor experience -
e.g. improving documentation, improving tests and CI/CD.
[issues query]: https://github.com/issues?q=is%3Aopen+is%3Aissue+archived%3Afalse+user%3Acrossplane+sort%3Acreated-desc+no%3Aassignee
[PRs query]: https://github.com/pulls?q=is%3Aopen+is%3Apr+archived%3Afalse+user%3Acrossplane+sort%3Aupdated-desc

View File

@ -0,0 +1,23 @@
---
title: Contributing
toc: true
weight: 1000
---
# Contributing
The following documentation is for developers who wish to contribute to or
extend Crossplane. Please [open an
issue](https://github.com/crossplane/crossplane/issues/new) for any additional
documentation you would like to see in this section.
1. [Provider Development Guide]
2. [Observability Developer Guide]
3. [Release Process]
4. [Community On-Duty]
[Provider Development Guide]: provider_development_guide.md
[Observability Developer Guide]: observability_developer_guide.md
[Release Process]: release-process.md
[Community On-Duty]: onduty.md

View File

@ -0,0 +1,648 @@
---
title: Provider Development Guide
toc: true
weight: 1001
indent: true
---
# Provider Development Guide
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 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].
## 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 Managed Service]. 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 -->
[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]: ../concepts/managed-resources.md
[`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]: ../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/provider-aws/blob/master/CODE_GENERATION.md

View File

@ -0,0 +1,267 @@
---
title: Release Process
toc: true
weight: 1003
indent: true
---
# Release Process
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 expected features should be
["complete"](https://github.com/crossplane/crossplane/blob/master/design/one-pager-definition-of-done.md)
and merged into main development branch. This includes user guides, examples,
API documentation, and test updates.
* 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 [Crossplane repo
settings](https://github.com/crossplane/crossplane/settings/branches).
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://crossplane.io/docs/latest)
* [Configuration Packages](https://cloud.upbound.io/browse)
### 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

23
docs/v1.2/faqs/faqs.md Normal file
View File

@ -0,0 +1,23 @@
---
title: FAQ
toc: true
weight: 1200
---
# Frequently Asked Questions (FAQs)
### 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]: related_projects.md

View File

@ -0,0 +1,87 @@
---
title: Related Projects
toc: true
weight: 1201
indent: true
---
# Related Projects
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 and
closed source.
## 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 closed-source.
## 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://kubernetes.io/docs/concepts/extend-kubernetes/service-catalog/
[GCP OSB]: https://cloud.google.com/kubernetes-engine/docs/concepts/google-cloud-platform-service-broker
[GCP Config Connector]: https://cloud.google.com/config-connector/docs/overview
[AWS Controllers for Kubernetes]: https://github.com/aws-controllers-k8s/community
[Terraform]: https://www.terraform.io/
[Pulumi]: https://www.pulumi.com/

View File

@ -0,0 +1,741 @@
---
title: Create a Configuration
toc: true
weight: 4
indent: true
---
# Create a Configuration
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 `CompositePostgreSQLInstance` and its `PostgreSQLInstance` resource claim.
```yaml
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: compositepostgresqlinstances.database.example.org
spec:
group: database.example.org
names:
kind: CompositePostgreSQLInstance
plural: compositepostgresqlinstances
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/master/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 `CompositePostgreSQLInstance` 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.
<ul class="nav nav-tabs">
<li class="active"><a href="#aws-tab-2" data-toggle="tab">AWS (Default VPC)</a></li>
<li><a href="#aws-new-tab-2" data-toggle="tab">AWS (New VPC)</a></li>
<li><a href="#gcp-tab-2" data-toggle="tab">GCP</a></li>
<li><a href="#azure-tab-2" data-toggle="tab">Azure</a></li>
</ul>
<br>
<div class="tab-content">
<div class="tab-pane fade in active" id="aws-tab-2" markdown="1">
> 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: compositepostgresqlinstances.aws.database.example.org
labels:
provider: aws
guide: quickstart
vpc: default
spec:
writeConnectionSecretsToNamespace: crossplane-system
compositeTypeRef:
apiVersion: database.example.org/v1alpha1
kind: CompositePostgreSQLInstance
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: "9.6"
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/master/docs/snippets/package/aws/composition.yaml
```
</div>
<div class="tab-pane fade" id="aws-new-tab-2" markdown="1">
> 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: CompositePostgreSQLInstance
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/v1alpha4
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: "9.6"
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/master/docs/snippets/package/aws-with-vpc/composition.yaml
```
</div>
<div class="tab-pane fade" id="gcp-tab-2" markdown="1">
```yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: compositepostgresqlinstances.gcp.database.example.org
labels:
provider: gcp
guide: quickstart
spec:
writeConnectionSecretsToNamespace: crossplane-system
compositeTypeRef:
apiVersion: database.example.org/v1alpha1
kind: CompositePostgreSQLInstance
resources:
- name: cloudsqlinstance
base:
apiVersion: database.gcp.crossplane.io/v1beta1
kind: CloudSQLInstance
spec:
forProvider:
databaseVersion: POSTGRES_9_6
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/crossplane/master/docs/snippets/package/gcp/composition.yaml
```
</div>
<div class="tab-pane fade" id="azure-tab-2" markdown="1">
> 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: compositepostgresqlinstances.azure.database.example.org
labels:
provider: azure
guide: quickstart
spec:
writeConnectionSecretsToNamespace: crossplane-system
compositeTypeRef:
apiVersion: database.example.org/v1alpha1
kind: CompositePostgreSQLInstance
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/master/docs/snippets/package/azure/composition.yaml
```
</div>
<div class="tab-pane fade" id="alibaba-tab-2" markdown="1">
```yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: compositepostgresqlinstances.alibaba.database.example.org
labels:
provider: alibaba
guide: quickstart
spec:
writeConnectionSecretsToNamespace: crossplane-system
compositeTypeRef:
apiVersion: database.example.org/v1alpha1
kind: CompositePostgreSQLInstance
resources:
- name: rdsinstance
base:
apiVersion: database.alibaba.crossplane.io/v1alpha1
kind: RDSInstance
spec:
forProvider:
engine: PostgreSQL
engineVersion: "9.4"
dbInstanceClass: rds.pg.s1.small
securityIPList: "0.0.0.0/0"
masterUsername: "myuser"
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.dbInstanceStorageInGB"
connectionDetails:
- fromConnectionSecretKey: username
- fromConnectionSecretKey: password
- fromConnectionSecretKey: endpoint
- fromConnectionSecretKey: port
```
```console
curl -OL https://raw.githubusercontent.com/crossplane/crossplane/master/docs/snippets/package/alibaba/composition.yaml
```
</div>
</div>
## 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.
<ul class="nav nav-tabs">
<li class="active"><a href="#aws-tab-3" data-toggle="tab">AWS (Default VPC)</a></li>
<li><a href="#aws-new-tab-3" data-toggle="tab">AWS (New VPC)</a></li>
<li><a href="#gcp-tab-3" data-toggle="tab">GCP</a></li>
<li><a href="#azure-tab-3" data-toggle="tab">Azure</a></li>
</ul>
<br>
<div class="tab-content">
<div class="tab-pane fade in active" id="aws-tab-3" markdown="1">
```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.0.0-0"
dependsOn:
- provider: crossplane/provider-aws
version: ">=v0.14.0"
```
```console
curl -OL https://raw.githubusercontent.com/crossplane/crossplane/master/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:master
```
> Note that the Crossplane CLI will not follow symbolic links for files in the
> root package directory.
</div>
<div class="tab-pane fade" id="aws-new-tab-3" markdown="1">
```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.0.0-0"
dependsOn:
- provider: crossplane/provider-aws
version: ">=v0.14.0"
```
```console
curl -OL https://raw.githubusercontent.com/crossplane/crossplane/master/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:master
```
> Note that the Crossplane CLI will not follow symbolic links for files in the
> root package directory.
</div>
<div class="tab-pane fade" id="gcp-tab-3" markdown="1">
```yaml
apiVersion: meta.pkg.crossplane.io/v1
kind: Configuration
metadata:
name: getting-started-with-gcp
annotations:
guide: quickstart
provider: gcp
spec:
crossplane:
version: ">=v1.0.0-0"
dependsOn:
- provider: crossplane/provider-gcp
version: ">=v0.13.0"
```
```console
curl -OL https://raw.githubusercontent.com/crossplane/crossplane/master/docs/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:master
```
> Note that the Crossplane CLI will not follow symbolic links for files in the
> root package directory.
</div>
<div class="tab-pane fade" id="azure-tab-3" markdown="1">
```yaml
apiVersion: meta.pkg.crossplane.io/v1
kind: Configuration
metadata:
name: getting-started-with-azure
annotations:
guide: quickstart
provider: azure
spec:
crossplane:
version: ">=v1.0.0-0"
dependsOn:
- provider: crossplane/provider-azure
version: ">=v0.13.0"
```
```console
curl -OL https://raw.githubusercontent.com/crossplane/crossplane/master/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:master
```
> Note that the Crossplane CLI will not follow symbolic links for files in the
> root package directory.
</div>
</div>
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]: provision-infrastructure.md
[composed]: ../concepts/composition.md
[composition]: ../concepts/composition.md
[Docker Hub]: https://hub.docker.com/
[packages]: ../concepts/packages.md
[concepts]: ../concepts/overview.md

View File

@ -0,0 +1,516 @@
---
title: Install & Configure
toc: true
weight: 2
indent: true
---
# Choosing Hosted or Self-Hosted Crossplane
Users looking to use Crossplane for the first time have two options available to
them today. The first way is to use a hosted Crossplane service like [Upbound
Cloud][Upbound Cloud]. Alternatively, users looking for some more
flexibility can install Crossplane into their own Kubernetes cluster.
Crossplane will be installed using the regularly published Helm chart. The Helm
chart contains all the custom resources and controllers needed to deploy and
configure Crossplane.
Users choosing the self-hosted option can reference our [Install] and
[Configure] docs for installing alternate versions and more detailed
instructions.
<ul class="nav nav-tabs">
<li class="active"><a href="#using-hosted-crossplane" data-toggle="tab">Hosted Crossplane</a></li>
<li><a href="#using-self-hosted-crossplane" data-toggle="tab">Self-Hosted Crossplane</a></li>
</ul>
<br>
<div class="tab-content">
<div class="tab-pane fade in active" id="using-hosted-crossplane" markdown="1">
## Start with a Hosted Crossplane
Upbound Cloud is a managed service of Crossplane created by the founders of
Crossplane. You can [create an account](https://cloud.upbound.io/register) to
get started. Once logged in, you can
[create](https://cloud.upbound.io/docs/getting-started/set-up-upbound-cloud) and
then
[connect](https://cloud.upbound.io/docs/getting-started/connect-to-your-platform)
to your hosted Crossplane cluster.
Once you've completed these two steps, skip down to [Install Crossplane
CLI](#install-crossplane-cli) for further setup instructions.
> Note that Upbound Cloud does not yet include support for Crossplane's alpha
> Open Application Model (OAM) functionality. You'll need to install a self
> hosted Crossplane if you'd like to try the 'Run Applications' part of this
> guide.
<i>Want see another hosted Crossplane service listed? Please [reach out on
Slack][Slack] and our community will highlight it here!</i>
</div>
<div class="tab-pane fade" id="using-self-hosted-crossplane" markdown="1">
## Start with a Self-Hosted 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
<ul class="nav nav-tabs">
<li class="active"><a href="#setup-mac-brew" data-toggle="tab">macOS via Homebrew</a></li>
<li><a href="#setup-mac-linux" data-toggle="tab">macOS / Linux</a></li>
<li><a href="#setup-windows" data-toggle="tab">Windows</a></li>
</ul>
<br>
<div class="tab-content">
<div class="tab-pane fade in active" id="setup-mac-brew" markdown="1">
For macOS via Homebrew use the following:
```console
brew upgrade
brew install kind
brew install kubectl
brew install helm
kind create cluster --image kindest/node:v1.16.15 --wait 5m
```
</div>
<div class="tab-pane fade" id="setup-mac-linux" markdown="1">
For macOS / Linux use the following:
* [Kubernetes cluster]
* [Kind]
* [Minikube], minimum version `v0.28+`
* etc.
* [Helm], minimum version `v3.0.0+`.
</div>
<div class="tab-pane fade" id="setup-windows" markdown="1">
For Windows use the following:
* [Kubernetes cluster]
* [Kind]
* [Minikube], minimum version `v0.28+`
* etc.
* [Helm], minimum version `v3.0.0+`.
</div>
</div>
### Install Crossplane
<ul class="nav nav-tabs">
<li class="active"><a href="#install-tab-helm3" data-toggle="tab">Helm 3 (stable)</a></li>
<li><a href="#install-tab-helm3-latest" data-toggle="tab">Helm 3 (latest)</a></li>
</ul>
<br>
<div class="tab-content">
<div class="tab-pane fade in active" id="install-tab-helm3" markdown="1">
Use Helm 3 to install the latest official `stable` release of Crossplane, suitable for community use and testing:
```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
```
> Note that OAM is an alpha feature that is disabled by default. Make sure to
> install the Crossplane Helm chart with the `--set alpha.oam.enabled=true` flag
> if you would like to follow the 'Run Applications' part of the guide.
</div>
<div class="tab-pane fade" id="install-tab-helm3-latest" markdown="1">
Use Helm 3 to install the latest pre-release version of Crossplane:
```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>
```
For example:
```console
helm install crossplane --namespace crossplane-system crossplane-master/crossplane \
--version 0.11.0-rc.100.gbc5d311 --devel
```
> Note that OAM is an alpha feature that is disabled by default. Make sure to
> install the Crossplane Helm chart with the `--set alpha.oam.enabled=true` flag
> if you would like to follow the 'Run Applications' part of the guide.
</div>
</div>
### Check Crossplane Status
```console
helm list -n crossplane-system
kubectl get all -n crossplane-system
```
</div>
</div>
## Install Crossplane CLI
The Crossplane CLI extends `kubectl` with functionality to build, push, and
install [Crossplane packages]:
<ul class="nav nav-tabs">
<li class="active"><a href="#install-tab-cli" data-toggle="tab">Stable</a></li>
<li><a href="#install-tab-cli-latest" data-toggle="tab">Latest</a></li>
</ul>
<br>
<div class="tab-content">
<div class="tab-pane fade in active" id="install-tab-cli" markdown="1">
```console
curl -sL https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh | sh
```
</div>
<div class="tab-pane fade" id="install-tab-cli-latest" markdown="1">
```console
curl -sL https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh | CHANNEL=master sh
```
You may also specify `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.
```console
curl -sL https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh | CHANNEL=master VERSION=v1.0.0-rc.0.130.g94f34fd3 sh
```
</div>
</div>
## Select a Getting Started Configuration
Crossplane goes beyond simply modelling infrastructure primitives as custom
resources - it enables you to define new custom resources with schemas of your
choosing. We call these "composite resources" (XRs). Composite resources compose
managed resources -- Kubernetes custom resources that offer a high fidelity
representation of an infrastructure primitive, like an SQL instance or a
firewall rule.
We use two special Crossplane resources to define and configure these new custom
resources:
- A `CompositeResourceDefinition` (XRD) _defines_ a new kind of composite
resource, including its schema. An XRD may optionally _offer_ a claim (XRC).
- A `Composition` specifies which resources a composite resource will be
composed of, and how they should be configured. You can create multiple
`Composition` options for each composite resource.
XRDs and Compositions may be packaged and installed as a _configuration_. A
configuration is a [package] of composition configuration that can easily be
installed to Crossplane by creating a declarative `Configuration` resource, or
by using `kubectl crossplane install configuration`.
In the examples below we will install a configuration that defines a new
`CompositePostgreSQLInstance` 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!
<ul class="nav nav-tabs">
<li class="active"><a href="#aws-tab-1" data-toggle="tab">AWS (Default VPC)</a></li>
<li><a href="#aws-new-tab-1" data-toggle="tab">AWS (New VPC)</a></li>
<li><a href="#gcp-tab-1" data-toggle="tab">GCP</a></li>
<li><a href="#azure-tab-1" data-toggle="tab">Azure</a></li>
</ul>
<br>
<div class="tab-content">
<div class="tab-pane fade in active" id="aws-tab-1" markdown="1">
### Install Configuration Package
> If you prefer to see the contents of this configuration package and how it is
> constructed prior to install, skip ahead to the [create a configuration]
> section.
```console
kubectl crossplane install configuration registry.upbound.io/xp/getting-started-with-aws:latest
```
Wait until all packages become healthy:
```
kubectl get pkg --watch
```
### Get AWS Account Keyfile
Using an AWS account with permissions to manage RDS databases:
```console
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
```console
kubectl create secret generic aws-creds -n crossplane-system --from-file=creds=./creds.conf
```
### Configure the Provider
We will create the following `ProviderConfig` object to configure credentials
for AWS Provider:
```yaml
apiVersion: aws.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: aws-creds
key: creds
```
```console
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/master/docs/snippets/configure/aws/providerconfig.yaml
```
</div>
<div class="tab-pane fade" id="aws-new-tab-1" markdown="1">
### Install Configuration Package
> If you prefer to see the contents of this configuration package and how it is
> constructed prior to install, skip ahead to the [create a configuration]
> section.
```console
kubectl crossplane install configuration registry.upbound.io/xp/getting-started-with-aws-with-vpc:latest
```
Wait until all packages become healthy:
```
kubectl get pkg --watch
```
### Get AWS Account Keyfile
Using an AWS account with permissions to manage RDS databases:
```console
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
```console
kubectl create secret generic aws-creds -n crossplane-system --from-file=creds=./creds.conf
```
### Configure the Provider
We will create the following `ProviderConfig` object to configure credentials
for AWS Provider:
```yaml
apiVersion: aws.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: aws-creds
key: creds
```
```console
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/master/docs/snippets/configure/aws/providerconfig.yaml
```
</div>
<div class="tab-pane fade" id="gcp-tab-1" markdown="1">
### Install Configuration Package
> If you prefer to see the contents of this configuration package and how it is
> constructed prior to install, skip ahead to the [create a configuration]
> section.
```console
kubectl crossplane install configuration registry.upbound.io/xp/getting-started-with-gcp:latest
```
Wait until all packages become healthy:
```
kubectl get pkg --watch
```
### Get GCP Account Keyfile
```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
```
### Create a Provider Secret
```console
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:
```console
# 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 -
```
</div>
<div class="tab-pane fade" id="azure-tab-1" markdown="1">
### Install Configuration Package
> If you prefer to see the contents of this configuration package and how it is
> constructed prior to install, skip ahead to the [create a configuration]
> section.
```console
kubectl crossplane install configuration registry.upbound.io/xp/getting-started-with-azure:latest
```
Wait until all packages become healthy:
```
kubectl get pkg --watch
```
### Get Azure Principal Keyfile
```console
# create service principal with Owner role
az ad sp create-for-rbac --sdk-auth --role Owner > "creds.json"
# we need to get the clientId from the json file to add Azure Active Directory
# permissions.
if which jq > /dev/null 2>&1; then
AZURE_CLIENT_ID=$(jq -r ".clientId" < "./creds.json")
else
AZURE_CLIENT_ID=$(cat creds.json | grep clientId | cut -c 16-51)
fi
RW_ALL_APPS=1cda74f2-2616-4834-b122-5cb1b07f8a59
RW_DIR_DATA=78c8a3c8-a07e-4b9e-af1b-b5ccab50a175
AAD_GRAPH_API=00000002-0000-0000-c000-000000000000
az ad app permission add --id "${AZURE_CLIENT_ID}" --api ${AAD_GRAPH_API} --api-permissions ${RW_ALL_APPS}=Role ${RW_DIR_DATA}=Role
az ad app permission grant --id "${AZURE_CLIENT_ID}" --api ${AAD_GRAPH_API} --expires never > /dev/null
az ad app permission admin-consent --id "${AZURE_CLIENT_ID}"
```
### Create a Provider Secret
```console
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
```
```console
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/master/docs/snippets/configure/azure/providerconfig.yaml
```
</div>
</div>
## Next Steps
Now that you have configured Crossplane with support for `PostgreSQLInstance`,
you can [provision infrastructure].
## 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.
<!-- Named Links -->
[package]: ../concepts/packages.md
[provision infrastructure]: provision-infrastructure.md
[create a configuration]: create-configuration.md
[Install]: ../reference/install.md
[Configure]: ../reference/configure.md
[Uninstall]: ../reference/uninstall.md
[Kubernetes cluster]: https://kubernetes.io/docs/setup/
[Minikube]: https://kubernetes.io/docs/tasks/tools/install-minikube/
[Helm]:https://docs.helm.sh/using_helm/
[Kind]: https://kind.sigs.k8s.io/docs/user/quick-start/
[Crossplane packages]: ../concepts/packages.md
[Slack]: http://slack.crossplane.io/
[Upbound Cloud]: https://upbound.io

View File

@ -0,0 +1,283 @@
---
title: Provision Infrastructure
toc: true
weight: 3
indent: true
---
# Provision Infrastructure
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 `CompositePostgreSQLInstance` 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!
<ul class="nav nav-tabs">
<li class="active"><a href="#aws-tab-2" data-toggle="tab">AWS (Default VPC)</a></li>
<li><a href="#aws-new-tab-2" data-toggle="tab">AWS (New VPC)</a></li>
<li><a href="#gcp-tab-2" data-toggle="tab">GCP</a></li>
<li><a href="#azure-tab-2" data-toggle="tab">Azure</a></li>
</ul>
<br>
<div class="tab-content">
<div class="tab-pane fade in active" id="aws-tab-2" markdown="1">
> 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/master/docs/snippets/compose/claim-aws.yaml
```
</div>
<div class="tab-pane fade" id="aws-new-tab-2" markdown="1">
> 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/master/docs/snippets/compose/claim-aws.yaml
```
</div>
<div class="tab-pane fade" id="gcp-tab-2" markdown="1">
```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/master/docs/snippets/compose/claim-gcp.yaml
```
</div>
<div class="tab-pane fade" id="azure-tab-2" markdown="1">
```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/master/docs/snippets/compose/claim-azure.yaml
```
</div>
</div>
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 `CompositePostgreSQLInstance`.
> - `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:9.6
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/master/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]: ../concepts/composition.md
[setup]: install-configure.md
[next section]: create-configuration.md

View File

@ -0,0 +1,236 @@
---
title: Managed Resources
toc: true
weight: 250
indent: true
---
# Using Managed Resources Directly
Crossplane allows you to provision infrastructure anywhere using the Kubernetes
API. While users are encouraged to make use of [composition] to expose
infrastructure resources, you may opt to use managed resources directly. Once
you have [installed a provider] and [configured your credentials], you can
create any infrastructure currently supported by the provider. Let's start by
provisioning a database on your provider of choice.
Each provider below offers their own flavor of a managed database. When you
install a provider it extends Crossplane by adding support for several "managed
resources". A managed resource is a cluster-scoped Kubernetes custom resource
that represents an infrastructure object, such as a database instance. Managed
resources are cluster-scoped because they are only intended to be used directly
when an infrastructure admin is creating a single resource that is intended to
be shared across teams and namespaces. Infrastructure consumers, such as
application teams, are expected to _always_ provision and interact with
infrastructure via claims (XRCs).
<ul class="nav nav-tabs">
<li class="active"><a href="#aws-tab-1" data-toggle="tab">AWS</a></li>
<li><a href="#gcp-tab-1" data-toggle="tab">GCP</a></li>
<li><a href="#azure-tab-1" data-toggle="tab">Azure</a></li>
</ul>
<br>
<div class="tab-content">
<div class="tab-pane fade in active" id="aws-tab-1" markdown="1">
The AWS provider supports provisioning an [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: "9.6"
skipFinalSnapshotBeforeDeletion: true
writeConnectionSecretToRef:
namespace: crossplane-system
name: aws-rdspostgresql-conn
```
```console
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/master/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
```
</div>
<div class="tab-pane fade" id="gcp-tab-1" markdown="1">
The GCP provider supports provisioning a [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_9_6
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/master/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
```
</div>
<div class="tab-pane fade" id="azure-tab-1" markdown="1">
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/master/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
```
</div>
</div>
## Clean Up
Let's check whether there are any managed resources before deleting the
provider.
```console
kubectl get managed
```
If there are any, please delete them first, so you don't lose the track of them.
Then delete all the `ProviderConfig`s you created. An example command if you used
AWS Provider:
```
kubectl delete providerconfig.aws --all
```
List installed providers:
```console
kubectl get provider.pkg
```
Delete the one you want to delete:
```
kubectl delete provider.pkg <provider-name>
```
<!-- Named Links -->
[composition]: ../concepts/composition.md
[installed a provider]: ../concepts/providers.md
[configured your credentials]: ../concepts/providers.md
[RDS]: https://aws.amazon.com/rds/
[CloudSQL]: https://cloud.google.com/sql
[Azure Database for PostgreSQL]: https://azure.microsoft.com/en-us/services/postgresql/
[Resource Group]: https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/manage-resource-groups-portal#what-is-a-resource-group
[ApsaraDB for RDS]: https://www.alibabacloud.com/product/apsaradb-for-rds-postgresql

View File

@ -0,0 +1,31 @@
---
title: Guides
toc: true
weight: 200
---
# Guides
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]
- [Run Applications Using OAM]
- [Using Managed Resources Directly]
<!-- 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]: upgrading-to-v0.14.md
[Upgrading to v1.x]: upgrading-to-v1.x.md
[Vault Provider Credential Injection]: vault-injection.md
[Run Applications Using OAM]: oam-applications.md
[Using Managed Resources Directly]: direct-managed.md

View File

@ -0,0 +1,319 @@
---
title: Multi-Tenant Crossplane
toc: true
weight: 240
indent: true
---
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.
- [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)
## 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: key
```
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: compositemysqlinstances.example.org
spec:
group: example.org
names:
kind: CompositeMySQLInstance
plural: compositemysqlinstances
claimNames:
kind: MySQLInstance
plural: mysqlinstances
...
```
When the example above is created, Crossplane will produce two
[CustomResourceDefinitions]:
1. A cluster-scoped type with `kind: CompositeMySQLInstance`. 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
`CompositeMySQLInstance` 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 `CompositeMySQLInstance` / `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 `CompositeMySQLInstance` / `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 and manage `MySQLInstances` in their given namespace, but not the
ability to see those defined in other namespaces.
Futhermore, 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: key
```
2. Define a `Composition` that patches the name 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.
<!-- Named Links -->
[managed resources]: ../concepts/managed-resources.md
[RBAC]: https://kubernetes.io/docs/reference/access-authn-authz/rbac/
[Composition]: ../concepts/composition.md
[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]: ../concepts/packages.md
[OCI images]: https://github.com/opencontainers/image-spec
[EKS Cluster]: https://doc.crds.dev/github.com/crossplane/provider-aws/eks.aws.crossplane.io/Cluster/v1beta1@v0.17.0
[provider-aws]: https://github.com/crossplane/provider-aws
[provider-helm]: https://github.com/crossplane-contrib/provider-helm

View File

@ -0,0 +1,486 @@
---
title: OAM
toc: true
weight: 240
indent: true
---
# Run Applications
> Note that OAM is an alpha feature that is disabled by default. Make sure you
> installed the Crossplane Helm chart with the `--set alpha.oam.enabled=true`
> flag enabled before following this part of the guide.
Crossplane strives to be the best Kubernetes add-on to provision and manage the
infrastructure and services your applications need directly from kubectl. A huge
part of this mission is arriving at an elegant, flexible way to model and manage
cloud native applications. Crossplane allows your team to deploy and run
applications using the [Open Application Model] (OAM).
OAM is a team-centric model for cloud native apps. Like Crossplane, OAM focuses
on the different people who might be involved in the deployment of a cloud
native application. In this getting started guide:
* _Infrastructure Operators_ provide the infrastructure applications need.
* _Application Developers_ build and supply the components of an application.
* _Application Operators_ compose, deploy, and run application configurations.
We'll play the roles of each of these team members as we deploy an application -
Service Tracker - that consists of several services. One of these services, the
`data-api`, is backed by a managed PostgreSQL database that is provisioned
on-demand by Crossplane.
![Service Tracker Diagram]
> This guide follows on from the previous one in which we covered defining,
> [composing], and offering infrastructure. You'll need to have defined and
> offered a PostgreSQLInstance with at least one working Composition in order
> to create the OAM application we'll use in this guide.
## Infrastructure Operator
### Install workloads and traits
As the infrastructure operator our work is almost done - we defined, published,
and composed the infrastructure that our application developer and operator
teammates will use in the previous guide. One task remains, which is to define
the [_workloads_] and [_traits_] that our platform supports.
OAM applications consist of workloads, each of which may be modified by traits.
The infrastructure operator may choose which workloads and traits by creating
or deleting `WorkloadDefinitions` and `TraitDefinitions` like below:
```yaml
---
apiVersion: core.oam.dev/v1alpha2
kind: WorkloadDefinition
metadata:
name: postgresqlinstances.database.example.org
spec:
definitionRef:
name: postgresqlinstances.database.example.org
---
# The OAM controller needs RBAC access to reconcile any non-core workloads.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
rbac.oam.dev/aggregate-to-controller: "true"
name: oam:claim:postgresqlinstancesdatabase.example.org:aggregate-to-controller
rules:
- apiGroups:
- database.example.org
resources:
- postgresqlinstances
verbs:
- '*'
```
Run the following command to add support for all the workloads and traits required
by this guide:
```console
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/master/docs/snippets/run/definitions.yaml
```
## Application Developer
### Publish Application Components
Now we'll play the role of the application developer. Our Service Tracker
application consists of a UI service, four API services, and a PostgreSQL
database. Under the Open Application Model application developers define
[_components_] that application operators may compose into applications, which
produce workloads. Creating components allows us as application developers to
communicate any fundamental, suggested, or optional properties of our services
and their infrastructure claims.
```yaml
---
apiVersion: core.oam.dev/v1alpha2
kind: Component
metadata:
name: data-api-database
spec:
workload:
apiVersion: database.example.org/v1alpha1
kind: PostgreSQLInstance
metadata:
name: app-postgresql
spec:
parameters:
storageGB: 20
compositionSelector:
matchLabels:
guide: quickstart
parameters:
- name: database-secret
description: Secret to which to write PostgreSQL database connection details.
required: true
fieldPaths:
- spec.writeConnectionSecretToRef.name
- name: database-provider
description: |
Cloud provider that should be used to create a PostgreSQL database.
Either alibaba, aws, azure, or gcp.
fieldPaths:
- spec.compositionSelector.matchLabels.provider
---
apiVersion: core.oam.dev/v1alpha2
kind: Component
metadata:
name: data-api
spec:
workload:
apiVersion: core.oam.dev/v1alpha2
kind: ContainerizedWorkload
metadata:
name: data-api
spec:
containers:
- name: data-api
image: artursouza/rudr-data-api:0.50
env:
- name: DATABASE_USER
fromSecret:
key: username
- name: DATABASE_PASSWORD
fromSecret:
key: password
- name: DATABASE_HOSTNAME
fromSecret:
key: endpoint
- name: DATABASE_PORT
fromSecret:
key: port
- name: DATABASE_NAME
value: postgres
- name: DATABASE_DRIVER
value: postgresql
ports:
- name: http
containerPort: 3009
protocol: TCP
livenessProbe:
exec:
command: [wget, -q, http://127.0.0.1:3009/status, -O, /dev/null, -S]
parameters:
- name: database-secret
description: Secret from which to read PostgreSQL connection details.
required: true
fieldPaths:
- spec.containers[0].env[0].fromSecret.name
- spec.containers[0].env[1].fromSecret.name
- spec.containers[0].env[2].fromSecret.name
- spec.containers[0].env[3].fromSecret.name
---
apiVersion: core.oam.dev/v1alpha2
kind: Component
metadata:
name: flights-api
spec:
workload:
apiVersion: core.oam.dev/v1alpha2
kind: ContainerizedWorkload
metadata:
name: flights-api
spec:
containers:
- name: flights-api
image: sonofjorel/rudr-flights-api:0.49
env:
- name: DATA_SERVICE_URI
ports:
- name: http
containerPort: 3003
protocol: TCP
parameters:
- name: data-uri
description: URI at which the data service is serving
required: true
fieldPaths:
- spec.containers[0].env[0].value
---
apiVersion: core.oam.dev/v1alpha2
kind: Component
metadata:
name: quakes-api
spec:
workload:
apiVersion: core.oam.dev/v1alpha2
kind: ContainerizedWorkload
metadata:
name: quakes-api
spec:
containers:
- name: quakes-api
image: sonofjorel/rudr-quakes-api:0.49
env:
- name: DATA_SERVICE_URI
ports:
- name: http
containerPort: 3012
protocol: TCP
parameters:
- name: data-uri
description: URI at which the data service is serving
required: true
fieldPaths:
- spec.containers[0].env[0].value
---
apiVersion: core.oam.dev/v1alpha2
kind: Component
metadata:
name: service-tracker-ui
spec:
workload:
apiVersion: core.oam.dev/v1alpha2
kind: ContainerizedWorkload
metadata:
name: web-ui
spec:
containers:
- name: service-tracker-ui
image: sonofjorel/rudr-web-ui:0.49
env:
- name: FLIGHT_API_ROOT
- name: WEATHER_API_ROOT
- name: QUAKES_API_ROOT
ports:
- name: http
containerPort: 8080
protocol: TCP
parameters:
- name: flights-uri
description: URI at which the flights service is serving
required: true
fieldPaths:
- spec.containers[0].env[0].value
- name: weather-uri
description: URI at which the weather service is serving
required: true
fieldPaths:
- spec.containers[0].env[1].value
- name: quakes-uri
description: URI at which the quakes service is serving
required: true
fieldPaths:
- spec.containers[0].env[2].value
---
apiVersion: core.oam.dev/v1alpha2
kind: Component
metadata:
name: weather-api
spec:
workload:
apiVersion: core.oam.dev/v1alpha2
kind: ContainerizedWorkload
metadata:
name: weather-api
spec:
containers:
- name: weather-api
image: sonofjorel/rudr-weather-api:0.49
env:
- name: DATA_SERVICE_URI
ports:
- name: http
containerPort: 3015
protocol: TCP
parameters:
- name: data-uri
description: URI at which the data service is serving
required: true
fieldPaths:
- spec.containers[0].env[0].value
```
```console
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/master/docs/snippets/run/components.yaml
```
Each of the above components describes a particular kind of workload. The
Service Tracker application consists of two kinds of workload:
* A [`ContainerizedWorkload`] is a long-running containerized process.
* A `PostgreSQLInstance` is a PostgreSQL instance and database.
All OAM components configure a kind of workload, and any kind of Kubernetes
resource may act as an OAM workload as long as an infrastructure operator has
allowed it to by authoring a `WorkloadDefinition`.
## Application Operator
### Run The Application
Finally, we'll play the role of an application operator and tie together the
application components and infrastructure that our application developer and
infrastructure operator team-mates have published. In OAM this is done by
authoring an [_application configuration_]:
```yaml
apiVersion: core.oam.dev/v1alpha2
kind: ApplicationConfiguration
metadata:
name: service-tracker
spec:
components:
- componentName: data-api-database
parameterValues:
- name: database-secret
value: tracker-database-secret
- componentName: data-api
parameterValues:
- name: database-secret
value: tracker-database-secret
- componentName: flights-api
parameterValues:
- name: data-uri
value: "http://data-api.default.svc.cluster.local:3009/"
traits:
- trait:
apiVersion: core.oam.dev/v1alpha2
kind: ManualScalerTrait
metadata:
name: flights-api
spec:
replicaCount: 2
- componentName: quakes-api
parameterValues:
- name: data-uri
value: "http://data-api.default.svc.cluster.local:3009/"
traits:
- trait:
apiVersion: core.oam.dev/v1alpha2
kind: ManualScalerTrait
metadata:
name: quakes-api
spec:
replicaCount: 2
- componentName: weather-api
parameterValues:
- name: data-uri
value: "http://data-api.default.svc.cluster.local:3009/"
traits:
- trait:
apiVersion: core.oam.dev/v1alpha2
kind: ManualScalerTrait
metadata:
name: weather-api
spec:
replicaCount: 2
- componentName: service-tracker-ui
parameterValues:
- name: flights-uri
value: "http://flights-api.default.svc.cluster.local:3003/"
- name: weather-uri
value: "http://weather-api.default.svc.cluster.local:3015/"
- name: quakes-uri
value: "http://quakes-api.default.svc.cluster.local:3012/"
```
```console
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/master/docs/snippets/run/appconfig.yaml
```
This application configuration names each of components the application
developer created earlier to produce workloads. The application operator may (or
in some cases _must_) provide parameter values for a component in order to
override or specify certain configuration values. Component parameters represent
configuration settings that the component author - the application developer -
deemed to be of interest to application operators.
```yaml
- componentName: data-api-database
parameterValues:
- name: database-provider
value: azure
```
> If you created Compositions for more than one provider in the previous guide
> you can add the above parameter to the `data-api-database` component to choose
> which cloud provider the Service Tracker's database should run on.
You might notice that some components include a [`ManualScalerTrait`]. Traits
augment the workload produced by a component with additional features, allowing
application operators to make decisions about the configuration of a component
without having to involve the developer. The `ManualScalerTrait` allows an
application operator to specify how many replicas should exist of any scalable
kind of workload.
> Note that the OAM spec also includes the concept of an _application scope_.
> Crossplane does not yet support scopes.
## Use The Application
Finally, we'll open and use the Service Tracker application we just deployed.
<ul class="nav nav-tabs">
<li class="active"><a href="#connect-tab-lb" data-toggle="tab">Load Balancer</a></li>
<li><a href="#connect-tab-forward" data-toggle="tab">Port Forward</a></li>
</ul>
<br>
<div class="tab-content">
<div class="tab-pane fade in active" id="connect-tab-lb" markdown="1">
If you deployed Service Tracker to a managed cluster like AKS, ACK, EKS, or GKE
with support for load balancer Services you should be able to browse to the IP
of the `web-ui` service on port 8080 - for example <http://10.0.0.1:8080>.
```console
kubectl get svc web-ui -o=jsonpath={.status.loadBalancer.ingress[0].ip}
```
</div>
<div class="tab-pane fade" id="connect-tab-forward" markdown="1">
If you're using a cluster that doesn't support load balancer Services, like Kind
or Minikube you can use a port forward instead, and connect to
<http://localhost:8080.>
```console
kubectl port-forward deployment/web-ui 8080
```
</div>
</div>
You should see the Service Tracker dashboard in your browser. Hit 'Refresh Data'
for each of the services to ensure the Service Tracker web UI can connect to its
various data API services and populate its PostgreSQL database:
![Service Tracker Dashboard]
If everything was successful you should be able to browse to Flights,
Earthquakes, or Weather to see what's going on in the world today:
![Service Tracker Flights]
## Clean Up
To shut down your application, simply run:
```console
kubectl delete applicationconfiguration service-tracker
```
If you also wish to delete the components, workload definitions, and trait
definitions we created in this guide, run:
```console
kubectl delete -f https://raw.githubusercontent.com/crossplane/crossplane/master/docs/snippets/run/components.yaml
kubectl delete -f https://raw.githubusercontent.com/crossplane/crossplane/master/docs/snippets/run/definitions.yaml
```
[Open Application Model]: https://oam.dev/
[composing]: compose-infrastructure.md
[Service Tracker Diagram]: ../media/run-applications-diagram.jpg
[_workloads_]: https://github.com/oam-dev/spec/blob/1.0.0-alpha2/3.workload.md
[_traits_]: https://github.com/oam-dev/spec/blob/1.0.0-alpha2/6.traits.md
[_components_]: https://github.com/oam-dev/spec/blob/1.0.0-alpha2/4.component.md
[_application configuration_]: https://github.com/oam-dev/spec/blob/1.0.0-alpha2/7.application_configuration.md
[`ContainerizedWorkload`]: https://github.com/oam-dev/spec/blob/1.0.0-alpha2/core/workloads/containerized_workload/containerized_workload.md
[`ManualScalerTrait`]: https://github.com/oam-dev/spec/blob/1.0.0-alpha2/core/traits/manual_scaler_trait.md
[_application scope_]: https://github.com/oam-dev/spec/blob/1.0.0-alpha2/5.application_scopes.md
[Service Tracker Dashboard]:../media/run-applications-dash.png
[Service Tracker Flights]: ../media/run-applications-flights.png

View File

@ -0,0 +1,166 @@
---
title: Upgrading to v0.14
toc: true
weight: 210
indent: true
---
# Upgrading to v0.14
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: compositepostgresqlinstances.database.example.org
spec:
claimNames:
kind: PostgreSQLInstance
plural: postgresqlinstances
connectionSecretKeys:
- username
- password
- endpoint
- port
crdSpecTemplate:
group: database.example.org
version: v1alpha1
names:
kind: CompositePostgreSQLInstance
plural: compositepostgresqlinstances
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: compositepostgresqlinstances.database.example.org
spec:
group: database.example.org
names:
kind: CompositePostgreSQLInstance
plural: compositepostgresqlinstances
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.

View File

@ -0,0 +1,37 @@
---
title: Upgrading to v1.x
toc: true
weight: 220
indent: true
---
# Upgrading to v1.x
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
To upgrade from the currently installed version, run:
```console
# Update to the latest stable Helm chart for the desired version
helm --namespace crossplane-system upgrade crossplane crossplane-stable/crossplane --version <version>
```

View File

@ -0,0 +1,326 @@
---
title: Vault Credential Injection
toc: true
weight: 230
indent: true
---
# Using Vault for Provider Credentials
> This guide is adapted from the [Vault on Minikube] and [Vault Kubernetes
> Sidecar] guides.
Most Crossplane providers support supplying credentials from at least the
following sources:
- Kubernetes Secret
- Environment Variable
- Filesystem
A provider may optionally support additional credentials sources, but the common
sources cover a wide variety of use cases. One specific use case that is popular
among organizations that use [Vault] for secrets management is using a sidecar
to inject credentials into the filesystem. This guide will demonstrate how to
use the [Vault Kubernetes Sidecar] to provide credentials for [provider-gcp].
> Note: in this guide we will copy GCP credentials into Vault's KV secrets
> engine. This is a simple generic approach to managing secrets with Vault, but
> is not as robust as using Vault's dedicated cloud provider secrets engines for
> [AWS], [Azure], and [GCP].
## Setup
> Note: this guide walks through setting up Vault running in the same cluster as
> Crossplane. You may also choose to use an existing Vault instance that runs
> outside the cluster but has Kubernetes authentication enabled.
Before getting started, you must ensure that you have installed Crossplane and
Vault and that they are running in your cluster.
1. Install Crossplane
```console
kubectl create namespace crossplane-system
helm repo add crossplane-stable https://charts.crossplane.io/stable
helm repo update
helm install crossplane --namespace crossplane-system crossplane-stable/crossplane
```
2. Install Vault Helm Chart
```console
helm repo add hashicorp https://helm.releases.hashicorp.com
helm install vault hashicorp/vault
```
3. Unseal Vault Instance
In order for Vault to access encrypted data from physical storage, it must be
[unsealed].
```console
kubectl exec vault-0 -- vault operator init -key-shares=1 -key-threshold=1 -format=json > cluster-keys.json
VAULT_UNSEAL_KEY=$(cat cluster-keys.json | jq -r ".unseal_keys_b64[]")
kubectl exec vault-0 -- vault operator unseal $VAULT_UNSEAL_KEY
```
4. Enable Kubernetes Authentication Method
In order for Vault to be able to authenticate requests based on Kubernetes
service accounts, the [Kubernetes authentication backend] must be enabled. This
requires logging in to Vault and configuring it with a service account token,
API server address, and certificate. Because we are running Vault in Kubernetes,
these values are already available via the container filesystem and environment
variables.
```console
cat cluster-keys.json | jq -r ".root_token" # get root token
kubectl exec -it vault-0 -- /bin/sh
vault login # use root token from above
vault auth enable kubernetes
vault write auth/kubernetes/config \
token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" \
kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
```
5. Exit Vault Container
The next steps will be executed in your local environment.
```console
exit
```
## Create GCP Service Account
In order to provision infrastructure on GCP, you will need to create a service
account with appropriate permissions. In this guide we will only provision a
CloudSQL instance, so the service account will be bound to the `cloudsql.admin`
role. The following steps will setup a GCP service account, give it the
necessary permissions for Crossplane to be able to manage CloudSQL instances,
and emit the service account credentials in a JSON file.
```console
# replace this with your own gcp project id and the name of the service account
# that will be created.
PROJECT_ID=my-project
NEW_SA_NAME=test-service-account-name
# create service account
SA="${NEW_SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
gcloud iam service-accounts create $NEW_SA_NAME --project $PROJECT_ID
# enable cloud API
SERVICE="sqladmin.googleapis.com"
gcloud services enable $SERVICE --project $PROJECT_ID
# grant access to cloud API
ROLE="roles/cloudsql.admin"
gcloud projects add-iam-policy-binding --role="$ROLE" $PROJECT_ID --member "serviceAccount:$SA"
# create service account keyfile
gcloud iam service-accounts keys create creds.json --project $PROJECT_ID --iam-account $SA
```
You should now have valid service account credentials in `creds.json`.
## Store Credentials in Vault
After setting up Vault, you will need to store your credentials in the [kv
secrets engine].
> Note: the steps below involve copying credentials into the container
> filesystem before storing them in Vault. You may also choose to use Vault's
> HTTP API or UI by port-forwarding the container to your local environment
> (`kubectl port-forward vault-0 8200:8200`).
1. Copy Credentials File into Vault Container
Copy your credentials into the container filesystem so that your can store them
in Vault.
```console
kubectl cp creds.json vault-0:/tmp/creds.json
```
2. Enable KV Secrets Engine
Secrets engines must be enabled before they can be used. Enable the `kv-v2`
secrets engine a the `secret` path.
```console
kubectl exec -it vault-0 -- /bin/sh
vault secrets enable -path=secret kv-v2
```
3. Store GCP Credentials in KV Engine
The path of your GCP credentials is how the secret will be referenced when
injecting it into the `provider-gcp` controller `Pod`.
```console
vault kv put secret/provider-creds/gcp-default @tmp/creds.json
```
4. Clean Up Credentials File
You no longer need our GCP credentials file in the container filesystem, so go
ahead and clean it up.
```console
rm tmp/creds.json
```
## Create a Vault Policy for Reading Provider Credentials
In order for our controllers to have the Vault sidecar inject the credentials
into their filesystem, you must associate the `Pod` with a [policy]. This policy
will allow for reading and listing all secrets on the `provider-creds` path in
the `kv-v2` secrets engine.
```console
vault policy write provider-creds - <<EOF
path "secret/data/provider-creds/*" {
capabilities = ["read", "list"]
}
EOF
```
## Create a Role for Crossplane Provider Pods
1. Create Role
The last step is to create a role that is bound to the policy you created and
associate it with a group of Kubernetes service accounts. This role can be
assumed by any (`*`) service account in the `crossplane-system` namespace.
```console
vault write auth/kubernetes/role/crossplane-providers \
bound_service_account_names="*" \
bound_service_account_namespaces=crossplane-system \
policies=provider-creds \
ttl=24h
```
2. Exit Vault Container
The next steps will be executed in your local environment.
```console
exit
```
## Install provider-gcp
You are now ready to install `provider-gcp`. Crossplane provides a
`ControllerConfig` type that allows you to customize the deployment of a
provider's controller `Pod`. A `ControllerConfig` can be created and referenced
by any number of `Provider` objects that wish to use its configuration. In the
example below, the `Pod` annotations indicate to the Vault mutating webhook that
we want for the secret stored at `secret/provider-creds/gcp-default` to be
injected into the container filesystem by assuming role `crossplane-providers`.
There is also so template formatting added to make sure the secret data is
presented in a form that `provider-gcp` is expecting.
{% raw %}
```console
echo "apiVersion: pkg.crossplane.io/v1alpha1
kind: ControllerConfig
metadata:
name: vault-config
spec:
metadata:
annotations:
vault.hashicorp.com/agent-inject: \"true\"
vault.hashicorp.com/role: "crossplane-providers"
vault.hashicorp.com/agent-inject-secret-creds.txt: "secret/provider-creds/gcp-default"
vault.hashicorp.com/agent-inject-template-creds.txt: |
{{- with secret \"secret/provider-creds/gcp-default\" -}}
{{ .Data.data | toJSON }}
{{- end -}}
---
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-gcp
spec:
package: crossplane/provider-gcp:v0.16.0
controllerConfigRef:
name: vault-config" | kubectl apply -f -
```
{% endraw %}
## Configure provider-gcp
One `provider-gcp` is installed and running, you will want to create a
`ProviderConfig` that specifies the credentials in the filesystem that should be
used to provision managed resources that reference this `ProviderConfig`.
Because the name of this `ProviderConfig` is `default` it will be used by any
managed resources that do not explicitly reference a `ProviderConfig`.
> Note: make sure that the `PROJECT_ID` environment variable that was defined
> earlier is still set correctly.
```console
echo "apiVersion: gcp.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
projectID: ${PROJECT_ID}
credentials:
source: Filesystem
fs:
path: /vault/secrets/creds.txt" | kubectl apply -f -
```
## Provision Infrastructure
The final step is to actually provision a `CloudSQLInstance`. Creating the
object below will result in the creation of a Cloud SQL Postgres database on
GCP.
```console
echo "apiVersion: database.gcp.crossplane.io/v1beta1
kind: CloudSQLInstance
metadata:
name: postgres-vault-demo
spec:
forProvider:
databaseVersion: POSTGRES_9_6
region: us-central1
settings:
tier: db-custom-1-3840
dataDiskType: PD_SSD
dataDiskSizeGb: 10
writeConnectionSecretToRef:
namespace: crossplane-system
name: cloudsqlpostgresql-conn" | kubectl apply -f -
```
You can monitor the progress of the database provisioning with the following
command:
```console
kubectl get cloudsqlinstance -w
```
<!-- named links -->
[Vault on Minikube]: https://learn.hashicorp.com/tutorials/vault/kubernetes-minikube
[Vault Kubernetes Sidecar]: https://learn.hashicorp.com/tutorials/vault/kubernetes-sidecar
[Vault]: https://www.vaultproject.io/
[Vault Kubernetes Sidecar]: https://www.vaultproject.io/docs/platform/k8s/injector
[provider-gcp]: https://github.com/crossplane/provider-gcp
[AWS]: https://www.vaultproject.io/docs/secrets/aws
[Azure]: https://www.vaultproject.io/docs/secrets/azure
[GCP]: https://www.vaultproject.io/docs/secrets/gcp
[unsealed]: https://www.vaultproject.io/docs/concepts/seal
[Kubernetes authentication backend]: https://www.vaultproject.io/docs/auth/kubernetes
[kv secrets engine]: https://www.vaultproject.io/docs/secrets/kv/kv-v2
[policy]: https://www.vaultproject.io/docs/concepts/policies

BIN
docs/v1.2/media/arch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
docs/v1.2/media/banner.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 KiB

310
docs/v1.2/media/logo.svg Normal file
View File

@ -0,0 +1,310 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 1312.19 279.51" style="enable-background:new 0 0 1312.19 279.51;" xml:space="preserve">
<style type="text/css">
.st0{clip-path:url(#SVGID_2_);fill:#F7D186;}
.st1{clip-path:url(#SVGID_4_);fill:#FF9234;}
.st2{clip-path:url(#SVGID_6_);enable-background:new ;}
.st3{clip-path:url(#SVGID_8_);}
.st4{clip-path:url(#SVGID_10_);}
.st5{clip-path:url(#SVGID_12_);fill:#FFCD3C;}
.st6{clip-path:url(#SVGID_14_);enable-background:new ;}
.st7{clip-path:url(#SVGID_16_);}
.st8{clip-path:url(#SVGID_18_);}
.st9{clip-path:url(#SVGID_20_);fill:#F3807B;}
.st10{clip-path:url(#SVGID_22_);enable-background:new ;}
.st11{clip-path:url(#SVGID_24_);}
.st12{clip-path:url(#SVGID_26_);}
.st13{clip-path:url(#SVGID_28_);fill:#35D0BA;}
.st14{clip-path:url(#SVGID_30_);fill:#D8AE64;}
.st15{clip-path:url(#SVGID_32_);fill:#004680;}
.st16{clip-path:url(#SVGID_34_);fill:#004680;}
.st17{clip-path:url(#SVGID_36_);fill:#004680;}
.st18{clip-path:url(#SVGID_38_);fill:#004680;}
.st19{clip-path:url(#SVGID_40_);fill:#004680;}
.st20{clip-path:url(#SVGID_42_);fill:#004680;}
.st21{clip-path:url(#SVGID_44_);fill:#004680;}
.st22{clip-path:url(#SVGID_46_);fill:#004680;}
.st23{clip-path:url(#SVGID_48_);fill:#004680;}
.st24{clip-path:url(#SVGID_50_);fill:#004680;}
</style>
<g>
<g>
<defs>
<path id="SVGID_1_" d="M115.47,94.13c-8.4,0-15.22,6.81-15.22,15.22v143.2c0,8.4,6.81,15.22,15.22,15.22s15.22-6.81,15.22-15.22
v-143.2C130.68,100.94,123.87,94.13,115.47,94.13"/>
</defs>
<clipPath id="SVGID_2_">
<use xlink:href="#SVGID_1_" style="overflow:visible;"/>
</clipPath>
<rect x="89.53" y="83.41" class="st0" width="51.87" height="195.07"/>
</g>
<g>
<defs>
<path id="SVGID_3_" d="M176.53,75.36c0.05-0.96,0.07-1.93,0.07-2.9c0-0.95-0.02-1.89-0.07-2.82
c-1.47-32.22-28.06-57.88-60.64-57.88S56.72,37.42,55.25,69.64c-0.04,0.94-0.07,1.88-0.07,2.82c0,1.04,0.03,2.07,0.08,3.09
c-0.02,0.5-0.08,1-0.08,1.51v99.64c0,19.06,15.59,34.65,34.65,34.65h52.14c19.06,0,34.65-15.59,34.65-34.65V77.07
C176.62,76.49,176.56,75.93,176.53,75.36"/>
</defs>
<clipPath id="SVGID_4_">
<use xlink:href="#SVGID_3_" style="overflow:visible;"/>
</clipPath>
<rect x="44.47" y="1.04" class="st1" width="142.87" height="221.04"/>
</g>
<g>
<defs>
<path id="SVGID_5_" d="M55.55,69.64c-0.04,0.93-0.06,1.87-0.06,2.82c0,1.04,0.02,2.07,0.08,3.09c-0.02,0.51-0.08,1-0.08,1.52
v99.64c0,19.05,15.59,34.64,34.64,34.64h52.14c19.06,0,34.65-15.59,34.65-34.64V77.07c0-0.58-0.06-1.14-0.09-1.71
c0.05-0.96,0.07-1.93,0.07-2.89c0-0.95-0.02-1.89-0.06-2.82c-1.47-32.22-28.06-57.88-60.64-57.88
C83.61,11.76,57.02,37.42,55.55,69.64z"/>
</defs>
<clipPath id="SVGID_6_">
<use xlink:href="#SVGID_5_" style="overflow:visible;"/>
</clipPath>
<g class="st2">
<g>
<defs>
<rect id="SVGID_7_" x="16.08" y="24.9" width="197.24" height="197.24"/>
</defs>
<clipPath id="SVGID_8_">
<use xlink:href="#SVGID_7_" style="overflow:visible;"/>
</clipPath>
<g class="st3">
<defs>
<rect id="SVGID_9_" x="9.23" y="92.99" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -54.1638 118.2926)" width="212.95" height="63.07"/>
</defs>
<clipPath id="SVGID_10_">
<use xlink:href="#SVGID_9_" style="overflow:visible;"/>
</clipPath>
<g class="st4">
<defs>
<rect id="SVGID_11_" x="54.67" y="9.89" width="124.35" height="201.53"/>
</defs>
<clipPath id="SVGID_12_">
<use xlink:href="#SVGID_11_" style="overflow:visible;"/>
</clipPath>
<rect x="7.4" y="16.22" class="st5" width="216.62" height="216.62"/>
</g>
</g>
</g>
</g>
</g>
<g>
<defs>
<path id="SVGID_13_" d="M55.55,69.64c-0.04,0.93-0.06,1.87-0.06,2.82c0,1.04,0.02,2.07,0.08,3.09c-0.02,0.51-0.08,1-0.08,1.52
v99.64c0,19.05,15.59,34.64,34.64,34.64h52.14c19.06,0,34.65-15.59,34.65-34.64V77.07c0-0.58-0.06-1.14-0.09-1.71
c0.05-0.96,0.07-1.93,0.07-2.89c0-0.95-0.02-1.89-0.06-2.82c-1.47-32.22-28.06-57.88-60.64-57.88
C83.61,11.76,57.02,37.42,55.55,69.64z"/>
</defs>
<clipPath id="SVGID_14_">
<use xlink:href="#SVGID_13_" style="overflow:visible;"/>
</clipPath>
<g class="st6">
<g>
<defs>
<rect id="SVGID_15_" x="-37.52" y="-28.7" width="207.96" height="207.96"/>
</defs>
<clipPath id="SVGID_16_">
<use xlink:href="#SVGID_15_" style="overflow:visible;"/>
</clipPath>
<g class="st7">
<defs>
<rect id="SVGID_17_" x="-40.95" y="35.1" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -33.3744 68.1028)" width="212.95" height="78.48"/>
</defs>
<clipPath id="SVGID_18_">
<use xlink:href="#SVGID_17_" style="overflow:visible;"/>
</clipPath>
<g class="st8">
<defs>
<rect id="SVGID_19_" x="54.67" y="9.89" width="124.35" height="201.53"/>
</defs>
<clipPath id="SVGID_20_">
<use xlink:href="#SVGID_19_" style="overflow:visible;"/>
</clipPath>
<rect x="-48.24" y="-39.42" class="st9" width="227.51" height="227.51"/>
</g>
</g>
</g>
</g>
</g>
<g>
<defs>
<path id="SVGID_21_" d="M55.55,69.64c-0.04,0.93-0.06,1.87-0.06,2.82c0,1.04,0.02,2.07,0.08,3.09c-0.02,0.51-0.08,1-0.08,1.52
v99.64c0,19.05,15.59,34.64,34.64,34.64h52.14c19.06,0,34.65-15.59,34.65-34.64V77.07c0-0.58-0.06-1.14-0.09-1.71
c0.05-0.96,0.07-1.93,0.07-2.89c0-0.95-0.02-1.89-0.06-2.82c-1.47-32.22-28.06-57.88-60.64-57.88
C83.61,11.76,57.02,37.42,55.55,69.64z"/>
</defs>
<clipPath id="SVGID_22_">
<use xlink:href="#SVGID_21_" style="overflow:visible;"/>
</clipPath>
<g class="st10">
<g>
<defs>
<rect id="SVGID_23_" x="61.1" y="69.92" width="197.24" height="197.24"/>
</defs>
<clipPath id="SVGID_24_">
<use xlink:href="#SVGID_23_" style="overflow:visible;"/>
</clipPath>
<g class="st11">
<defs>
<rect id="SVGID_25_" x="53.98" y="137.74" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -72.6974 163.0359)" width="212.95" height="63.07"/>
</defs>
<clipPath id="SVGID_26_">
<use xlink:href="#SVGID_25_" style="overflow:visible;"/>
</clipPath>
<g class="st12">
<defs>
<rect id="SVGID_27_" x="54.67" y="9.89" width="124.35" height="201.53"/>
</defs>
<clipPath id="SVGID_28_">
<use xlink:href="#SVGID_27_" style="overflow:visible;"/>
</clipPath>
<rect x="52.14" y="60.96" class="st13" width="216.62" height="216.62"/>
</g>
</g>
</g>
</g>
</g>
<g>
<defs>
<path id="SVGID_29_" d="M104.38,211.52l26.4,26.39V211.3C130.78,211.3,103.72,211.52,104.38,211.52"/>
</defs>
<clipPath id="SVGID_30_">
<use xlink:href="#SVGID_29_" style="overflow:visible;"/>
</clipPath>
<rect x="93.65" y="200.58" class="st14" width="47.85" height="48.06"/>
</g>
<g>
<defs>
<path id="SVGID_31_" d="M307.52,195.1c-38.8,0-70.21-31.6-70.21-70.41c0-38.6,31.4-70.21,70.21-70.21c20.2,0,39.6,8.8,52.81,24
c4.2,5,3.8,12.2-1,16.4c-4.8,4.4-12.2,3.8-16.4-1c-9-10.2-21.8-16-35.4-16c-25.8,0-47.01,21-47.01,46.8
c0,26,21.2,47.01,47.01,47.01c13.6,0,26.4-5.8,35.4-16c4.2-4.8,11.6-5.4,16.4-1c4.8,4.2,5.2,11.4,1,16.4
C347.12,186.3,327.72,195.1,307.52,195.1"/>
</defs>
<use xlink:href="#SVGID_31_" style="overflow:visible;fill-rule:evenodd;clip-rule:evenodd;fill:#004680;"/>
<clipPath id="SVGID_32_">
<use xlink:href="#SVGID_31_" style="overflow:visible;"/>
</clipPath>
<rect x="226.59" y="43.77" class="st15" width="147.35" height="162.05"/>
</g>
<g>
<defs>
<path id="SVGID_33_" d="M438.53,98.89c0,6.4-5.2,11.6-11.8,11.6c-12.8,0-22.4,10.4-22.4,24.6v48.41c0,6.4-5.2,11.6-11.6,11.6
c-6.4,0-11.6-5.2-11.6-11.6V96.49c0-6.4,5.2-11.6,11.6-11.6c5.4,0,9.8,3.6,11.2,8.6c6.8-4,14.6-6.2,22.8-6.2
C433.33,87.29,438.53,92.49,438.53,98.89"/>
</defs>
<use xlink:href="#SVGID_33_" style="overflow:visible;fill-rule:evenodd;clip-rule:evenodd;fill:#004680;"/>
<clipPath id="SVGID_34_">
<use xlink:href="#SVGID_33_" style="overflow:visible;"/>
</clipPath>
<rect x="370.4" y="74.17" class="st16" width="78.84" height="131.65"/>
</g>
<g>
<defs>
<path id="SVGID_35_" d="M497.53,195.7c-30.4,0-55-24.8-55-55c0-30.4,24.6-55.21,55-55.21c30.4,0,55.21,24.8,55.21,55.21
C552.74,170.9,527.94,195.7,497.53,195.7 M497.53,108.69c-17.6,0-31.8,14.4-31.8,32c0,17.4,14.2,31.8,31.8,31.8
c17.6,0,31.8-14.4,31.8-31.8C529.34,123.09,515.14,108.69,497.53,108.69"/>
</defs>
<use xlink:href="#SVGID_35_" style="overflow:visible;fill-rule:evenodd;clip-rule:evenodd;fill:#004680;"/>
<clipPath id="SVGID_36_">
<use xlink:href="#SVGID_35_" style="overflow:visible;"/>
</clipPath>
<rect x="431.81" y="74.77" class="st17" width="131.65" height="131.65"/>
</g>
<g>
<defs>
<path id="SVGID_37_" d="M571.94,174.9c-2.8-5.8-0.2-12.8,5.6-15.4c6-2.8,12.8-0.2,15.4,5.6c1.6,3.2,6,6.8,13.8,6.8
c10.8,0,14.6-6.6,14.6-11c0-6-1.6-7.8-17.2-11.8c-7-1.6-14.2-3.4-20.4-7.4c-8.4-5.6-13-14-13-24.4c0-8.2,3.6-16.4,9.8-22.4
c6.6-6.4,15.8-10,26.2-10c14.8,0,27.41,7.2,32.8,19c2.8,5.8,0.2,12.6-5.6,15.4c-5.8,2.8-12.8,0.2-15.4-5.6
c-1.2-2.6-5-5.6-11.8-5.6c-9.2,0-12.6,5.8-12.6,9.2c0,4,0.8,5.6,15.6,9.4c13,3.2,34.8,8.6,34.8,34.2c0,8.6-3.6,17.2-10,23.6
c-5,4.8-13.8,10.6-27.8,10.6C590.94,195.1,577.54,187.3,571.94,174.9"/>
</defs>
<use xlink:href="#SVGID_37_" style="overflow:visible;fill-rule:evenodd;clip-rule:evenodd;fill:#004680;"/>
<clipPath id="SVGID_38_">
<use xlink:href="#SVGID_37_" style="overflow:visible;"/>
</clipPath>
<rect x="560.02" y="74.17" class="st18" width="95.25" height="131.65"/>
</g>
<g>
<defs>
<path id="SVGID_39_" d="M663.75,174.9c-2.8-5.8-0.2-12.8,5.6-15.4c6-2.8,12.8-0.2,15.4,5.6c1.6,3.2,6,6.8,13.8,6.8
c10.8,0,14.6-6.6,14.6-11c0-6-1.6-7.8-17.2-11.8c-7-1.6-14.2-3.4-20.4-7.4c-8.4-5.6-13-14-13-24.4c0-8.2,3.6-16.4,9.8-22.4
c6.6-6.4,15.8-10,26.2-10c14.81,0,27.41,7.2,32.8,19c2.8,5.8,0.2,12.6-5.6,15.4c-5.8,2.8-12.8,0.2-15.4-5.6
c-1.2-2.6-5-5.6-11.8-5.6c-9.2,0-12.6,5.8-12.6,9.2c0,4,0.8,5.6,15.6,9.4c13,3.2,34.8,8.6,34.8,34.2c0,8.6-3.6,17.2-10,23.6
c-5,4.8-13.8,10.6-27.8,10.6C682.75,195.1,669.35,187.3,663.75,174.9"/>
</defs>
<use xlink:href="#SVGID_39_" style="overflow:visible;fill-rule:evenodd;clip-rule:evenodd;fill:#004680;"/>
<clipPath id="SVGID_40_">
<use xlink:href="#SVGID_39_" style="overflow:visible;"/>
</clipPath>
<rect x="651.83" y="74.17" class="st19" width="95.25" height="131.65"/>
</g>
<g>
<defs>
<path id="SVGID_41_" d="M859.17,139.9c0,14.8-5,28.4-14.4,38.61c-9.8,10.6-23.2,16.6-38,16.6c-10.6,0-20.6-3.2-29-8.8v47.2
c0,6.4-5.4,11.6-11.8,11.6c-6.4,0-11.6-5.2-11.6-11.6V96.49c0-6.4,5.2-11.6,11.6-11.6c5.4,0,10.2,3.8,11.4,9
c8.6-5.8,18.8-9,29.4-9c14.8,0,28.2,5.8,38,16.4C854.17,111.49,859.17,125.29,859.17,139.9 M835.96,139.9
c0-18.4-12.2-31.8-29.2-31.8c-16.8,0-29,13.4-29,31.8c0,18.4,12.2,31.8,29,31.8C823.77,171.7,835.96,158.3,835.96,139.9"/>
</defs>
<use xlink:href="#SVGID_41_" style="overflow:visible;fill-rule:evenodd;clip-rule:evenodd;fill:#004680;"/>
<clipPath id="SVGID_42_">
<use xlink:href="#SVGID_41_" style="overflow:visible;"/>
</clipPath>
<rect x="743.64" y="74.17" class="st20" width="126.25" height="181.65"/>
</g>
<g>
<defs>
<path id="SVGID_43_" d="M889.77,195.1c-6.4,0-11.6-5.2-11.6-11.6V66.29c0-6.4,5.2-11.6,11.6-11.6c6.4,0,11.8,5.2,11.8,11.6V183.5
C901.57,189.9,896.17,195.1,889.77,195.1"/>
</defs>
<use xlink:href="#SVGID_43_" style="overflow:visible;fill-rule:evenodd;clip-rule:evenodd;fill:#004680;"/>
<clipPath id="SVGID_44_">
<use xlink:href="#SVGID_43_" style="overflow:visible;"/>
</clipPath>
<rect x="867.45" y="43.97" class="st21" width="44.84" height="161.85"/>
</g>
<g>
<defs>
<path id="SVGID_45_" d="M1025.38,96.49v87.01c0,6.4-5.2,11.6-11.6,11.6c-5.6,0-10.2-3.8-11.4-9c-8.4,5.8-18.6,9-29.4,9
c-14.8,0-28.2-5.8-38.01-16.6c-9.2-10-14.4-23.8-14.4-38.4c0-14.8,5.2-28.6,14.4-38.61c9.8-10.8,23.21-16.6,38.01-16.6
c10.8,0,21,3.2,29.4,9c1.2-5.2,5.8-9,11.4-9C1020.18,84.89,1025.38,90.09,1025.38,96.49 M1002.18,140.1c0-18.6-12.4-32-29.2-32
c-17,0-29.2,13.4-29.2,32c0,18.4,12.2,31.8,29.2,31.8C989.78,171.9,1002.18,158.5,1002.18,140.1"/>
</defs>
<use xlink:href="#SVGID_45_" style="overflow:visible;fill-rule:evenodd;clip-rule:evenodd;fill:#004680;"/>
<clipPath id="SVGID_46_">
<use xlink:href="#SVGID_45_" style="overflow:visible;"/>
</clipPath>
<rect x="909.85" y="74.17" class="st22" width="126.25" height="131.65"/>
</g>
<g>
<defs>
<path id="SVGID_47_" d="M1136.79,132.7v50.8c0,6.4-5.2,11.6-11.8,11.6c-6.4,0-11.6-5.2-11.6-11.6v-50.8
c0-11.8-6.6-24.6-21.4-24.6c-13.4,0-23.4,10.6-23.4,24.6v0.8v0.8v49.2c0,6.4-5.2,11.6-11.6,11.6c-6.4,0-11.6-5.2-11.6-11.6v-49.4
v-1.4V96.49c0-6.4,5.2-11.6,11.6-11.6c4.8,0,8.8,2.8,10.6,6.8c7-4.4,15.4-6.8,24.4-6.8
C1117.39,84.89,1136.79,105.49,1136.79,132.7"/>
</defs>
<use xlink:href="#SVGID_47_" style="overflow:visible;fill-rule:evenodd;clip-rule:evenodd;fill:#004680;"/>
<clipPath id="SVGID_48_">
<use xlink:href="#SVGID_47_" style="overflow:visible;"/>
</clipPath>
<rect x="1034.66" y="74.17" class="st23" width="112.85" height="131.65"/>
</g>
<g>
<defs>
<path id="SVGID_49_" d="M1207.2,196.1c-14.8,0-28.2-6.4-38.01-17.2c-9.4-10-14.4-23.81-14.4-38.4c0-31.61,22.2-55.21,51.4-55.21
c29.41,0,50.8,23.2,50.8,55.21c0,6.4-5.2,11.6-11.8,11.6h-65.41c4,12.2,14.4,20.8,27.4,20.8c7.83,0,14.48-1.65,19.23-6.21
c1.44-1.38,2.7-3.03,3.77-4.99c3.4-5.6,10.6-7.2,16-4c5.6,3.4,7.2,10.6,4,16C1241.2,189.9,1225.6,196.1,1207.2,196.1
M1179.59,128.7h52.61c-4-13.8-15-20.2-26-20.2C1195.4,108.49,1183.79,114.89,1179.59,128.7"/>
</defs>
<use xlink:href="#SVGID_49_" style="overflow:visible;fill-rule:evenodd;clip-rule:evenodd;fill:#004680;"/>
<clipPath id="SVGID_50_">
<use xlink:href="#SVGID_49_" style="overflow:visible;"/>
</clipPath>
<rect x="1144.07" y="74.57" class="st24" width="123.65" height="132.25"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 841 KiB

View File

@ -0,0 +1,26 @@
---
title: Configure
toc: true
weight: 302
indent: true
---
# Configure Your Cloud Provider Account
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]: ../cloud-providers/gcp/gcp-provider.md
[Microsoft Azure Service Principal]: ../cloud-providers/azure/azure-provider.md
[Amazon Web Services (AWS) IAM User]: ../cloud-providers/aws/aws-provider.md

View File

@ -0,0 +1,161 @@
---
title: Install
toc: true
weight: 301
indent: true
---
# Install Crossplane
Crossplane can be easily installed into any existing Kubernetes cluster using
the regularly published Helm chart. The Helm chart contains all the custom
resources and controllers needed to deploy and configure Crossplane.
## Pre-requisites
* [Kubernetes cluster], minimum version `v1.16.0+`
* [Helm], minimum version `v3.0.0+`.
## Installation
Helm charts for Crossplane are currently published to the `stable` and `master`
channels.
### Stable
The stable channel is the most recent release of Crossplane that is considered
ready for the community.
```console
kubectl create namespace crossplane-system
helm repo add crossplane-stable https://charts.crossplane.io/stable
helm repo update
helm install crossplane --namespace crossplane-system crossplane-stable/crossplane
```
### Master
The `master` channel contains the latest commits, with all automated tests
passing. `master` is subject to instability, incompatibility, and features may
be added or removed without much prior notice. It is recommended to use one of
the more stable channels, but if you want the absolute newest Crossplane
installed, then you can use the `master` channel.
To install the Helm chart from master, you will need to pass the specific
version returned by the `search` command:
```console
kubectl create namespace crossplane-system
helm repo add crossplane-master https://charts.crossplane.io/master/
helm repo update
helm search repo crossplane-master --devel
helm install crossplane --namespace crossplane-system crossplane-master/crossplane --devel --version <version>
```
## Uninstalling the Chart
To uninstall/delete the `crossplane` deployment:
```console
helm delete crossplane --namespace crossplane-system
```
That command removes all Kubernetes components associated with Crossplane,
including all the custom resources and controllers.
## Configuration
The following tables lists the configurable parameters of the Crossplane chart
and their default values.
| Parameter | Description | Default |
| --- | --- | --- |
| `affinity` | Enable affinity for Crossplane pod | `{}` |
| `image.repository` | Image | `crossplane/crossplane` |
| `image.tag` | Image tag | `master` |
| `image.pullPolicy` | Image pull policy used in all containers | `IfNotPresent` |
| `imagePullSecrets` | Names of image pull secrets to use | `dockerhub` |
| `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 | `{}` |
| `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` |
| `alpha.oam.enabled` | Deploy the `crossplane/oam-kubernetes-runtime` Helm chart | `false` |
| `metrics.enabled` | Expose Crossplane and RBAC Manager metrics endpoint | `false` |
| `extraEnvVarsCrossplane` | List of extra environment variables to set in the crossplane deployment | `{}` |
| `extraEnvVarsRBACManager` | List of extra environment variables to set in the crossplane rbac manager deployment | `{}` |
### Command Line
You can pass the settings with helm command line parameters. Specify each
parameter using the `--set key=value[,key=value]` argument to `helm install`.
For example, the following command will install Crossplane with an image pull
policy of `IfNotPresent`.
```console
helm install --namespace crossplane-system crossplane-stable/crossplane --set image.pullPolicy=IfNotPresent
```
### Settings File
Alternatively, a yaml file that specifies the values for the above parameters
(`values.yaml`) can be provided while installing the chart.
```console
helm install crossplane --namespace crossplane-system crossplane-stable/crossplane -f values.yaml
```
Here are the sample settings to get you started.
```yaml
replicas: 1
deploymentStrategy: RollingUpdate
image:
repository: crossplane/crossplane
tag: alpha
pullPolicy: Always
imagePullSecrets:
- dockerhub
```
<!-- Named Links -->
[Kubernetes cluster]: https://kubernetes.io/docs/setup/
[Minikube]: https://kubernetes.io/docs/tasks/tools/install-minikube/
[Helm]: https://docs.helm.sh/using_helm/

View File

@ -0,0 +1,38 @@
---
title: Learn More
toc: true
weight: 305
indent: true
---
# Learn More
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#community-meeting)
- 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

View File

@ -0,0 +1,28 @@
---
title: Reference
toc: true
weight: 300
---
# Overview
The reference documentation includes answers to frequently asked questions,
information about similar projects, and links to resources that can help you
learn more about Crossplane and Kubernetes. If you have additional information
that you think would be valuable for the community, please feel free to [open a
pull request] and add it.
1. [Install]
1. [Configure]
1. [Uninstall]
1. [Troubleshoot]
1. [Learn More]
<!-- Named Links -->
[open a pull request]: https://github.com/crossplane/crossplane/compare
[Install]: install.md
[Configure]: configure.md
[Uninstall]: uninstall.md
[Troubleshoot]: troubleshoot.md
[Learn More]: learn_more.md

View File

@ -0,0 +1,93 @@
---
title: Release Cycle
toc: true
weight: 306
indent: true
---
Starting with the v1.0.0 release, Crossplane is released on an eight week
cadence. A cycle is comprised of three general stages:
- Weeks 1-6: [Active Development]
- Week 7: [Feature Freeze]
- Week 8: [Code Freeze]
This results in six releases per year, with the most recent three releases being
maintained at any given time. When a new release is cut, the fourth most recent
release reaches end of life (EOL). Users can expect any given release to be
maintained for six months.
### Definition of Maintenance
The Crossplane community defines maintenance in that relevant bug fixes that are
merged to the main development branch will be eligible to be back-ported to the
release branch of any currently maintained version, and patch releases will be
cut appropriately. It is also possible that a fix may be merged directly to the
release branch if no longer applicable on the main development branch.
Maintenance does not indicate any SLA on response time for user support in the
form of Slack messages or issues, but problems will be addressed on a best
effort basis by maintainers and contributors for currently maintained releases.
### Patch Releases
_This policy is subject to change in the future._
Patch releases are cut for currently maintained minor versions on an as-needed
basis. Any critical back-ported fixes will be included in a patch release as
soon as possible after merge.
### Pre-Releases
_This policy is subject to change in the future._
Alpha, Beta, and RC releases are cut for an upcoming release on an as-needed
basis. As a policy, at least one pre-release will be cut prior to any minor
release. Pre-releases will not be made on release branches.
### Provider Releases
The Crossplane release cycle is not required to be adhered to by any other
Crossplane projects, but a similar cadence is encouraged. Maintainers listed in
each repository's `OWNERS.md` file are responsible for determining and
publishing the release cycle for their project.
## Release Stages
The following stages are the main milestones in a Crossplane release.
### Active Development
During active development, any code that meets the requisite criteria (i.e.
passing appropriate tests, approved by a maintainer, etc.) will be merged into
the main development branch. At present, there is no requirement to formally
submit an enhancement proposal prior to the start of the release cycle, but
contributors are encouraged to open an issue and gather feedback before starting
work on a major implementation (see [CONTRIBUTING.md] for more information).
### Feature Freeze
During feature freeze, no new functionality should be merged into the main
development branch. Bug fixes, documentation changes, and non-critical changes
may be made. In the case that a new feature is deemed absolutely necessary for a
release, the Crossplane maintainers will weigh the impact of the change and make
a decision on whether it should be included.
### Code Freeze
During code freeze, there should be no changes merged to the main development
branch with the following exceptions:
- Fixes to a failing test that is deemed to be incorrectly testing
functionality.
- Documentation only changes. It is possible that a documentation freeze will be
implemented in the future, but it is not currently enforced.
- Fixes to a critical bug that was not previously identified. Merging a bug fix
during code freeze requires application for and approval of an exception by
Crossplane maintainers. This process is currently informal, but may be
formalized in the future.
<!-- Named links -->
[Active Development]: #active-development
[Feature Freeze]: #feature-freeze
[Code Freeze]: #code-freeze
[CONTRIBUTING.md]: https://github.com/crossplane/crossplane/blob/master/CONTRIBUTING.md

View File

@ -0,0 +1,146 @@
---
title: Troubleshoot
toc: true
weight: 304
indent: true
---
# Troubleshooting
* [Requested Resource Not Found]
* [Resource Status and Conditions]
* [Resource Events]
* [Crossplane Logs]
* [Pausing Crossplane]
* [Deleting When a Resource Hangs]
## Requested Resource Not Found
If you use the kubectl Crossplane plugin to install a `Provider` or `Configuration`
(e.g. `kubectl crossplane install provider crossplane/provider-aws:master`) and
get `the server could not find the requested resource` error, more often than
not, that is an indicator that the kubectl Crossplane you're using is outdated.
In other words some Crossplane API has been graduated from alpha to beta or stable
and the old plugin is not aware of this change.
You can follow the [install Crossplane CLI] instructions to upgrade the plugin.
## Resource Status and Conditions
Most Crossplane resources have a `status` section that can represent the current
state of that particular resource. Running `kubectl describe` against a
Crossplane resource will frequently give insightful information about its
condition. For example, to determine the status of a GCP `CloudSQLInstance`
managed resource, run:
```shell
kubectl describe cloudsqlinstance my-db
```
This should produce output that includes:
```console
Status:
Conditions:
Last Transition Time: 2019-09-16T13:46:42Z
Reason: Creating
Status: False
Type: Ready
```
Most Crossplane resources set the `Ready` condition. `Ready` represents the
availability of the resource - whether it is creating, deleting, available,
unavailable, binding, etc.
## Resource Events
Most Crossplane resources emit _events_ when something interesting happens. You
can see the events associated with a resource by running `kubectl describe` -
e.g. `kubectl describe cloudsqlinstance my-db`. You can also see all events in a
particular namespace by running `kubectl get events`.
```console
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning CannotConnectToProvider 16s (x4 over 46s) managed/postgresqlserver.database.azure.crossplane.io cannot get referenced ProviderConfig: ProviderConfig.azure.crossplane.io "default" not found
```
> Note that events are namespaced, while many Crossplane resources (XRs, etc)
> are cluster scoped. Crossplane emits events for cluster scoped resources to
> the 'default' namespace.
## Crossplane Logs
The next place to look to get more information or investigate a failure would be
in the Crossplane pod logs, which should be running in the `crossplane-system`
namespace. To get the current Crossplane logs, run the following:
```shell
kubectl -n crossplane-system logs -lapp=crossplane
```
Remember that much of Crossplane's functionality is provided by providers. You
can use `kubectl logs` to view provider logs too.
> 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 (or your provider) with the `--debug` flag if you can't
> find what you're looking for.
## 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
```
Remember that much of Crossplane's functionality is provided by Providers. You
can use `kubectl scale` to pause Provider controller pods too.
## Deleting When a Resource Hangs
The resources that Crossplane manages will automatically be cleaned up so as not
to leave anything running behind. This is accomplished by using finalizers, but
in certain scenarios the finalizer can prevent the Kubernetes object from
getting deleted.
To deal with this, we essentially want to patch the object to remove its
finalizer, which will then allow it to be deleted completely. Note that this
won't necessarily delete the external resource that Crossplane was managing, so
you will want to go to your cloud provider's console and look there for any
lingering resources to clean up.
In general, a finalizer can be removed from an object with this command:
```console
kubectl patch <resource-type> <resource-name> -p '{"metadata":{"finalizers": []}}' --type=merge
```
For example, for a `CloudSQLInstance` managed resource (`database.gcp.crossplane.io`) named
`my-db`, you can remove its finalizer with:
```console
kubectl patch cloudsqlinstance my-db -p '{"metadata":{"finalizers": []}}' --type=merge
```
<!-- Named Links -->
[Requested Resource Not Found]: #requested-resource-not-found
[install Crossplane CLI]: ../getting-started/install-configure.md#install-crossplane-cli
[Resource Status and Conditions]: #resource-status-and-conditions
[Resource Events]: #resource-events
[Crossplane Logs]: #crossplane-logs
[Pausing Crossplane]: #pausing-crossplane
[Deleting When a Resource Hangs]: #deleting-when-a-resource-hangs

View File

@ -0,0 +1,92 @@
---
title: Uninstall
toc: true
weight: 303
indent: true
---
# Uninstalling
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 patch lock lock -p '{"metadata":{"finalizers": []}}' --type=merge
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]: troubleshoot.md

View File

@ -0,0 +1,13 @@
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

View File

@ -0,0 +1,13 @@
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

View File

@ -0,0 +1,13 @@
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

View File

@ -0,0 +1,34 @@
apiVersion: v1
kind: Pod
metadata:
name: see-db
namespace: default
spec:
containers:
- name: see-db
image: postgres:9.6
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

View File

@ -0,0 +1,12 @@
---
apiVersion: aws.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: aws-creds
key: creds

View File

@ -0,0 +1,53 @@
#!/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:
key: $AWS_CREDS_BASE64
kind: Secret
metadata:
name: aws-creds
namespace: crossplane-system
type: Opaque" | kubectl apply -f -

View File

@ -0,0 +1,12 @@
---
apiVersion: azure.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: azure-creds
key: creds

View File

@ -0,0 +1,84 @@
#!/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

View File

@ -0,0 +1,160 @@
---
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: CompositePostgreSQLInstance
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/v1alpha4
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: "9.6"
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

View File

@ -0,0 +1,15 @@
apiVersion: meta.pkg.crossplane.io/v1alpha1
kind: Configuration
metadata:
name: getting-started-with-aws-with-vpc
annotations:
guide: quickstart
provider: aws
vpc: new
spec:
crossplane:
version: ">=v1.0.0-0"
dependsOn:
# TODO(negz): Update Composition for compatibility with v0.17.0.
- provider: crossplane/provider-aws
version: "v0.16.0"

View File

@ -0,0 +1,38 @@
---
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: compositepostgresqlinstances.database.example.org
spec:
group: database.example.org
names:
kind: CompositePostgreSQLInstance
plural: compositepostgresqlinstances
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

View File

@ -0,0 +1,44 @@
---
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: compositepostgresqlinstances.aws.database.example.org
labels:
provider: aws
guide: quickstart
vpc: default
spec:
writeConnectionSecretsToNamespace: crossplane-system
compositeTypeRef:
apiVersion: database.example.org/v1alpha1
kind: CompositePostgreSQLInstance
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: "9.6"
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

View File

@ -0,0 +1,14 @@
apiVersion: meta.pkg.crossplane.io/v1alpha1
kind: Configuration
metadata:
name: getting-started-with-aws
annotations:
guide: quickstart
provider: aws
vpc: default
spec:
crossplane:
version: ">=v1.0.0-0"
dependsOn:
- provider: crossplane/provider-aws
version: ">=v0.14.0"

View File

@ -0,0 +1,38 @@
---
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: compositepostgresqlinstances.database.example.org
spec:
group: database.example.org
names:
kind: CompositePostgreSQLInstance
plural: compositepostgresqlinstances
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

View File

@ -0,0 +1,71 @@
---
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: compositepostgresqlinstances.azure.database.example.org
labels:
provider: azure
guide: quickstart
spec:
writeConnectionSecretsToNamespace: crossplane-system
compositeTypeRef:
apiVersion: database.example.org/v1alpha1
kind: CompositePostgreSQLInstance
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

View File

@ -0,0 +1,13 @@
apiVersion: meta.pkg.crossplane.io/v1alpha1
kind: Configuration
metadata:
name: getting-started-with-azure
annotations:
guide: quickstart
provider: azure
spec:
crossplane:
version: ">=v1.0.0-0"
dependsOn:
- provider: crossplane/provider-azure
version: ">=v0.13.0"

View File

@ -0,0 +1,38 @@
---
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: compositepostgresqlinstances.database.example.org
spec:
group: database.example.org
names:
kind: CompositePostgreSQLInstance
plural: compositepostgresqlinstances
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

View File

@ -0,0 +1,38 @@
---
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: compositepostgresqlinstances.database.example.org
spec:
group: database.example.org
names:
kind: CompositePostgreSQLInstance
plural: compositepostgresqlinstances
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

View File

@ -0,0 +1,47 @@
---
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: compositepostgresqlinstances.gcp.database.example.org
labels:
provider: gcp
guide: quickstart
spec:
writeConnectionSecretsToNamespace: crossplane-system
compositeTypeRef:
apiVersion: database.example.org/v1alpha1
kind: CompositePostgreSQLInstance
resources:
- name: cloudsqlinstance
base:
apiVersion: database.gcp.crossplane.io/v1beta1
kind: CloudSQLInstance
spec:
forProvider:
databaseVersion: POSTGRES_9_6
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"

View File

@ -0,0 +1,13 @@
apiVersion: meta.pkg.crossplane.io/v1alpha1
kind: Configuration
metadata:
name: getting-started-with-gcp
annotations:
guide: quickstart
provider: gcp
spec:
crossplane:
version: ">=v1.0.0-0"
dependsOn:
- provider: crossplane/provider-gcp
version: ">=v0.13.0"

View File

@ -0,0 +1,38 @@
---
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: compositepostgresqlinstances.database.example.org
spec:
group: database.example.org
names:
kind: CompositePostgreSQLInstance
plural: compositepostgresqlinstances
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

View File

@ -0,0 +1,16 @@
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: "9.6"
skipFinalSnapshotBeforeDeletion: true
writeConnectionSecretToRef:
namespace: crossplane-system
name: aws-rdspostgresql-conn

View File

@ -0,0 +1,28 @@
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

View File

@ -0,0 +1,15 @@
apiVersion: database.gcp.crossplane.io/v1beta1
kind: CloudSQLInstance
metadata:
name: cloudsqlpostgresql
spec:
forProvider:
databaseVersion: POSTGRES_9_6
region: us-central1
settings:
tier: db-custom-1-3840
dataDiskType: PD_SSD
dataDiskSizeGb: 10
writeConnectionSecretToRef:
namespace: crossplane-system
name: cloudsqlpostgresql-conn

View File

@ -0,0 +1,59 @@
---
apiVersion: core.oam.dev/v1alpha2
kind: ApplicationConfiguration
metadata:
name: service-tracker
spec:
components:
- componentName: data-api-database
parameterValues:
- name: database-secret
value: tracker-database-secret
- componentName: data-api
parameterValues:
- name: database-secret
value: tracker-database-secret
- componentName: flights-api
parameterValues:
- name: data-uri
value: "http://data-api.default.svc.cluster.local:3009/"
traits:
- trait:
apiVersion: core.oam.dev/v1alpha2
kind: ManualScalerTrait
metadata:
name: flights-api
spec:
replicaCount: 2
- componentName: quakes-api
parameterValues:
- name: data-uri
value: "http://data-api.default.svc.cluster.local:3009/"
traits:
- trait:
apiVersion: core.oam.dev/v1alpha2
kind: ManualScalerTrait
metadata:
name: quakes-api
spec:
replicaCount: 2
- componentName: weather-api
parameterValues:
- name: data-uri
value: "http://data-api.default.svc.cluster.local:3009/"
traits:
- trait:
apiVersion: core.oam.dev/v1alpha2
kind: ManualScalerTrait
metadata:
name: weather-api
spec:
replicaCount: 2
- componentName: service-tracker-ui
parameterValues:
- name: flights-uri
value: "http://flights-api.default.svc.cluster.local:3003/"
- name: weather-uri
value: "http://weather-api.default.svc.cluster.local:3015/"
- name: quakes-uri
value: "http://quakes-api.default.svc.cluster.local:3012/"

View File

@ -0,0 +1,197 @@
---
apiVersion: core.oam.dev/v1alpha2
kind: Component
metadata:
name: data-api-database
spec:
workload:
apiVersion: database.example.org/v1alpha1
kind: PostgreSQLInstance
metadata:
name: app-postgresql
spec:
parameters:
storageGB: 20
compositionSelector:
matchLabels:
guide: quickstart
parameters:
- name: database-secret
description: Secret to which to write PostgreSQL database connection details.
required: true
fieldPaths:
- spec.writeConnectionSecretToRef.name
- name: database-provider
description: |
Cloud provider that should be used to create a PostgreSQL database.
Either alibaba, aws, azure, or gcp.
fieldPaths:
- spec.compositionSelector.matchLabels.provider
---
apiVersion: core.oam.dev/v1alpha2
kind: Component
metadata:
name: data-api
spec:
workload:
apiVersion: core.oam.dev/v1alpha2
kind: ContainerizedWorkload
metadata:
name: data-api
spec:
containers:
- name: data-api
image: artursouza/rudr-data-api:0.50
env:
- name: DATABASE_USER
fromSecret:
key: username
- name: DATABASE_PASSWORD
fromSecret:
key: password
- name: DATABASE_HOSTNAME
fromSecret:
key: endpoint
- name: DATABASE_PORT
fromSecret:
key: port
- name: DATABASE_NAME
value: postgres
- name: DATABASE_DRIVER
value: postgresql
ports:
- name: http
containerPort: 3009
protocol: TCP
livenessProbe:
exec:
command: [wget, -q, http://127.0.0.1:3009/status, -O, /dev/null, -S]
parameters:
- name: database-secret
description: Secret from which to read PostgreSQL connection details.
required: true
fieldPaths:
- spec.containers[0].env[0].fromSecret.name
- spec.containers[0].env[1].fromSecret.name
- spec.containers[0].env[2].fromSecret.name
- spec.containers[0].env[3].fromSecret.name
---
apiVersion: core.oam.dev/v1alpha2
kind: Component
metadata:
name: flights-api
spec:
workload:
apiVersion: core.oam.dev/v1alpha2
kind: ContainerizedWorkload
metadata:
name: flights-api
spec:
containers:
- name: flights-api
image: sonofjorel/rudr-flights-api:0.49
env:
- name: DATA_SERVICE_URI
ports:
- name: http
containerPort: 3003
protocol: TCP
parameters:
- name: data-uri
description: URI at which the data service is serving
required: true
fieldPaths:
- spec.containers[0].env[0].value
---
apiVersion: core.oam.dev/v1alpha2
kind: Component
metadata:
name: quakes-api
spec:
workload:
apiVersion: core.oam.dev/v1alpha2
kind: ContainerizedWorkload
metadata:
name: quakes-api
spec:
containers:
- name: quakes-api
image: sonofjorel/rudr-quakes-api:0.49
env:
- name: DATA_SERVICE_URI
ports:
- name: http
containerPort: 3012
protocol: TCP
parameters:
- name: data-uri
description: URI at which the data service is serving
required: true
fieldPaths:
- spec.containers[0].env[0].value
---
apiVersion: core.oam.dev/v1alpha2
kind: Component
metadata:
name: service-tracker-ui
spec:
workload:
apiVersion: core.oam.dev/v1alpha2
kind: ContainerizedWorkload
metadata:
name: web-ui
spec:
containers:
- name: service-tracker-ui
image: sonofjorel/rudr-web-ui:0.49
env:
- name: FLIGHT_API_ROOT
- name: WEATHER_API_ROOT
- name: QUAKES_API_ROOT
ports:
- name: http
containerPort: 8080
protocol: TCP
parameters:
- name: flights-uri
description: URI at which the flights service is serving
required: true
fieldPaths:
- spec.containers[0].env[0].value
- name: weather-uri
description: URI at which the weather service is serving
required: true
fieldPaths:
- spec.containers[0].env[1].value
- name: quakes-uri
description: URI at which the quakes service is serving
required: true
fieldPaths:
- spec.containers[0].env[2].value
---
apiVersion: core.oam.dev/v1alpha2
kind: Component
metadata:
name: weather-api
spec:
workload:
apiVersion: core.oam.dev/v1alpha2
kind: ContainerizedWorkload
metadata:
name: weather-api
spec:
containers:
- name: weather-api
image: sonofjorel/rudr-weather-api:0.49
env:
- name: DATA_SERVICE_URI
ports:
- name: http
containerPort: 3015
protocol: TCP
parameters:
- name: data-uri
description: URI at which the data service is serving
required: true
fieldPaths:
- spec.containers[0].env[0].value

View File

@ -0,0 +1,22 @@
---
apiVersion: core.oam.dev/v1alpha2
kind: WorkloadDefinition
metadata:
name: postgresqlinstances.database.example.org
spec:
definitionRef:
name: postgresqlinstances.database.example.org
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
rbac.oam.dev/aggregate-to-controller: "true"
name: oam:claim:postgresqlinstancesdatabase.example.org:aggregate-to-controller
rules:
- apiGroups:
- database.example.org
resources:
- postgresqlinstances
verbs:
- '*'