Running a Script in Docker
Here is a simple example of a wrapper script to call a docker image using the docker python library.
import argparse
import docker
parser = argparse.ArgumentParser(description="Docker test script")
parser.add_argument("--phrase", type=str)
if __name__ == "__main__":
args = parser.parse_args()
client = docker.from_env()
print(client.containers.run("docker/whalesay", f"cowsay {args.phrase}").decode('utf-8'))
When running in this configuration, whatever environment the worker is running in must have access to docker. Additionally, if you want assets generated by a dockerfile, you should mount the current working directory to wherever the docker image outputs files to. For example, if a docker image output files to /output, the above invocation would be changed to:
import argparse
import os
import docker
from docker.types import Mount
parser = argparse.ArgumentParser(description="Docker test script")
if __name__ == "__main__":
args = parser.parse_args()
client = docker.from_env()
# IMPORTANT #
# This assumes we have a host directory for media storage (the MEDIA_ROOT setting) that has the same
# path inside the container as the host (e.g. volume: /host/path:/host/path)
wooey_data_dir = os.getcwd()
print(
client.containers.run(
image="busybox",
command=f"dd if=/dev/urandom of=/output/test.garbage bs=1M count=1",
mounts=[Mount(target="/output", source=wooey_data_dir, type='bind')],
).decode(
"utf-8"
)
)
If you are running Wooey inside Docker, then this becomes a bit more complicated as the data directory may be on a mount point different on the host than inside the container. The following script shows how to handle these scenarios:
import argparse
import os
import django
django.setup()
from django.conf import settings
import docker
from docker.types import Mount
parser = argparse.ArgumentParser(description="Docker test script")
if __name__ == "__main__":
args = parser.parse_args()
client = docker.from_env()
# our volume is called `wooey_user_uploads`. If we had a NAS, then we could simplify this by ensuring the path
# inside the container matches the path on the host -- in which case the above snippet is all that is needed.
volume = client.volumes.get('wooey_user_uploads')
volume_mount = volume.attrs['Mountpoint']
current_dir = os.getcwd()
wooey_data_dir = os.path.join(volume_mount.rstrip('/'), current_dir.replace(settings.MEDIA_ROOT, '').lstrip('/'))
print(
client.containers.run(
image="busybox",
command=f"dd if=/dev/urandom of=/output/test.garbage bs=1M count=1",
mounts=[Mount(target="/output", source=wooey_data_dir, type='bind')],
).decode(
"utf-8"
)
)