Build and Deploy Flask REST API on Docker
Tags: flask, docker, python
Published: 2022-08-16 11:18:00

Docker is an OS level virtualization software platform that enables developers to develop, package, ship and run applications by using containers. Containers allow developers to package an application with dependencies and libraries. Docker containers not only make it easier to create, deploy and run applications but also makes you confident that your application will run on any machine regardless of the host machine's specifications.

In this section, we will explore the steps to dockerize your flask app.

## Getting Started

### Requirements
- python
- flask
- docker

### Step 1: Install docker
Download the docker installer from https://docs.docker.com/desktop. In this tutorial, we will be deploying the flask api on a windows machine. Download the windows installer and double-click on it to install.
Enable Hyper-V Windows Feature on the Configuration page.
Follow the installation process and after completion, click Close and restart your machine.
Sometimes, docker does not start automatically. To start the Docker tool, search docker on the search bar and select Docker Desktop from the search results.

> Docker needs **virtualization technology to be enabled from the BIOS** settings. If not then enable it. **Install Linux subsystems for windows** to start docker on your machine. Follow the link https://docs.microsoft.com/en-us/windows/wsl/install-manual#step-6---install-your-linux-distribution-of-choice to install it.

### Step 2: Install python and flask
### Install python
Python is a prerequisite for creating flask APIs. If not installed, install python3 from the official site [download]. Check the add to path option while installing it. You can also add it manually to the path in System / User variables.
![python path](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yy4tfppbnoi594uegqe2.png)

### Install flask
- Install virtual environment package, if not installed.
```
python -m pip install virtualenv
```
- Create a folder named app and open the command prompt in that folder.
- Create a virtual environment named venv.
```
python -m venv venv
```
- Switch to the virtual environment.
```
venv/Scripts/activate
```
- Install the flask package.
```
pip install flask
```

### Step 3: Create flask API
Create an API for providing book information using the flask package. Create a file named `app.py` under the current directory and add the following code to it.

```
import flask
from flask import request, jsonify
app = flask.Flask(__name__)
app.config["DEBUG"] = True
# Create some test data for our catalog in the form of a list of dictionaries.
books = [
    {
        "id": 1,
        "isbn":"9781593279509",
        "title":"Eloquent JavaScript, Third Edition",
        "subtitle":"A Modern Introduction to Programming",
        "author":"Marijn Haverbeke",
        "published":"2018-12-04T00:00:00.000Z",
        "publisher":"No Starch Press",
        "pages":472,
        "description":"JavaScript lies at the heart of almost every modern web application, from social apps like Twitter to browser-based game frameworks like Phaser and Babylon. Though simple for beginners to pick up and play with, JavaScript is a flexible, complex language that you can use to build full-scale applications.",
        "website":"http://eloquentjavascript.net/"
    },
    {
        "id": 2,
        "isbn":"9781491943533",
        "title":"Practical Modern JavaScript",
        "subtitle":"Dive into ES6 and the Future of JavaScript",
        "author":"Nicolás Bevacqua",
        "published":"2017-07-16T00:00:00.000Z",
        "publisher":"O'Reilly Media",
        "pages":334,
        "description":"To get the most out of modern JavaScript, you need learn the latest features of its parent specification, ECMAScript 6 (ES6). This book provides a highly practical look at ES6, without getting lost in the specification or its implementation details.",
        "website":"https://github.com/mjavascript/practical-modern-javascript"
    }
]
@app.route('/', methods=['GET'])
def home():
    return '''<h1>VLib - Online Library</h1>
                <p>A flask api implementation for book information.   </p>'''
@app.route('/api/v1/books/all', methods=['GET'])
def api_all():
    return jsonify(books)@app.route('/api/v1/books', methods=['GET'])
def api_id():
    if 'id' in request.args:
        id = int(request.args['id'])
    else:
        return "Error: No id field provided. Please specify an id."results = []
    for book in books:
        if book['id'] == id:
            results.append(book)return jsonify(results)
@app.route("/api/v1/books",  methods = ['POST'])
def api_insert():
    book = request.get_json()
    books.append(book)
    return "Success: Book information has been added."
@app.route("/api/v1/books/<id>", methods=["DELETE"])
def api_delete(id):
    for book in books:
        if book['id'] == int(id):
            books.remove(book)
    return "Success: Book information has been deleted."
if __name__ == '__main__':
    app.run(host="0.0.0.0", port=5000)
```
Explanation of the above code,

- Imported the flask package and create an app using `flask.Flask(__name__)` method.
- `books` dictionary contains book-related information.
- Created get, post, delete APIs to perform CRUD operations on books dictionary.
- `@app.route(‘/’, methods=[‘GET’])`, `@app.route(‘/api/v1/books/all’, methods=[‘GET’])` apis for reading, `@app.route(“/api/v1/books”, methods = [‘POST’])` api for inserting, `@app.route(“/api/v1/books/<id>”, methods=[“DELETE”])` for deleting the book information.
- Finally created a server in the localhost with port 5000 using `app.run(host=”0.0.0.0", port=5000)
`
### Step 4: Run and Test
Execute the app.py file in the terminal using the following command to run the flask app.
```
python app.py
```
![run flask api](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z835qy58wktn24qwm8ko.PNG)
Great! You have created your own flask API.

### Step 5: Generate requirements file
The `requirements.txt` file contains all package-related information used in the project. Create the `requirements.txt` file by executing the following command.
```
pip freeze > requirements.txt
```
### Step 6: Create dockerfile
Dockerfile is an essential document which contains instructions to build a Docker image.

Create a `dockerfile` under the current directory and add the following code to it,

```
FROM alpine:latest
RUN apk update
RUN apk add py-pip
RUN apk add --no-cache python3-dev 
RUN pip install --upgrade pip
WORKDIR /app
COPY . /app
RUN pip --no-cache-dir install -r requirements.txt
CMD ["python3", "app.py"]
```
- Dockerfile starts with `FROM` command to set the base image to alphine.
- `RUN` command is used to execute commands in the container. It is useful to perform system update, pip upgradation, and package installation.
- `WORKDIR` command creates a directory named app for the container.
- `COPY` command transfer files / folders to the file system of the container.
- `CMD` command runs the python command app.py in the container.

### Step 7: Build and run the docker image
- Build the docker image using the following command,
```
docker build -t flask-rest-api .
```
**flask-rest-api** is the image name(you can change if required).
![docker run](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6rqfskd4jydtowpe8yag.png)
- To list the docker images, use the following command,
```
docker images
```
![docker images](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r4im1fn70dqq7ume7tlj.PNG)
- Run the docker image using the following command,
```
docker run -d -p 5000:5000 flask-rest-api
```
![docker run](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cbpzpptf5nbbn27yn48g.PNG)
- To list the docker image status, use the following command,
```
docker ps -a
```
![docker ps a](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n0txzlwzxc3j3uvdbnrl.PNG)
- You can use the logs command to list the logs of a container by specifying the container id.
```
docker logs <CONTAINER ID OR CONTAINER NAME>
docker logs ebae5d67bff984937e1700eee05afd760e331923ac3be73c825ef1e49f8b6bee
```
![docker logs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kj9pd3b1dz4xstzgm2a7.PNG)
There you have it! Your own flask app in the docker container :)

Now you can test the APIs using a browser or postman.

![output 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gtnng6ckkls0dae7p3gr.PNG)
![output 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5tht6ggpbvsaytff19xq.PNG)
![output 3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/072a5hq03rsl0b7pyhpd.PNG)
![output 4](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pu33fr0xjnjomdgtlogc.PNG)
![output 5](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0nwpervhvdotngrovnq2.PNG)

### Step 8: Push and pull Docker images (optional)
GitHub is a platform to push and pull our codes. Similar to GitHub, we can push and pull Docker image onto Docker Hub. Docker Hub is an online platform to host, find, and share docker images.

In this section, we will push the newly created docker image onto Docker Hub.

- Login to Docker Hub using your credentials. If you don’t have one, create a new account using the link https://hub.docker.com/signup.
Click on create repository button to create a new repository.

![docker hub repository creation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9bhq8rf5ae84ua1bke9c.PNG)
- Provide a name and description for the repository. Set visibility to Public and click on the create button.

![docker hub repository creation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ts7lmewmrwzognxs4ca7.PNG)
- Login to the docker on your terminal using the following command,
```
docker login --username=<your-username>
```
- Tag your image with the repository. Find the docker image id using docker images command if required.
```
docker images
docker tag <your-image-id> <dockerhub-username>/<repo-name>:<tag>
```
- Push your image to the repo.
```
docker push <dockerhub-username>/<repo-name>
```
![docker push](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8949raow81hjppj53idp.PNG)
- Execute the following command to save the image as a tar file (if required),
```
docker save <repo-name> > <repo-name>.tar
```
- Execute the following command to load the docker image from the archived tar file (if required),
```
docker load — input <repo-name>.tar
```
You can also use the search option to search the docker images from docker hub and pull them using the pull command,
```
docker search <repo-name>
docker pull <dockerhub-username>/<repo-name>
```
![docker pull](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ynw9c9dy72ipa47z449.PNG)

Thanks for reading this article.

Thanks Gowri M Bhatt for reviewing the content.

If you enjoyed this article, please click on the heart button ♥ and share to help others find it!

The article is also available on [Medium](https://medium.com/@codemaker2016/build-and-deploy-flask-rest-api-on-docker-bc8d506b3549).

The full source code for this tutorial can be found here,

[GitHub - codemaker2015/flask-api-docker: Flask api containerization using docker](https://github.com/codemaker2015/flask-api-docker)