I am trying to create a Python Flask API on WSGI
that I want to run on Google Cloud Run.
The code is stored in a Github repository. In https://console.cloud.google.com/run I have added the Github repository so that when a new push is made to main branch then a build will be done.
The code is a Flask API running on WSGI webserver. I get some error messages when I try to run it on Google Run: ERROR: build step 2 "gcr.io/google.com/cloudsdktool/cloud-sdk:slim" failed: step exited with non-zero status: 1
config/flask-site-nginx.conf
server { location / { try_files $uri @yourapplication; } location @yourapplication { include uwsgi_params; uwsgi_pass unix:///tmp/uwsgi.sock; } }
config/nginx.conf
# based on default config of nginx 1.12.1 # Define the user that will own and run the Nginx server user nginx; # Define the number of worker processes; recommended value is the number of # cores that are being used by your server # auto will default to number of vcpus/cores worker_processes auto; # altering default pid file location pid /tmp/nginx.pid; # turn off daemon mode to be watched by supervisord daemon off; # Enables the use of JIT for regular expressions to speed-up their processing. pcre_jit on; # Define the location on the file system of the error log, plus the minimum # severity to log messages for error_log /var/log/nginx/error.log warn; # events block defines the parameters that affect connection processing. events { # Define the maximum number of simultaneous connections that can be opened by a worker process worker_connections 1024; } # http block defines the parameters for how NGINX should handle HTTP web traffic http { # Include the file defining the list of file types that are supported by NGINX include /etc/nginx/mime.types; # Define the default file type that is returned to the user default_type text/html; # Don't tell nginx version to clients. server_tokens off; # Specifies the maximum accepted body size of a client request, as # indicated by the request header Content-Length. If the stated content # length is greater than this size, then the client receives the HTTP # error code 413. Set to 0 to disable. client_max_body_size 0; # Define the format of log messages. log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; # Define the location of the log of access attempts to NGINX # access_log /var/log/nginx/access.log main; access_log /dev/stdout main; # Define the parameters to optimize the delivery of static content sendfile on; tcp_nopush on; tcp_nodelay on; # Define the timeout value for keep-alive connections with the client keepalive_timeout 65; # Define the usage of the gzip compression algorithm to reduce the amount of _data to transmit #gzip on; # Include additional parameters for virtual host(s)/server(s) include /etc/nginx/conf.d/*.conf; }
supervisord.conf
[supervisord] nodaemon=true [program:uwsgi] command=/usr/local/bin/uwsgi --ini /etc/uwsgi/uwsgi.ini --die-on-term stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0 [program:nginx] command=/usr/sbin/nginx stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0
uwsgi.ini
[uwsgi] module = src.wsgi callable = app uid = nginx gid = nginx socket = /tmp/uwsgi.sock chown-socket = nginx:nginx chmod-socket = 664 cheaper = 1 processes = %(%k + 1)
src/__init__
.py
(empty file)
src/main.py
import os from flask import Flask from flask_cors import CORS app = Flask(__name__) cors = CORS(app) app.config['CORS_HEADERS'] = 'Content-Type' # Routes @app.route('/', methods=['GET']) def __index(): return "Hello from Flask API running on WSGI" # - Main start ---------------------------------------------------------------- if __name__ == "__main__": # Start app print("main() :: Flask API is starting at: http://127.0.0.1:8080") app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
src/wsgi.py
import os from src.main import app if __name__ == "__main__": print("wsgi() :: Flask API is starting at: http://127.0.0.1:8080") app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
Dockerfile
# Specify Python FROM python:latest # Copy files RUN mkdir /app WORKDIR /app COPY . . # Install Nginx web server RUN apt-get update RUN apt-get install -y --no-install-recommends libatlas-base-dev gfortran nginx supervisor # Install uWSGI Web Server Gateway Interface RUN pip install uwsgi # Install requiremets RUN pip install -r requirements.txt # Configure Nginx and uWSGI RUN useradd --no-create-home nginx RUN rm /etc/nginx/sites-enabled/default RUN rm -r /root/.cache COPY config/nginx.conf /etc/nginx/ COPY config/flask-site-nginx.conf /etc/nginx/conf.d/ COPY config/uwsgi.ini /etc/uwsgi/ COPY config/supervisord.conf /etc/ CMD ["/usr/bin/supervisord"]
requirements.txt
flask flask-unittest Flask-RESTful flask-cors
When I try to push the code Google Run builds it but it gives me errors:
Creating revision:
The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable. Logs for this revision might contain more information. Logs URL: https://console.cloud.google.com/logs/viewer?project=engineering-infra&resource=cloud_run_revision/service_name/template-google-cloud-run-backend/revision_name/template-google-cloud-run-backend-00009-rew&advancedFilter=resource.type%3D%22cloud_run_revision%22%0Aresource.labels.service_name%3D%22template-google-cloud-run-backend%22%0Aresource.labels.revision_name%3D%22template-google-cloud-run-backend-00009-rew%22 For more troubleshooting guidance, see https://cloud.google.com/run/docs/troubleshooting#container-failed-to-start
Routing traffic
Pending
Building and deploying from repository:
Trigger execution failed: source code could not be built or deployed; find more information in build logs Revision ‘template-google-cloud-run-backend-00009-rew’ is not ready and cannot serve traffic. The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable. Logs for this revision might contain more information. Logs URL: https://console.cloud.google.com/logs/viewer?project=engineering-infra&resource=cloud_run_revision/service_name/template-google-cloud-run-backend/revision_name/template-google-cloud-run-backend-00009-rew&advancedFilter=resource.type%3D%22cloud_run_revision%22%0Aresource.labels.service_name%3D%22template-google-cloud-run-backend%22%0Aresource.labels.revision_name%3D%22template-google-cloud-run-backend-00009-rew%22 For more troubleshooting guidance, see https://cloud.google.com/run/docs/troubleshooting#container-failed-to-start
The build logs gives me:
Step #2 - "Deploy": 219f975b51dc: Pull complete Step #2 - "Deploy": Digest: sha256:8dde46b24ab5c496d1fb11bdd87a68a07f8d752098caac87bc60d59d904a1ff5 Step #2 - "Deploy": Status: Downloaded newer image for gcr.io/google.com/cloudsdktool/cloud-sdk:slim Step #2 - "Deploy": gcr.io/google.com/cloudsdktool/cloud-sdk:slim Step #2 - "Deploy": Deploying... Step #2 - "Deploy": Creating Revision....failed Step #2 - "Deploy": Deployment failed Step #2 - "Deploy": ERROR: (gcloud.run.services.update) The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable. Logs for this revision might contain more information. Step #2 - "Deploy": Step #2 - "Deploy": Logs URL: https://console.cloud.google.com/logs/viewer?project=engineering-infra&resource=cloud_run_revision/service_name/template-google-cloud-run-backend/revision_name/template-google-cloud-run-backend-00009-rew&advancedFilter=resource.type%3D%22cloud_run_revision%22%0Aresource.labels.service_name%3D%22template-google-cloud-run-backend%22%0Aresource.labels.revision_name%3D%22template-google-cloud-run-backend-00009-rew%22 Step #2 - "Deploy": For more troubleshooting guidance, see https://cloud.google.com/run/docs/troubleshooting#container-failed-to-start Finished Step #2 - "Deploy" ERROR ERROR: build step 2 "gcr.io/google.com/cloudsdktool/cloud-sdk:slim" failed: step exited with non-zero status: 1
Advertisement
Answer
Firstly,the error that is seen during the build execution step clearly states that the revision for the build is not ready on the path, which could be due to the build not ready or the process not recognizing this build due to tag issue.
Trigger execution failed: source code could not be built or deployed; find more information in build logs Revision 'template-google-cloud-run-backend-00009-rew' is not ready and cannot serve traffic
To prevent this issue,ensure that the revision build is ready to be picked and try again.Also try to remove that “revision”tag and try again.
These changes will help because when updating traffic, “0%” traffic was being assigned to every revision specified in the traffic field and as of now since this revision is not ready, any operation that is assigning traffic (even though 0%) would cause the error.
Secondly, the listener port error suggests that when your container starts, it expects a response on port $PORT (8080),as per the environment variable is set.Now as the build is not ready it does not follow the Cloud Run requirements and is terminated when Cloud Run detects no response / incorrect response on port $PORT.
Read this document to better understand the runtime environment contract.
Please review this document which lists a series of steps to follow when encountering this error in order to fix the issue.
Also have a look at these similar examples: