Beyond Infrastructure-as-Code: A Java Developer’s Guide to Cloud Control with Crossplane

As Java developers, we've mastered application-level abstractions. We use Hibernate to abstract SQL, Spring Cloud to abstract service discovery, and Maven to abstract dependencies. But when it's time to provision the cloud infrastructure our apps run on, we often drop down to templating languages like Terraform's HCL or fragmented shell scripts. Crossplane introduces a powerful new abstraction: Cloud Infrastructure as Kubernetes-native APIs.

What is Crossplane? The Kubernetes-native Cloud Control Plane

In simple terms, Crossplane extends Kubernetes to manage anything—not just containers, but also cloud services like databases, message queues, and storage buckets. It allows you to define and provision cloud resources using familiar Kubernetes YAML/JSON, which are then managed using standard tools like kubectl.

Think of it as "Kubernetes Custom Resource Definitions (CRDs) for your entire cloud."

Why should a Java developer care? Because it allows your application teams to self-serve the cloud resources they need, using the same GitOps workflows they already use for application deployment, without needing deep expertise in specific cloud providers.

The Java Developer's Dilemma: The Infrastructure Divide

Imagine your team is building a new microservice that needs an Amazon SQS queue and a PostgreSQL database.

The Old Way (Divergent Workflows):

  1. You, the Java dev, write the app code and a Deployment.yaml.
  2. You file a ticket for the platform team.
  3. They write Terraform code in a separate repository to create an RDS instance and an SQS queue.
  4. After a lengthy process, the infrastructure is ready.
  5. You now have to manually copy the database connection string and queue URL into your Kubernetes ConfigMap or Secret.

This creates a bottleneck, context switching, and a fragile handover.

How Crossplane Works: Declarative Cloud APIs

Crossplane runs in your Kubernetes cluster and has two key concepts:

  1. Providers: These are packages that enable Crossplane to manage external resources. There are providers for AWS, Azure, GCP, and even other SaaS offerings. They act as the connector.
  2. Managed Resources (XRs): These are the Custom Resource Definitions (CRDs) that represent cloud services. For example, an RDSInstance or SQSQueue.

The magic happens with the Composition layer, which allows platform teams to create simplified, self-service abstractions for application developers.

A Practical Example: Self-Serving a Database for a Spring Boot App

Let's see how a Java team would use Crossplane to get a PostgreSQL database.

Step 1: Platform Team defines a "Composition" (The Abstract Template)

The platform team creates a high-level CompositeResourceDefinition (XRD). They might call it CompositePostgreSQLInstance. This defines the schema for a simple, company-approved database.

# x-postgresql-instance.yaml (Platform Team)
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: compositepostgresqlinstances.platform.example.com
spec:
group: platform.example.com
names:
kind: CompositePostgreSQLInstance
plural: compositepostgresqlinstances
claimNames:
kind: PostgreSQLInstance
plural: postgresqlinstances
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
parameters:
type: object
properties:
storageGB:
type: integer
default: 20
required: [parameters]

They then create a Composition that defines how to fulfill that abstract definition with real AWS resources.

# composition-postgres.yaml (Platform Team)
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: postgresqlinstances.aws.platform.example.com
spec:
compositeTypeRef:
apiVersion: platform.example.com/v1alpha1
kind: CompositePostgreSQLInstance
resources:
- name: rdsinstance
base:
apiVersion: database.aws.crossplane.io/v1beta1
kind: RDSInstance
spec:
forProvider:
region: us-west-2
dbInstanceClass: db.t3.small
engine: postgres
engineVersion: "13.7"
masterUsername: masteruser
skipFinalSnapshotBeforeDeletion: true
writeConnectionSecretToRef:
namespace: crossplane-system
patches:
- fromFieldPath: "spec.parameters.storageGB"
toFieldPath: "spec.forProvider.allocatedStorage"

Step 2: Java Developer requests a "Claim" (The Self-Service)

Now, as a Java developer, you don't need to understand the complexities of RDS. You just need a database. You create a simple, declarative "Claim":

# my-app-database-claim.yaml (Java Developer)
apiVersion: platform.example.com/v1alpha1
kind: PostgreSQLInstance
metadata:
name: my-springboot-app-db
namespace: default
spec:
parameters:
storageGB: 25

You apply it just like any other Kubernetes resource:

kubectl apply -f my-app-database-claim.yaml

Crossplane sees this claim, and based on the Composition, it provisions a real AWS RDS instance. Once it's ready, Crossplane creates a Kubernetes Secret with the connection details.

Step 3: Java App consumes the Secret

Your Spring Boot application can now consume the connection details directly from the secret, for example, using the Kubernetes Secrets volume mount or an external secrets manager. Your deployment doesn't care that the database was dynamically provisioned by Crossplane.

# deployment.yaml (Java Developer)
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-springboot-app
spec:
template:
spec:
containers:
- name: app
image: mycompany.io/my-springboot-app:latest
env:
- name: DB_URL
valueFrom:
secretKeyRef:
name: my-springboot-app-db-conn # Secret created by Crossplane
key: url
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: my-springboot-app-db-conn
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: my-springboot-app-db-conn
key: password

The Big Picture: A True Internal Developer Platform

Crossplane enables platform teams to build a Internal Developer Platform (IDP) using Kubernetes as the control plane. For Java developers, this means:

  • Self-Service: No more tickets for basic infrastructure. Need a cache? Deploy a RedisInstance claim.
  • GitOps for Everything: Manage both your app and its essential cloud dependencies in the same repository and deployment pipeline.
  • Standardization & Guardrails: The platform team ensures all provisioned resources are secure, compliant, and cost-optimized by default.
  • Cloud Agnosticism: The abstractions defined by the platform team can potentially target AWS, Azure, or GCP, making your application more portable.

Conclusion: Unifying Application and Infrastructure Logic

Crossplane represents the next level of cloud-native abstraction. It allows Java developers to interact with the cloud using the same declarative, Kubernetes-native patterns they already use for their applications. By treating infrastructure as just another API endpoint managed by the Kubernetes control plane, Crossplane reduces cognitive load, accelerates development, and finally bridges the gap between application code and the cloud platform it runs on.

For a Java team, it means you can focus on what you do best—writing business logic in Java—while having a powerful, automated platform to provision the exact cloud resources your code needs to thrive.


Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper