Container
The container resource defines Docker containers that run as part of your lab’s sandbox environment. Containers provide isolated environments for running applications, services, and tools that users interact with during the lab.
Use Cases
Section titled “Use Cases”As a lab author, you can use containers to create diverse lab environments:
- Run Standard Images: Deploy your applications directly from standard Docker images without modification
- Development Environments: Provide pre-configured development environments with specific tools, languages, and frameworks installed
- Multi-Service Architectures: Build complex distributed systems with multiple interconnected containers representing different components
Containers are the primary building blocks for creating interactive, hands-on learning experiences in Instruqt labs.
HCL Syntax
Section titled “HCL Syntax”Basic Syntax
Section titled “Basic Syntax”resource "container" "name" { image { name = "ubuntu:22.04" }}Full Syntax
Section titled “Full Syntax”resource "container" "name" { image { name = "image:tag" }
# Optional configurations entrypoint = ["executable", "param1"] command = ["arg1", "arg2"] environment = { KEY = "value" } privileged = false
# Network configuration network { id = resource.network.main.meta.id ip_address = "10.0.0.5" }
# Resource constraints resources { cpu = 1000 # 1 CPU = 1000 memory = 512 # MB
gpu { driver = "nvidia" device_ids = ["0"] } }
# Volumes volume { source = "/host/path" destination = "/container/path" read_only = false }
# Ports port { local = "8080" host = "8080" protocol = "tcp" }
port_range { range = "3000-3010" enable_host = true protocol = "tcp" }
# Security capabilities { add = ["SYS_ADMIN"] drop = ["NET_RAW"] }
# User configuration run_as { user = "1000" group = "1000" }
# Health check health_check { timeout = "10s"
http { address = "http://localhost/health" method = "GET" } }}Resource Structure
Section titled “Resource Structure”container├─ image (required)│ └─ name, username, password├─ basic configuration│ ├─ entrypoint, command│ ├─ environment, labels│ ├─ dns│ ├─ privileged│ ├─ max_restart_count├─ networking│ └─ network[] (repeatable)│ ├─ id, ip_address, aliases├─ storage│ └─ volume[] (repeatable)│ ├─ source, destination, type│ └─ read_only├─ port exposure│ ├─ port[] (repeatable)│ │ ├─ local, host, protocol, open_in_browser│ └─ port_range[] (repeatable)│ ├─ range, enable_host, protocol├─ resource limits│ └─ resources│ ├─ cpu, memory│ └─ gpu│ ├─ driver, device_ids├─ security│ ├─ capabilities│ │ ├─ add[], drop[]│ └─ run_as│ ├─ user, group└─ monitoring └─ health_check ├─ timeout ├─ http[] (address, method, body, headers, success_codes) ├─ tcp[] (address) └─ exec[] (command, script, exit_code)Fields
| Field | Type | Required | Description |
|---|---|---|---|
entrypoint | list(string) | — | Define the command or script that runs automatically when the container starts. ConstraintsSpaces are not allowed, add a new item instead |
command | list(string) | — | Add commands that run when the container starts to configure or initialize your environment. |
environment | map(string) | — | Set environment variables to pass configuration values, API keys, or secrets to the container. |
labels | map(string) | — | Use labels to organize or identify containers with metadata, such as environment or version tags. |
dns | list(string) | — | Configure DNS servers or custom hostnames for your container to resolve network addresses. ConstraintsMust be a valid IP address |
privileged | bool | — | Allow the container to run with extended system permissions. Only enable this for advanced use cases. Default false |
max_ | number | — | Set how many times the container should restart automatically if it stops or fails. Default 0ConstraintsMust be at least -1 (-1 for unlimited, 0 to disable, positive for specific count); Maximum 10 |
image | block | ✓ | Image to use for the container |
network | block | — | Connect your container to a specific network to enable communication between containers or services.repeatable |
port | block | — | Expose specific ports so learners can access web apps, APIs, or services running in the container.repeatable |
port_ | block | — | Specify a range of ports to open for applications that require multiple connections, such as clusters or multi-service environments.repeatable |
volume | block | — | Attach persistent storage or share data between containers using volumes.repeatable |
capabilities | block | — | Add or remove Linux capabilities to control system-level permissions available inside the container. |
resources | block | — | Resource constraints for the container |
health_ | block | — | Define checks to confirm that your container is running and responsive. Helps restart unhealthy containers automatically. |
run_ | block | — | Set the user and group under which the container runs. This helps control permissions and improve security. |
Image
Image to use for the container
| Field | Type | Required | Description |
|---|---|---|---|
name | string | ✓ | Docker image name with optional tag ConstraintsMust match `^[a-z0-9]([a-z0-9-]*[a-z0-9])*(\.[a-z0-9]([a-z0-9-]*[a-z0-9])*)*(/[a-z0-9]+([a-z0-9._-]*[a-z0-9])*)*(:[a-z0-9]+([a-z0-9._-]*[a-z0-9])*)?$` |
username | string | — | Docker registry user to use for private repositories |
password | string | — | Docker registry password to use for private repositories |
Network
Attach to the correct network
| Field | Type | Required | Description |
|---|---|---|---|
id | string | ✓ | ID of the network to attach the container |
ip_ | string | — | Static IP address to assign container for the network, the ip address must be within range defined by the network subnet. If this parameter is omitted an IP address will be automatically assigned. |
aliases | list(string) | — | Aliases allow alternate names to specified for the container |
Port
Ports to expose
| Field | Type | Required | Description |
|---|---|---|---|
local | number | ✓ | The local port in the container ConstraintsMinimum 1; Maximum 65535 |
remote | number | — | Remote port of the service ConstraintsMinimum 1; Maximum 65535 |
host | number | — | The host port to map the local port to ConstraintsMinimum 1; Maximum 65535 |
protocol | string | — | The protocol to use when exposing the port Allowed tcp udpDefault tcp |
open_ | string | — | When a host port is defined open this port with the given path in a browser |
Port Range
Range of ports to expose
| Field | Type | Required | Description |
|---|---|---|---|
range | string | ✓ | The port range to expose, e.g, `8080-8082` would expose the ports `8080`, `8081`, `8082` ConstraintsRange format is "<number>-<number>" |
enable_ | bool | — | Expose the port range on the host |
protocol | string | — | The protocol to use when exposing the port Allowed tcp udpDefault tcp |
Volume
Volumes to attach to the container
| 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. |
destination | string | ✓ | The destination in the container to mount the volume to, must be an absolute path |
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 |
Capabilities
Capabilities to add or drop from the container
| Field | Type | Required | Description |
|---|---|---|---|
add | list(string) | — | List of kernel capabilities to add to the container. Allowed 41 valuesCAP_AUDIT_CONTROLCAP_AUDIT_READCAP_AUDIT_WRITECAP_BLOCK_SUSPENDCAP_BPFCAP_CHECKPOINT_RESTORECAP_CHOWNCAP_DAC_OVERRIDECAP_DAC_READ_SEARCHCAP_FOWNERCAP_FSETIDCAP_IPC_LOCKCAP_IPC_OWNERCAP_KILLCAP_LEASECAP_LINUX_IMMUTABLECAP_MAC_ADMINCAP_MAC_OVERRIDECAP_MKNODCAP_NET_ADMINCAP_NET_BIND_SERVICECAP_NET_BROADCASTCAP_NET_RAWCAP_PERFMONCAP_SETFCAPCAP_SETGIDCAP_SETPCAPCAP_SETUIDCAP_SYS_ADMINCAP_SYS_BOOTCAP_SYS_CHROOTCAP_SYS_MODULECAP_SYS_NICECAP_SYS_PACCTCAP_SYS_PTRACECAP_SYS_RAWIOCAP_SYS_RESOURCECAP_SYS_TIMECAP_SYS_TTY_CONFIGCAP_SYSLOGCAP_WAKE_ALARM |
drop | list(string) | — | List of kernel capabilities to drop from the container. Allowed 41 valuesCAP_AUDIT_CONTROLCAP_AUDIT_READCAP_AUDIT_WRITECAP_BLOCK_SUSPENDCAP_BPFCAP_CHECKPOINT_RESTORECAP_CHOWNCAP_DAC_OVERRIDECAP_DAC_READ_SEARCHCAP_FOWNERCAP_FSETIDCAP_IPC_LOCKCAP_IPC_OWNERCAP_KILLCAP_LEASECAP_LINUX_IMMUTABLECAP_MAC_ADMINCAP_MAC_OVERRIDECAP_MKNODCAP_NET_ADMINCAP_NET_BIND_SERVICECAP_NET_BROADCASTCAP_NET_RAWCAP_PERFMONCAP_SETFCAPCAP_SETGIDCAP_SETPCAPCAP_SETUIDCAP_SYS_ADMINCAP_SYS_BOOTCAP_SYS_CHROOTCAP_SYS_MODULECAP_SYS_NICECAP_SYS_PACCTCAP_SYS_PTRACECAP_SYS_RAWIOCAP_SYS_RESOURCECAP_SYS_TIMECAP_SYS_TTY_CONFIGCAP_SYSLOGCAP_WAKE_ALARM |
Resources
Resource constraints for the container
| 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 |
disk | number | — | Disk space limit in MB |
gpu | block | — | GPU resource constraints |
GPU
GPU resource constraints
| Field | Type | Required | Description |
|---|---|---|---|
driver | string | ✓ | Select the GPU driver to use for hardware acceleration or GPU-based workloads. |
device_ | list(string) | ✓ | Specify which GPU devices the container can access when running GPU-based tasks. |
Health Check
Health checks for the container
| Field | Type | Required | Description |
|---|---|---|---|
timeout | string | ✓ | The maximum duration to wait before marking the health check as failed. Expressed as a Go duration, e.g. 1s = 1 second, 100ms = 100 milliseconds. Default 30sConstraintsMust be a valid duration (e.g. 30s, 5m) |
exec | block | — | Runs a command or script inside the container. The check passes when the command exits with code 0.repeatable |
http | block | — | Sends an HTTP request to the address and passes when the response matches the expected success codes.repeatable |
tcp | block | — | Attempts to open a TCP connection to the address. If the connection opens, the check passes.repeatable |
Exec Health Check
Execute command health check
| Field | Type | Required | Description |
|---|---|---|---|
command | list(string) | — | Command to execute |
script | string | — | Script to execute |
exit_ | number | — | Expected exit code |
HTTP Health Check
HTTP health check
| Field | Type | Required | Description |
|---|---|---|---|
address | string | ✓ | The URL to check, health check expects a HTTP status code to be returned by the URL in order to pass the health check. |
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 Health Check
TCP health check
| Field | Type | Required | Description |
|---|---|---|---|
address | string | ✓ | TCP address to check |
Run As
User block for mapping the user id and group id inside the container
| Field | Type | Required | Description |
|---|---|---|---|
user | string | ✓ | The user to run the container as |
group | string | ✓ | The group to run the container as |
Computed Attributes
These attributes are set by the system and are read-only.
| Attribute | Type | Description |
|---|---|---|
container_name | string | Fully qualified domain name for the container, this can be used to access the container from other sources |
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. |
network[].name | string | Name will equal the name of the network as created by jumppad |
network[].assigned_address | string | AssignedAddress will equal if IPAddress is set, else it will be the value automatically assigned from the network |
Examples
Section titled “Examples”Basic Container
Section titled “Basic Container”resource "container" "ubuntu" { image { name = "ubuntu:22.04" }}Web Application Container
Section titled “Web Application Container”resource "container" "webapp" { image { name = "myapp:latest" }
environment = { NODE_ENV = "production" PORT = "3000" }
port { local = "3000" host = "8080" }
resources { cpu = 2000 # 2 CPUs memory = 1024 # 1GB }
health_check { timeout = "5s"
http { address = "http://localhost:3000/health" method = "GET" } }}Database Container with Volume
Section titled “Database Container with Volume”resource "container" "postgres" { image { name = "postgres:15" }
environment = { POSTGRES_PASSWORD = "secret" POSTGRES_DB = "myapp" }
volume { source = "postgres-data" destination = "/var/lib/postgresql/data" }
port { local = "5432" }
network { id = resource.network.backend.meta.id }}Development Container with Multiple Networks
Section titled “Development Container with Multiple Networks”resource "container" "devbox" { image { name = "instruqt/devbox:latest" }
privileged = true
network { id = resource.network.frontend.meta.id ip_address = "10.0.1.10" }
network { id = resource.network.backend.meta.id ip_address = "10.0.2.10" }
volume { source = "./code" destination = "/workspace" }
volume { source = "/var/run/docker.sock" destination = "/var/run/docker.sock" }
capabilities { add = ["SYS_PTRACE"] }
run_as { user = "developer" group = "developer" }}GPU-Enabled Container
Section titled “GPU-Enabled Container”resource "container" "ml_workspace" { image { name = "tensorflow/tensorflow:latest-gpu" }
resources { cpu = 4000 memory = 8192
gpu { driver = "nvidia" device_ids = ["0", "1"] } }
environment = { CUDA_VISIBLE_DEVICES = "0,1" }}Best Practices
Section titled “Best Practices”- Image Tags: Always specify explicit image tags rather than using
latest - Resource Limits: Set appropriate CPU and memory limits to prevent resource exhaustion
- Health Checks: Configure health checks for services to ensure availability
- Non-Root Users: Use the
run_asblock to run containers as non-root users when possible - Environment Variables: Use environment variables for configuration instead of hardcoding values
