Install the Runtime Terraform Module
Overview
This page shows how to install the Upwind runtime components on an existing Amazon ECS cluster with the aws-ecs-runtime Terraform module. Pick the tab that matches your cluster. For what the module deploys and its prerequisites, see the overview.
- Get Upwind credentials.
- Add the module to your Terraform project and apply it.
- On Fargate, add the tracer to your workloads.
- Test connectivity.
Get Upwind credentials
The Upwind console's ECS connect flow does not offer this module yet, so use the examples on this page. You only need the console to create sensor credentials.
-
Log in to the Upwind Management Console .
-
Select the + (plus) symbol at the top of the screen and select Connect ECS cluster.
-
Under Sensor credentials, click Generate a new one to create a new client ID and client secret. Provide a name and click Generate. If you already have Sensor credentials, you can use them instead.
ImportantThe credentials can be viewed only once. If you use existing credentials, you must provide the client secret.
The module takes the client ID and client secret as input. In the examples below, they come from the variables upwind_client_id and upwind_client_secret.
Choose where the cluster manager runs
The cluster manager is an ECS service. You choose where it runs with cluster_manager.launch_type:
"EC2"(the default). The cluster manager runs on your EC2 container instances."FARGATE". The cluster manager runs on Fargate, and the module injects the tracer sidecar into its task.
This choice is independent of where your workloads run. The tabs below decide sensor.enabled and scanner.enabled from where your workloads run. Both are EC2 daemon services and both default to true. For launch type details, see cluster manager configuration.
Add the module
Create a main.tf in a new or existing Terraform project and add the module call for your cluster type. Replace the placeholder values with your own.
- EC2
- Fargate-only
- Mixed
On an EC2 cluster, the module runs the sensor and scanner as daemon services on every container instance. The cluster manager runs as an ECS service on EC2. Both daemons are enabled by default, so you do not set them.
variable "upwind_client_id" {
type = string
}
variable "upwind_client_secret" {
type = string
sensitive = true
}
module "upwind_ecs_runtime" {
source = "https://get.upwind.io/terraform/modules/aws-ecs-runtime/aws-ecs-runtime-1.5.1.tar.gz"
ecs_cluster_name = "my-ecs-cluster"
vpc_id = "vpc-0123456789abcdef0"
subnets = ["subnet-0123456789abcdef0", "subnet-0fedcba9876543210"]
credentials = {
client_id = var.upwind_client_id
client_secret = var.upwind_client_secret
}
}
Set subnets to private subnets with a route to a NAT gateway. The cluster manager does not get a public IP address.
A Fargate-only cluster has no EC2 instances, so the sensor and scanner daemon services cannot run. Both default to true, so you must turn both off. You must also set the cluster manager launch type to FARGATE, because the default is EC2.
variable "upwind_client_id" {
type = string
}
variable "upwind_client_secret" {
type = string
sensitive = true
}
module "upwind_ecs_runtime" {
source = "https://get.upwind.io/terraform/modules/aws-ecs-runtime/aws-ecs-runtime-1.5.1.tar.gz"
ecs_cluster_name = "my-ecs-cluster"
vpc_id = "vpc-0123456789abcdef0"
subnets = ["subnet-0123456789abcdef0", "subnet-0fedcba9876543210"]
credentials = {
client_id = var.upwind_client_id
client_secret = var.upwind_client_secret
}
# Both daemons default to true and both need EC2 instances.
sensor = { enabled = false }
scanner = { enabled = false }
# The default launch type is "EC2".
cluster_manager = { launch_type = "FARGATE" }
}
With the FARGATE launch type, the module adds the tracer sidecar to the cluster manager task. Set subnets to private subnets with a route to a NAT gateway.
A mixed cluster has both EC2 and Fargate capacity. The sensor and scanner daemons run on the EC2 instances, which is the default. The cluster manager runs on Fargate in this example, with the tracer sidecar. Fargate workloads use the tracer as described below.
variable "upwind_client_id" {
type = string
}
variable "upwind_client_secret" {
type = string
sensitive = true
}
module "upwind_ecs_runtime" {
source = "https://get.upwind.io/terraform/modules/aws-ecs-runtime/aws-ecs-runtime-1.5.1.tar.gz"
ecs_cluster_name = "my-ecs-cluster"
vpc_id = "vpc-0123456789abcdef0"
subnets = ["subnet-0123456789abcdef0", "subnet-0fedcba9876543210"]
credentials = {
client_id = var.upwind_client_id
client_secret = var.upwind_client_secret
}
# The sensor and scanner stay enabled and run on the EC2 instances.
cluster_manager = {
launch_type = "FARGATE"
resources = {
cpu = 512
memory = 1024
}
}
}
If you prefer to run the cluster manager on EC2, leave out the cluster_manager block.
Apply the configuration
-
Initialize Terraform in the project directory:
terraform init -
Apply the configuration:
terraform apply -
Review the planned changes and enter
yesto confirm.
Terraform deploys the Upwind components within a few minutes.
Add the tracer to your workloads
Fargate tasks cannot run the sensor daemon, so each Fargate workload runs the Upwind tracer as a sidecar container.
Choose how to add the tracer to your task definitions. Most setups use the public ECR tracer image, which is the default for both methods.
- Terraform
- upwindctl
The module returns the tracer settings as the tracer output. It has these attributes:
| Attribute | Description |
|---|---|
tracer.container | The sidecar container definition. Its name is upwind-tracer. |
tracer.entrypoint | The tracer binary path. Set it as the entrypoint of your app container. |
tracer.env | Environment variables for your app container, including UPWIND_TRACER_API_HOST, which points at the cluster manager. |
Add the sidecar to the task definition, then update your application container with the environment, volumesFrom, entrypoint, command, and linuxParameters settings:
resource "aws_ecs_task_definition" "example" {
family = "my-app"
requires_compatibilities = ["FARGATE"]
network_mode = "awsvpc"
cpu = 1024
memory = 2048
container_definitions = jsonencode([
# Your application container.
{
name = "my-app"
image = "my-app-image:latest"
essential = true
# Point the tracer at the Upwind cluster manager.
environment = [
for name, value in module.upwind_ecs_runtime.tracer.env : {
name = name
value = value
}
]
# Map the tracer's container image directory into your application image.
volumesFrom = [
{
sourceContainer = module.upwind_ecs_runtime.tracer.container.name
readOnly = true
}
]
# If you already use an entrypoint, move it to be the first argument
# of the command field.
entrypoint = [module.upwind_ecs_runtime.tracer.entrypoint]
# Set the command to the existing entrypoint or command for the task.
command = ["/path/to/command", "--arg1", "--arg2"]
# SYS_PTRACE lets the tracer monitor the processes and connections of
# the application, even if it runs under a non-root user.
linuxParameters = {
capabilities = {
add = ["SYS_PTRACE"]
}
}
},
# Upwind tracer sidecar container.
module.upwind_ecs_runtime.tracer.container
])
}
The tracer reaches the cluster manager at the address in UPWIND_TRACER_API_HOST. Workload tasks must be able to reach the cluster manager on port 8082.
If you pull images from a registry mirror, set tracer.image on the module. See tracer configuration.
Use upwindctl ecs patch to inject the tracer into an existing task definition without editing it by hand. Pass a task definition JSON file path, an ARN, or - to read from stdin. The command outputs a new task definition with the tracer injected.
The tracer must report to the cluster manager. The API host is the module's cluster_manager_discovery_endpoint output plus port 8082. The output does not include the port. To print it:
terraform output -raw cluster_manager_discovery_endpoint
This example patches a task definition by ARN and registers the new revision:
upwindctl ecs patch arn:aws:ecs:<region>:<account>:task-definition/<family>:<revision> \
--container <app-container> \
--api-host <cluster-manager-endpoint>:8082 \
--register
With --register, upwindctl registers the new revision and prints {"arn": "..."}. Use the new ARN in your service.
| Flag | Description |
|---|---|
--api-host | The cluster manager API host the tracer reports to. |
--container | The container to patch. Repeat the flag for more containers. If omitted, all containers are patched. |
--register | Register the new task definition revision. |
--output | The output format. The default is json. |
--tracer-image | The tracer image. The default is the public ECR tracer image. |
--api-security | Enable API security reporting. |
If you pull images from a registry mirror, pass --tracer-image with your mirror's tracer image.
To install upwindctl, see Install upwindctl. For prerequisites and the upwindctl ecs instrument command, see upwindctl ECS command. Patching by ARN and using --register need AWS credentials.
Test connectivity
To verify the cluster manager, run the following command:
aws ecs describe-services \
--cluster [your-cluster-name] \
--services upwind-cluster-manager \
--query "services[*].{ \
ServiceName:serviceName, \
ServiceStatus:status, \
DesiredCount:desiredCount, \
RunningCount:runningCount, \
DeploymentStatuses:deployments[*].status, \
DeploymentsCount:length(deployments) \
}" \
--output json
Expected output:
[
{
"ServiceName": "upwind-cluster-manager",
"ServiceStatus": "ACTIVE",
"DesiredCount": 1,
"RunningCount": 1,
"DeploymentStatuses": ["PRIMARY"],
"DeploymentsCount": 1
}
]
| Check | Description |
|---|---|
ServiceStatus | Ensure ServiceStatus is ACTIVE. |
DesiredCount and RunningCount for upwind-cluster-manager | Ensure both counts are equal, typically set to 1. |
DeploymentStatuses | Ensure all deployments have PRIMARY status, and the DeploymentsCount matches the expected number. |