Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Docker Python script can't find file

I've successfully built a Docker container and copied my application's files into the container in the Dockerfile. However, I am trying to execute a Python script that references an input file (that was copied into the container during the Docker build). I can't seem to figure out why my script is telling me it cannot locate the input file. I am including the Dockerfile I used to build the container below, and the relevant portion of the Python script that is looking for the input file it cannot find.

Dockerfile:

FROM alpine:latest

RUN mkdir myapplication

COPY . /myapplication

RUN apk add --update \
    python \
    py2-pip && \
    adduser -D aws

WORKDIR /home/aws

RUN mkdir aws && \
    pip install --upgrade pip && \
    pip install awscli && \
    pip install -q --upgrade pip && \
    pip install -q --upgrade setuptools && \
    pip install -q -r /myapplication/requirements.txt

CMD ["python", "/myapplication/script.py", "/myapplication/inputfile.txt"]

Relevant portion of the Python script:

if len(sys.argv) >= 2:
    sys.exit('ERROR: Received 2 or more arguments. Expected 1: Input file name')

elif len(sys.argv) == 2:
    try:
        with open(sys.argv[1]) as f:
            topics = f.readlines()
    except Exception:
        sys.exit('ERROR: Expected input file %s not found' % sys.argv[1])
else:
    try:
        with open('inputfile.txt') as f:
            topics = f.readlines()
    except:
        sys.exit('ERROR: Default inputfile.txt not found. No alternate input file was provided')

Docker command on host resulting in error:

sudo docker run -it -v $HOME/.aws:/home/aws/.aws discursive python \
    /discursive/index_twitter_stream.py

The error from the command above:

ERROR: Default inputfile.txt not found. No alternate input file was provided

The AWS stuff is drawn from a tutorial on how to pass your host's AWS credentials into the Docker container for use in interacting with AWS services. I used elements from here: https://github.com/jdrago999/aws-cli-on-CoreOS

like image 627
LouiseEMastiz Avatar asked Oct 29 '22 13:10

LouiseEMastiz


1 Answers

There are two issues I've identified so far. Maya G points out a third in the comments below.

Incorrect conditional logic

You need to replace:

if len(sys.argv) >= 2:
    sys.exit('ERROR: Received 2 or more arguments. Expected 1: Input file name')

With:

if len(sys.argv) > 2:
    sys.exit('ERROR: Received more than two arguments. Expected 1: Input file name')

Bear in mind that the first argument given to the script is always its own name. This means you should be expecting either 1 or 2 arguments in sys.argv.

Issues with locating the default file

Another problem is that your docker container's working directory is /home/aws, so when you execute your Python script it will try to resolve paths relative to this.

This means that:

with open('inputfile.txt') as f:

Will be resolved as /home/aws/inputfile.txt, not /home/aws/myapplication/inputfile.txt.

You can fix this by either changing the code to:

with open('myapplication/inputfile.txt') as f:

Or (preferred):

with open(os.path.join(os.path.dirname(__file__), 'inputfile.txt')) as f:

(Source for the above variation)

Using CMD vs. ENTRYPOINT

It also seems like your script apparently isn't receiving myapplication/inputfile.txt as an argument. This might be a quirk with CMD.

I'm not 100% clear on the distinction between these two operations, but I always use ENTRYPOINT in my Dockerfiles and it's given me no grief. See this answer and try replacing:

CMD ["python", "/myapplication/script.py", "/myapplication/inputfile.txt"]

With:

ENTRYPOINT ["python", "/myapplication/script.py", "/myapplication/inputfile.txt"]

(thanks Maya G)

like image 126
Tagc Avatar answered Nov 15 '22 06:11

Tagc