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
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With