├── Dockerfile ├── README.md ├── app.ini ├── entrypoint.sh └── nginx.conf /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | MAINTAINER Christian Gatzlaff 3 | 4 | # basic flask environment 5 | RUN apk add --no-cache bash git nginx uwsgi uwsgi-python py2-pip \ 6 | && pip2 install --upgrade pip \ 7 | && pip2 install flask 8 | 9 | # application folder 10 | ENV APP_DIR /app 11 | 12 | # app dir 13 | RUN mkdir ${APP_DIR} \ 14 | && chown -R nginx:nginx ${APP_DIR} \ 15 | && chmod 777 /run/ -R \ 16 | && chmod 777 /root/ -R 17 | VOLUME ${APP_DIR} 18 | WORKDIR ${APP_DIR} 19 | 20 | # expose web server port 21 | # only http, for ssl use reverse proxy 22 | EXPOSE 80 23 | 24 | # copy config files into filesystem 25 | COPY nginx.conf /etc/nginx/nginx.conf 26 | COPY app.ini /app.ini 27 | COPY entrypoint.sh /entrypoint.sh 28 | 29 | # exectute start up script 30 | ENTRYPOINT ["/entrypoint.sh"] 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Alpine OS](https://hub.docker.com/_/alpine/) running [Python Flask](http://flask.pocoo.org/) (with Python 2.7 or 3.5) 2 | 3 | [![](https://images.microbadger.com/badges/image/jazzdd/alpine-flask.svg)](https://microbadger.com/images/jazzdd/alpine-flask "Get your own image badge on microbadger.com") 4 | 5 | 6 | ## Tags: 7 | * latest - flask running on python 2.7 8 | * python3 - flask running on python 3.6 9 | 10 | --- 11 | This image is used to run flask applications. To start a container use 12 | 13 | ``` 14 | docker run --name flaskapp --restart=always \ 15 | -p 80:80 \ 16 | -v /path/to/app/:/app \ 17 | -d jazzdd/alpine-flask 18 | ``` 19 | 20 | `-v /path/to/app/:/app` - specifies the path to the folder containing a file named app.py, which should be your main application 21 | 22 | `-p 80:80` - the image exposes port 80, in this example it is mapped to port 80 on the host 23 | 24 | --- 25 | ## Installing additional python or flask packages 26 | This image comes with a basic set of python packages and the basic flask and python-pip installation. 27 | 28 | If you need any non-default python or flask packages, the container will install them on its first run using python pip and a requirements.txt file. Save a requirements.txt file in the root folder of your app, which is mounted to the /app folder of the container. The format of the file is described in the [pip documentation](https://pip.readthedocs.org/en/1.1/requirements.html#requirements-file-format). After that you can create a new container with the above docker command. The entrypoint script will take care of the package installation listed in the requirements file. 29 | 30 | If an additional package is needed during runtime of the container it can be installed with following command. 31 | 32 | ``` 33 | docker exec YOUR_CONTAINER_ID/NAME /bin/bash -c "pip install package-name" 34 | ``` 35 | 36 | --- 37 | ## Installing additional Alpine packages 38 | Sometimes, additional python or flask packages need to build some dependecies. Additional Alpine packages can be installed into the container using a requirements file similar to the python requirements file. Listed packages will be installed on the first run of the container. 39 | 40 | You need to save a file named requirements_image.txt into the root folder of your app, which is mounted to the /app folder of the container. Just write the packages separated with space or a new line into the file. 41 | 42 | 43 | --- 44 | ## Internals 45 | The flask application is started using a UWSGI socket. 46 | 47 | Nginx is used to map the socket to port 80 within the image. This image does not offer any SSL capability, please use a [nginx proxy](https://github.com/jwilder/nginx-proxy) for this. Nginx will deliver static content (e.g. CSS or JS Files) directly without going through flask or uwsgi. 48 | 49 | ### Log messages 50 | Logs can be displayed using `docker logs -f CONTAINER_ID/NAME` 51 | 52 | --- 53 | ## Using this image to control docker with flask 54 | 55 | This image can be used to create a privileged container, which can control your docker server. Therfore the docker socket must be mounted as volume within this container and an additional option is needed to run the container. 56 | 57 | ``` 58 | docker run --name flaskapp --restart=always \ 59 | -p 80:80 \ 60 | -v /path/to/app/:/app \ 61 | -v /var/run/docker.sock:/var/run/docker.sock \ 62 | -d jazzdd/alpine-flask -o gid 63 | ``` 64 | 65 | `-o gid` enables the docker option (docker will be installed into the container on the first run). GID is the docker group id of your host system. The container matches the gid of the docker group and adds the nginx user (this user is running nginx and uwsgi) to the docker group. 66 | 67 | Now you could use: 68 | 69 | ``` 70 | from subprocess import call 71 | call(["docker", "run", "-p 80" ,"-v /path/to/app/:/app", "-d jazzdd/alpine-flask"]) 72 | ``` 73 | to get another container running with the flask app. 74 | 75 | ## Debug mode 76 | 77 | Debug mode means the container doesn't use uwsgi and nginx but starts the flask app with a simple `python app.py`. So you can make use of the build-in flask development webserver and the automated reload system after editing the application. 78 | 79 | To start a container in debug mode use: 80 | 81 | ``` 82 | docker run --name flaskapp --restart=always \ 83 | -p 80:80 \ 84 | -v /path/to/app/:/app \ 85 | -d jazzdd/alpine-flask -d 86 | ``` 87 | 88 | Your app.py file must have a section similiar to the following example to start the app within the debug mode. 89 | 90 | ```python 91 | if __name__ == '__main__': 92 | app.run(host='0.0.0.0', port=80, debug=True) 93 | ``` 94 | 95 | To get the command line output of your app use `docker logs -f CONTAINER_ID/NAME`. 96 | -------------------------------------------------------------------------------- /app.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | plugins = /usr/lib/uwsgi/python 3 | chdir = /app 4 | module = app:app 5 | uid = nginx 6 | gid = nginx 7 | socket = /run/uwsgiApp.sock 8 | pidfile = /run/.pid 9 | processes = 4 10 | threads = 2 11 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ ! -f /debug0 ]; then 3 | if [ -e requirements_image.txt ]; then 4 | apk add --no-cache $(cat requirements_image.txt) 5 | fi 6 | 7 | if [ -e requirements.txt ]; then 8 | pip2 install -r requirements.txt 9 | fi 10 | 11 | touch /debug0 12 | 13 | while getopts 'hdo:' flag; do 14 | case "${flag}" in 15 | h) 16 | echo "options:" 17 | echo "-h show brief help" 18 | echo "-d debug mode, no nginx or uwsgi, direct start with 'python app.py'" 19 | echo "-o gid installs docker into the container, gid should be the docker group id of your docker server" 20 | exit 0 21 | ;; 22 | d) 23 | touch /debug1 24 | ;; 25 | o) 26 | apk add --no-cache docker shadow 27 | groupmod -g ${OPTARG} docker 28 | gpasswd -a nginx docker 29 | ;; 30 | *) 31 | break 32 | ;; 33 | esac 34 | done 35 | fi 36 | 37 | if [ -e /debug1 ]; then 38 | echo "Running app in debug mode!" 39 | python2 app.py 40 | else 41 | echo "Running app in production mode!" 42 | nginx && uwsgi --ini /app.ini 43 | fi 44 | -------------------------------------------------------------------------------- /nginx.conf: -------------------------------------------------------------------------------- 1 | user nginx; 2 | worker_processes 4; 3 | pid /run/nginx.pid; 4 | 5 | events { 6 | worker_connections 20000; 7 | } 8 | 9 | http { 10 | include mime.types; 11 | sendfile on; 12 | keepalive_timeout 65; 13 | gzip off; 14 | 15 | server { 16 | listen 80; 17 | access_log off; 18 | error_log off; 19 | 20 | location / { try_files $uri @flaskApp; } 21 | location @flaskApp { 22 | include uwsgi_params; 23 | uwsgi_pass unix:/run/uwsgiApp.sock; 24 | } 25 | } 26 | } 27 | --------------------------------------------------------------------------------