Home > database >  Calling a Docker container through Python subprocess
Calling a Docker container through Python subprocess

Time:10-19

I am novice to Docker and containers.

I am running 2 containers. 1st runs FAST API the 2nd one runs a tool in Go language.

From an endpoint, I want to invoke the GO container and run the tool.

I have docker-compose:

version: '3'

services:
  fastapi:
    build: ./
    image: myimage
    command: uvicorn app.main:app --reload --workers 1 --host 0.0.0.0 --port 8000
    ports:
      - 8000:8000
    networks:
      - test_network

  amass_git_worker:
    build: https://github.com/OWASP/Amass.git
    stdin_open: true
    tty: true
    entrypoint: ['/bin/sh']
    networks:
      - test_network

networks:
  test_network:
    driver: bridge 

Main fastapi app Dockerfile:

FROM python:3.10-slim

WORKDIR /app
COPY requirements.txt ./
RUN pip3 install --no-cache-dir -r requirements.txt

COPY . .
EXPOSE 8000 

The endpoint calls this function:

def amass_wrapper(search_key:str):
    try:
        subprocess.run(['docker', 'run', '-v', 'OUTPUT_DIR_PATH:/.config/amass/', 'integrate_scanning_modules-amass_git_worker/bin/sh', 'enum' ,'-d', 'owasp.org'])

When I call this endpoint, I get this error:

Process failed because the executable could not be found.
No such file or directory: 'docker'

Does this mean that i need to install docker in the fastapi container.

Any other advice how I can invoke the Go container through Python subprocess.

CodePudding user response:

You should install the Go binary in the Python application's image, and then call it normally using the subprocess module. Do not do anything Docker-specific here, and especially do not try to run a docker command.

Most Go programs compile down to a single binary, so it's simple enough to put this binary in $PATH somewhere. For example, your Dockerfile might say

FROM python:3.10-slim

# Install OS-level dependencies
RUN apt-get update \
 && DEBIAN_FRONTEND=noninteractive \
    apt-get install --assume-yes --no-install-recommends \
      curl \
      unzip

# Download and unpack the Amass zip file, saving only the binary
RUN cd /usr/local \
 && curl -LO https://github.com/OWASP/Amass/releases/download/v3.20.0/amass_linux_amd64.zip \
 && unzip amass_linux_amd64.zip \
 && mv amass_linux_amd64/amass bin \
 && rm -rf amass_linux_amd64 amass_linux_amd64.zip

# Install your application the same way you have it already
WORKDIR /app
COPY requirements.txt ./
RUN pip3 install --no-cache-dir -r requirements.txt

COPY . .
EXPOSE 8000
CMD uvicorn app.main:app --reload --workers 1 --host 0.0.0.0 --port 8000

Now since your image contains a /usr/local/bin/amass binary, you can just run it.

subprocess.run(['amass', 'enum', '-d', 'wasp.org'])

And you do not need the "do-nothing" container in the Compose setup

version: '3.8'
services:
  fastapi:
    build: .
    ports:
      - '8000:8000'

It's difficult to programmatically run a command in an existing container. Running a new temporary container to launch the program is no easier but is at least somewhat better style. In both cases you'd need to install either the docker binary or the Docker SDK, and give your container access to the host's Docker socket; this access comes with unrestricted root access to the entire host, should you choose to take advantage of it. So this setup is both tricky to test and also comes with some significant security implications, and I'd generally avoid it if possible.

  • Related