# Flask web app with Bulma frontend run on Docker with Prometheus metrics.

# Purpose
This post we sharing our experience building web app with Flask server backend and CSS Bulma frontend. The [source code](https://github.com/koperak/simpleapi) of application will be explained in detail needed to illustrate technical concept. 
The business concept is to have an application:
* web based and good looking - support modern CSS framework 👁 
* displaying host and network information - our business 💑 requirements
* easy to deploy and monitor - container based 📦 with easy metrics

## Assumptions
We asssume the you are avare of Prometheus metrics, know how to build and run Docker containers, and understand Flask framework.  

# Web application with Flask and Bulma CSS
While this is very simple application we can go via this step by step. You have to
```
git clone https://github.com/koperak/simpleapp.git && cd simpleapp
docker build . -t simpleapp
docker run -d -p 5000:5000 simpleapp
```

and point to `http://127.0.0.1:5000/` to see it in action. 

Let's go through the project structure:

```
|   .dockerignore
|   .gitignore
|   app.py
|   Dockerfile
|   README.md
|   requirements.txt
|
\---templates
        index.html
``` 
* `requirements.txt` file have Python requirements for application, they are latest version of  [Flask ](https://pypi.org/project/Flask/) and  [Prometheus library for Flask](https://github.com/rycus86/prometheus_flask_exporter)  

* `app.py` and `templates\index.html` are main files for simple Flask application, in this case it contains business logic and template for view. This is not optimal Flask application structure and you would like to avoid it in your production code. Instead apply for [best practices from Flask experts](http://alanpryorjr.com/2019-05-20-flask-api-example/).

So you are warned and I am going into the `app.py` file which have some crucial parts:

* initialization of templating for Flask and metrics for prometheus, which are dependencies described in `requirements.txt` file:

```
from flask import Flask, render_template
from prometheus_flask_exporter import PrometheusMetrics

app = Flask(__name__)
metrics = PrometheusMetrics(app)
```
* rendering `index.html` template with additional parameters and serving it on `/` path:

```
@app.route("/")
def index():
    return render_template('index.html', server_ip = server_ip, server_name = server_name)
```    

* simple logic to deliver business requirements:

```
import socket

try: 
    server_name = socket.gethostname() 
    server_ip = socket.gethostbyname(server_name) 
except: 
    server_name = "Unable to get Hostname"
    server_ip = "Unable to get IP"
```

[Jinja](https://jinja.palletsprojects.com/en/2.11.x/templates/) based template `index.html` file contains:

* main page for application with Bulma CSS styles included:

```
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.min.css">
```

* variables with some values that are coming from main application file, they are rendered as Jinja expressions having Bulma's `title` class :

```
<h1 class="title">
  {{ server_ip }} 
  {{ server_name }}
</h1>
```

Our sample application is packed into Docker container which instruct Docker image building command `docker build . -t sampleapp` to do the following:

* start from base image which is required by Flask application `FROM python:3.9-alpine`

* create and go into `code` directory inside container where our source code will be located by `COPY . /code` 

* set environment variables for Flask application if you want to know more please study Flask documentation

* installing required libraries `RUN pip install -r /code/requirements.txt`

* `EXPOSE 5000` instruct other users of this container image that we are exposing some service on HTTP port 5000  

* finaly previously installed `flask` library is `run`  

And there are some additional files:
* `.dockerignore` contains files and directories we don't want to be included in out container, usually those are secrets, logs or workspace specific directories.

* `.gitignore` contains files and dirs we don't want track with source control system for example secrets, binaries and other compilates, it is shared from Python project to project so contains quite a lot files.

# Summary
When you run container and browse to `http://127.0.0.1:5000/` you will see nice looking web application which supports our business 💑 users. But there is also one more path `http://127.0.0.1:5000/metrics` which deliver expected monitoring 🔦 functionality. 

