Deploying Databases on DigitalOcean with Crossplane
Table of Contents
While Kubernetes has become the go-to platform for deploying business workloads, a major challenge still lies in managing the resources and services that your applications depend on, which often live outside the Kubernetes cluster.
Crossplane is a cool open-source project that extends the Kubernetes control plane to provision and manage cloud resources across multiple providers. Unlike Terraform, which relies on state files stored externally, Crossplane leverages Kubernetes primitives like custom resources and controllers to manage the desired state of your cloud resources. It continuously reconciles the actual state against the defined specifications, making changes as needed to match the desired state.
In this tutorial, we will go through how you can deploy a DigitalOcean database using Crossplane and Civo as a management cluster
Why Civo for Your Management Cluster?
Aside from simplicity, the biggest benefit of using Civo for your management cluster is cost. Civo's pricing plans are incredibly cost-effective, making it an attractive choice for hosting a management cluster that doesn't necessarily need to be on the same cloud provider as your workloads.
Additionally, hosting your management cluster on a different cloud provider adds redundancy and resilience to your setup. In the event of an outage or issue with your primary cloud provider, you can still access and manage your resources from the separate management cluster.
Encore is the Development Platform for building event-driven and distributed systems. Move faster with purpose-built local dev tools and DevOps automation for AWS/GCP. Get Started for FREE today.
What are the Benefits of Crossplane?
Now that we understand the benefits of separating your management cluster, let's turn our attention to using Crossplane. Here are some reasons to consider using Crossplane:
Unified Management
Crossplane enables you to manage resources from different cloud providers within your Kubernetes cluster, offering a centralized view of your infrastructure. without jumping between different management consoles or CLI tools!
Familiar Complexity
By leveraging familiar Kubernetes concepts like Custom Resource Definitions (CRDs) and controllers, Crossplane simplifies infrastructure management. If your team is already well-versed in Kubernetes, this can be a huge productivity boost, as you can apply the same mental models and workflows to manage cloud resources.
Continuous Reconciliation
Like Kubernetes itself, Crossplane continuously monitors the desired state of your resources and reconciles any deviations. This GitOps-like approach ensures that your infrastructure stays in sync with your defined configurations, reducing manual interventions and potential misconfigurations. In contrast, Terraform operates through a plan-and-apply cycle, where you define your desired state, review the planned changes, and then apply them. While this allows for a preview of changes before execution, it's a more manual and discrete process. Crossplane's continuous reconciliation model aims to provide a more automated and self-healing approach, automatically correcting drift from the desired state as it occurs, similar to how Kubernetes manages application deployments.
Prerequisites
This tutorial assumes some familiarity with Kubernetes. In addition, you will need the following to continue:
- Civo CLI (v1.0.75+)
- DigitalOcean Account
- Kubectl (v1.25.0+)
- Helm (v3.9.3+)
Creating a Management Cluster
We’ll begin by firing up our management cluster using the Civo CLI:
civo k3s create --create-firewall --nodes 1 -m --save --switch --wait do-crossplane
This will provision a one-node Kubernetes cluster, to verify your cluster was created successfully run, kubectl get nodes
Output is similar to:
NAME STATUS ROLES AGE VERSION
k3s-do-crossplane-c0cf-22cf12-node-pool-70a6-hywcj Ready <none> 3m24s v1.28.7+k3s1
Installing Crossplane
Much like Terraform, Crossplane has a concept of providers. Providers enable Crossplane to provision infrastructure on an external service.
Begin by installing Crossplane:
# create a namespace
kubectl create namespace crossplane-system
# add helm chart
helm repo add crossplane-stable https://charts.crossplane.io/stable
helm repo update
# install crds
helm install crossplane --namespace crossplane-system crossplane-stable/crossplane
You can verify the installation was a success by looking at the pods in the Crossplane Namsespace:
kubectl get pods -n crossplane-system
Output is similar to:
NAME READY STATUS RESTARTS AGE
crossplane-rbac-manager-747cbc499b-hjfvz 1/1 Running 0 4m52s
crossplane-d577689b8-ss92k 1/1 Running 0 4m52s
With Crossplane deployed, we can install the Digital Ocean provider. This will give us access to custom resources for deploying our database. Apply the following manifest to your cluster to install the Digital Ocean provider:
kubectl apply -f - <<EOF
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-digitalocean
spec:
package: xpkg.upbound.io/digitalocean/provider-digitalocean:v0.2.0
EOF
Finally, we will need to tell our cluster about the custom resources DigitalOcean provides, this isn’t bundled in with the provider install as such, we will need to source them from the Crossplane repo directly.
Verify the provider is installed correctly by running:
kubectl get provider
⚠️ Note: Providers are a Crossplane-specific concept and are installed as part of the custom resource definitions.
Output is similar to:
Clone the repo:
git clone git@github.com:crossplane-contrib/provider-digitalocean.git && cd provider-digitalocean
Apply the CRDs:
kubectl apply -f package/crds
Configuring the DigitalOcean Crossplane Provider
Before interacting with DigitalOcean resources, we need to provide credentials to the Crossplane provider. This involves creating a Kubernetes Secret to store your DigitalOcean API token securely.
⚠️ For this demonstration, we will be storing credentials using Kubernetes secrets. In a production environment, you would want to use a more fully fledged secret management solution such as Hashicorp Vault, or the external secrets operator and rotate these credentials regularly.
Encode Your API Token:
Before creating the Secret, encode your DigitalOcean API token using base64. You can achieve this in your terminal by running:
echo "<your do api token>" | base64
⚠️ Replace <your DO API token>
with your actual token.
Next, let’s create a provider config:
kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
namespace: crossplane-system
name: provider-do-secret
type: Opaque
data:
token: <your b64 encoded DO token>
---
apiVersion: do.crossplane.io/v1alpha1
kind: ProviderConfig
metadata:
name: civo-demo
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: provider-do-secret
key: token
EOF
In the code above, we create a ProviderConfig
resource named civo-demo
to reference the Secret containing the credentials. This ProviderConfig
essentially tells Crossplane how to connect to your DigitalOcean account.
Encore is the Development Platform for building event-driven and distributed systems. Move faster with purpose-built local dev tools and DevOps automation for AWS/GCP. Get Started for FREE today.
Provisioning the Database
With the Crossplane provider configured, we're ready to create and provision a PostgreSQL cluster.
1. Apply the DODatabaseCluster Manifest:
To initiate the database provisioning process, apply the following YAML manifest to your Kubernetes cluster using kubectl apply -f <filename>.yaml
.
kubectl apply -f - <<EOF
apiVersion: database.do.crossplane.io/v1alpha1
kind: DODatabaseCluster
metadata:
name: civo-cluster
spec:
forProvider:
engine: pg # Database engine (PostgreSQL)
version: "13" # Desired PostgreSQL version
numNodes: 1 # Number of database nodes in the cluster
size: db-s-2vcpu-4gb # Resource size for the database cluster
region: nyc3 # Region where the cluster will be provisioned
tags: # Optional tags for the cluster
- "from-crossplane"
- "civo-demo"
providerConfigRef:
name: civo-demo # Reference to the Crossplane provider config
EOF
This manifest defines a DODatabaseCluster
resource named civo-cluster
. The forProvider
section specifies the desired configuration for your database cluster, including:
engine
: Database engine (set to pg for PostgreSQL)version
: PostgreSQL versionnumNodes
: Number of database nodessize
: Resource allocation for the clusterregion
: Region where the cluster will be deployedtags
: Optional tags for identification
The providerConfigRef
references the civo-demo
Crossplane provider config you created earlier, which establishes the connection to your DigitalOcean account.
2. Monitor the Provisioning Process:
Once you apply the manifest, you can track the provisioning status of your database cluster using the kubectl get
command:
kubectl get dodatabaseclusters.database.do.crossplane.io
This command will display information about your civo-cluster resource, including its current status. Initially, you'll likely see a status of Creating or Pending. As Crossplane interacts with the DigitalOcean API, the status will eventually transition to Ready once the database cluster is successfully provisioned.
You can also verify that the cluster was created by heading to the databases tab in your Digital Ocean Dashboard.
Taking a closer look, you can see some of the tags we included in the manifest also show up on the dashboard.
Clean up
Once you're finished experimenting with your database cluster, it's good practice to clean up the resources to avoid unnecessary costs and clutter in your environment. Here's how to remove the database cluster we provisioned:
1. Delete the DODatabaseCluster Manifest:
Use kubectl delete
to remove the DODatabaseCluster
manifest that created the cluster. This will initiate the deletion process within Crossplane, which will then signal DigitalOcean to delete the actual database cluster.
kubectl delete dodatabaseclusters.database.do.crossplane.io civo-cluster
2. (Optional) Delete the Crossplane Provider Config (civo-demo):
If you don't plan on using Crossplane with DigitalOcean anymore in this cluster, you can also delete the ProviderConfig
resource named civo-demo
. This will remove the configuration that Crossplane used to connect to your DigitalOcean account.
kubectl delete providerconfigs civo-demo
Remember, deleting the DODatabaseCluster
manifest is sufficient to clean up the database cluster on DigitalOcean. The second step is optional and only needed if you want to completely remove Crossplane's connection to your DigitalOcean account within this cluster.
3. Tearing Down the Civo Kubernetes Cluster (Optional)
While we focused on managing DigitalOcean resources through Crossplane within the Kubernetes cluster, you might also want to remove the Civo Kubernetes cluster itself. To do this, you can use the Civo CLI:
civo k3s delete do-crossplane
Once you're done with the tutorial, it's essential to clean up the resources you created. This section will guide readers on how to remove the database and any associated resources provisioned by Crossplane.
Encore is the Development Platform for building event-driven and distributed systems. Move faster with purpose-built local dev tools and DevOps automation for AWS/GCP. Get Started for FREE today.
Summary
In this tutorial, we explored how to leverage Crossplane within a Kubernetes cluster to simplify the deployment and management of database resources on DigitalOcean.
Remember, avoiding manually deleting resources provisioned with Crossplane is generally recommended. Crossplane is designed to continuously reconcile the desired state defined in your manifests with the actual state of your infrastructure. Manually deleting resources on the cloud provider side can disrupt this process and lead to inconsistencies.
The Practical DevOps Newsletter
Your weekly source of expert tips, real-world scenarios, and streamlined workflows!