Bootstrap FreeKB - Flask - Install meinheld gunicorn Flask on Docker
Flask - Install meinheld gunicorn Flask on Docker

Updated:   |  Flask articles

A Docker image contains the code used to create a Docker container, such as creating a Nginx web server, or a mySQL server, or a home grown app, and the list goes on. In this way, an image is like a template used to create a container. An image is kind of like a virtual machine, but much more light weight, using significantly less storage a memory (containers are usually megabytes in size).

 

There are two Docker repo's that are commonly used for Flask:

According to https://hub.docker.com/r/tiangolo/uwsgi-nginx-flask:

"tiangolo/meinheld-gunicorn-flask will give you about 400% (4x) the performance of this tiangolo/uwsgi-nginx-flask"

So unless there is some reason you must use tiangolo/uwsgi-nginx-flask, I would go with tiangolo/meinheld-gunicorn-flask.

When I would try to start a container using the meinheld-gunicorn-flask image, I was getting this traceback.

[Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/gunicorn/util.py", line 71, in load_class
    return pkg_resources.load_entry_point(dist, section, name)
  File "/usr/local/lib/python3.9/site-packages/pkg_resources/__init__.py", line 474, in load_entry_point
    return get_distribution(dist).load_entry_point(group, name)
  File "/usr/local/lib/python3.9/site-packages/pkg_resources/__init__.py", line 2846, in load_entry_point
    return ep.load()
  File "/usr/local/lib/python3.9/site-packages/pkg_resources/__init__.py", line 2449, in load
    self.require(*args, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/pkg_resources/__init__.py", line 2472, in require
    items = working_set.resolve(reqs, env, installer, extras=self.extras)
  File "/usr/local/lib/python3.9/site-packages/pkg_resources/__init__.py", line 777, in resolve
    raise VersionConflict(dist, req).with_context(dependent_req)
pkg_resources.VersionConflict: (greenlet 3.0.0 (/usr/local/lib/python3.9/site-packages), Requirement.parse('greenlet<0.5,>=0.4.5'))
]

{"loglevel": "info", "workers": 4, "bind": "0.0.0.0:80", "workers_per_core": 2.0, "host": "0.0.0.0", "port": "80"}

 

According to https://github.com/tiangolo/meinheld-gunicorn-docker/issues/22, greenlet version 0.4.5 or higher up to version 0.5 must be installed so it probably makes sense to create a Dockerfile that includes greenlet, perhaps something like this.

FROM tiangolo/meinheld-gunicorn-flask:python3.9
RUN apt-get update -y
RUN pip install --upgrade pip
RUN pip install greenlet==3.0.0

 

It is also noteworthy that I was able to get a container up and running just fine with just these minimal settings. But when I tried to create a container with Flask-SQLAlchemy version 3.0.5, the container failed to start because Flask-SQLAlchemy version 3.0.5 includes greenlet version 3.0.0, and the meinheld-gunicorn-flask image is incompatible with greenlet version 3.0.0.

 

Then use the docker build command to create the image, running this command in the same directory as the Dockerfile.

docker build --tag meinheld-gunicorn-flask-python3.9 .

 

The docker images command can be used to display the image.

~]$ sudo docker images
REPOSITORY                           TAG          IMAGE ID       CREATED          SIZE
tiangolo/meinheld-gunicorn-flask     python3.9    9b7b1a3b4eff   4 days ago       1.01GB

 

Create a file somewhere on your Docker system such as /usr/local/docker/flask/main.py that contains the following.

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World"

if __name__ == "__main__":
    app.run(host='0.0.0.0', debug=True, port=80)

The following command can then be used to create and start the ngninx container. Let's break down this command.

  • The docker run command is used to create and start the nginx container.
  • The --detach flag is used to run the container in the background.
  • The --publish option is used both the Docker server and nginx container to listen on HTTP port 80, which adds a rule to iptables to allow connections between the Docker system and container on port 80.
  • The --volume option is used to mount the main.py file on your Docker system to /app/main.py in the container.
  • The --name option is used to give the container a specific name.
  • The --restart unless-stopped option is used so that the container is started if the Docker server is restarted
  • The meinheld-gunicorn-flask image is used.
sudo docker run --detach --restart unless-stopped --publish 0.0.0.0:80:80 --volume /usr/local/docker/main.py:/app/main.py --name flask tiangolo/meinheld-gunicorn-flask:latest

 

The docker container ls command can be used to ensure the container is running.

~]$ sudo docker container ls
CONTAINER ID   IMAGE                COMMAND                  CREATED              STATUS                 PORTS                             NAMES
be0cc8e9aa4d   meinheld-gunicorn-flask    "/entrypoint.sh /sta…"   About a minute ago   Up About a minute      443/tcp, 0.0.0.0:80->80/tcp    flask

 

The docker logs command should return something like this.

~]# sudo docker logs uwsgi-nginx-flask
2022-12-17 03:47:14,238 INFO success: quit_on_failure entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)

 

If running Docker on a Linux system, ensure connections are allowed in firewalld or iptables on ports 80 and 443.

firewall-cmd --add-service=http --permanent
firewall-cmd --add-service=https --permanent
firewall-cmd --reload

 

If running Docker on an Amazon Web Services (AWS) EC2 Instance, ensure the Security Group Inbound Rules allow connections on ports 80 and 443.

 

You should then be able to access main.py should be returned to return Hello World at http://<hostname or IP address of your Docker system>.

 




Did you find this article helpful?

If so, consider buying me a coffee over at Buy Me A Coffee



Comments


Add a Comment


Please enter b83c03 in the box below so that we can be sure you are a human.