Dockerizing your first web app with python and flask
Tags: docker, python
Published: 2020-07-19 21:02:28

Second part of [how to measure covid-19 impact on Jitsi project with python and elasticsearch](https://dev.to/anajsana95/how-to-measure-covid-19-impact-on-jitsi-project-with-python-and-elasticsearch-154j). This time, my colleagues ([David](https://www.linkedin.com/in/david-dur%C3%A1n-prieto-86326b17a/), [Gerardo](https://www.linkedin.com/in/gerardoadrianaguirrevivar/)) and I ([Ana](https://www.linkedin.com/in/ana-jim%C3%A9nez-santamar%C3%ADa/)) built a web app with Python technology and Flask framework and dockerized it. Here we explain you how

# Docker architecture

First, we have to build a docker application with three containers:

* ElasticSearch image
* Kibana image
* Web app image

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/0fc1l36wew4xqcmll5ak.png)

For ElasticSearch and Kibana, we use pre-built images from **DockerHub** using 7.8.0 version. Web application uses a redis-alpine image.


> *Note: The reason why using alpine, is because this alternative is smaller and more resource efficient than traditional GNU/Linux distributions (such as Ubuntu)*

# Required files and configuration

You can get the required materials on [GitLab](https://gitlab.com/msdatascienceurjc/docker-jitsi-app). The image below shows the different files you will get by cloning the repo

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/mj5uq81ywtnzv85supi8.png)

### Docker-compose.yml structure

`docker-compose.yml` file shows the structure explained in previous section

```yml

version: '3'
services:
  web:
    build: .
  ports:
    - 5000:5000
  networks:
    - elastic
redis:
   image: "redis:alpine"
es01:
   image: docker.elastic.co/elasticsearch/elasticsearch:7.8.0
   container_name: es01
   environment:
      - node.name=es01
      - cluster.name=es-docker-cluster
      - discovery.type=single-node
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms1024m -Xmx1024m"
  ulimits:
    memlock:
        soft: -1
        hard: -1
    volumes:
      - data01:/usr/share/elasticsearch/data
    ports:
      - 9200:9200
    networks:
      - elastic
  kib01:
    image: docker.elastic.co/kibana/kibana:7.8.0
    container_name: kib01
    ports:
      - 5601:5601
    environment:
      ELASTICSEARCH_URL: http://es01:9200
      ELASTICSEARCH_HOSTS: http://es01:9200
    networks:
      - elastic
volumes:
  data01:
    driver: local
  data02:
    driver: local
  data03:
    driver: local
networks:
  elastic:
    driver: bridge

```
Let's take a look at the main tags stated at `docker-compose.yml`

* Ports: configures docker port with host machine port where docker runs. In this case, 5000, 5601 and 9200.

* Image: docker image that is downloaded for the required service

* Networks: this is named as 'elastic' in order to connect the three services

* Environment: configures environment variables essential to operate among services, such as RAM memory parameters. Within Kibana service, it is necessary to define the variables `ELASTICSEARCH_URL` and `ELASTICSEARCH_HOSTS`, in order to link it with the Elasticsearch service.

### Dockerfile configuration

`Dockerfile` has the required steps to configure the web application to link with our python script that extract and store the data in an Elasticsearch cluster, that at the same time imports `impact_dashboard.ndjson` on Kibana for previous visualization.

It runs on alpine distribution to copy the required folders to get the app running. Moreover, and thanks to `requirements.txt`, you can add all the dependencies that the python script needs.

```dockerfile
FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP jitsi-data.py
ENV FLASK_RUN_HOST 0.0.0.0
RUN apk add --no-cache git
RUN apk add --no-cache tk-dev
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
COPY mapping.json mapping.json
COPY templates templates
COPY impact_dashboard.ndjson impact_dashboard.ndjson
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run"]

```
# How to start containters

In order to start the application (with docker and docker-compose previously installed) open your terminal and execute the following command

```bash
$ docker-compose up
```
This will initiate the different commands stated in dockerfile and download the required docker images. Once that's finished, you can check that Elasticsearch (localhost:9200) and Kibana (localhost:5601) are succesfully running.

Now, it's time to go where python Flask application web app is located, using port `5000`

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/bdgpwjr7erskgbabf5jm.png)

Clicking on `start button` will initialize data extraction from Jitsi git data (check `jitsi-data.py` for more details) and will store such data to our ElasticSearch. Finally, it will import `impact_dashboard.ndjson` to our Kibana, allowing us to interactively play with the data.

Once the process is finished, the browser will show the next message:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/1sp3n4dv335v5fa8erp9.png)

Of course, we can see if our Elasticsearch index and Kibana dashboard have successfully being added to our instances:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/kjmu8sf90cjcxyzt3eoy.png)

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/uhymzlhkkknaf0m9k629.png)


By default the time filter is set to the last 15 minutes. You can use the Time Picker to change the time filter or select a specific time interval or time range in the histogram at the top of the page.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/atm4deo5nw6u92s6fwg4.png)

*et voilà* now you have a cool dashboard up and running to analyze how a pandemic can impact Jitsi software development activity.

# Bonus point: uploading a Docker image to Docker Hub

With a Docker Hub account, you can build an image where `dockerfile` is located. Simply type:

```
$ docker build -t dockerhubID/DockerHubreponame:imagetag .
```
Then, upload the image to your Docker Hub repo (you can create the repo using the Docker Hub UI

```
$ sudo docker push dockerhubID/DockerHubreponame:imagetag
```
Once the image is uploaded to Docker Hub, any user can use and run the app with the following docker-compose.yml

```yml
version: '3'
services:
  web:
    image: daviddp92/jitsi-data-extraction:1.0.0
    ports:
      - 5000:5000
    networks:
      - elastic
  es01:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.8.0
    container_name: es01
    environment:
      - node.name=es01
      - cluster.name=es-docker-cluster
      - discovery.type=single-node
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms1024m -Xmx1024m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - data01:/usr/share/elasticsearch/data
    ports:
      - 9200:9200
    networks:
      - elastic
  kib01:
    image: docker.elastic.co/kibana/kibana:7.8.0
    container_name: kib01
    ports:
      - 5601:5601
    environment:
      ELASTICSEARCH_URL: http://es01:9200
      ELASTICSEARCH_HOSTS: http://es01:9200
    networks:
      - elastic
volumes:
  data01:
    driver: local
  data02:
    driver: local
  data03:
    driver: local
networks:
  elastic:
    driver: bridge

```
## Closing thoughts

We have learned how to dockerize a web app with Python technology and Flask framework using docker-compose. We also saw how to use and run the application using Docker Hub images.

What do you think about this project? What should we improve? Feedback is more than welcome :)