├── .gitignore ├── Dockerfile ├── Makefile ├── README.md ├── Vagrantfile ├── app └── wsgi.py ├── conf ├── app_nginx.conf ├── app_supervisor.conf ├── app_uwsgi.ini └── uwsgi_params ├── scripts ├── fix-boot2docker-dns.sh ├── get-boot2docker-ip.sh └── make-boot2docker-cli.sh └── vagrant └── Vagrantfile /.gitignore: -------------------------------------------------------------------------------- 1 | boot2docker 2 | boot2docker-cli/ 3 | .vagrant/ 4 | .container-id 5 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # DOCKER-VERSION 0.11.1 2 | 3 | FROM ubuntu:trusty 4 | MAINTAINER Maximilian Fellner 5 | 6 | RUN apt-get install -y python3 python3-pip 7 | RUN apt-get install -y nginx supervisor 8 | RUN pip3 install uwsgi Flask 9 | 10 | ADD ./app /docker/app 11 | ADD ./conf /docker/conf 12 | RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf 13 | RUN rm /etc/nginx/sites-enabled/default 14 | RUN ln -s /docker/conf/app_nginx.conf /etc/nginx/sites-enabled/ 15 | RUN ln -s /docker/conf/app_supervisor.conf /etc/supervisor/conf.d/ 16 | 17 | EXPOSE 80 18 | CMD ["supervisord", "-n"] 19 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | CONTAINER_NAME = flask-app 3 | PUBLISH_PORT = 8000:80 4 | DOCKER_ERROR := $(shell docker info 2>&1 | grep -i 'cannot connect') 5 | OS := $(shell uname) 6 | 7 | 8 | all: setup clean build run 9 | @echo "done" 10 | 11 | 12 | .PHONY: setup 13 | setup: 14 | ifneq ($(DOCKER_ERROR),) 15 | ifeq ($(OS),Darwin) 16 | @echo "make boot2docker-cli" 17 | @./scripts/make-boot2docker-cli.sh 18 | @if [[ ! -d ~/.boot2docker ]]; \ 19 | then \ 20 | ./boot2docker init; \ 21 | fi; 22 | @./boot2docker start 23 | @./scripts/fix-boot2docker-dns.sh 24 | @echo "boot2docker-cli setup done" 25 | else 26 | @echo $(DOCKER_ERROR) 27 | endif 28 | else 29 | @echo "docker is running" 30 | endif 31 | 32 | 33 | .PHONY: clean 34 | clean: 35 | @if [[ -f .container-id ]]; \ 36 | then \ 37 | echo "stopping docker container"; \ 38 | cat .container-id | xargs docker stop; \ 39 | rm .container-id; \ 40 | fi; 41 | @docker ps -a -q | xargs docker rm 42 | @echo "removing old docker images" 43 | @docker images --no-trunc | grep 'none' | awk '{print $3}' | xargs docker rmi 44 | 45 | 46 | .PHONY: build 47 | build: clean 48 | @echo "building docker container" 49 | @docker build -t $(CONTAINER_NAME) . 50 | 51 | 52 | .PHONY: run 53 | run: build 54 | @echo "starting docker container" 55 | @CONTAINER_ID="$(shell docker run -p $(PUBLISH_PORT) -d $(CONTAINER_NAME))"; \ 56 | echo $$CONTAINER_ID >> .container-id; 57 | 58 | 59 | .PHONY: test 60 | test: 61 | @if [ -a boot2docker ] && [[ -n `./boot2docker status | grep -o running` ]]; \ 62 | then \ 63 | echo `./scripts/get-boot2docker-ip.sh`:8000 | xargs curl; \ 64 | elif [ -d .vagrant ] && [[ -n `vagrant status 2>/dev/null | grep -o 'running (docker)'` ]]; \ 65 | then \ 66 | curl localhost:8000; \ 67 | else \ 68 | curl localhost:80; \ 69 | fi; 70 | 71 | 72 | .PHONY: vagrant 73 | vagrant: 74 | @vagrant up --provider=docker 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Docker Flask Example 2 | 3 | This is a simple example project that shows how to run a simple [Flask](http://flask.pocoo.org) application inside a Docker container. 4 | 5 | ##### Docker & Boot2Docker (OS X) 6 | 7 | ```bash 8 | make run 9 | ``` 10 | 11 | Builds and runs the project directly as a Docker container. This should potentially also work on Linux as long as Docker is installed and running. 12 | 13 | If you're on **OS X** and a Docker instance is not already running somehow, this will install and use [boot2docker-cli](https://github.com/boot2docker/boot2docker-cli) in the current directory (requires Go). 14 | 15 | ```bash 16 | make clean 17 | ``` 18 | 19 | Stops and removes the container and any remaining garbage. 20 | 21 | ##### Vagrant & Docker 22 | 23 | ```bash 24 | make vagrant 25 | ``` 26 | 27 | Runs the project via the Vagrant docker provider. In order to use port forwarding, a custom box (declared in `vagrant/`) is being used. 28 | 29 | Please note that the other Makefile targets `setup`, `clean`, `build` and `run` are reserved for using Docker *directly*. Refer to the [Vagrant docs](https://docs.vagrantup.com/v2/docker/index.html) for information on how to interact with Docker. 30 | 31 | ##### Test the connection 32 | 33 | ```bash 34 | make test 35 | ``` 36 | 37 | This just `curl`s the *Boot2Docker* VM or the *Vagrant* VM. When using Boot2Docker a script is used to find out the ip address of the VM. With Vagrant the target is simply *localhost*. 38 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | VAGRANTFILE_API_VERSION = "2" 5 | 6 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| 7 | config.vm.provider "docker" do |d| 8 | d.build_dir = "." 9 | d.ports = ["80:80"] 10 | d.vagrant_vagrantfile = "vagrant/Vagrantfile" 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /app/wsgi.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | app = Flask(__name__) 4 | 5 | @app.route('/') 6 | def hello_world(): 7 | return 'Hello, Flask World!\n' 8 | 9 | if __name__ == '__main__': 10 | app.run('0.0.0.0', debug=True) 11 | -------------------------------------------------------------------------------- /conf/app_nginx.conf: -------------------------------------------------------------------------------- 1 | upstream flaskapp { 2 | server unix:/docker/conf/flaskapp.sock; 3 | } 4 | 5 | server { 6 | listen 80 default_server; 7 | charset utf-8; 8 | 9 | location /static { 10 | alias /docker/app/static; 11 | } 12 | 13 | location / { 14 | uwsgi_pass flaskapp; 15 | include /docker/conf/uwsgi_params; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /conf/app_supervisor.conf: -------------------------------------------------------------------------------- 1 | [program:flaskapp] 2 | command = uwsgi --ini /docker/conf/app_uwsgi.ini 3 | 4 | [program:nginx] 5 | command = service nginx restart 6 | -------------------------------------------------------------------------------- /conf/app_uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | chdir = /docker/app/ 3 | module = wsgi:app 4 | 5 | master = true 6 | processes = 4 7 | socket = /docker/conf/flaskapp.sock 8 | chmod-socket = 666 9 | -------------------------------------------------------------------------------- /conf/uwsgi_params: -------------------------------------------------------------------------------- 1 | 2 | uwsgi_param QUERY_STRING $query_string; 3 | uwsgi_param REQUEST_METHOD $request_method; 4 | uwsgi_param CONTENT_TYPE $content_type; 5 | uwsgi_param CONTENT_LENGTH $content_length; 6 | 7 | uwsgi_param REQUEST_URI $request_uri; 8 | uwsgi_param PATH_INFO $document_uri; 9 | uwsgi_param DOCUMENT_ROOT $document_root; 10 | uwsgi_param SERVER_PROTOCOL $server_protocol; 11 | uwsgi_param HTTPS $https if_not_empty; 12 | 13 | uwsgi_param REMOTE_ADDR $remote_addr; 14 | uwsgi_param REMOTE_PORT $remote_port; 15 | uwsgi_param SERVER_PORT $server_port; 16 | uwsgi_param SERVER_NAME $server_name; 17 | -------------------------------------------------------------------------------- /scripts/fix-boot2docker-dns.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -a $PWD/boot2docker ]; 4 | then 5 | BOOT2DOCKER_BIN=$PWD/boot2docker 6 | elif [ -a $PWD/../boot2docker ]; 7 | then 8 | BOOT2DOCKER_BIN=$PWD/../boot2docker 9 | else 10 | echo "boot2docker not found" 11 | exit -1 12 | fi 13 | 14 | if [ `./boot2docker status` != "running" ]; 15 | then 16 | echo "boot2docker is not running" 17 | exit -1 18 | fi 19 | 20 | # Fix issue https://github.com/boot2docker/boot2docker-cli/issues/102 21 | ${BOOT2DOCKER_BIN} ssh 2>/dev/null "echo 'nameserver 8.8.8.8' > /etc/resolv.conf && cat /etc/resolv.conf && exit" 22 | -------------------------------------------------------------------------------- /scripts/get-boot2docker-ip.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -a $PWD/boot2docker ]; 4 | then 5 | BOOT2DOCKER_BIN=$PWD/boot2docker 6 | elif [ -a $PWD/../boot2docker ]; 7 | then 8 | BOOT2DOCKER_BIN=$PWD/../boot2docker 9 | else 10 | echo "boot2docker not found" 11 | exit -1 12 | fi 13 | 14 | if [ `./boot2docker status` != "running" ]; 15 | then 16 | echo "boot2docker is not running" 17 | exit -1 18 | fi 19 | 20 | echo `${BOOT2DOCKER_BIN} ssh 2>/dev/null ip addr show eth1 | grep -o -E '\d+\.\d+\.\d+\.\d+' | head -1 && exit` 21 | -------------------------------------------------------------------------------- /scripts/make-boot2docker-cli.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | PLATFORM=darwin 4 | 5 | ROOT_DIR=`pwd` 6 | SRC_DIR=src/github.com/boot2docker/boot2docker-cli/ 7 | export GOPATH=${ROOT_DIR}/boot2docker-cli/ 8 | 9 | if hash go 2>/dev/null; then 10 | echo "Downloading/updating boot2docker-cli..." 11 | go get -u github.com/boot2docker/boot2docker-cli 12 | cd ${GOPATH}${SRC_DIR} 13 | make clean 14 | make ${PLATFORM} 15 | ln -sf `pwd`/boot2docker*${PLATFORM}* ${ROOT_DIR}/boot2docker 16 | echo "Successfully built boot2docker-cli. Run with './boot2docker'" 17 | else 18 | echo "Error, Go not installed. Install with 'brew install go'" 19 | exit -1 20 | fi 21 | -------------------------------------------------------------------------------- /vagrant/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | VAGRANTFILE_API_VERSION = "2" 5 | 6 | # Custom docker host VM http://vimeo.com/93180496 7 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| 8 | config.vm.box = "trusty" 9 | config.vm.box_url = "http://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box" 10 | # forwarding port for docker container 11 | config.vm.network :forwarded_port, guest: 80, host: 8000 12 | config.vm.provision "docker" 13 | # kill all open ssh connections, forcing vagrant to relog 14 | config.vm.provision "shell", inline: "ps aux | grep 'sshd:' | awk '{print $2}' | xargs kill" 15 | end 16 | --------------------------------------------------------------------------------