Skip to content

Commit c3a6952

Browse files
authored
feat: Add support for OpenTelemetry and Datadog sidecars in ECS module (#44)
- Introduced new example for X-Ray tracing with OpenTelemetry. - Added provider configuration for AWS in the new example. - Created variables for OpenTelemetry and Datadog configurations. - Updated main module to include sidecar configurations for Datadog and OpenTelemetry. - Refactored container definitions to support sidecar dependencies. - Removed legacy container definitions and replaced with modular definitions for server, drain, scheduler, and VCS gateway. - Enhanced secrets management to include Datadog API key and OpenTelemetry configuration content. - Updated IAM and secrets management to accommodate new sidecar configurations. - Improved documentation and variable descriptions for clarity.
1 parent 7e99aed commit c3a6952

30 files changed

+1354
-291
lines changed

.spacelift/config.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
version: 2
2-
module_version: "1.6.0"
2+
module_version: "2.0.0"
33

44
tests:
55
- name: Basic example
@@ -22,5 +22,4 @@ tests:
2222
TF_VAR_ecr_backend_repository_url: "666640173260.dkr.ecr.eu-central-1.amazonaws.com/spacelift-backend-e89fd"
2323
TF_VAR_ecr_launcher_repository_url: "666640173260.dkr.ecr.eu-central-1.amazonaws.com/spacelift-launcher-e89fd"
2424
TF_VAR_spacelift_version: "v0.0.1-moduletests"
25-
TF_VAR_license_token_wo: "<YOUR_LICENSE_TOKEN_HERE>"
26-
TF_VAR_license_token_wo_version: 1
25+
TF_VAR_license_token: "<YOUR_LICENSE_TOKEN_HERE>"

README.md

Lines changed: 75 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,73 @@ This module creates an ECS cluster with all the necessary resources to run Space
44

55
This module is closely tied to the [terraform-aws-spacelift-selfhosted](https://github.com/spacelift-io/terraform-aws-spacelift-selfhosted) module, which contains the necessary surrounding infrastructure.
66

7+
> [!IMPORTANT]
8+
> ## 🔄 Upgrading to v2.0.0 - New features and breaking changes
9+
>
10+
> Click below to see the full upgrade guide with breaking changes and new features.
11+
12+
<details>
13+
<summary><h3>📋 Full v2.0.0 Upgrade Guide</h3></summary>
14+
15+
<br>
16+
17+
Version 2.0.0 adds observability features and simplifies secret management. A few variables have been removed - see below for details.
18+
19+
### ✨ New Features
20+
21+
**Improved Secret Handling**
22+
- License token is now protected from state file exposure using write-only attributes
23+
- Secrets are automatically versioned when changed - no manual tracking needed (`license_token_wo_version` removed)
24+
25+
**Observability & Tracing Support**
26+
27+
This module now supports **Datadog** and **OpenTelemetry (OTEL)** sidecar containers for comprehensive application tracing and metrics:
28+
- **Datadog**: Full APM support with the Datadog agent sidecar
29+
- **OpenTelemetry**: Flexible OTEL collector sidecar that can be fully customized or configured for AWS X-Ray compatibility
30+
31+
**Important**: AWS X-Ray SDK/Daemon enters maintenance mode on **February 25th, 2026**, with AWS limiting releases to security fixes only. AWS is transitioning to OpenTelemetry as the primary instrumentation standard for application tracing. We recommend using the OpenTelemetry sidecar option for X-Ray integration rather than the legacy X-Ray daemon.
32+
33+
See [examples/with-datadog-tracing](./examples/with-datadog-tracing), [examples/with-xray-tracing](./examples/with-xray-tracing), and [examples/with-otel-tracing](./examples/with-otel-tracing) for complete configuration examples.
34+
35+
### ⚠️ Breaking Changes
36+
37+
**Removed Variables**
38+
- `database_url` and `database_read_only_url` (already discouraged in v1.x) - use `sensitive_env_vars` instead
39+
- `license_token_wo` and `license_token_wo_version` - consolidated into single `license_token` variable
40+
41+
**Migration:**
42+
43+
**Database URLs** (if you were still using these variables):
44+
```hcl
45+
# Before (v1.x)
46+
database_url = "<connection-string>"
47+
database_read_only_url = "<read-only-connection-string>"
48+
49+
# After (v2.0.0)
50+
sensitive_env_vars = [
51+
{
52+
name = "DATABASE_URL"
53+
valueFrom = "${module.spacelift_infra.database_secret_arn}:DATABASE_URL::"
54+
},
55+
{
56+
name = "DATABASE_READ_ONLY_URL"
57+
valueFrom = "${module.spacelift_infra.database_secret_arn}:DATABASE_READ_ONLY_URL::"
58+
}
59+
]
60+
```
61+
62+
**License Token**:
63+
```hcl
64+
# Before (v1.x)
65+
license_token_wo = "<your-license-token>"
66+
license_token_wo_version = 1 # Had to manually increment on rotation
67+
68+
# After (v2.0.0)
69+
license_token = "<your-license-token>" # Automatically versioned
70+
```
71+
72+
</details>
73+
774
## Module registries
875

976
The module is also available [on the OpenTofu registry](https://search.opentofu.org/module/spacelift-io/ecs-spacelift-selfhosted/aws/latest) where you can browse the input and output variables.
@@ -12,7 +79,8 @@ The module is also available [on the OpenTofu registry](https://search.opentofu.
1279

1380
Check out the [Terraform](https://developer.hashicorp.com/terraform/language/backend) or the [OpenTofu](https://opentofu.org/docs/language/settings/backends/configuration/) backend documentation for more information on how to configure the state storage.
1481

15-
> ⚠️ Do **not** import the state into Spacelift after the installation: that would cause circular dependencies, and in case you accidentally break the Spacelift installation, you wouldn't be able to fix it.
82+
> [!WARNING]
83+
> Do **not** import the state into Spacelift after the installation: that would cause circular dependencies, and in case you accidentally break the Spacelift installation, you wouldn't be able to fix it.
1684
1785
## ✨ Usage
1886

@@ -34,18 +102,17 @@ module "spacelift_infra" {
34102
}
35103
36104
module "spacelift_services" {
37-
source = "github.com/spacelift-io/terraform-aws-ecs-spacelift-selfhosted?ref=v1.6.0"
105+
source = "github.com/spacelift-io/terraform-aws-ecs-spacelift-selfhosted"
38106
39107
region = local.region
40108
unique_suffix = module.spacelift_infra.unique_suffix
41109
kms_key_arn = module.spacelift_infra.kms_key_arn
42110
server_domain = local.website_domain
43111
mqtt_broker_endpoint = local.mqtt_endpoint
44112
45-
license_token_wo = "<your-license-token-issued-by-Spacelift>" # 'wo' stands for 'write-only', it means that the token will not be stored in the state file
46-
license_token_wo_version = "1" # Bump this when rotating the token
113+
license_token = "<your-license-token-issued-by-Spacelift>"
47114
48-
encryption_type = "kms"
115+
encryption_type = "kms"
49116
kms_encryption_key_arn = module.spacelift_infra.kms_encryption_key_arn
50117
kms_signing_key_arn = module.spacelift_infra.kms_signing_key_arn
51118
@@ -115,7 +182,7 @@ You can pass in a log configuration for each service. See [the official document
115182

116183
```hcl
117184
module "spacelift_services" {
118-
source = "github.com/spacelift-io/terraform-aws-ecs-spacelift-selfhosted?ref=v1.6.0"
185+
source = "github.com/spacelift-io/terraform-aws-ecs-spacelift-selfhosted"
119186
120187
server_log_configuration = {
121188
logDriver : "awslogs",
@@ -161,7 +228,7 @@ module "spacelift_services" {
161228

162229
```hcl
163230
module "spacelift_services" {
164-
source = "github.com/spacelift-io/terraform-aws-ecs-spacelift-selfhosted?ref=v1.6.0"
231+
source = "github.com/spacelift-io/terraform-aws-ecs-spacelift-selfhosted"
165232
166233
execution_role_arn = aws_iam_role.execution_role.arn
167234
server_role_arn = aws_iam_role.spacelift_server_role.arn
@@ -200,7 +267,7 @@ You will need to create a DNS record for it, then pass the following configurati
200267

201268
```hcl
202269
module "spacelift_services" {
203-
source = "github.com/spacelift-io/terraform-aws-ecs-spacelift-selfhosted?ref=v1.6.0"
270+
source = "github.com/spacelift-io/terraform-aws-ecs-spacelift-selfhosted"
204271
205272
vcs_gateway_domain = "vcs-gateway.mycorp.io" # The DNS record for the VCS Gateway service, without protocol.
206273
vcs_gateway_security_group_id = module.spacelift_infra.vcs_gateway_security_group_id

examples/basic-example/providers.tf

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,3 @@
1-
terraform {
2-
required_providers {
3-
aws = {
4-
source = "hashicorp/aws"
5-
version = "< 6.0"
6-
}
7-
}
8-
}
9-
101
provider "aws" {
112
region = var.region
123

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Datadog Agent Sidecar Configuration
2+
3+
This module supports injecting a Datadog agent sidecar container into all ECS services (server, drain, scheduler, and vcs-gateway).
4+
5+
## Usage
6+
7+
### Basic Example
8+
9+
```hcl
10+
module "spacelift" {
11+
source = "github.com/spacelift-io/terraform-aws-ecs-spacelift-selfhosted"
12+
13+
# ... other required variables ...
14+
15+
# Enable Datadog sidecar
16+
enable_datadog_agent_sidecar = true
17+
datadog_api_key = var.datadog_api_key # Your Datadog API key, stored in SecretsManager (versions automatically managed)
18+
datadog_agent_config = {
19+
image = "public.ecr.aws/datadog/agent:7"
20+
site = "datadoghq.com" # or "datadoghq.eu" for EU
21+
tags = [
22+
"env:production",
23+
"service:spacelift",
24+
"team:platform"
25+
]
26+
log_configuration = {
27+
logDriver = "awslogs"
28+
options = {
29+
"awslogs-group" = "/aws/ecs/datadog-agent"
30+
"awslogs-region" = var.region
31+
"awslogs-create-group" = "true"
32+
"awslogs-stream-prefix" = "datadog"
33+
}
34+
}
35+
}
36+
}
37+
```
38+
39+
> [!IMPORTANT]
40+
> **Rotating Datadog API Key**
41+
>
42+
> The Datadog API key is stored in AWS Secrets Manager. To rotate it, simply update the value and apply:
43+
>
44+
> ```hcl
45+
> datadog_api_key = var.new_datadog_api_key
46+
> ```
47+
48+
> [!TIP]
49+
> **Start with Logs Enabled**
50+
>
51+
> It's always recommended to start with CloudWatch logging enabled for the Datadog agent sidecar when first setting up tracing. This allows you to verify the agent is working correctly and troubleshoot any issues. Once you've confirmed everything is working as expected, you can remove the `log_configuration` to save on CloudWatch Logs costs.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
2+
module "spacelift" {
3+
source = "github.com/spacelift-io/terraform-aws-ecs-spacelift-selfhosted"
4+
5+
# ... other required variables ...
6+
7+
# Observability configuration
8+
enable_datadog_agent_sidecar = true
9+
datadog_api_key = var.datadog_api_key
10+
datadog_agent_config = {
11+
image = "public.ecr.aws/datadog/agent:7"
12+
site = var.datadog_site
13+
tags = ["env:selfhosted", "service:spacelift"]
14+
log_configuration = {
15+
logDriver = "awslogs"
16+
options = {
17+
"awslogs-group" = "/aws/ecs/datadog-agent"
18+
"awslogs-region" = var.region
19+
"awslogs-create-group" = "true"
20+
"awslogs-stream-prefix" = "datadog"
21+
}
22+
}
23+
}
24+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
provider "aws" {
2+
region = var.region
3+
4+
default_tags {
5+
tags = {
6+
TfModule = "terraform-aws-ecs-spacelift-selfhosted"
7+
Repository = "https://github.com/spacelift-io/terraform-aws-ecs-spacelift-selfhosted"
8+
TestCase = "WithDatadogTracing"
9+
}
10+
}
11+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
variable "region" {
2+
type = string
3+
}
4+
5+
variable "unique_suffix" {
6+
type = string
7+
}
8+
9+
variable "spacelift_version" {
10+
type = string
11+
}
12+
13+
variable "vpc_id" {
14+
type = string
15+
}
16+
17+
variable "public_subnet_ids" {
18+
type = list(string)
19+
}
20+
21+
variable "private_subnet_ids" {
22+
type = list(string)
23+
}
24+
25+
variable "server_security_group_id" {
26+
type = string
27+
}
28+
29+
variable "drain_security_group_id" {
30+
type = string
31+
}
32+
33+
variable "scheduler_security_group_id" {
34+
type = string
35+
}
36+
37+
variable "kms_key_arn" {
38+
type = string
39+
}
40+
41+
variable "kms_encryption_key_arn" {
42+
type = string
43+
}
44+
45+
variable "kms_signing_key_arn" {
46+
type = string
47+
}
48+
49+
variable "server_lb_name" {
50+
type = string
51+
description = "The name of the server load balancer."
52+
default = null
53+
}
54+
55+
variable "lb_certificate_arn" {
56+
type = string
57+
}
58+
59+
variable "website_domain" {
60+
type = string
61+
}
62+
63+
variable "mqtt_broker_endpoint" {
64+
type = string
65+
}
66+
67+
variable "ecr_backend_repository_url" {
68+
type = string
69+
}
70+
71+
variable "ecr_launcher_repository_url" {
72+
type = string
73+
}
74+
75+
variable "load_balancer_security_group_id" {
76+
type = string
77+
default = null
78+
description = "The security group ID to use for the main load balancer. If not provided, a new security group will be created."
79+
}
80+
81+
variable "datadog_api_key" {
82+
type = string
83+
description = "The Datadog API key."
84+
sensitive = true
85+
}
86+
87+
variable "datadog_site" {
88+
type = string
89+
description = "The Datadog site to send metrics and traces to."
90+
default = "datadoghq.com"
91+
}

0 commit comments

Comments
 (0)