Dockerize Python Flask Web Application

Dockerize Python Flask Web Application

Task

  • Create a 'Dockerfile' for a simple web application (e.g. a Node.js or Python app)

  • Build the image using the Dockerfile and run the container

  • Verify that the application is working as expected by accessing it in a web browser

  • Push the image to a public or private repository (e.g. Docker Hub).


How to Set Up the Project?

Requirements

  • Install Git

  • Install Docker engine

Clone source code from GitHub

  • Create VM or EC2 instance for project.

  • Update repository using apt update .

File Structure of Source code,

linux$ sudo apt update
linux$ mkdir projects && cd projects
linux$ mkdir python && cd python

Now, clone GitHub repository,

projects/python$ git clone git@github.com:ojasjawale/flask-app.git

shuhari@debian:~/projects/python/flask-app$ tree .
.
├── app.py
├── README.md
├── requirements.txt
├── static
│   └── css
│       └── styles.css
└── templates
    ├── api_response.html
    └── index.html

3 directories, 6 files

Now, Let's create Dockerfile for our application.

Here is Dockerfile,

# Use the official Python 3.11 image based on Alpine
FROM python:3.11-alpine

# Set the working directory in the container
WORKDIR /app

# Copy the source code into the container
COPY . /app

# Install any needed packages specified in requirements.txt
RUN pip install -r requirements.txt

# Run app
CMD ["python", "app.py"]

Breaking down the Dockerfile,

  • This line sets the base image to Python 3.11 on Alpine Linux, a lightweight distribution known for its small footprint.
# Use the official Python 3.11 image based on Alpine
FROM python:3.11-alpine
  • Sets the working directory inside the container to /app. Basically this directory will have all source code copied from local to container.
# Set the working directory in the container
WORKDIR /app
  • Copy all source code from local system to container environment.
# Copy the source code into the container
COPY . /app
  • Installs the Python dependencies listed in requirements.txt without caching to ensure the latest versions are fetched.
# Install any needed packages specified in requirements.txt
RUN pip install -r requirements.txt
  • Specifies the command to run when the container starts, launching the Flask application.
# Run app
CMD ["python", "app.py"]


Build an Docker image from Dockerfile

  • Building a Docker image is a crucial step in containerizing your Flask application.

  • It involves packaging your application, along with its dependencies, into a single, portable image.

  • To build the Docker image, open a terminal and navigate to the directory containing your Dockerfile and application code. Execute the following command,

projects/python/flask-app$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

projects/python/flask-app$ docker build -t flask-app:v1 .
Sending build context to Docker daemon  67.58kB
Step 1/5 : FROM python:3.11-alpine
3.11-alpine: Pulling from library/python
ec99f8b99825: Pull complete
a0aab5935990: Pull complete
0017c34ace6c: Pull complete
704141445f22: Pull complete
7d353c5632ce: Pull complete
Digest: sha256:eb8afe385f10ccc9da8378e8712fea8b26f4ed009648f8afea4518836d8b3ed3
Status: Downloaded newer image for python:3.11-alpine
 ---> 955947f2ffec
Step 2/5 : WORKDIR /app
 ---> Running in e4d530eca3f2
Removing intermediate container e4d530eca3f2
 ---> 5b75e87e74f8
Step 3/5 : COPY . /app
 ---> c8ed1a5c8154
Step 4/5 : RUN pip install -r requirements.txt
 ---> Running in 371f833bae6b
Collecting Flask==2.1.1 (from -r requirements.txt (line 1))
  Downloading Flask-2.1.1-py3-none-any.whl.metadata (3.9 kB)
Collecting Werkzeug==2.2.2 (from -r requirements.txt (line 2))
  Downloading Werkzeug-2.2.2-py3-none-any.whl.metadata (4.4 kB)
Collecting Jinja2>=3.0 (from Flask==2.1.1->-r requirements.txt (line 1))
  Downloading jinja2-3.1.4-py3-none-any.whl.metadata (2.6 kB)
Collecting itsdangerous>=2.0 (from Flask==2.1.1->-r requirements.txt (line 1))
  Downloading itsdangerous-2.2.0-py3-none-any.whl.metadata (1.9 kB)
Collecting click>=8.0 (from Flask==2.1.1->-r requirements.txt (line 1))
  Downloading click-8.1.7-py3-none-any.whl.metadata (3.0 kB)
Collecting MarkupSafe>=2.1.1 (from Werkzeug==2.2.2->-r requirements.txt (line 2))
  Downloading MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl.metadata (3.0 kB)
Downloading Flask-2.1.1-py3-none-any.whl (95 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 95.2/95.2 kB 6.5 MB/s eta 0:00:00
Downloading Werkzeug-2.2.2-py3-none-any.whl (232 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 232.7/232.7 kB 12.1 MB/s eta 0:00:00
Downloading click-8.1.7-py3-none-any.whl (97 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 97.9/97.9 kB 6.1 MB/s eta 0:00:00
Downloading itsdangerous-2.2.0-py3-none-any.whl (16 kB)
Downloading jinja2-3.1.4-py3-none-any.whl (133 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 133.3/133.3 kB 7.4 MB/s eta 0:00:00
Downloading MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl (33 kB)
Installing collected packages: MarkupSafe, itsdangerous, click, Werkzeug, Jinja2, Flask
Successfully installed Flask-2.1.1 Jinja2-3.1.4 MarkupSafe-2.1.5 Werkzeug-2.2.2 click-8.1.7 itsdangerous-2.2.0
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv

[notice] A new release of pip is available: 24.0 -> 24.1.2
[notice] To update, run: pip install --upgrade pip
Removing intermediate container 371f833bae6b
 ---> c80d32562bb2
Step 5/5 : CMD ["python", "app.py"]
 ---> Running in b8233c6e8082
Removing intermediate container b8233c6e8082
 ---> 801ca0af339a
Successfully built 801ca0af339a
Successfully tagged flask-app:v1

projects/python/flask-app$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
flask-app           v1                  801ca0af339a        About a minute ago   74.5MB
python              3.11-alpine         955947f2ffec        12 days ago          58.2MB

Breakdown of docker build command,

  • docker build : This command is use to create docker image from Dockerfile.

  • -t : This flag allows us to specify tag to an image

  • flask-app:v1 - This is an image name and tag specified

  • . (dot) : Means location where Dockerfile is located i.e curent location


Run an Docker image as an container

  • Once you have successfully built your Docker image, the next step is to run it as a container.

  • This involves creating an instance of your image, which is a runnable environment for your Flask application.

  • Execute the following command in the terminal:

projects/python/flask-app$ docker run --name flask -p 5000:5000 flask-app:v1
 * Serving Flask app 'app' (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:5000
 * Running on http://172.17.0.2:5000
Press CTRL+C to quit
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 120-061-676

Breakdown of docker run command,

  • docker run : Initiates the container creation process

  • -d : Run container in detached mode i.e in background mode

  • --name : Specify container name

  • -p : Specify port to expose from host port and container port. Here, 5000:5000(Host port : Container port).

  • flask-app:v1 - Mention image name form which container will be created.


Trying to run flask application on browser

Visit <IP_of_your_server>:host_port. To get our flask application running.

i.e in our case, http://192.168.80.141:5000.

API endpoint logs,


How to stop and delete the container and image

To delete the container first stop said container and then delete,

projects/python/flask-app$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
ce43bbb24722        flask-app:v1        "python app.py"     9 minutes ago       Exited (0) 10 seconds ago                       flask

To delete image,

projects/python/flask-app$ docker rmi flask-app
Untagged: flask-app:v1
Deleted: sha256:801ca0af339ad55982baedd94cdb89bab670dc27b5cb82d32375ebf7fe2ab814
Deleted: sha256:c80d32562bb25729a87988cf7d373db4dee7669915ef9e567b147dff376eb40a
Deleted: sha256:26f833163e785cf17cdc76ded632ade5075192967dc7d8ed562338219b5cc289
Deleted: sha256:c8ed1a5c81542d1b82e777eca103eb6b3277e46c57e3bfcace80a790ee8b09e1
Deleted: sha256:228ee1ddf222570e53bc1385e56ad1e31465a7c504f856a1682b54f88a7af436
Deleted: sha256:5b75e87e74f8e11d4490b34b17460878b7b1dee06931a822e97a3ce5b8d8d5ac
Deleted: sha256:f06e4fa8099a1f23ec3c121c4d1a391afb430c3d86fd1655942cb822e31528fb


Connect with Me

LinkedIn | GitHub

Follow me for more amazing content :)