diff --git a/examples/castai-anywhere-terraform/README.md b/examples/castai-anywhere-terraform/README.md new file mode 100644 index 000000000..d997c9abe --- /dev/null +++ b/examples/castai-anywhere-terraform/README.md @@ -0,0 +1,137 @@ +# CAST AI Anywhere Terraform Deployment + +This repository contains Terraform code to deploy CAST AI components on an "anywhere" (on-prem/Minikube) Kubernetes cluster. The configuration deploys two components: + +- **CAST AI Agent** +- **CAST AI Cluster Controller** +- **CAST AI Evictor +- **CAST AI Pod Mutator +- **CAST AI Workload Autoscaler + +## Prerequisites + +Before deploying, ensure you have the following installed and configured: + +- **Terraform** (v1.x recommended) + [Download Terraform](https://www.terraform.io/downloads) +- **Minikube** + [Start Minikube](https://minikube.sigs.k8s.io/docs/start/) +- **Docker Desktop** (make sure Docker is running) + [Download Docker Desktop](https://www.docker.com/products/docker-desktop) +- **kubectl** + [Install kubectl](https://kubernetes.io/docs/tasks/tools/) +- **Helm** + [Install Helm](https://helm.sh/docs/intro/install/) + +You will also need: +- A valid **CAST AI API Key** (https://docs.cast.ai/docs/authentication) +- A unique cluster identifier (for example, `minikube-anywhere-cluster`) + +## Repository Structure + +- **main.tf** + Contains the Terraform configuration to: + - Start Minikube and wait until it is ready. + - Configure the Kubernetes and Helm providers (using the `minikube` context). + - Create the required namespace. + - Deploy the CAST AI Components. +- **variables.tf** + Defines variables for CAST AI API key, cluster identifier, and configurations. +- **outputs.tf** + Displays outputs such as the status of the deployed components. + +## Setup and Deployment + +### 1. Clone the Repository + +Clone the repository to your local machine: + +```sh +git clone https://github.com/juliette-cast/castai-anywhere-terraform.git +cd castai-anywhere-terraform +``` + +### 2. Initialize Terraform + +Run the following command to initialize Terraform and download the required providers: + +```sh +terraform init +``` + +### 3. Validate the Terraform Configuration + +Ensure the configuration is correct: + +```sh +terraform validate +``` + +### 4. Plan the Deployment + +Preview what Terraform will create: + +```sh +terraform plan +``` + +### 5. 1st Apply the Configuration + +This will create the cluster and Deploy the CAST AI Agentand connect to the UI, then you will use the clustr ID from the console to add to your vaoraibles to deploy the other components + +```sh +terraform apply +``` + +### 6. 2nd Apply to deploy the other components + +```sh +terraform apply +``` + +### 7. Verify Deployment + +Check the status of deployed components: + +```sh +kubectl get pods -n castai-agent +``` + +Expected output: +```sh +NAME READY STATUS RESTARTS AGE +castai-agent-79bf777cc8-8w88l 2/2 Running 0 22m +castai-agent-79bf777cc8-kvf2q 2/2 Running 0 22m +castai-agent-cpvpa-964fc94b6-pqfzc 1/1 Running 0 23m +castai-cluster-controller-77dffcd8f5-7jflv 2/2 Running 0 19m +castai-cluster-controller-77dffcd8f5-cpnp6 2/2 Running 0 19m +castai-evictor-64bdd9fb6c-tmxjv 1/1 Running 0 37s +castai-evictor-cpvpa-6c6bdf8f74-r2m4b 1/1 Running 0 37s +castai-pod-mutator-7556c5db85-pqrwx 1/1 Running 0 16m +castai-pod-mutator-7556c5db85-tqzsh 1/1 Running 1 16m +castai-workload-autoscaler-64655596c4-b72l7 1/1 Running 0 15m +castai-workload-autoscaler-64655596c4-x7bj8 1/1 Running 1 (15m ago) 15m +``` + +### 7. Check CAST AI Console + +1. **Log in to [CAST AI Console](https://app.cast.ai)** +2. **Navigate to `Clusters`** +3. **Confirm that the Minikube cluster is "Connected"** + +### 8. Optional: Destroy the Deployment + +If you need to remove the deployment, run: + +```sh +terraform destroy +``` +or delete the castai-agent namespace +```sh +kubectl delete ns castai-agent +``` +If you need to delete the minikube cluster, run the below command then check on Docker if it's deleted: + +```sh +minikube delete +``` \ No newline at end of file diff --git a/examples/castai-anywhere-terraform/main.tf b/examples/castai-anywhere-terraform/main.tf new file mode 100644 index 000000000..ad37f7200 --- /dev/null +++ b/examples/castai-anywhere-terraform/main.tf @@ -0,0 +1,167 @@ +# Start Minikube using the Docker driver +resource "null_resource" "start_minikube" { + provisioner "local-exec" { + command = "minikube start --driver=docker" + } +} + +# Wait for Minikube to be ready +data "external" "wait_for_minikube" { + program = ["bash", "-c", "while ! kubectl get nodes >/dev/null 2>&1; do sleep 5; done; echo '{}'"] + depends_on = [null_resource.start_minikube] +} + +# Configure the Kubernetes provider +provider "kubernetes" { + config_path = "~/.kube/config" + config_context = "minikube" +} + +# Configure the Helm provider +provider "helm" { + kubernetes { + config_path = "~/.kube/config" + config_context = "minikube" + } +} + +# Create the namespace "castai-agent" +resource "kubernetes_namespace" "castai" { + depends_on = [data.external.wait_for_minikube] + metadata { + name = "castai-agent" + labels = { + "app.kubernetes.io/managed-by" = "Helm" + } + annotations = { + "meta.helm.sh/release-name" = "castai-agent" + "meta.helm.sh/release-namespace" = "castai-agent" + } + } +} + +# Install CAST AI Agent +resource "helm_release" "castai_agent" { + depends_on = [kubernetes_namespace.castai] + name = "castai-agent" + repository = "https://castai.github.io/helm-charts" + chart = "castai-agent" + namespace = "castai-agent" + create_namespace = false + timeout = 600 + + set { + name = "apiKey" + value = var.cast_ai_api_key + } + set { + name = "clusterName" + value = var.cluster_name + } + set { + name = "provider" + value = "anywhere" + } +} + +# Install CAST AI Cluster Controller +resource "helm_release" "castai_cluster_controller" { + depends_on = [helm_release.castai_agent] + name = "castai-cluster-controller" + repository = "https://castai.github.io/helm-charts" + chart = "castai-cluster-controller" + namespace = "castai-agent" + create_namespace = false + timeout = 600 + + set { + name = "castai.apiKey" + value = var.cast_ai_api_key + } + set { + name = "castai.clusterID" + value = var.cluster_id + } + set { + name = "enableTopologySpreadConstraints" + value = "true" + } + set { + name = "autoscaling.enabled" + value = "false" + } +} + +# Install CAST AI Evictor +resource "helm_release" "castai_evictor" { + depends_on = [helm_release.castai_cluster_controller] + name = "castai-evictor" + repository = "https://castai.github.io/helm-charts" + chart = "castai-evictor" + namespace = "castai-agent" + create_namespace = false + timeout = 600 + + set { + name = "managedByCASTAI" + value = var.managed_by_castai + } + set { + name = "replicaCount" + value = "1" + } + set { + name = "aggressive_mode" + value = "false" # change to true if needed but use with caution + } +} + +# Install CAST AI Pod Mutator +resource "helm_release" "castai_pod_mutator" { + depends_on = [helm_release.castai_cluster_controller] + name = "castai-pod-mutator" + repository = "https://castai.github.io/helm-charts" + chart = "castai-pod-mutator" + namespace = "castai-agent" + create_namespace = false + timeout = 600 + + set { + name = "castai.apiKey" + value = var.cast_ai_api_key + } + set { + name = "castai.clusterID" + value = var.cluster_id + } + set { + name = "enableTopologySpreadConstraints" + value = "true" + } + + set { + name = "castai.organizationID" + value = var.organization_id + } +} + + +# Install CAST AI Workload Autoscaler +resource "helm_release" "castai_workload_autoscaler" { + depends_on = [helm_release.castai_pod_mutator] + name = "castai-workload-autoscaler" + repository = "https://castai.github.io/helm-charts" + chart = "castai-workload-autoscaler" + namespace = "castai-agent" + create_namespace = false + timeout = 600 + + set { + name = "castai.apiKey" + value = var.cast_ai_api_key + } + set { + name = "castai.clusterID" + value = var.cluster_id + } +} diff --git a/examples/castai-anywhere-terraform/outputs.tf b/examples/castai-anywhere-terraform/outputs.tf new file mode 100644 index 000000000..09390b5a4 --- /dev/null +++ b/examples/castai-anywhere-terraform/outputs.tf @@ -0,0 +1,19 @@ +output "castai_agent_status" { + value = helm_release.castai_agent.status +} + +output "castai_cluster_controller_status" { + value = helm_release.castai_cluster_controller.status +} + +output "castai_evictor_status" { + value = helm_release.castai_evictor.status +} + +output "castai_pod_mutator_status" { + value = helm_release.castai_pod_mutator.status +} + +output "castai_workload_autoscaler_status" { + value = helm_release.castai_workload_autoscaler.status +} diff --git a/examples/castai-anywhere-terraform/variables.tf b/examples/castai-anywhere-terraform/variables.tf new file mode 100644 index 000000000..35daab783 --- /dev/null +++ b/examples/castai-anywhere-terraform/variables.tf @@ -0,0 +1,31 @@ +variable "cast_ai_api_key" { + description = "Your CAST AI API key" + type = string + sensitive = true + default = "" # add your api key +} + + + +variable "cluster_name" { + description = "Name of your cluster" + type = string + default = "" # give a name for your cluster +} + +variable "cluster_id" { + description = "Identifier for your CAST AI cluster" + type = string + default = "" # add the cluster ID you copied from the UI from the 1st apply +} + +variable "organization_id" { + description = "Your CAST AI Organization ID" + type = string +} + +variable "managed_by_castai" { + description = "Flag to indicate if the components are managed by CAST AI" + type = bool + default = false # if its true, CAST overrides every changes made +}