Docker + Flask + Vue + Nginx - deployment and development in one package (1)
Tags: flask, docker, nginx
Published: 2020-04-10 20:17:21

### Building a minimalist Flask + uWSGI + Vue.js + Nginx app
with docker deployment


#### keep it to a good practice as possible.


#Chapter 1. Backend (Flask + uWSGI)

* First, establish a virtual environment use pipenv.

```
mkdir backend

pipenv shell`

pipenv install flask, uWSGI
```

* Second, create a bare minimal flask app named as `app.py`

```
from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'

if __name__ == "__main__":
    app.run(host='0.0.0.0')

```


* Third, create a `wsgi.py` 
```
from app import app

if __name__ == "__main__":
    app.run()
```

* Lastly, create a `app.ini` file for uWSGI configs
```
[uwsgi]
# the module itself, by referring to the wsgi.py file minus the extension, and the callable within the file, app:
module = wsgi:app

# Enable hot reload!
py-autoreload = 1

# Nginx to handle actual client connections, which will then pass requests to uWSGI. 
socket = :8080


master = true
processes = 4
threads = 2

#  giving the Nginx group ownership of the uWSGI process later on, 
#  so we need to make sure the group owner of the socket can read information from it and write to it.
chmod-socket = 660

# clean up the socket when the process stops by adding the vacuum option:
vacuum = true
die-on-term = true
```

* After all of this, our python backend is ready, create a requirements.txt by 

```
pipenv lock -r > requirements.txt
```

* Now we just need to create a docker file, which will copy files and then install necessary libraries (as outlined in requirements.txt) and get our uWSGI server up and running.

```
# use python container image
From python:3.6-stretch

# set the working directory of the image filesystem 
WORKDIR /backend

# copy current directory to the working directory 
ADD . /backend

# Install the python dependencies
RUN pip install -r requirements.txt

# start the uWSGI
CMD ["uwsgi", "app.ini"]

```

In our backend folder, we should have these files now:
```
app.ini
app.py
Dockerfile
Pipfile
requirements.txt
wsgi.py
```




#Chapter 3. Deployment (nginx)
* ### All we need to do is to re-direct request from outside to our uWSGI server in container. Luckily we can directly access to them using the image name.

for more details: http://nginx.org/en/docs/beginners_guide.html

The nginx listen to 80 port and direct calls to different locations such as "/diary" to different internal ports. (flask: 8080 in this case) 


```
server {

    listen 80;

    location / {
        include uwsgi_params;
        uwsgi_pass flask:8080;
    }
}
```

* Then, the Dockerfile

```
FROM nginx

# remove the default conf
RUN rm /etc/nginx/conf.d/default.conf

#  copy the nginx.conf in our filesystem into the image filesystem
COPY nginx.conf /etc/nginx/conf.d
```


# Chapter 4: docker-compose to connect all containers
 All the containers are in a virtual lan environment.

* go to the root folder of the project, now you should have following folders

```
backend/
frontend/
database/
nginx/
```

* Create a new file called `docker-compose.yml`



```
# check your version: https://docs.docker.com/compose/compose-file/
version: "3.7"


services:
# first container
    backend:
        # look for dockerfile and build the container
        build: ./backend
        container_name:  backend
        restart: always
        # set enviornemt variables
        environment: 
            - APP_NAME=FlaskApp
        #  mount the volumes so we can change code and hot reload
        volumes:
            - './backend:/backend'
        #  expose port on the container, only to other containers
        expose:
            - 8080
        
    nginx:
        build: ./nginx
        container_name:  nginx
        restart: always
        # port allows the host machine to link to container
        # pass 80 from host machine to 80 of the image filesystem
        ports:
            - "80:80"
```
* NOTE: we added a volumes here that allows future hot-reload to happen. (together with the uWSGI's py-autoreload)

* NOTE: The difference about ports and expose: 
expose allow communication between multiple containers
ports map one of the container port to the host machine port (the real internet)