DEV Community

Cover image for Using docker-compose to build a simple flask api
Alisson Zampietro
Alisson Zampietro

Posted on • Updated on

Using docker-compose to build a simple flask api

Today, i waked up with a great idea: Learn how to build a docker-compose from scratch.

Actually, on my linux machine, i don't have any development environment prepared to run something, because i've thinking about a big goal, that is run everything on docker. Yeap, i don't even wanna install any package manager. I don't have experience working with python, but i wanna use it to build my first environment.

If you have no idea what docker is, i recommend watch this video and this one that will give an overview of how docker works.

For installing the Docker follow the instructions and this one to install docker-compose.

What's docker compose?

In short, docker-compose works as a manager of docker containers. Let's supose that you are creating a web app where you are going to split it in 3 differents containers (front-end, api, database). This way, you may create a dockerfile for each environment individually.

What's our challenge?

We're going to create a python api using flask. I'm not used to develop in python, i've studied some features and you can checkout this on my github.

Hands-on

In this section i'm going to explain the structure, and our python application associated files.

Let's create our directory structure:

 - api-nasa/
    - requirements.txt
    - app.py
    - Dockerfile
 - docker-compose.yml
Enter fullscreen mode Exit fullscreen mode

The file api-nasa/requirements.txt represents the list of external libraries that is going to be used, in our case we only need the flask library:

flask
Enter fullscreen mode Exit fullscreen mode

I don't want to dig in details about our api-nasa/app.py implementation for now, for that, i'm just creating a basic endpoint and you can see some details in the code's comments:

import os
from flask import Flask, jsonify
app = Flask(__name__)

#we define the route /
@app.route('/')
def welcome():
    # return a json
    return jsonify({'status': 'api working'})

if __name__ == '__main__':
    #define the localhost ip and the port that is going to be used
    # in some future article, we are going to use an env variable instead a hardcoded port 
    app.run(host='0.0.0.0', port=os.getenv('PORT'))
Enter fullscreen mode Exit fullscreen mode

Dockerhub

It's an image's repository, where you can register your own image. Let's say that you want to Download a image from Node JS, you only need to run the following command: docker pull node. After that,to check if image is there, just run docker images.

Dockerfile

Let's see the Dockerfile as a recipe, where from that, it's going to be built the os image.

FROM python:3.6
RUN mkdir /usr/src/app/
COPY . /usr/src/app/
WORKDIR /usr/src/app/
EXPOSE 5000
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
Enter fullscreen mode Exit fullscreen mode

Let's check each line:

FROM python:3.6
Enter fullscreen mode Exit fullscreen mode

We set the image that we wanna use, in our case lets
use the python in version 3.6. If the image is not downloaded in your computer (open the terminal and type docker images), it's going to search and download on DockerHub. This part is really interesting, because this dockerfile, won't generate a container, but an image, and you can upload to docker hub to use in the future.


RUN mkdir /usr/src/app/
Enter fullscreen mode Exit fullscreen mode

Run is used to run operations inside the container, for sample, if you want to install any additional program, you just use the command RUN apt-get install whatever -y. In this case, we're creating the folder where our application will run in the container.


COPY . /usr/src/app/
Enter fullscreen mode Exit fullscreen mode

It's going to copy everything from ./ local directory and move to /usr/src/app/ host directory.


WORKDIR /usr/src/app/
Enter fullscreen mode Exit fullscreen mode

It sets the path where the CMD and the RUN commands will run.


EXPOSE 5000
Enter fullscreen mode Exit fullscreen mode

Exposes the port 5000 of the container to be external accessed.


RUN pip install -r requirements.txt
Enter fullscreen mode Exit fullscreen mode

Executes when the image is been generated. It works for when you want to install something in the image.


CMD ["python", "app.py"]
Enter fullscreen mode Exit fullscreen mode

It sets the command that's going to run when the container starts. We've defined the startup of our application. Maybe you can ask: Why not put this command in the previous RUN? It's because this command only runs when container start, let's say that it's the entrypoint of container.


docker-compose

Here where the magic start to happens. We're going to dig in details about implementation. How you can see in the file, we have identation because we're using YAML files, so, if the instruction have some properties then the bottom line is more indented.

version: '3.8'
services: 
    api-service:
        build: ./api-nasa/
        volumes: 
            - ./api-nasa/:/usr/src/app/
        ports: 
            - 5000:5000
        environment: 
            PORT: 5000
            FLASK_DEBUG: 1
Enter fullscreen mode Exit fullscreen mode

Let's check each line:

version: '3'
Enter fullscreen mode Exit fullscreen mode

here you define the version of docker-compose that you're using. Actually the current is the 3.


    api-service:
Enter fullscreen mode Exit fullscreen mode

It's our api service.


        build: ./api-nasa/
Enter fullscreen mode Exit fullscreen mode

In this section, we say to docker-compose the path where our Dockerfile is.


        volumes: 
            - ./api-nasa/:/usr/src/app/
Enter fullscreen mode Exit fullscreen mode

Volumes are the way that we sync the files in our local computer to our containers. We can define volumes in Dockerfiles but only if you're handling container straight, but,how the handler of our container is docker-compose, we are defining them here.


        ports: 
            - 5000:5000
Enter fullscreen mode Exit fullscreen mode

We've talked about PORTS in Dockerfile, but here we can set a port on our localhost where you can access the container. Really cool, not? Basically we are saying: "Listen the port 5000 in our container and set the port 5000 to your localhost".


        environment: 
            PORT: 5000
            FLASK_DEBUG: 1
Enter fullscreen mode Exit fullscreen mode

It's really interesing, you can define environment variables and get them in the language that you're going to use. You can checkout in the python file api-nasa/app.py the code snippet os.getenv('PORT').


After everything is ready, let's run our docker-compose file.

    docker-compose up
Enter fullscreen mode Exit fullscreen mode

This should be the result:

Output docker-compose

To check if it's working, acess the url http://localhost:5000 in your browser.

You can checkout the project on my github. See you folks.

Top comments (0)