Sidecar
The sidecar resource creates a supplementary container that runs alongside a target container. Sidecars are commonly used for logging, monitoring, proxying, or other supporting services that complement the main application container.
Use Cases
Section titled “Use Cases”As a lab author, you can use sidecars to enhance your lab environment without modifying main application containers:
- Add Observability: Attach log collectors (e.g. Fluent Bit), metrics exporters (e.g. Prometheus node-exporter), or APM agents to demonstrate monitoring without changing your app
- Simulate Production Patterns: Include service mesh proxies (e.g. Envoy), load balancers, or security scanners to show real-world architectures
- Provide Development Tools: Add debugging containers, code hot-reload watchers, or development proxies to create better learning experiences
Sidecars let you create rich, multi-container lab environments that mirror production complexity while keeping your main application containers simple and focused.
HCL Syntax
Section titled “HCL Syntax”Basic Syntax
Section titled “Basic Syntax”resource "sidecar" "proxy" { target = resource.container.app
image { name = "envoyproxy/envoy:v1.28.0" }}Full Syntax
Section titled “Full Syntax”resource "sidecar" "monitoring" { target = resource.container.app
image { name = "prometheus/node-exporter:latest" username = "registry_user" password = "registry_pass" }
# Container configuration entrypoint = ["/bin/node_exporter"] command = ["--path.rootfs=/host"] privileged = false max_restart_count = 3
# Environment variables environment = { NODE_ID = "worker-1" METRICS_PORT = "9100" }
# Labels labels = { service = "monitoring" component = "exporter" }
# Volume mounts volume { source = "/proc" destination = "/host/proc" type = "bind" read_only = true }
volume { source = "/sys" destination = "/host/sys" type = "bind" read_only = true }
# Resource constraints resources { cpu = 100 # 0.1 CPU memory = 128 # 128MB
gpu { driver = "nvidia" device_ids = ["0"] } }
# Health check health_check { timeout = "30s"
http { address = "http://localhost:9100/metrics" success_codes = [200] }
tcp { address = "localhost:9100" }
exec { script = <<-EOF #!/bin/bash curl -f http://localhost:9100/metrics || exit 1 EOF } }}Fields
| Field | Type | Required | Description |
|---|---|---|---|
target | referencecontainer | ✓ | Reference to the container to attach the sidecar to |
image | block | ✓ | Container image for the sidecar |
entrypoint | list(string) | — | Entrypoint to use when starting the container |
command | list(string) | — | Command to use when starting the container |
environment | map(string) | — | Environment variables to set |
labels | map(string) | — | Labels to set on the container |
volume | block | — | Attach persistent storage or share data between containers using volumesrepeatable |
privileged | bool | — | Run the container in privileged mode |
resources | block | — | Resource constraints for the sidecar |
health_ | block | — | Health check configuration |
max_ | number | — | Maximum number of restarts |
Image
Container image for the sidecar
| Field | Type | Required | Description |
|---|---|---|---|
name | string | ✓ | Full Docker image reference, including the registry and an optional tag. Include a specific tag to ensure consistent lab environments. ConstraintsMust be a valid Docker image reference (e.g. ubuntu:24.04, docker.io/hashicorp/vault:1.14) |
username | string | — | Only required for private Docker registries. Leave empty for public images. |
password | string | — | Only required for private Docker registries. Leave empty for public images. |
Volume
Volumes to attach to the sidecar
| Field | Type | Required | Description |
|---|---|---|---|
source | string | ✓ | The source volume to mount in the container, can be specified as a relative `./` or absolute path `/usr/local/bin`. Relative paths are relative to the file declaring the container. ConstraintsSource path must not be empty |
destination | string | ✓ | The destination in the container to mount the volume to, must be an absolute path ConstraintsDestination path must not be empty |
type | string | — | The type of the mount, can be one of the following values:
- bind: bind the source path to the destination path in the container
- volume: source is a Docker volume
- tmpfs: create a temporary filesystem Allowed bind volume tmpfsDefault bind |
read_ | bool | — | Whether or not the volume is read only |
bind_ | string | — | Configures bind propagation for Docker volume mounts, only applies to bind mounts, can be one of the following values:
- shared
- slave
- private
- rslave
- rprivate
For more information please see the Docker documentation Allowed shared private slave rslave rprivateDefault shared |
bind_ | bool | — | Configures recursiveness of the bind mount. By default Docker mounts with the equivalent of `mount --rbind` meaning that mounts below the the source directory are visible in the container. For instance running `docker run --rm --mount type=bind,src=/,target=/host,readonly` busybox will make `/run` of the host available as `/host/run` in the container. To make matters even worse it will be writable (since only the toplevel bind is set readonly, not the children). If `bind_propagation_non_recursive` is set to true then the container will only see an empty `/host/run`, meaning the `tmpfs` which is typically mounted to `/run` on the host is not propagated into the container. |
selinux_ | string | — | Configures Selinux relabeling for the container (usually specified as :z or :Z) and can be one of the following values:
- shared (Equivalent to :z)
- private (Equivalent to :Z) Allowed shared private |
Resources
Resource constraints for the sidecar
| Field | Type | Required | Description |
|---|---|---|---|
cpu | number | — | Limit how much CPU power your container can use to optimize performance and cost ConstraintsMinimum 100; Maximum 8000 |
cpu_ | list(number) | — | Pin your container to specific CPU cores for more predictable performance or isolation ConstraintsAt least 1 item(s); At most 32 item(s) |
memory | number | — | Specify how much memory the container can use to prevent crashes or resource contention ConstraintsMinimum 128; Maximum 32768 |
Health Check
Health check configuration
| Field | Type | Required | Description |
|---|---|---|---|
timeout | string | ✓ | Timeout for health checks (e.g., '30s') ConstraintsMust be a valid duration (e.g. 30s, 5m) |
http | block | — | HTTP health checksrepeatable |
tcp | block | — | TCP health checksrepeatable |
exec | block | — | Exec health checksrepeatable |
HTTP
HTTP health checks
| Field | Type | Required | Description |
|---|---|---|---|
address | string | — | The URL to check. Leave empty to check this resource on the given port; set it to check a specific endpoint, such as another resource by its sandbox.internal name. The check passes when the endpoint returns one of the success codes. |
scheme | string | — | http or https; used when address is empty Allowed http httpsDefault http |
port | number | — | The port the app listens on inside this resource ConstraintsMinimum 1; Maximum 65535 |
path | string | — | The HTTP path to request when checking this resource via port Default / |
method | string | — | HTTP method to use when executing the check |
body | string | — | HTTP body to send with the request |
headers | map(list(string)) | — | HTTP headers to send with the check |
success_ | list(number) | — | HTTP status codes returned from the endpoint when called. If the returned status code matches any in the array then the health check will pass. |
TCP
TCP health checks
| Field | Type | Required | Description |
|---|---|---|---|
address | string | — | Host and port to connect to, e.g. db.sandbox.internal:5432. Leave empty to check this resource on the given port. The check passes as soon as the connection is accepted. |
port | number | — | The port the app listens on inside this resource ConstraintsMinimum 1; Maximum 65535 |
Exec
Exec health checks
| Field | Type | Required | Description |
|---|---|---|---|
command | list(string) | — | The command to run, given as the executable followed by its arguments. Use either a command or a script, not both. |
script | string | — | An inline shell script to run instead of a single command. Must start with a shebang, e.g. #!/bin/bash. |
exit_ | number | — | The exit code that counts as healthy. Defaults to 0. |
Computed Attributes
These attributes are set by the system and are read-only.
| Attribute | Type | Description |
|---|---|---|
image.id | string | Unique identifier for the image, this is independent of tag and changes each time the image is built. An image that has been tagged multiple times also shares the same ID. |
container_name | string | Fully qualified docker address for the sidecar container |
Examples
Section titled “Examples”Logging Sidecar Example
Section titled “Logging Sidecar Example”resource "container" "app" { image { name = "myapp:latest" }}
resource "sidecar" "logs" { target = resource.container.app
image { name = "fluent/fluent-bit:latest" }
volume { source = "./fluent-bit.conf" destination = "/fluent-bit/etc/fluent-bit.conf" type = "bind" read_only = true }}Proxy Sidecar Example
Section titled “Proxy Sidecar Example”resource "container" "backend" { image { name = "backend-service:latest" }}
resource "sidecar" "proxy" { target = resource.container.backend
image { name = "envoyproxy/envoy:v1.28.0" }
command = [ "envoy", "-c", "/etc/envoy/envoy.yaml", "--service-cluster", "backend", "--service-node", "backend-proxy" ]
volume { source = "./envoy.yaml" destination = "/etc/envoy/envoy.yaml" type = "bind" read_only = true }
health_check { timeout = "10s"
http { address = "http://localhost:9901/ready" success_codes = [200] } }}Monitoring Sidecar with Resource Constraints
Section titled “Monitoring Sidecar with Resource Constraints”resource "container" "web" { image { name = "nginx:alpine" }}
resource "sidecar" "metrics" { target = resource.container.web
image { name = "nginx/nginx-prometheus-exporter:latest" }
command = [ "-nginx.scrape-uri=http://localhost:8080/metrics" ]
resources { cpu = 50 # 0.05 CPU memory = 64 # 64MB }
health_check { timeout = "5s"
tcp { address = "localhost:9113" } }}Best Practices
Section titled “Best Practices”- Resource Limits: Set appropriate CPU and memory limits to prevent sidecars from consuming excessive resources
- Health Checks: Configure health checks for critical sidecars to ensure they’re functioning properly
- Volume Mounts: Use read-only mounts when the sidecar only needs to read configuration files
- Image Tags: Always specify explicit image tags rather than using
latest - Target Dependencies: Ensure the target container is properly configured before adding sidecars
- Single Responsibility: Keep each sidecar focused on a single function (logging, monitoring, proxying)
- Shared Volumes: Use shared volumes to facilitate communication between the main container and sidecar
