Introducing Cloud Run
Today, Google announced Cloud Run, a product that is really beautiful in its simplicity:
1) You write an service/app/function/whatever that listens for HTTP requests on $PORT
;
2) You write a Dockerfile
that inherits from any base image, installs any necessary dependencies, and starts your service;
3) You deploy the image to Cloud Run, and it scales on demand (even to zero).
Basically, it's "serverless Docker containers as a service" and it's exactly what I think the PaaS/FaaS development community could use right now, for a number of reasons:
The most idiomatic runtime possible
There's no potential for vendor-specific weirdness here. Really, you can't get more idiomatic than using FROM python:3.7
, or whatever other base image you want to use.
Customizability without paying for idle virtual machines
If you have specific workloads that don't fit within the bounds of the most "common" runtimes usually provided, before now your best option was to spin up a custom VM which won't scale to zero and will spend a lot of time sitting idle. With Cloud Run, you can use the Dockerfile
to customize your runtime to your heart's content.
Containerization means portability
Defining your runtime with a standard Dockerfile
means you can take it anywhere—even locally—which means that you're not locked into a specific vendor, and that local development of your application is built right in without needing to do anything special.
These are all great, and they'll certainly help developers do great things...
...But what if you wanted to do something really silly with it instead?
Introducing the first Python 1.x serverless runtime
When I first started playing with Cloud Run, I really wanted to test the limits of what I could do with it. Could I really run any runtime I wanted? Could I run a super modern Python 3.8.0a3 alpha release? (Yes). Well, what about a "vintage" version of Python? Could I deploy a "Hello World" app running on Python 1.x to Cloud run? 🤔
Searching for "vintage" images
The first problem was finding a base image for Python 1.x. The official Python Docker images only publish images for 2.7 and up, so no luck there. I couldn't find it anywhere else, so it looked like I'd have to build the base image from scratch myself.
Searching for "vintage" source
Building the base image from scratch meant that I had to:
a) Find the old source code for a Python 1.x version;
b) Get it to compile on a modern distribution's base image;
c) Publish this new base image.
Finding the source was slightly challenging. The source for modern Python releases is published on https://www.python.org/downloads/source/, but this only goes back as far as Python 2.0.1, released June 22, 2001.
Luckily, I found https://legacy.python.org/download/releases/src/, which includes source releases as far back as Python 1.0.1, which was released just over 25 years ago on February 15th, 1994.
I decided to attempt to target the latest Ubuntu distribution, and amazingly, with just some small patches, I was able to get Python 1.0.1, 1.1, 1.2 and 1.3 to compile under Ubuntu 18.04.
Publishing some "vintage" images
I published these resulting builds as Docker images under the vintage-python
repository, so this means you can now start a vintage Python REPL whenever you want:
$ docker run -it dustingram/vintage-python:1.0.1
Python 1.0.1 (Feb 23 2019)
Copyright 1991-1994 Stichting Mathematisch Centrum, Amsterdam
>>> print "Hello world!"
Hello world!
It also means I can do FROM dustingram/vintage-python:1.0.1
in my Dockerfile
, which is a huge step towards having my silly runtime.
Searching for an HTTP server
I had my heart set on Python 1.0.1, but after realizing that Python didn't ship with an HTTP server until Python 1.3, I decided to use that instead of attempting to backport the HTTP server to an older version.
In Python 1.3, I was able to write this:
import sys
from BaseHTTPServer import HTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
class MyHandler(SimpleHTTPRequestHandler):
protocol_version = "HTTP/1.1"
def do_GET(self):
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
self.wfile.write("Hello from Python " + sys.version)
if __name__ == '__main__':
print('Running...')
HTTPServer(('0.0.0.0', 8080), MyHandler).serve_forever()
This sets up a basic HTTP/1.1 server on port 8080 that responds to every request with the given message. I really wanted to prove that this was a vintage version of Python serving the request, so I included the sys.version
along with the response.
Containerizing some vintage Python
After saving that as app.py
, all that was left to do was write the Dockerfile
. Since my app doesn't have any dependencies, the Dockerfile
is pretty close to the Dockerfile
in the Cloud Run quickstart
FROM dustingram/vintage-python:1.3
# Copy local code to the container image.
ENV APP_HOME /app
WORKDIR $APP_HOME
COPY . .
# Service must listen to $PORT environment variable.
# This default value facilitates local development.
ENV PORT 8080
# Run the web service on container startup.
CMD ["python", "app.py"]
Here, we inherit from my vintage Python image, copy in my app.py
to the container, set the PORT
environment variable (for local development), and then start the server by running python app.py
.
Deploying some vintage Python
With Cloud Run, there's a two step deploy:
Build and submit your image with Cloud Build:
$ gcloud builds submit --tag gcr.io/my_project_id/helloworld
Then, deploy the submitted image to Cloud Run:
$ gcloud beta run deploy --image gcr.io/my_project_id/helloworld
And then it was deployed!
See it in action here: https://helloworld-bpzdnjbrsq-uc.a.run.app/
Conclusion
Cloud Run is definitely flexible enough to run any runtime I could throw at it -- even one of the oldest versions of Python. Obviously I wouldn't seriously encourage anyone to use Python 1.x in production: any version past it's EOL is essentially unmaintained and severely feature-limited.
From here, you can:
- See the
vintage-python
Github repo for more details on the runtimes; - Use the
vintage-python
images in your own silly project; - See the Cloud Run quickstart;
- Follow me on Twitter.