22

I have a flask app inside of a docker container. I would like to use the python package zappa to deploy that app to Amazon Web Services.

Unfortunately zappa requires that it and all of my apps dependencies be installed in a python virtual environment.

So I have rebuilt my docker image and moved everything into a virtual environment in it.

The problem is that now i can't run commands like:

docker exec <container> flask <sub command> 

because flask is installed in a virtual environment which has not been activated.

I can still do this:

host$ docker exec -it <container> bash container$ source venv/bin/activate container$ flask <sub command> 

Also, I can no longer run my default Dockerfile CMD (gunicorn) because that is also is my virtual environment.

Does this make any more sense?

4
  • Your container shouldn't have any attachment to whatever environment you run on your host machine; rather, you should look to run your Python app/env in your container. Commented May 19, 2017 at 19:13
  • The virtualenv was created in the container at build. I'd like to have it automatically invoked by docker on entry, so when a CMD is passed, is executed in the context of the virtualenv. Commented May 19, 2017 at 19:17
  • Can you list some commands that you would normally use to do this? It sounds like you just need a simple shell script with the commands that you use as an ENTRYPOINT in the Dockerfile. It is something we can help with but you don't provide much information on what needs to happen. Commented May 19, 2017 at 20:08
  • Ok, I tried to say exactly what my problem is. Thank you. Commented May 19, 2017 at 20:27

3 Answers 3

28

As an alternative to just sourcing the script inline with the command, you could make a script that acts as an ENTRYPOINT. An example entrypoint.sh would look something like:

#!/bin/bash source venv/bin/activate exec "$@" 

Then in your Dockerfile you would copy this file and set it as the ENTRYPOINT:

FROM myimage COPY entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] 

Now you can run it like docker run mynewimage flask <sub command> or docker run mynewimage gunicorn.

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

3 Comments

Awesome! I had to add RUN chmod 700 entrypoint.sh before the ENTRYPOINT as well. Thanks!
Yes awesome great idea. Minor nitpick, the shebang line should really be bash not sh because sh doesn't have source it uses the dot .
Perfect solution! At first I've missed the significance of using "exec" command in this script. After few hours of debugging now I see that this will make flask (or any other program) run with PID==1, which will guarantee correct signal handling inside container. Most elegant way to do it :)
18

You don't need to activate the env. Prepend /path/to/virtualenv/bin to $PATH, then python, pip, etc. automatically point to the commands in the virtualenv.

FROM python:3.4-alpine WORKDIR /deps ENV PATH=/virtualenv/bin:$PATH RUN pip install virtualenv && \ mkdir virtualenv && \ virtualenv /virtualenv COPY . /deps 

Example working:

#Build dockerfile docker build . -t="venv_example" #Run all python commands in virtualenv w/ no hassle docker run --rm venv_example which python >/virtualenv/bin/python docker run --rm venv_example which pip >/virtualenv/bin/pip 

5 Comments

Thanks for pointing this out! I feel dumb for not having thought it myself. In my opinion this is the best way, much better than what the other answers suggest.
OOOOHHHH yea. I've spent many hours over the years trying to come up w/ something that was clean, and let me run commands against venv.
Really elegant !
I guess this should be the accepted solution as using the environment variable makes it super clean.
While this may work well in many use cases, it should be noted that properly activating a virtual env does slightly more than prepending the path. Apart from adapting the prompt, it also exports $VIRTUAL_ENV to the virtual env root dir. So you could face issues if you're running some tooling that depends on an explicitly exposed virtual env. Of course you could further mirror the behavior of activate, but it isn't 100% clean.
4

Try:

docker exec <container> sh -c 'source venv/bin/activate; flask <sub command>' 

Your command can be:

CMD sh -c 'source venv/bin/activate; gunicorn...' 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.