Crossplane(IaC), New Kid On The Block

In the past, managing IT infrastructure was a hard job. System administrators had to manually manage and configure all of the hardware and software that was needed for the applications to run.

However, in recent years, things have changed dramatically. Advancements in Cloud, Agile, and DevOps practices have revolutionised designing, developing, and maintaining the IT infrastructure. Infrastructure as Code(IaC) is one of the critical components of these practices. IaC manages your IT infrastructure using configuration files and provides benefits such as enhanced speed, efficiency, and consistency. IaC facilitates faster infrastructure deployments as the teams don’t have to maintain the settings of individual deployment environments.

There are several IaC solutions available in the market. Terraform, current industry leader in IaC, is a fantastic tool; however, you must be fluent in Terraform Domain-Specific Language like HashiCorp Configuration Language (HCL). Pulumi is another open source IaC tool that is more targeted towards developers as is it supports languages such as Python, JavaScript, Java,TypeScript, Go, and .NET. You can develop reusable functions, packages, classes, and Pulumi components with these languages. But there’s a new player in IaC market, crossplane(https://crossplane.io/), that follows GitOps approach to IaC and we would be covering about this new player in this blog.

You might be wondering with Terraform, Pulumi, and even Ansible in the mix, why should I consider Crossplane?

Well, there are a few things that really intrigued me about Crossplane:

  • Adhering to the principles of Infrastructure as Data. It’s Kubernetes-native, so you use Kubernetes Custom Resources (YAML — i.e. text) to declaratively provision Cloud infrastructure.
  • No state file. Unlike Terraform and Pulumi, Crossplane doesn’t use a state file. As a Kubernetes Operator, it has a controller to reconcile desired state against current state, making use of etcd to do so.
  • Source of Truth. unlike Terraform and Pulumi, if someone tries to do something sneaky like update a Cloud resource using the CLI or an admin console, Crossplane won’t let you get away with it.

What is CrossPlane?

Crossplane is an open source Kubernetes add-on that transforms your cluster into a universal control plane. Crossplane enables platform teams to assemble infrastructure from multiple vendors, and expose higher level self-service APIs for application teams to consume, without having to write any code.

Crossplane extends your Kubernetes cluster to support orchestrating any infrastructure or managed service.

Crossplane is a Cloud Native Compute Foundation project.

Concepts

Crossplane introduces multiple building blocks that enable you to provision, compose, and consume infrastructure using the Kubernetes API. These individual concepts work together to allow for powerful separation of concern between different personas in an organization, meaning that each member of a team interacts with Crossplane at an appropriate level of abstraction.

Packages

Packages allow Crossplane to be extended to include new functionality. This typically looks like bundling a set of Kubernetes CRDs and controllers that represent and manage external infrastructure (i.e. a provider), then installing them into a cluster where Crossplane is running. Crossplane handles making sure any new CRDs do not conflict with existing ones, as well as manages the RBAC and security of new packages. Packages are not strictly required to be providers, but it is the most common use-case for packages at this time.

Providers

Providers are packages that enable Crossplane to provision infrastructure on an external service. They bring CRDs (i.e. managed resources) that map one-to-one to external infrastructure resources, as well as controllers to manage the life-cycle of those resources. You can read more about providers, including how to install and configure them, in the providers documentation.

Managed Resources

Managed resources are Kubernetes custom resources that represent infrastructure primitives. Managed resources with an API version of v1beta1 or higher support every field that the cloud provider does for the given resource. You can find the Managed Resources and their API specifications for each provider on the Upbound Marketplace and learn more in the managed resources documentation.

Composite Resources

A composite resource (XR) is a special kind of custom resource that is defined by a CompositeResourceDefinition. It composes one or more managed resources into a higher level infrastructure unit. Composite resources are infrastructure operator facing, but may optionally offer an application developer facing composite resource claim that acts as a proxy for a composite resource. You can learn more about all of these concepts in the composition documentation.

Getting Started

Choosing Your Crossplane Distribution

Users looking to use Crossplane for the first time have two options available to them today. The first way is to use the version of Crossplane which is maintained and released by the community and found on the Crossplane GitHub.

The second option is to use a vendor supported Crossplane distribution. These distributions are certified by the CNCF to be conformant with Crossplane, but may include additional features or tooling around it that makes it easier to use in production environments.

Start with Upstream Crossplane

Installing Crossplane into an existing Kubernetes cluster will require a bit more setup, but can provide more flexibility for users who need it.

Get a Kubernetes Cluster

  1. macOS via HomeBrew
brew upgrade
brew install kind
brew install kubectl
brew install helm
kind create cluster --image kindest/node:v1.23.0 --wait 5m

2. For macOS / Linux use the following:

Install Crossplane

Helm 3 Stable

Use Helm 3 to install the latest official stable release of Crossplane, suitable for community use and testing:

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

Check Crossplane Status

helm list -n crossplane-system

kubectl get all -n crossplane-system

Install Crossplane CLI

curl -sL https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh | sh

Select a Getting Started Configuration

Crossplane goes beyond simply modelling infrastructure primitives as custom resources — it enables you to define new custom resources with schemas of your choosing. We call these “composite resources” (XRs). Composite resources compose managed resources — Kubernetes custom resources that offer a high fidelity representation of an infrastructure primitive, like an SQL instance or a firewall rule.

We use two special Crossplane resources to define and configure these new custom resources:

  • A CompositeResourceDefinition (XRD) defines a new kind of composite resource, including its schema. An XRD may optionally offer a claim (XRC).
  • A Composition specifies which resources a composite resource will be composed of, and how they should be configured. You can create multiple Composition options for each composite resource.

XRDs and Compositions may be packaged and installed as a configuration. A configuration is a [package] of composition configuration that can easily be installed to Crossplane by creating a declarative Configuration resource, or by using kubectl crossplane install configuration.

In the examples below we will install a configuration that defines a new XPostgreSQLInstance XR and PostgreSQLInstance XRC that takes a single storageGB parameter, and creates a connection Secret with keys for username, password, and endpoint. A Configuration exists for each provider that can satisfy a PostgreSQLInstance. Let’s get started!

Install Configuration Package

GCP

kubectl crossplane install configuration registry.upbound.io/xp/getting-started-with-gcp:v1.10.1

Wait until all packages become healthy:

watch kubectl get pkg

Get GCP Account Keyfile

# 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

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:

# 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 -

Provision Infrastructure

GCP

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
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-1.10/docs/snippets/compose/claim-gcp.yaml

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:

kubectl get postgresqlinstance my-db
  • kubectl get claim: get all resources of all claim kinds, like PostgreSQLInstance.
  • kubectl get composite: get all resources that are of composite kind, like XPostgreSQLInstance.
  • kubectl get managed: get all resources that represent a unit of external infrastructure.
  • kubectl get <name-of-provider>: get all resources related to <provider>.
  • kubectl get crossplane: get all resources related to Crossplane.

Try the following command to watch your provisioned resources become ready:

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:

$ 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.

apiVersion: v1
kind: Pod
metadata:
name: see-db
namespace: default
spec:
containers:
- name: see-db
image: postgres:12
command: ['psql']
args: ['-c', 'SELECT current_database();']
env:
- name: PGDATABASE
value: postgres
- name: PGHOST
valueFrom:
secretKeyRef:
name: db-conn
key: endpoint
- name: PGUSER
valueFrom:
secretKeyRef:
name: db-conn
key: username
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: db-conn
key: password
- name: PGPORT
valueFrom:
secretKeyRef:
name: db-conn
key: port
kubectl apply -f https://raw.githubusercontent.com/crossplane/crossplane/release-1.10/docs/snippets/compose/pod.yaml

This Pod simply connects to a PostgreSQL database and prints its name, so you should see the following output (or similar) after creating it if you run kubectl logs see-db:

current_database
------------------
postgres
(1 row)

Clean Up

To clean up the Pod, run:

kubectl delete pod see-db

To clean up the infrastructure that was provisioned, you can delete the PostgreSQLInstance XRC:

kubectl delete postgresqlinstance my-db

Conclusion

Crossplane unlike Terraform and Pulumi, which keep state files, and let you alter Cloud infrastructure outside the tool (with possibly devastating consequences), Crossplane doesn’t let you get away with that.

Like Ansible, it adheres to the principles of Infrastructure as Data, using YAML to declaratively provision Cloud resources. This definitely puts it in my good books.

Crossplane hasn’t been around for very long, and it shows. While there’s a lot of support for AWS resources, support for Google Cloud is rather lacking in comparison. That said, I’m sure that as it picks up steam in coming future.

Contributors
Version history
Last update:
‎12-01-2022 07:28 AM
Updated by: