Skip to content

Docker Support

This document describes Structyl's Docker integration.

Overview

Structyl supports running builds inside Docker containers, providing:

  • Reproducible builds across environments
  • No need to install language toolchains locally
  • Isolation between different language runtimes
  • CI/local build parity

Enabling Docker Mode

Command Line Flag

bash
structyl build cs --docker
structyl test --docker
structyl ci --docker

Environment Variable

bash
export STRUCTYL_DOCKER=1
structyl build  # Runs in Docker

Or per-command:

bash
STRUCTYL_DOCKER=1 structyl build

Activation Precedence

ConditionDocker Mode
--docker flag presentEnabled
--no-docker flag presentDisabled (overrides env var)
STRUCTYL_DOCKER = 1, true, yes (case-insensitive)Enabled
STRUCTYL_DOCKER = 0, false, noDisabled
STRUCTYL_DOCKER unset or emptyDisabled
STRUCTYL_DOCKER = other valueWarning emitted; disabled

Command-line flags take precedence over environment variables. The --no-docker flag explicitly disables Docker mode even if STRUCTYL_DOCKER is set.

Docker Compose Configuration

Structyl uses Docker Compose to manage containers. The compose file can be:

  1. Auto-generated by Structyl (default)
  2. User-provided for custom configuration

Auto-Generated Compose File

If no docker-compose.yml exists, Structyl generates one based on .structyl/config.json:

yaml
# Auto-generated by Structyl
services:
  cs:
    build:
      context: .
      dockerfile: cs/Dockerfile
    volumes:
      - ./cs:/workspace/cs
      - ./tests:/workspace/tests:ro
    working_dir: /workspace/cs

  py:
    build:
      context: .
      dockerfile: py/Dockerfile
    volumes:
      - ./py:/workspace/py
      - ./tests:/workspace/tests:ro
    working_dir: /workspace/py

User-Provided Compose File

Place a docker-compose.yml at project root. Structyl will use it instead of generating one.

Dockerfile Templates

Each target needs a Dockerfile. Options:

1. Built-in Templates (Default)

Structyl provides default Dockerfiles for common languages:

LanguageBase Image
C#mcr.microsoft.com/dotnet/sdk:8.0
Gogolang:1.22
Kotlingradle:8-jdk21
Pythonpython:3.12-slim
Rrocker/verse:latest
Rustrust:1.75
TypeScriptnode:20-slim

2. Custom Dockerfile

Place a Dockerfile in the target directory:

cs/
├── Dockerfile       # Custom Dockerfile
└── MyProject.csproj

Custom Dockerfile takes precedence over built-in template.

3. Configuration Override

Specify in .structyl/config.json:

json
{
  "docker": {
    "services": {
      "cs": {
        "base_image": "mcr.microsoft.com/dotnet/sdk:9.0",
        "dockerfile": "docker/cs.Dockerfile"
      }
    }
  }
}

Volume Mounts

Standard volume mounts:

MountPurpose
./<target>:/workspace/<target>Target source code (read-write)
./tests:/workspace/tests:roTest data (read-only)
./.structyl/config.json:/workspace/.structyl/config.json:roConfiguration (read-only)

Cache Volumes

To avoid permission conflicts, use separate cache directories for Docker:

yaml
services:
  cs:
    volumes:
      - ./cs/.nuget-docker:/tmp/.nuget
  rs:
    volumes:
      - ./rs/.cargo-docker:/tmp/.cargo

Add to .gitignore:

**/.nuget-docker
**/.cargo-docker
**/.cache-docker

Platform Considerations

ARM64 (Apple Silicon)

Some images don't support ARM64. Specify platform explicitly:

json
{
  "docker": {
    "services": {
      "r": {"platform": "linux/amd64"},
      "pdf": {"platform": "linux/amd64"}
    }
  }
}

Docker Desktop uses Rosetta for emulation.

User Mapping

Structyl maps the container user to avoid root-owned files on the host.

PlatformBehavior
LinuxRun as host user: --user "$(id -u):$(id -g)"
macOSRun as host user: --user "$(id -u):$(id -g)"
WindowsRun as default container user (user mapping not supported)

On Unix systems, the equivalent command is:

bash
docker compose run --rm --user "$(id -u):$(id -g)" cs bash -c "dotnet build"

On Windows, user mapping is omitted:

powershell
docker compose run --rm cs powershell -Command "dotnet build"

Note: On Windows, files created in containers may be owned by root. Use separate cache directories (see "Cache Volumes" above) to mitigate permission issues.

Docker Commands

Build Images

bash
structyl docker-build        # Build all images
structyl docker-build cs py  # Build specific images

Clean Docker Resources

bash
structyl docker-clean        # Remove containers, images, volumes

Example Dockerfiles

C# (.NET)

dockerfile
FROM mcr.microsoft.com/dotnet/sdk:8.0

WORKDIR /workspace/cs
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
ENV NUGET_PACKAGES=/tmp/.nuget

Python

dockerfile
FROM python:3.12-slim

WORKDIR /workspace/py
RUN pip install --upgrade pip

Rust

dockerfile
FROM rust:1.75

WORKDIR /workspace/rs
ENV CARGO_HOME=/tmp/.cargo

Go

dockerfile
FROM golang:1.22

WORKDIR /workspace/go
ENV GOCACHE=/tmp/.cache
ENV GOPATH=/tmp/go

Configuration Reference

json
{
  "docker": {
    "compose_file": "docker-compose.yml",
    "env_var": "STRUCTYL_DOCKER",
    "services": {
      "<target>": {
        "base_image": "image:tag",
        "dockerfile": "path/to/Dockerfile",
        "platform": "linux/amd64",
        "volumes": ["additional:/mounts"]
      }
    }
  }
}
FieldDescriptionDefault
compose_filePath to compose filedocker-compose.yml
env_varEnv var to enable Docker modeSTRUCTYL_DOCKER
services.<target>.base_imageBase Docker imageLanguage-specific
services.<target>.dockerfileCustom Dockerfile path<target>/Dockerfile
services.<target>.platformTarget platformHost platform
services.<target>.volumesAdditional volume mounts[]

Troubleshooting

Permission Denied

If files are owned by root after Docker build:

  1. Ensure user mapping is enabled
  2. Use separate cache directories (e.g., .nuget-docker)

Image Not Found

bash
structyl docker-build  # Rebuild all images

Slow Builds on Apple Silicon

ARM64 emulation is slow. Options:

  1. Use native ARM64 images where available
  2. Accept slower builds for x64-only tools
  3. Use native builds for development, Docker for CI only

Released under the MIT License.