Accepted (Implemented)
The run command starts Docker Compose services on the target VM. To test this in the
E2E configuration tests (e2e_config_and_release_tests.rs), we need Docker to be
available inside the test container that simulates a provisioned VM.
Previously, the provisioned-instance Docker container did not have Docker installed
or available, so the run command could not be tested. We had a workaround
(TORRUST_TD_SKIP_RUN_IN_CONTAINER) to skip the run command in container-based tests,
but this meant we could not verify the complete deployment workflow in E2E tests.
- Docker Compose must be able to run inside the test container
- The solution must work on GitHub Actions CI/CD
- The solution should not significantly increase test time
- Security considerations should be documented
- Test Coverage: We want to test the complete deployment workflow including
run - CI Compatibility: Must work on GitHub Actions runners
- Simplicity: Prefer simpler solutions that are easier to maintain
- Security: Understand and document security implications
Run a full Docker daemon inside the container using --privileged mode.
Changes Required:
- Install Docker daemon in
docker/provisioned-instance/Dockerfile - Add Docker daemon to supervisor configuration
- Run container with
--privilegedflag in testcontainers - Wait for Docker daemon to be ready before running tests
Pros:
- Complete isolation - containers created inside are truly nested
- Realistic simulation of a VM with Docker installed
- No side effects on host Docker
Cons:
- Requires
--privilegedflag (security concern) - Docker daemon startup adds ~5-10 seconds to test time
- More complex supervisor configuration
- May have issues on some CI environments
Mount the host's Docker socket (/var/run/docker.sock) into the container.
Changes Required:
- Install Docker CLI (not daemon) in
docker/provisioned-instance/Dockerfile - Mount Docker socket when starting container in testcontainers
- Add
torrustuser todockergroup
Pros:
- Simpler setup - no daemon to manage
- Faster - no Docker daemon startup time
- No
--privilegedflag needed - Works reliably on most CI environments
Cons:
- Containers created are siblings, not children
- Shares host Docker daemon (potential resource conflicts)
- Container names may conflict with host containers
- Less isolation
Keep the skip flag and only test run command with real LXD VMs.
Changes Required:
- None - keep current implementation
- Document that
runis only tested ine2e_tests_full.rsand manual tests
Pros:
- No additional complexity
- Tests real VM behavior
- No security concerns
Cons:
- Incomplete E2E test coverage in container-based tests
runcommand not tested in CI
We choose DinD because:
- Realistic Testing: The container accurately simulates a VM with Docker installed
- Complete Isolation: No interference with host Docker or other tests
- CI Compatibility: GitHub Actions supports privileged containers
- Consistent Behavior: Same Docker version inside container regardless of host
The --privileged flag is acceptable for test containers because:
- Test containers are ephemeral and isolated
- No untrusted code runs inside
- GitHub Actions already runs with elevated privileges
Add Docker installation to docker/provisioned-instance/Dockerfile:
# Install iptables for Docker networking
RUN apt-get update && apt-get install -y iptables
# Install Docker using official installation script
# This installs both Docker daemon and Docker Compose plugin
RUN curl -fsSL https://get.docker.com | sh \
&& rm -rf /var/lib/apt/lists/*
# Create torrust user with docker group membership
RUN useradd -m -s /bin/bash -G sudo,docker torrustAdd Docker daemon to supervisord.conf with vfs storage driver:
[program:dockerd]
command=/usr/bin/dockerd --host=unix:///var/run/docker.sock --storage-driver=vfs
stdout_logfile=/var/log/supervisor/dockerd.log
stderr_logfile=/var/log/supervisor/dockerd.log
autorestart=true
startretries=3
priority=5Important: The vfs storage driver is required because the default overlay2 driver
does not work in nested Docker environments (fails with "invalid argument" error).
The vfs driver is slower but compatible with Docker-in-Docker scenarios.
Modify testcontainers configuration in src/testing/e2e/containers/provisioned.rs:
- Use
with_privileged(true)fromtestcontainers::ImageExttrait - Wait for Docker daemon to be ready by checking for
dockerd entered RUNNING statein supervisor logs (instead of waiting for sshd)
// Wait for Docker daemon to be ready (not just SSH)
.with_wait_condition(WaitFor::message_on_stdout("dockerd entered RUNNING state"))
// Start with privileged mode for Docker-in-Docker
image.with_privileged(true).start().awaitA challenge discovered during implementation: Ansible's Docker installation playbook
installs docker.io package, which conflicts with Docker CE (containerd.io) installed
via get.docker.com script in the Dockerfile.
Solution: Add environment variable TORRUST_TD_SKIP_DOCKER_INSTALL_IN_CONTAINER
to skip Docker/Docker Compose installation via Ansible when Docker is already
pre-installed in the container.
In src/bin/e2e_config_and_release_tests.rs:
// SAFETY: Set before async runtime starts
unsafe {
std::env::set_var("TORRUST_TD_SKIP_DOCKER_INSTALL_IN_CONTAINER", "true");
}In src/application/command_handlers/configure/handler.rs:
let skip_docker = std::env::var("TORRUST_TD_SKIP_DOCKER_INSTALL_IN_CONTAINER")
.map(|v| v == "true")
.unwrap_or(false);
if skip_docker {
// Skip Docker and Docker Compose installation steps
}Removed TORRUST_TD_SKIP_RUN_IN_CONTAINER environment variable since the run command
now works in container-based E2E tests.
- Complete E2E test coverage for all commands including
run - Tests verify real Docker Compose behavior
- CI/CD validates complete deployment workflow
- Test containers require
--privilegedmode - Slightly longer test startup time (~2-3 seconds for Docker daemon)
- More complex container configuration
- Must use
vfsstorage driver (slower thanoverlay2)
- Need to document privileged mode requirement
- Docker installation skipped via environment variable to avoid package conflicts
-
Storage Driver Compatibility: The
overlay2storage driver does not work in nested Docker environments. Thevfsdriver must be used, which is slower but compatible. -
Package Conflicts: Docker CE (
containerd.iofromget.docker.com) conflicts withdocker.iopackage. When Docker is pre-installed in the container, Ansible's Docker installation must be skipped. -
Rust 1.81+ Safety:
std::env::set_varis nowunsafein Rust 1.81+. Environment variables must be set in anunsafeblock with a safety comment explaining why concurrent access is not possible. -
Wait Conditions: Waiting for
dockerd entered RUNNING statein supervisor logs is more reliable than waiting for SSH, as it ensures Docker is ready before tests run.