diff --git a/Dockerfile b/Dockerfile index 982fe77..1848758 100644 --- a/Dockerfile +++ b/Dockerfile @@ -65,6 +65,18 @@ RUN ARCH=$(dpkg --print-architecture) && \ rm /tmp/glab.deb && \ glab --version +# Install Docker CLI from official repository (for Docker socket mounting) +RUN curl -fsSL https://download.docker.com/linux/debian/gpg | \ + gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg && \ + chmod 644 /usr/share/keyrings/docker-archive-keyring.gpg && \ + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \ + $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list && \ + apt-get update && \ + apt-get install -y docker-ce-cli && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* && \ + docker --version + # Create non-root user ARG USER_ID=1000 ARG GROUP_ID=1000 @@ -72,6 +84,8 @@ ARG USERNAME=agent RUN groupadd -g ${GROUP_ID} ${USERNAME} || true && \ useradd -m -u ${USER_ID} -g ${GROUP_ID} -s /bin/zsh ${USERNAME} && \ + (getent group docker || groupadd docker) && \ + usermod -aG docker,0 ${USERNAME} && \ echo "${USERNAME} ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/${USERNAME} && \ chmod 0440 /etc/sudoers.d/${USERNAME} @@ -209,4 +223,4 @@ RUN bash -c "source $NVM_DIR/nvm.sh && \ # Entrypoint ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] -CMD ["/bin/zsh"] \ No newline at end of file +CMD ["/bin/zsh"] diff --git a/README.md b/README.md index 9927382..a429cd9 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,23 @@ Start your coding agent in the agentbox directory and issue this (example) promp Then you can go to your project directory and run (e.g.) `agentbox --tool copilot`. Thanks to [Felix Medam](https://github.com/SputnikTea) for this very cool idea. +## Docker Access + +AgentBox can optionally mount the host's Docker socket, allowing you to run Docker commands inside the container: + +```bash +agentbox --docker +``` + +This mounts `/var/run/docker.sock` (or Docker Desktop's socket on macOS) and handles group permissions automatically. Useful for projects that need to build/run Docker images. + +**How it works:** +- Your current directory is always mounted as `/workspace` +- Additional directories are mounted using their folder names (e.g., `/foo`, `/bar`) +- All directories are writable - changes sync back to the host +- The mounting order follows the order you specify in the flag + + ## Helpful Commands ```bash @@ -60,6 +77,9 @@ agentbox -c # Mount additional directories for multi-project access agentbox --add-dir ~/proj1 --add-dir ~/proj2 +# Enable Docker commands inside container +agentbox --docker + # Start shell with sudo privileges agentbox shell --admin diff --git a/agentbox b/agentbox index 36dfcd6..24e0572 100755 --- a/agentbox +++ b/agentbox @@ -240,7 +240,8 @@ run_container() { local container_name="$1" local -n extra_dirs_to_mount=$2 local tool="$3" - shift 3 + local mount_docker_socket="$4" + shift 4 # Check if first arg is "shell" mode local shell_mode=false @@ -285,6 +286,30 @@ run_container() { log_warning "SSH not configured. Run 'agentbox ssh-init' to enable SSH operations." fi + # Mount Docker socket if requested + if [[ "$mount_docker_socket" == "true" ]]; then + local docker_socket="" + # Check for Docker Desktop on macOS first, then Linux + if [[ -S "${HOME}/.docker/run/docker.sock" ]]; then + docker_socket="${HOME}/.docker/run/docker.sock" + elif [[ -S /var/run/docker.sock ]]; then + docker_socket="/var/run/docker.sock" + fi + + if [[ -n "$docker_socket" ]]; then + mount_opts+=(-v "${docker_socket}:/var/run/docker.sock") + # Add container user to docker socket's group for permission access + local docker_gid + docker_gid=$(stat -c '%g' "$docker_socket" 2>/dev/null || stat -f '%g' "$docker_socket" 2>/dev/null) + if [[ -n "$docker_gid" ]]; then + mount_opts+=(--group-add "$docker_gid") + fi + log_info "Docker socket mounted (container has access to host Docker)" + else + log_warning "Docker socket not found" + fi + fi + # Mount cache directories for package managers local cache_dir="${HOME}/.cache/agentbox/${container_name}" mkdir -p "${cache_dir}/npm" "${cache_dir}/pip" "${cache_dir}/maven" "${cache_dir}/gradle" @@ -422,6 +447,7 @@ Options: -h, --help Show this help message --tool TOOL Choose tool: claude (default) or opencode -p PORT Forward a port from host to container (can be used multiple times) + --docker Mount Docker socket (enables docker commands inside container) --rebuild Force rebuild of the image --add-dir DIR Mount additional directory (can be used multiple times) @@ -439,6 +465,7 @@ Examples: agentbox --tool opencode # Start OpenCode instead of Claude agentbox -p 3002 # Forward port 3002 agentbox -p 3002:8080 # Map host port 3002 to container port 8080 + agentbox --docker # Enable docker commands inside container agentbox shell # Start interactive shell instead of Claude agentbox shell --admin # Start admin shell with sudo access agentbox --add-dir ~/1 --add-dir ~/2 # Add dirs with Claude CLI @@ -495,6 +522,7 @@ main() { local force_rebuild=false local shell_mode=false local admin_mode=false + local docker_mount=false local cmd_args=() declare -a ports=() local extra_dirs=() @@ -537,6 +565,10 @@ main() { tool="$1" shift ;; + --docker) + docker_mount=true + shift + ;; shell) shell_mode=true shift @@ -605,12 +637,12 @@ main() { # Run or attach to container if [[ "$shell_mode" == "true" ]]; then if [[ "$admin_mode" == "true" ]]; then - run_container "$container_name" validated_dirs "$tool" "shell" "--admin" "${cmd_args[@]}" + run_container "$container_name" validated_dirs "$tool" "$docker_mount" "shell" "--admin" "${cmd_args[@]}" else - run_container "$container_name" validated_dirs "$tool" "shell" "${cmd_args[@]}" + run_container "$container_name" validated_dirs "$tool" "$docker_mount" "shell" "${cmd_args[@]}" fi else - run_container "$container_name" validated_dirs "$tool" "${cmd_args[@]}" + run_container "$container_name" validated_dirs "$tool" "$docker_mount" "${cmd_args[@]}" fi }