1 minute read

This is an example of how to create ECS infrastructure using Crossplane. It generates Cluster, Service, and TaskDefinition resources for simplicity. The objective is to demonstrate how to leverage Crossplane for provisioning infrastructure and deploying workloads using Helm charts atop Crossplane compositions.

Architecture

ECS Architecture

Crossplane

Crossplane is a tool designed for provisioning and managing infrastructure across various cloud providers. It utilizes Kubernetes Custom Resource Definitions (CRDs) to specify infrastructure resources and their configurations.

ECS Architecture

ECS Cluster

apiVersion: microservices.dmaganto.infra/v1alpha1
kind: ECSCluster
metadata:
  name: {{ .Values.tenant }}
spec:
  compositionSelector:
    matchLabels:
      dmaganto.infra/provider: upbound
      dmaganto.infra/cluster-type: tenant
  resourceConfig:
    providerConfigName: default
    tenant: {{ .Values.tenant }}
    name: {{ .Values.tenant }}
    deletionPolicy: Delete
    region: {{ .Values.region }}
  parameters:
    clusterName: {{ .Values.clusterName }}

ECS Service

apiVersion: microservices.dmaganto.infra/v1alpha1
kind: ECSService
metadata:
  name: {{ .Values.serviceName }}
spec:
  compositionSelector:
    matchLabels:
      dmaganto.infra/provider: upbound
      dmaganto.infra/service-type: tenant
  resourceConfig:
    providerConfigName: default
    tenant: {{ .Values.tenant }}
    name: {{ .Values.serviceName }}
    deletionPolicy: Delete
    region: {{ .Values.region }}
  parameters:
    clusterName: {{ .Values.clusterName }}
    family: {{ .Values.serviceName }}
    task_id: "{{ .Values.containerDefinitions | toString | sha256sum | trunc 10 }}"
    desiredCount: {{ .Values.replicas }}
    securityGroups: ["sg-xxxxxxxxxx"]
    subnets: ["subnet-xxxxxxxxxx","subnet-xxxxxxxxxx"]

ECS TaskDefinition

apiVersion: microservices.dmaganto.infra/v1alpha1
kind: ECSTaskdef
metadata:
  name: {{ .Values.serviceName }}-{{ .Values.containerDefinitions | toString | sha256sum | trunc 10 }}
spec:
  compositionSelector:
    matchLabels:
      dmaganto.infra/provider: upbound
      dmaganto.infra/taskdef-type: tenant
  resourceConfig:
    providerConfigName: default
    tenant: {{ .Values.tenant }}
    name: {{ .Values.serviceName }}
    deletionPolicy: Delete
    region: {{ .Values.region }}
  parameters:
    family: {{ .Values.serviceName }}
    task_id: "{{ .Values.containerDefinitions | toString | sha256sum | trunc 10 }}"
    containerDefinitions: |- 
      [  
{{ .Values.containerDefinitions | toPrettyJson | indent 8}}
      ]

As you can notice in the task definition object we need to do the trick using this expression:

{{.Values.containerDefinitions | toString | sha256sum | trunc 10 }}

This expression will generate a hash of the container definition object and use the first 10 characters of the hash to generate the task definition name.

Once you apply those object with ArgoCD (to follow the GitOps WoW) or using directly Helm will create the new TaskDefinition with the new hash and remove the old one, and the service using the same definition could obtain the id from task_idand deploy it.

You can find the full code in the repository