6

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

4
  • Try overriding the entry-point with /bin/bash so you can go and play around inside the container. Confirm that all expected files are present and within expected directories, etc. Commented Jan 27, 2017 at 15:16
  • I can list the directory fine, and see the intputfile.txt in the right place. Using: sudo docker run -it -v $HOME/.aws:/home/aws/.aws containername ls /myapplication Commented Jan 27, 2017 at 15:21
  • It's odd that with this CMD it even reaches the else. Since sys.argv has a length of 2, you should be entering the elif and either opening a file, or exiting, based on the code in that branch, not the code in the else. Commented Jan 27, 2017 at 15:37
  • Actually the first condition in the if should be met, because sys.argv meets that condition >= 2. Commented Jan 27, 2017 at 15:38

1 Answer 1

5

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)

Sign up to request clarification or add additional context in comments.

4 Comments

It doesn't get the argument because the CMD command should be CMD ["python", "/myapplication/script.py /myapplication/inputfile.txt"]
@MayaG According to the docs, it should work okay as it is already: CMD ["executable","param1","param2"]
you're right. Maybe this will solve the problem stackoverflow.com/questions/32554448/…
Thanks all! Works like a charm!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.