Published on 2024-02-24
Flask DockerOne of the issues we often encounter during software development is that our solution works in the development environment, but when deploy to the production environment, it miraculously stops working! Docker provides a consistent environment across development, testing, and production environments
Docker is a name given to the container/package/image which contains the source code and its dependencies i.e. code, runtime, system tools, system libraries, binaries, settings and even operation system), thereby, providing the consistent environment across development, testing and production environments.
Docker runs on the Docker Engine which enables containerized applications to run consistently on any infrastructures solving “dependency hell”. When running a container, it uses an isolated file system (Dockerfile). This custom filesystem is provided by a container image. Since the image contains the container’s filesystem, it must include everything needed to run the application – all dependencies, configurations, scripts, binaries, etc. The image also contains other configuration for the container such as environment variables, a default command to run and other metadata.
We will look at how we can package our application to an image with Docker and then host it onto Docker Hub.
Ok, now, assuming we are packaging our Flask application, the first step is
Create a Dockerfile listing the commands for installation of code dependencies at the root folder of the Flask Application
# Dockerfile is a filesystem with a list of commands written in Docker syntax to install dependencies for our app to run
# this is a combination of Docker Langauge and linux command
# We can either start creating an OS image from scratch (a base image) or use a parent image (From xxx).
FROM python:3.10-slim-buster
# set the working directory is /app (create the directory if not exist in the image)
WORKDIR /app
# copy requirements.txt file into our working directory /app in the image
COPY requirements.txt requirements.txt
# install the python modules in the requirements.txt
RUN pip3 install -r requirements.txt
# add the source code into the image
COPY . .
# which port are we using from the container?
EXPOSE 8000
# what happens when our image is executed inside a container
# CMD [ "python3", "-m" , "flask", "run", "--host=0.0.0.0", "--port=8000"]
# run flask with gunicorn in front
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "wsgi:app"]
In the command line, create an image with Docker CLI from dockerfile (by cd-ing to the directory where dockerfile exists). That's why we have '.' in our command line.
$ docker build -t <image-name> .
Like me, if you are running your docker in Mac with Apple Silicon (i.e. Mac with M1/2 Chips), when we build an image with docker command above, the image built is targeted for ARM64.
This poses a problem when we are deploying the image to the Operating System with Intel processor (AMD64). Since our image is built for ARM64 architecture, any operation system running on Intel processor will not be able to execute our image.
We can check the architecture of our computer by opening the Terminal application, and running the following command:
arch
There are two solutions to this:# Build for AMD64
docker build --platform=linux/amd64 -t <image-name>-amd64 .
(B) Update your Dockerfile
FROM --platform=linux/amd64 BASE_IMAGE:VERSION
$ docker run -dp 8000:8000 <image-name>
Above command runs a Docker container based on the specified image That's it! Now, flask application is run on the container port: 8000 and container will run on the host machine’s on port 8000. When we are running the docker image locally, we are hosting the docker container locally.
Note: CLI to remove the Docker container and image
$ docker ps
$ docker stop
Docker Hub So far, we have only been working in our local machine. Ultimately, we want to host our containerized application into a cloud service. The very first step is to push the image we created to Docker Hub. We can publish it privately or in public mode. Later on, our choice of Cloud Service will download the image from Docker Hub and host the web application on their cloud.
First, head to Docker Hub and register an account if you have not done it yet. We will push our image to Docker Hub from CLI.
$ docker login
Next, we need to tag our image with our Docker username/id. Why? To give a unique name.
$ docker tag <image-name> <dockerhub-username>/<image-name>
Then, we push the image to Docker Hub
$ docker push <dockerhub-username>/<image-name>
In next post, we will look at how we can deployed our containerized image to cloud service.