Skip to content

Instantly share code, notes, and snippets.

Intro

Crossplane v2 is here!

We got some very cool features that I want to go through.

We'll see the changes to Crossplane Composition schemas, a shift to Namespace-scoped resources, direct composition of any resources without the need to rely only on Crossplane Managed resources, new API versions, removal of deprecated features, and more.

I'm sure that, by the end of this walkthrough you'll see that two most requested features are here and that autoring Compositions is now easier.

Intro

Crossplane v2 is here!

We got some very cool features that I want to go through.

We'll see the changes to Crossplane Composition schemas, a shift to Namespace-scoped resources, direct composition of any resources without the need to rely only on Crossplane Managed resources, new API versions, removal of deprecated features, and more.

I'm sure that, by the end of this walkthrough you'll see that two most requested features are here and that autoring Compositions is now easier.

Intro

TODO: Volume is now lower

TODO: Show images conversation-* (6 of them) by adding them one on top or beside each other starting from when I say "like those" (it's like that one in the text) and keep them until the end of the paragraph. Show them starting from conversation-06 moving in descending order towards conversation-01 since that is the most important one.

During recent months I saw a lot of conversation and questions sparked by the release of kro, like the one in the picture. Many of them are related to comparison with Helm. Some people think that kro is, more or less, doing the same work as Helm. Others think that it is a different syntax that accomplishes the same result as Helm. Some are asking whether kro is a replacement for Helm.

Intro

TODO: Volume is now lower

"Crossplane is too complicated!" "Crossplane is only for infrastructure! I need something else for applications."

I hear those and other similar statement very often so I decided to clarify a few things and, hopefully, eliminate some missconceptions.

To be more precise, today I want to debunk one missconception about Crossplane and, at the same time, show how Crossplane addressed one semi-legitimate complaint in the recent v2 release.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
dev.okteto.com/generate-host: "true"
ingress.kubernetes.io/ssl-redirect: "false"
kubectl.kubernetes.io/last-applied-configuration: '{"apiVersion":"networking.k8s.io/v1","kind":"Ingress","metadata":{"annotations":{"dev.okteto.com/generate-host":"true","ingress.kubernetes.io/ssl-redirect":"false"},"labels":{"app.kubernetes.io/name":"silly-demo"},"name":"silly-demo","namespace":"staging"},"spec":{"ingressClassName":"contour","rules":[{"host":"staging.silly-demo.34.74.187.90.nip.io","http":{"paths":[{"backend":{"service":{"name":"silly-demo","port":{"number":8080}}},"path":"/","pathType":"ImplementationSpecific"}]}}]}}'
creationTimestamp: "2025-03-06T15:33:29Z"
generation: 1
labels:
apiVersion: v1
kind: Service
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: '{"apiVersion":"v1","kind":"Service","metadata":{"labels":{"app.kubernetes.io/name":"silly-demo"},"name":"silly-demo","namespace":"staging"},"spec":{"ports":[{"name":"http","port":8080,"protocol":"TCP","targetPort":8080}],"selector":{"app.kubernetes.io/name":"silly-demo"},"type":"ClusterIP"}}'
creationTimestamp: "2025-03-06T15:33:29Z"
labels:
app.kubernetes.io/name: silly-demo
name: silly-demo
namespace: staging
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
kubectl.kubernetes.io/last-applied-configuration: '{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"labels":{"app.kubernetes.io/name":"silly-demo"},"name":"silly-demo","namespace":"staging"},"spec":{"selector":{"matchLabels":{"app.kubernetes.io/name":"silly-demo"}},"template":{"metadata":{"labels":{"app.kubernetes.io/name":"silly-demo"}},"spec":{"containers":[{"env":[{"name":"DB_ENDPOINT","valueFrom":{"secretKeyRef":{"key":"endpoint","name":"silly-demo-db"}}},{"name":"DB_PASSWORD","valueFrom":{"secretKeyRef":{"key":"password","name":"silly-demo-db"}}},{"name":"DB_PORT","valueFrom":{"secretKeyRef":{"key":"port","name":"silly-demo-db","optional":true}}},{"name":"DB_USERNAME","valueFrom":{"secretKeyRef":{"key":"username","name":"silly-demo-db"}}},{"name":"DB_NAME","value":"main"}],"image":"ghcr.io/vfarcic/idp-full-demo:0.0.7","livenessProbe":{"httpGet":{"path":"/","port":8080}},"name":"silly-demo"

Intro

FIXME: The goals: FIXME: Do whatever needs to do done to develop something and test it under similar conditions as if it's running in production. FIXME: Everything (or almost everything) is in the repo.

FIXME: Example: Backend up that depends on a front-end and a database

FIXME: Welcome to DevOps Toolkit, the channel where we...

Intro

FIXME: Welcome to DevOps Toolkit, the channel where composing resources is the path to Internal Developer Platforms.

TODO: Title roll

Whomever is building developer platforms is bound to come to the conclusion that there is a need to compose resources and expose those compositions through APIs. If a developer needs a database, they should be able to specify what that database should be without having to deal with subnets, VPCs, internet gateways, and other lower-level components that are required, yet are not important for the vast majority of people who just want a database. We are likely to come to a similar conclusion if, for example, a developer wants to run an application. That developer might want to specify a container image, a port, and a host without having to worry about Kubernetes Deployments, Services, Ingresses, Scalers, VirtualServices, and other lower-level Kubernetes types of objects.

So, we need a way to create new API endpoints that will represent the right level of abstraction