Flask is a suitable web server during development, but if you are going to deploy in a production environment, a Python WSGI server such as Gunicorn should be used.
This also applies to Python Flask apps deployed to GCP Cloud Run. Gunicorn is necessary to tune the worker and thread count of each instance to your traffic shape and is more scalable and performant.
In this article I will show you how a Python web application can be developed and tested locally using either Flask or Gunicorn, and then deployed to GCP Cloud Run as a Docker image running Gunicorn.
Download project and create Python virtual environment
First download my github project and setup the isolated Python virtual environment with the required module dependencies.
# make sure essential OS packages are installed sudo apt-get install software-properties-common python3 python3-dev python3-pip python3-venv make curl git -y # download project git clone https://github.com/fabianlee/gcp-cloudrun-python3-gunicorn.git cd gcp-cloudrun-python3-gunicorn # create and load virtual env python3 -m venv . source bin/activate pip install -r requirements.txt
Test locally using Flask
If you are in the code-test-debug phase, Flask provides debug and reload abilities that create an efficient workflow for developers.
# run Python Flask app locally, open local browser to http://localhost:8080 python3 -m hellomodule.app run --port 8080
Test locally using Gunicorn
To test locally using the Python WSGI Gunicorn app server which will emulate production more closely, run the command below.
# run Gunicorn locally, open local browser to http://localhost:8080 gunicorn --config gunicorn.conf.py --log-config=gunicorn-logging.conf hellomodule.app:app
Deploy to GCP Cloud Run as Docker image using Gunicorn
Notice there is a Dockerfile located in the base directory of the project that invokes same pip install and gunicorn invocation done manually above.
$ cat Dockerfile ... RUN set -ex \ && pip install --no-cache-dir -r requirements.txt ... ENTRYPOINT [ "/usr/local/bin/gunicorn", "--config", "gunicorn.conf.py", "--log-config", "gunicorn-logging.conf", "hellomodule.app:app" ]
‘gcloud run deploy’ has the ability to build a Docker image using this Dockerfile and then deploy the image as a GCP Cloud Run service.
# enable GCP project level services gcloud services enable cloudbuild.googleapis.com artifactregistry.googleapis.com run.googleapis.com # setup variables app_name="gcp-cloudrun-python3-gunicorn" region=$(gcloud config get compute/region) project_id=$(gcloud config get project) # deploy to GCP Cloud Run gcloud run deploy $app_name --source=. --region=$region --ingress=all --allow-unauthenticated --execution-environment=gen2 --no-use-http2 --quiet # show details of Cloud Run deployment gcloud run services list gcloud run services describe $app_name --region=$region
Validate GCP Cloud Run deployment
A simple curl test can be done to validate the deployment.
# test pull of content run_url=$(gcloud run services describe $app_name --region=$region --format='value(status.url)') echo "CloudRun app at: $run_url" curl $run_url
And if you want to put load on the application, ‘hey‘ is a simple load tool available across multiple platforms.
# simple load tool sudo apt install hey -y # 200 total requests, 20 concurrent at a time hey -n 200 -c 20 $run_url
This kind of load testing would serve as the basis for tuning the workers, threads, logging, and other configuration to your specific needs and traffic shape.
REFERENCES
fabianlee github project, gcp-cloudrun-python3-gunicorn
google codelabs, Cloud Run and Python/Gunicorn example
google ref, QuickStart for Python Flask/Gunicorn on Cloud Run
google ref, Optimize Python apps and gunicorn for Cloud Run
google ref, General optimization tips for Cloud Run
gunicorn docs, worker-class design document