2

Forgive my ignorance..

I'm trying to learn how to schedule python scripts with Google Cloud. After a bit of research, I've seen many people suggest Docker + Google Cloud Run + Cloud Scheduler. I've attempted to get a "hello world" example working, to no avail.

Code

hello.py

print("hello world")

Dockerfile

# For more information, please refer to https://aka.ms/vscode-docker-python
FROM python:3.8-slim

# Keeps Python from generating .pyc files in the container
ENV PYTHONDONTWRITEBYTECODE=1

# Turns off buffering for easier container logging
ENV PYTHONUNBUFFERED=1

WORKDIR /app
COPY . /app

# Creates a non-root user with an explicit UID and adds permission to access the /app folder
# For more info, please refer to https://aka.ms/vscode-docker-python-configure-containers
RUN adduser -u 5678 --disabled-password --gecos "" appuser && chown -R appuser /app
USER appuser

# During debugging, this entry point will be overridden. For more information, please refer to https://aka.ms/vscode-docker-python-debug
CMD ["python", "hello.py"]

Steps

  1. Create a repo with Google Cloud Artifact Registry

    gcloud artifacts repositories create test-repo --repository-format=docker \
    --location=us-central1 --description="My test repo"
    
  2. Build the image

    docker image build --pull --file Dockerfile --tag 'testdocker:latest' .
    
  3. Configure auth

    gcloud auth configure-docker us-central1-docker.pkg.dev
    
  4. Tag the image with a registry name

    docker tag testdocker:latest \
    us-central1-docker.pkg.dev/gormanalysis/test-repo/testdocker:latest
    
  5. Push the image to Artifact Registry

    docker push us-central1-docker.pkg.dev/gormanalysis/test-repo/testdocker:latest
    

    enter image description here

  6. Deploy to Google Cloud Run

    enter image description here enter image description here enter image description here

Error

At this point, I get the error

The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable.

I've seen posts like this which say to add

app.run(port=int(os.environ.get("PORT", 8080)),host='0.0.0.0',debug=True)

but this looks like a flask thing, and my script doesn't use flask. I feel like i have a fundamental misunderstanding of how this is supposed to work. Any help would be appreciated it.

Ben
  • 20,038
  • 30
  • 112
  • 189
  • 1
    If you're not using Flask, what are you using? You need a web framework since at the end of the day, your 'hello world' is being invoked 'over the web' That web framework has to listen on port ```8080``` for incoming traffic – NoCommandLine Dec 14 '22 at 14:41
  • @NoCommandLine Thanks I had a feeling this is what I was missing. (I'm a lowly data scientist - not an engineer or web developer, so this was not obvious to me, and I don't think it's clearly communicated in the docs.) – Ben Dec 14 '22 at 14:47
  • 1
    We're all learning something new :) We have a blog article that explains deploying to Cloud Run and it includes a link to Google's ```hello world``` sample app. I believe that will help https://nocommandline.com/blog/step-by-step-guide-to-deploying-your-app-to-google-cloud-run/ . There's also an article there for securing your Cloud Run App and how to invoke it with Cloud Scheduler. Let me know if you still have questions – NoCommandLine Dec 14 '22 at 14:49
  • I recommend moving your Update into an Answer and then accepting it. What you figured out is an important distinction and people who have similar issues might not read the whole question (i.e. all the way down to your updates) but they'll most likely jump to an accepted answer – NoCommandLine Dec 14 '22 at 18:24
  • Where do you expect "hello world' to display? For Cloud Run, a print statement will be logged to Cloud Logging. If you want that string returned to the user/client, you must implement an HTTP request/response web server. If you want to process **tasks/jobs** non-interactively, then deploy as a Cloud Run Job. – John Hanley Dec 14 '22 at 21:13

2 Answers2

2

UPDATE
I've documented my problem and solution in much more detail here »


I had been trying to deploy my script as a Cloud Run Service. I should've tried deploying it as a Cloud Run Job. The difference is that cloud run services require your script to listen for a port. jobs do not.

enter image description here

Confusingly, you cannot deploy a cloud run job directly from Artifact Registry. You have to start from the cloud run dashboard.

Ben
  • 20,038
  • 30
  • 112
  • 189
0

Your Flask application should be something like below:

import os

from flask import Flask

app = Flask(__name__)


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


if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))

See this official documentation for step by step instruction: Deploy a Python service to Cloud Run

There is a plugin called: Cloud Code IDE plugin which makes the test and deployment easy. I am using it for VS code, once the initial setups and permissions are taken care, few clicks, you will be able to run locally, debug and deploy Cloud run services from your local instance.

Rathish Kumar B
  • 1,271
  • 10
  • 21
  • Yes, this works, but explain why Flask is necessary. What if I don't want to install Flask because it has nothing to do with my task of finding large prime numbers.. – Ben Dec 14 '22 at 15:40
  • 1
    Cloud Run is a managed compute platform that enables you to run containers that are invocable via requests or events. Simple terms, webserver/flask helps you to communicate with your function through requests. For example, calling https://service.com/getlargeprime uri, it will invoke your largeprime() method and give you the result. If you don't want to make http requests, try other compute services. – Rathish Kumar B Dec 14 '22 at 16:21
  • Thanks @Rathish. That's a much better answer. It provides the context I was missing when I posted this question. – Ben Dec 14 '22 at 17:43