Skip to main content

Create cloud infrastructure with Terraform

6 min read
A Namespace, Terraform, and the S3 bucket that Terraform creates for it

Okteto runs your infrastructure as code in the deploy and destroy commands of the Okteto Manifest, so every environment gets its own cloud resources, such as an S3 bucket or a Lambda function: they're created when the environment is deployed and deleted when it's destroyed. This tutorial creates an Amazon S3 bucket for each environment with Terraform.

Prerequisites​

  • Access to an Okteto instance, with your Okteto context configured.
  • The Okteto CLI installed on your machine.
  • An AWS account where you can create IAM roles and S3 buckets.

Cloud Credentials​

Your Terraform commands need access to your AWS account. With Cloud Credentials, an Admin connects Okteto to your cloud account once, and Okteto injects temporary credentials into the deploy, destroy, and test commands of every environment. Nobody has to store static access keys in variables or on their machine.

Follow the AWS Cloud Credentials guide to register your cluster as an identity provider in AWS, create an IAM role with access to S3, and configure the role in the Admin Dashboard. Guides for Google Cloud and Microsoft Azure work the same way.

info

Cloud Credentials are available in the commands that Okteto runs in your cluster. They aren't available inside a Development Container started with okteto up, nor during image builds.

The Terraform Configuration​

Create a folder for the tutorial with a main.tf file:

main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.0"
}
}

# Store the Terraform state in a Secret of the environment's Namespace
backend "kubernetes" {
secret_suffix = "s3-bucket"
}
}

variable "bucket_name" {
type = string
}

variable "region" {
type = string
default = "us-east-1"
}

provider "aws" {
region = var.region
}

resource "aws_s3_bucket" "bucket" {
bucket = var.bucket_name
force_destroy = true
}

output "bucket_name" {
value = aws_s3_bucket.bucket.bucket
}

The kubernetes backend stores the Terraform state in a Secret of the Namespace where the environment runs, so every environment has its own state and nothing else to configure. force_destroy lets Terraform delete the bucket even if it isn't empty.

Deploying the Infrastructure​

Create an okteto.yaml file next to main.tf:

okteto.yaml
deploy:
image: hashicorp/terraform:1.17
commands:
- name: Create the S3 bucket
command: |
export KUBE_CONFIG_PATH="$KUBECONFIG" KUBE_NAMESPACE="$OKTETO_NAMESPACE"
terraform init -input=false
terraform apply -input=false -auto-approve -var "bucket_name=${OKTETO_NAMESPACE}-okteto-tutorial"
echo "S3_BUCKET_NAME=$(terraform output -raw bucket_name)" >> "$OKTETO_ENV"
  • image is the container image the commands run in. Okteto runs them in your cluster with Remote Execution, so you don't need Terraform on your machine.
  • KUBE_CONFIG_PATH and KUBE_NAMESPACE tell the kubernetes backend where to store the state.
  • The bucket name includes $OKTETO_NAMESPACE, so every environment gets its own bucket. S3 bucket names are global across all AWS accounts, so change the okteto-tutorial suffix if the name is already taken.
  • The last line writes the bucket name to $OKTETO_ENV. The following commands of the deploy section can read it as $S3_BUCKET_NAME, for example to pass it to your application's Helm chart.

Deploy the environment from the folder:

okteto deploy

Okteto runs terraform apply, and the bucket shows up in your AWS account.

Destroying the Infrastructure​

Add a destroy section to okteto.yaml, so Okteto deletes the bucket together with the environment:

okteto.yaml
destroy:
image: hashicorp/terraform:1.17
commands:
- name: Delete the S3 bucket
command: |
export KUBE_CONFIG_PATH="$KUBECONFIG" KUBE_NAMESPACE="$OKTETO_NAMESPACE"
terraform init -input=false
terraform destroy -input=false -auto-approve -var "bucket_name=${OKTETO_NAMESPACE}-okteto-tutorial"

Okteto runs these commands when you run okteto destroy, when the Namespace is deleted, and when the Garbage Collector deletes an inactive environment, so no bucket outlives its environment:

okteto destroy

Showing the Bucket in the Okteto UI​

This step is optional. An external resource shows the bucket next to the rest of the environment in the Okteto UI, with a link to it and your own notes. Add it to okteto.yaml:

okteto.yaml
external:
bucket:
icon: aws
notes: bucket.md
endpoints:
- name: console

Then add a second command to the deploy section that sets the URL of the console endpoint. It goes in its own command because $S3_BUCKET_NAME is only available in the commands that follow the one that writes it to $OKTETO_ENV:

okteto.yaml
deploy:
image: hashicorp/terraform:1.17
commands:
- name: Create the S3 bucket
command: |
export KUBE_CONFIG_PATH="$KUBECONFIG" KUBE_NAMESPACE="$OKTETO_NAMESPACE"
terraform init -input=false
terraform apply -input=false -auto-approve -var "bucket_name=${OKTETO_NAMESPACE}-okteto-tutorial"
echo "S3_BUCKET_NAME=$(terraform output -raw bucket_name)" >> "$OKTETO_ENV"
- name: Link the bucket in the Okteto UI
command: echo "OKTETO_EXTERNAL_BUCKET_ENDPOINTS_CONSOLE_URL=https://s3.console.aws.amazon.com/s3/buckets/${S3_BUCKET_NAME}" >> "$OKTETO_ENV"

Okteto reads variables named OKTETO_EXTERNAL_<RESOURCE>_ENDPOINTS_<ENDPOINT>_URL from $OKTETO_ENV to set endpoint URLs that are only known after the deployment. bucket.md is a Markdown file in the same folder, shown in the Okteto UI: use it to explain what the bucket is for.

Other Infrastructure Tools​

Terraform is only an example. The same pattern works with any tool that runs in a container: create the resources in deploy, delete them in destroy, and share the values the rest of the deployment needs through $OKTETO_ENV. For example:

  • OpenTofu, with the same configuration as Terraform.
  • Pulumi, with pulumi up and pulumi destroy.
  • AWS SAM, to create a Lambda function for each environment with sam deploy and delete it with sam delete. The okteto/aws-lambda sample deploys a function behind API Gateway and shows its URL in the Okteto UI with an external resource. Its IAM role needs access to CloudFormation, Lambda, API Gateway, IAM, and S3.
  • AWS CloudFormation or the AWS CDK, with the AWS CLI or the CDK CLI.
  • Crossplane, applying its resources with kubectl.
  • The command-line tools of your cloud provider, such as aws, gcloud, or az.

Use the tool's image in the deploy and destroy sections, or your own image with every tool your deployment needs.

Subscribe to our newsletter

What we learn running development environments and coding agents on Kubernetes, in your inbox.

About Okteto

Okteto gives every developer, coding agent and pull request an on-demand environment on your Kubernetes.