WESLEY CHUN: Greetings, developers,
and welcome to Serverless Migration Station, where
we show you one serverless computer modernization
technique.
I'm Wesley Chun at Google, joined by Martin
and our friend Porter here to take you from point A
to point B. Today's migration represents a product crossover
showing you how to containerize your App Engine
apps to run on Cloud Run, our serverless container hosting
service.
MARTIN: Wow, that sounds pretty complicated.
Containerizing your app?
I'm just a simple web developer.
How much do I have to learn about containers?
WESLEY CHUN: Great question, Martin.
Developers out there already familiar with Docker
don't have much to learn since they've already been creating
and deploying containers.
Using Docker to create a container for Cloud Run
is pretty much the same as anywhere else.
On the other hand, if you're completely new to containers,
don't worry, we'll take care of you, too.
In this module 4 video, we'll focus on Docker.
But in module 5, we'll show you how
to containerize your apps without having to know anything
about Docker or containers.
MARTIN: That's great to know that Google Cloud is for Docker
veterans and container newbies.
So for folks like me who are new,
what's the elevator pitch for containers anyway?
WESLEY CHUN: Well, I'm glad you asked, Martin.
With a seed planted years ago, containers
came to the forefront when virtualization
became a thing around the beginning of the millennium,
and were accelerated specifically
for application packaging about a decade later by Docker.
Of course, programming has been around for longer than that.
And some of us have been writing code for ages
without containers.
While optional, containerizing gives developers
the most freedom and flexibility in bundling their app.
They're easily reproducible, and you can use or reuse them
anywhere you want, making them extremely portable, too.
MARTIN: Come on.
Those are just marketing buzzwords, Wes.
What do they mean for developers like us?
WESLEY CHUN: Well, you asked for the elevator pitch.
This is going to take a little longer than one elevator ride
now.
Well, containers give you the flexibility to bundle whatever
your apps need, freeing you from traditional serverless
restrictions like, you have to use this language,
or you can't muddle that library because it's in C++.
Furthermore, the container is reproducible.
You can figure how the container is built.
And if you use the same instructions,
you could create an identical container.
This is valuable, not just for testing, but also
for verifying your app works with which
versions of your dependencies.
No more deploying apps and hoping the production libraries
are compatible.
MARTIN: OK, so my users are based all over the world.
So I want to deploy the same service everywhere.
Also, if I had a bad build, I want
to roll back to the previous working version.
So the same container image can be deployed anywhere?
And if there's a problem, I can roll back
to a previous container image?
WESLEY CHUN: Oh, for sure.
I mean, I know we're talking serverless here.
But realize containers are ultra portable,
as that same container image can be deployed to your Compute
Engine VMs, Kubernetes, in the cloud, your VMs on-prem,
hybrid, or even multi-cloud.
Think of containers like a shopping bag
to bundle your code and its dependencies.
Imagine carrying everything you bought at the market
separately to your car or on the subway.
MARTIN: [CHUCKLES] That shopping-bag analogy
makes a lot of sense to me.
I'm sold on containers.
But do I have to containerize my App Engine apps?
I'm kind of used to App Engine's style of development, where
I improve my code, I deploy to staging, and then
eventually to production.
WESLEY CHUN: Yeah, as I mentioned earlier,
I've been writing apps for years without containers.
So if you're comfortable there, that's fine.
But realize that industry has moved towards containers
in a big way so they're there for you when you're ready.
I think you'll like our next video, though,
because we'll show you how to containerize apps
without knowing much about containers.
So stay tuned for that.
For now, Google has expressed long-term support
for App Engine.
But much of our effort is going to Cloud Run
because containers are a de facto standard now.
MARTIN: Well, I'm ready now.
But before that, I do have some Python 2 legacy apps.
I know it's been deprecated by the community and all that.
But so I'm concerned.
Do you have any options for me?
WESLEY CHUN: Yeah, you're not alone, Martin.
Many Python 2 developers share those concerns.
However, that long-term support page links to another page
where Google has committed to supporting the App Engine 2.7
runtime, letting you move when ready.
And did you already forget that Cloud Run
supports any language, any library, any binary?
Containerizing is one way to keep your Python 2 app alive
forever.
MARTIN: Well, if you put it that way, Wes,
I'm going to containerize two App Engine apps, the Python 2
Cloud NDB app from module 2 and the Python 3 Cloud Datastore
app from module 3.
WESLEY CHUN: Sure, Martin.
Porter has lots of energy today, so we'll
do both, which is why there are Python 2 and 3 folders
for module 4 when we're done.
Check out the module 2 or 3 videos and repo folders
to refamiliarize ourselves with each.
The Python 2 Cloud NDB up is in the module 2a folder
while the Python 3 Cloud Datastore
app is in the module 3b folder.
Let's pause for a moment for you to catch up and grab
your starting codebase.
Got it?
Great.
Now let's go containerize them.
As with most migrations, it's always a good idea
to check that you're starting from a working
app, whether the module 2 Cloud NDB Python 2
app or the module 3 Cloud Datastore Python 3 app,
please redeploy yours--
or ours, as suggested moments ago-- with gcloud app deploy,
and verify it works where you get the same output
as from previous modules.
Changing products from App Engine to Cloud Run
requires configuration changes, so we
suggest you make a full copy of your working app folder.
Now it's safe to make the necessary changes
containerizing that app.
First, delete the app.yaml file that is not used in Cloud Run.
If migrating the Python 2 Cloud NDB app, also delete App Engine
config.py and the lib folder, more App Engine artifacts
unused in Cloud Run.
Next let's tackle requirements.txt.
App Engine and Cloud Functions are an source-based instructor
app with a production-ready server.
Since Cloud Run is a bit more DIY, you need to roll your own.
Python Engine uses the gunicorn production-ready server
if you don't specify your own.
So let's use that one for Cloud Run
by adding it to requirements.txt.
I like to put my packages in lowest- to highest-level order,
which is why I listed it first.
For the Python 2 app, you'll have gunicorn, flask,
and cloud-ndb, whereas for the Python 3 app,
it'll be gunicorn, flask and cloud-datastore.
Version numbers are a good practice.
However, they change a lot and differ between Python 2 and 3.
So that's why we're not showing any here.
They're in the repo files though.
When using Docker, the main config
file your need is a Docker file.
So create that with the content you see on screen
or download it from the repo.
If you're new to Docker files, you
need to start with a base container, in this case
a minimal Python 2 or 3 image.
From here, create and cd into your working directory,
arbitrarily called "app," with the WORKDIR command.
Now copy all the source code into app
and run pip install so your application can
use those packages listed in requirements.txt.
Finally, ENTRYPOINT tells the system
to start gunicorn to serve your app.
Check the Dockerfile best practices page for more info.
Another good practice is to add a dockerignore file.
While it is optional, it helps keep unnecessary files
from being added to your container.
It's less important for our sample apps
since they're so small, but it can have a positive impact
on your apps, controlling container size
and preventing accidental exposure of secrets like API
keys or OAuth credentials.
This isn't Python-related, so you
can use the same dockerignore for both Python 2 and 3 apps.
Since we're migrating identical apps to Cloud Run,
there are no other changes other than configuration updates.
That means we can just deploy it now.
We're done.
Instead of gcloud app deploy for App Engine,
the command now is gcloud run deploy SVC_NAME,
dash-dash-source, dot to deploy the app from the source
code in the current directory.
Instead of deploying an app, with Cloud Run,
you deploy a service.
So you have to come up with a service name, hopefully
more exciting than App Engine's "default."
Cloud Run also has more options.
So you're going to be asked what region to deploy to
and whether you're allowing open internet traffic.
Lastly, Cloud Run is available in other form factors,
but the one closest to App Engine is fully managed.
If you don't want to get asked all of these every single time,
provide them on the command line as options, like this one
here that I'm using for our app, calling the service visitme.
And like your App Engine app, your service
should be available globally in under a minute
at a unique URL you can point to with the custom domain.
Hit it with your browser and confirm you now
have a running Cloud Run app.
Cool.
So what do you think, Martin?
MARTIN: Wow, Wes, that was way easier than I
thought it was going to be.
I was a bit apprehensive about learning these containers,
but it doesn't look that bad.
But watching you do it is too easy.
Where can I try these migrations myself?
WESLEY CHUN: Of course, Martin.
All modules have a corresponding codelab
linked in the repo and below, where
we walk through this migration step by step.
If things don't go well migrating the Python 2 Cloud
NDB app, grab it again from the module 2a Start folder.
The same is true with the Python 3 Cloud Datastore app.
Reset to its module 3b folder if you need to.
You can compare your solution with ours
in the module 4a or 4b Finish folders.
Another link we're leaving for you is to the gcloud run
deploy docs in case you're curious how it works
and what else you can do with it.
MARTIN: Great.
I'm looking forward to doing those by hand.
But I am still concerned about that Dockerfile.
Our sample app is quite simple, so there wasn't any trouble.
But you know, out in the real world--
WESLEY CHUN: Yeah, I know.
You have many more dependencies and it's
easier to create suboptimal or overly complex Docker files.
These can lead to slowing down the build,
deployment, and execution of your containerized app.
That's why you should check out module 5 where
you don't have to worry about Dockerfiles anymore.
We'll add a link to the video once it's ready.
But for now, you can already do its codelab.
MARTIN: Oh, I look forward to seeing that.
By the way, my DevOps coworkers told me
they prefer it if my app can be integrated in a CI/CD pipeline.
Can Cloud Run do that, Wes?
WESLEY CHUN: Oh yeah.
On the CD side, one cool feature of Cloud Run
is that you can deploy direct from a code push.
This is configured in the Cloud Console
if your code is in a repo system like GitHub or Bitbucket.
When a commit takes place, it triggers Cloud Build
to build and register your container,
then deploys it to Cloud Run.
If you slip in a service like GitHub actions
that builds and tests your code before sending it to Cloud Run,
you'll have that CI/CD environment you asked for.
See the link to our community tutorial
to learn more about how to do that.
MARTIN: OK, great.
Thanks, Wes.
Aside from containerizing my App Engine apps
for Cloud Run, what are some other migrations I
should consider?
WESLEY CHUN: Well, aside from the next video
on containerizing your app without Docker, if you're
on Cloud NDB and have other code using the Cloud Datastore
client library, consider consolidating
to one client library.
That's covered in module 3.
If you're excited about all those Firebase
features in Cloud Firestore and willing to move
your app to a new project, check out modules 6 and 10.
If your app uses App Engine task cues, migrate to Cloud Tasks.
And that's covered in modules 7, 8, and 9.
Finally, if your App Engine app is pretty small
or does only one thing, consider migrating to Cloud Functions.
That'll be found in module 11.
But note you have to port your code from Python 2 to 3 first,
as Cloud Functions only supports Python 3.
And thank all of you for staying with us on all
of these migration journeys.
Please join us for the module 5 migration station,
not only to learn more about containers,
but it's all of the stuff that we didn't get a chance
to cover today.
This is Wesley Chun from Google Cloud.
On behalf of Martin and Porter, we
hope to see you at the next Migration Station
or on another Serverless Expedition soon.
[MUSIC PLAYING]