5

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

Dan Lowe
  • 51,713
  • 20
  • 123
  • 112
LouiseEMastiz
  • 53
  • 1
  • 1
  • 3
  • 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. – Tagc Jan 27 '17 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` – LouiseEMastiz Jan 27 '17 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`. – Dan Lowe Jan 27 '17 at 15:37
  • Actually the first condition in the `if` should be met, because `sys.argv` meets that condition `>= 2`. – Dan Lowe Jan 27 '17 at 15:38

1 Answers1

4

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)

Community
  • 1
  • 1
Tagc
  • 8,736
  • 7
  • 61
  • 114
  • It doesn't get the argument because the CMD command should be `CMD ["python", "/myapplication/script.py /myapplication/inputfile.txt"]` – Maya G Jan 27 '17 at 15:46
  • @MayaG According to [the docs](https://docs.docker.com/engine/reference/builder/#cmd), it should work okay as it is already: `CMD ["executable","param1","param2"]` – Tagc Jan 27 '17 at 15:47
  • you're right. Maybe this will solve the problem http://stackoverflow.com/questions/32554448/command-line-arguments-to-docker-cmd – Maya G Jan 27 '17 at 15:50
  • Thanks all! Works like a charm! – LouiseEMastiz Jan 27 '17 at 16:18