Python FastAPI Tutorial (Part 19): Deploy with Docker - Serverless Containers and Custom Domain
1:19:13

Python FastAPI Tutorial (Part 19): Deploy with Docker - Serverless Containers and Custom Domain

Corey Schafer 21.04.2026 4 687 просмотров 191 лайков

Machine-readable: Markdown · JSON API · Site index

Поделиться Telegram VK Бот
Транскрипт Скачать .md
Анализ с AI
Описание видео
In this video, we'll be learning how to deploy our FastAPI application using Docker and Google Cloud Run. We'll containerize our app by writing a multi-stage Dockerfile, set up a serverless PostgreSQL database with Neon, deploy our container to Cloud Run, and configure a custom domain with HTTPS. We'll also add security headers to our application through middleware. This is a different approach from the VPS deployment in the previous video, where instead of managing our own server, Google handles the infrastructure for us and our app can scale to zero when nobody's using it. Let's get started... The code from this video can be found here: https://github.com/CoreyMSchafer/FastAPI-19-Deployment-Docker-GCR Full FastAPI Course: https://www.youtube.com/playlist?list=PL-osiE80TeTsak-c-QsVeg0YYG_0TeyXI Docker Desktop: https://www.docker.com/products/docker-desktop/ Create a New Google Cloud Project: console.cloud.google.com/projectcreate Google Cloud SDK: https://cloud.google.com/sdk/docs/install NameCheap (with Referral): https://namecheap.pxf.io/nyBgR Google Search Console: search.google.com/search-console/ ✅ Support My Channel Through Patreon: https://www.patreon.com/coreyms ✅ Become a Channel Member: https://www.youtube.com/channel/UCCezIgC97PvUuR4_gbFUs5g/join ✅ One-Time Contribution Through PayPal: https://goo.gl/649HFY ✅ Cryptocurrency Donations: Bitcoin Wallet - 3MPH8oY2EAgbLVy7RBMinwcBntggi7qeG3 Ethereum Wallet - 0x151649418616068fB46C3598083817101d3bCD33 Litecoin Wallet - MPvEBY5fxGkmPQgocfJbxP6EmTo5UUXMot ✅ Corey's Public Amazon Wishlist http://a.co/inIyro1 ✅ Equipment I Use and Books I Recommend: https://www.amazon.com/shop/coreyschafer ▶️ You Can Find Me On: My Website - http://coreyms.com/ My Second Channel - https://www.youtube.com/c/coreymschafer Facebook - https://www.facebook.com/CoreyMSchafer Twitter - https://twitter.com/CoreyMSchafer Instagram - https://www.instagram.com/coreymschafer/ #Python #FastAPI

Оглавление (16 сегментов)

Segment 1 (00:00 - 05:00)

Hey there, how's it going everybody? In this video we're going to be learning how to deploy our FastAPI application using Docker and Google Cloud Run. Now, in the last video we learned how to deploy our app to a traditional virtual private server where we had to manage everything ourselves from the operating system and security updates to setting up Nginx and systemd. And while that's a great way to learn the fundamentals and give you total control, it also comes with a lot of responsibility. Now, you don't need to have watched that video to follow along with this one, but I will reference it a few times as a point of comparison between the two deployments. So, in this video we're going to take a different approach. We're going to package our application into a Docker container and hand that container off to Google Cloud Run and they'll handle all of the infrastructure for us. That means automatic scaling, managed SSL, and it can even scale all the way down to zero when nobody's using your application. So, you only pay for what you actually use. We're also going to use a cloud-hosted Postgres database called Neon, so we don't have to manage our own database server either. So, with that said, let's go ahead and get started. Now, one quick note before we jump in, if you skip tutorial 18, then there is one small code change from that video that we need here. Uh the only actual code change that we made in that video was adding a health check endpoint. Everything else was infrastructure setup on the server. So, if you're jumping straight into this video from tutorial 17, then you'll want to make sure that you have this endpoint in your main. py. It just does a simple select one on our database to make sure that the connection is alive. And I will have this in the snippets that I include with the uh downloadable code in the description section below. And having a health check like this is important because load balancers and monitoring systems use it to know if your application is running correctly. If you already have this from tutorial 18, then you're all set. Uh if you don't, then you can go ahead and create that or go ahead and download that code. Okay, so now let's add the one code change that we actually need for this tutorial. So, if you watched tutorial 18, you may remember that our Nginx configuration added security headers to all of our responses, but Cloud Run doesn't have Nginx in front of our app. So, we need to add those headers ourselves in our application code. And actually, this is arguably better because now our security headers live in our application instead of Nginx, which means they work no matter where we deploy. So, I'm going to add this right after our router includes here in main. py uh with the other app level configurations. And this is a bit of typing, so I'm going to grab these from our snippets file, but I'll explain these after we put them in place. So, let me grab these here from my snippets and paste these in. And now let's go over exactly what we're doing here. So, this is actually the first time that we've used middleware in our application. You can see the first line here is app. middleware http and we're calling this function add security headers. It takes in the request and call next as parameters. Call next is a function that passes the request along to whatever route is supposed to handle it and gives us back the response. So, middleware sits in the middle of that. It can do something before the request is handled or after or both. In our case, we are letting the request go through normally with this call next and then we are taking that response and adding headers to the response before it gets sent back to the client. So, walking through these headers, we have X-Frame-Options set to sameorigin. That prevents other websites from embedding our site in an iframe, which protects against clickjacking attacks, things like that. Uh X-Content-Type-Options set to nosniff tells the browser to trust the content type header that we send and not try to guess what type of content it is. Referrer-Policy here, we set to this to strict-origin-when-cross-origin, but only if it hasn't already been set. And that's because, if you remember from an earlier tutorial, our reset password page sets referrer policy to no referrer to protect the reset token in the URL, so we don't want to overwrite that. And then the Strict-Transport-Security tells browsers to always use https when visiting our site, but we skip this for localhost and 127. 0. 0. 1 so that local development still works over plain http. And then at the end, we just return the response with all of our headers added. So, every single response

Segment 2 (05:00 - 10:00)

from our application will now include these security headers. Now, when it comes to something like this, don't be intimidated by this if it's not something that you would think to add on your own. I'm by no means a cybersecurity expert and don't have stuff like this memorized either. I don't know these security headers off the top of my head, but I found these from some online recommendations for hardening a website security and simply added them in. So, I mainly wanted to show you this because Nginx was adding these headers for us in the last video and we want our deployments to be as similar as possible. So, let me quickly test to make sure that these work. So, let me restart my web server here and I will run our development server and let me go back to our website and reload this. And now let me go to Google's dev tools here and I will click on the network tab. Let me reload the page. And let me see here. Let me click on this request and let's look at the headers. So, we can see our security headers are being added. So, here we have that referrer policy and those others are probably in here as well. Yeah, here we have the X-Content-Type, the X-Frame-Options, things like that. Now, you'll notice that the Strict-Transport-Security is not there and that's because we're on localhost and we skip it for local development just like we planned because we obviously don't have https connections here on our localhost. Okay, so I'm going to close this down and now we can go ahead and stop our server here. All right, so that's the only code change for this tutorial. Everything else from here on is Docker configuration and cloud deployment. Okay, so before we can build containers, we need to install Docker. Now, I'm on macOS and I use Homebrew, so I'll install Docker Desktop over here in my terminal with Homebrew. Now, for other operating systems, you can download Docker Desktop from docker. com for Windows or install Docker Engine directly through your package manager on Linux. And I'll leave a link in the description section below for installation instructions for different operating systems. But here on my system, this is going to be brew install and this is a cask and this is Docker Desktop, I believe, and not just Docker. I think Docker also links to that Docker Desktop as well, so either one I think works fine. Okay, so that installed correctly. Uh now, if you are on an Apple Silicon Mac, so that's the M chips, you may need to install Rosetta for some container images. Uh you can do that with software update install Rosetta agree to license. I'll just put that here on screen instead of typing that out because I already have that installed and that's not something that everyone will do. Now, after installing Docker Desktop, you need to actually open it. Uh the Docker daemon doesn't actually start automatically on macOS, so you need to launch Docker Desktop from your applications folder. So, I will launch Docker here and I'll just accept this here and use the recommended settings. Click finish there. Type in my password on my computer here and it opens that up and it'll also tell you that this is going to be able to run in the background here as well. Now, here you can sign in if you have an account. I'm just going to skip that for now and let me go ahead and just exit out of this. This might be talking about updates here. No, it's just telling me that I'm not signed in. Okay, so I'm going to go ahead and close that down. But, if you notice here, at least on a Mac, this stays running up here. So, if I see this whale icon, then Docker should be running. I can confirm that if I type Docker version here in my command line, we can see that we do have access to that Docker command. So, that is what we wanted for this video. Now, I don't know how many of you are familiar with Docker. I haven't done a series on Docker yet, but I do plan on doing that in the near future. So, just for people who haven't seen it, some quick terminology before we dive in here. So, a Dockerfile is the recipe that tells Docker how to build our container image. The image is the result of that build and a container is a running instance of that image. Once our application is packaged into an image, that same image runs on our laptop. It can run on Cloud Run, on Kubernetes, whatever. It's the same container, same behavior. Now, Google Cloud Run does have a simpler option where you just point it at your source code and it tries to figure things out. I'll talk about that near the end of this video, but I want to build a real Dockerfile first because that gives us more control and teaches what's actually happening. So, our Dockerfile is going to use a multi-stage

Segment 3 (10:00 - 15:00)

build. Don't worry, it's simpler than it sounds. We have two stages in one file. We have a builder stage that installs dependencies and a production stage that starts fresh and copies only what we need. The builder stage gets thrown away after the build and we'll see this in action in just a bit so that makes sense. Now, you might wonder if we need to install Postgres or image processing libraries in the container. The good news is that the Python packages we're using like psycopg and Pillow already bundle everything that they need. So, we don't have to install any extra system level software. Uh we'll start minimal and see if it works. All right, so let's go ahead and create our Dockerfile. So, I'm going to open my sidebar here and I'm going to create a new file in the root of our project and this is just going to be a Dockerfile with no extension. So, I will run that. Now, I do have the complete Dockerfile in my snippets that I'll paste in, but that's just to make sure that I don't mistype anything here. We're still going to go over each line individually uh to make sure we know exactly what's going on here. So, let me copy all of this and then paste this into our Dockerfile. And now, let's go over exactly what we're doing with this Dockerfile. Okay, so first we have our build stage up here at the top. We are using Python 3. 14. 4 slim bookworm as our base image and notice that I'm pinning the exact version here. Tags like 3. 14 or latest uh can change without warning. One day your build might work, the next day it could break because the underlying image updated. So, pinning the exact version ensures that we get reproducible builds and the same image every time. Now, the next line here, this copy from uh this is copying the UV binary from Astral's official Docker image. Cleaner than curling and an installation script and we pin the version for the same reproducibility reason. So, now this work/app, this sets the working directory inside the container. So, from this point on, any commands that we run or files that we copy will be relative to this /app. And now we are setting some ENV variables here. These are setting some UV configurations for Docker builds. So, UV compile bytecode precompiles Python files to bytecode at build time. Without this, Python has to compile them on first import, which makes the first request slower. Uh link mode equal to copy is needed because UV normally uses hard links to save disk space, but Docker's layers don't play well with hard links across stages, so files can get lost. Setting this to copy ensures that files are actually copied. And then python downloads equal zero here tells UV to use the Python from our base image instead of downloading its own. Okay, so then we have this copy pyproject. toml uv. lock with this directory here. So, the copy command here copies files from our machine into the container. The last argument is the destination. So, this dot and forward slash means the current working directory in the container, which is that forward slash app. So, we're just copying our pyproject. toml and uv. lock into the app directory and then we are installing dependencies here with uv. sync and I'll talk about these flags and options that we're using here in just a second because that leads into this next part here. Now, this next part is a Docker optimization trick. So, we copy our dependency files first, which are pyproject. toml and uv. lock, and install dependencies before we copy our application code. And this is us copying our application code here. So, why does that order matter? Because Docker caches each step as a layer and the moment something changes, that step and everything below it gets rebuilt. So, if we copied all of our code first, then every time we changed even one line of code, Docker would have to reinstall all of our dependencies, too. So, by putting the dependency installer higher up, a code change only triggers a rebuild uh from this step forward. Uh the dependency layers above it are still cached because pyproject. toml and uv. lock didn't change. So, for the uv. sync command, we have some flags you may not have seen yet. Uh locked means use the exact versions from the lock file. The no install project means don't install our app yet, just the dependencies, and that's because we haven't copied over our app code yet uh

Segment 4 (15:00 - 20:00)

for the reason that we just mentioned. And this no dev here, this skips development and dependencies like pytest that we don't need in production. Okay, so then we are copying everything from our project directory uh into the container here and then we run uv. sync again to finalize the installation now that our code is in place and you can see with this second one, we don't include this no install project flag. Uh the second run is fast because all the dependencies are already cached. Okay, so now we have the production stage here. Now, we start fresh from the same Python base image here, this 3. 14. 4. Now, all the UV binaries and the build junk from the first stage are going to be gone unless we explicitly copy them. Again, we are setting our work directory to /app and then here, this run user command, then we create a non-root user called app user and switch to it with this user command here. Now, basically the reason for this, if you watched tutorial 18, it's the same security principle. If someone exploits our app somehow, then they only get this app user privileges. They don't get root privileges. So, that's important just for security. And then this next line here, uh copy from builder, this is where the multi-stage build comes in. So, from builder here means copy from the builder stage, not from my local machine. And you might be wondering how Docker knows where the builder stage ends and this one begins. So, every from instruction in a Dockerfile starts a new stage. So, we can see up here that this one was as builder. That gave the stage a name that we can reference later. So, the second from down here starts a fresh stage and since it's the last from in our Dockerfile, uh this is the stage that becomes our final image. So, on this copy line here, here we are pulling in our code and the virtual environment with all of our installed packages from that builder stage, but everything else from that stage, so UV itself, its cached files, any temporary build files, none of that comes along. It stays behind in the builder stage, which gets thrown away. So, that's the whole point of doing this in two stages. So, our final image only has what we actually need to run the app, which keeps it small and clean. And this chown here ensures that the files are owned by our non-root user. Okay, and then we have these environment variables here. Here we add the. venv virtual directory uh to the path so that we can run FastAPI, Python, etc. uh without full paths. And that virtual environment was created by our uv. sync command. So, here we have python buffered equal to one. So, python buffered makes Python output appear immediately in logs instead of being buffered. Without this, print statements and logs might not show up until the buffer fills up, which is really confusing when you're trying to debug in Cloud Run's log viewer. Now, we're also setting the port here. We're setting a default port of 8080 for local testing. Cloud Run will overwrite this with its own port when deployed. And finally, down here with the CMD, we have a command to run when the container starts. Now, this one might look a little unusual here. Actually, let me turn on my word wrap. I usually don't like word wrap for uh coding, but uh I think we want to see all of this here. Okay, so we can see that our CMD here uh is an array and we have three parts. So, the first part here is this uh bin/sh, then we have this -c, and then the last part here is this long exec command for FastAPI run. So, the first part here is the program to run, which is sh, a shell. The second is -c, which is a flag that tells the shell the next argument is a command to execute. And the third is that entire command in a single string. So, we need a shell here because it's the shell that expands our port environment variable for us. Now, an important piece here is this exec at the beginning of our command. Without exec, the shell process stays running and our FastAPI app runs as a child process underneath that. The problem with that is that when Cloud Run tries to gracefully shut down the container, the shutdown signal goes to the shell and the shell doesn't forward it to our app. So, this exact here fixes that by replacing the shell with our FastAPI process, so the shutdown signal goes

Segment 5 (20:00 - 25:00)

directly to our app for a clean shutdown. So, the flags that we have here, we have a host of 0000, uh that listens on all network interfaces. In tutorial 18, we used 127. 0. 0. 1 because Nginx was on the same machine in a container, the network is isolated. So, we use 0000 for traffic to reach us, and then we are setting the port here, that is going to be 8080 that we have set there. Uh proxy headers and forward allow IPs that trust the X-Forwarded-Headers from Cloud Run's load balancer so that we get the real client IP and protocol. Now, you'll notice that there's no workers flag here, and that's intentional. So, Cloud Run scales by adding more containers, not by adding more workers within a container. So, a single process per container means faster cold starts and simpler memory management. On the VPS in the last tutorial, we set the number of workers based on how many CPU cores we had. Here, the auto scaler handle handles that for us by spinning up more containers as needed. All right, so that's an overview of the Dockerfile. Now, we need a Dockerfile, and this tells Docker which files to exclude when building an image. And if you've been using Git and have a Git ignore file, a lot of what's in there is usually good for the Docker ignore as well. Now, I have a standard Git ignore that I've been using for this series that I've been including with the downloadable content, but I've never gone over it in the videos. So, I'm going to use that as a starting point and also add a couple of Docker specific entries at the top. But, first, let me go ahead and create that Docker ignore file. So, we have to put a dot in front of that. This is a dot file, and this is going to be Docker ignore. And now, let's add a couple of things that are specific to Docker. So, first, I'm going to do dot git, and that is our Git history. That is not going to be needed in our container. And also the test directory, we do not need it either. That's going to just be for development, and this is for production. So, then, I'm going to take my standard Git ignore template that I use for most projects. Again, you can see this in the code in the description section below if you're interested, but it's just a standard template that you'd find online for most Git ignores. So, let me open this. I also have a comment here of how I created this with toptal. So, I'm just going to copy all of that and paste all of that there into my Docker ignore. So, the ones we added to Docker ignore, we ignore dot git because the container doesn't need our entire Git history, test because the test files aren't needed in production, and everything else below comes from the Git ignore, and that excludes things like, you know, dot venv, __pycache__,. env, and other files that we don't want in the container. Now, some that I already have in my Git ignore are important that you're going to want to add to your Docker ignore if they're not already there. So, first, the dot venv, let me see here. That's down here in the Python section, I believe. Actually, let me just search for it. It's in the environment section. So, dot venv exclusion is really important. Your local virtual environment was built for your machine's operating system and architecture. It won't work inside the container, which is running Linux. The container builds its own virtual environment from scratch using the Dockerfile. And just like I mentioned with the dot gitignore throughout the series, the other important one here is this dot env exclusion, and that's important for security. So, that has all of our access keys and things like that. We don't want our secrets baked into the Docker image. We're going to inject them as environment variables at runtime. All right, so before we test our Docker image, we need a database. So, Docker containers are stateless, meaning any data stored in the container is lost when it stops or restarts. So, you can't run Postgres inside the Cloud Run container that we're going to be creating. It would get wiped out every time the container restarts. So, what we need is an external database that's accessible over the internet. So, what I'm going to be using for this video, I'm going to use something called Neon, which is a serverless Postgres service, and Neon isn't a Google product. It's an independent company, so it's not like we're getting locked into Google's ecosystem. And this isn't a sponsored video. They're just a popular solution for this kind of thing. We could swap this for any Postgres database, and our code wouldn't change at all since it's

Segment 6 (25:00 - 30:00)

just standard Postgres. So, I chose this for a few reasons. It's really popular. It has a good free tier with half a gig of storage and plenty of compute hours for a small project. It also scales to zero just like Cloud Run. So, when nobody is using our app, we're not paying for the database either. And also, it's just standard Postgres, so no code changes are needed on our end, and it doesn't require a credit card to sign up. Now, there's other managed Postgres options out there, so feel free to use whatever you'd like. Since it's standard Postgres, the code would be the same regardless. Okay, so let's go ahead and set this up so that we can test Docker locally with a real database connection. So, I'm over here at neon. com. It redirects me to neon. tech when I'm logged in here. Like I said, it's free, no credit card required. So, once you sign up, you'll get a dashboard here. I'm going to create a new project. So, I'm going to call this project, let's just call this FastAPI-Blog. So, for the region here, I'm just going to use US East 1. We want to pick something close to where our Cloud Run service will be deployed to minimize latency. Postgres version 17, I believe that's the latest, so we'll go ahead and use that. Now, I need to create a database and uh connection strings. So, I will click on the create button down here. And now that database is created, I'm going to close down the pop-up there, and now I need to get connection strings. So, I'm going to click on this connect button here. And I'm sorry, I think I said earlier that we had our database created. We have our project created, and now we want to create our database. So, from the database drop-down here, I'm going to click on create new database. So, let's click that. Now, for the name, I'm just going to select blog here. And for the owner, I'm going to leave this as neon_db_owner, which is the default. So, let's create that. Okay, and now we need our connection strings. Now, I need two connection strings here, one for running migrations and one for our app at runtime. So, let me go ahead and copy both of these connection strings and modify them for our use case, and then I'll explain them. So, first, let me go back to my code and open my. env file. That way I have somewhere to paste and edit these. So, I'm just going these at the top here. And now, let's go back to Neon. So, first, I'm going to get the direct connection string, and this is going to be for migrations. So, I'm going to click on show password down here so that I can see the full string, and then I'll make sure that the connection pooling is disabled. And looks like it hid our password again, so again, let me show that. Okay, connection pooling is off. We are showing our password. So, now, let me copy that snippet, and I will paste this in here. I'll say that this is the direct one here. And again, I'll go ahead and turn on word wrapping here, and now let's edit this for our application. So, first of all, we can see that we have psql here and then the single quotes. Let's remove those single quotes and also that psql wrapper there. We just want the actual Postgres connection string. Now, I also want to change the Postgres here at the beginning, and I want this to instead be postgresql plus uh psycopg. So, that is psycopg. That's how I pronounce it. This is how you spell it. And then everything else here stays the same. Okay, so let me specify that this is for migrations. Now, we added this plus psycopg here, and we can see that we also have it down here in our current database URL. That's the async driver that we've been using, so we want to use that async driver. Okay, now for the pulled connection string, I will go back to Neon here. Let's enable connection pooling here. Again, let's show password and copy that, and then let's go ahead and paste this in as well. I will say that this is pulled, and it's for runtime. Let me paste this in. Again, I will remove that Postgres or that psql wrapper, and I will add in the psycopg here. Now, the key difference here is you'll notice that after this at symbol, we have the host name, and the host name has this - pooler in it. That's how you know that it's a pulled connection. Okay, so why do we need two connection strings? So, the pulled connection uses PG bouncer for connection pooling. So, Cloud Run can scale up multiple container instances rapidly and each instance opens database connections.

Segment 7 (30:00 - 35:00)

Without pooling, these connection spikes could overwhelm the database. So, the pulled endpoint can handle a lot more concurrent connections. But, we need the direct connection for migrations because the pooler can interfere with some of the things that Alembic needs to do. So, the simple rule here is we're going to use pulled for our app and the direct connection for Alembic migrations. So now, I'm going to comment both of these out here. And now, we need to run our migrations on this new Neon database. Since we need the direct connection for migrations, let me set this direct URL here as our database URL for now. Let me also close down the sidebar here so that we can see a little better. Now, everything else in the. env stays the same. So, the secret key, front-end URL, all the mail settings, they those all stay as they are. Now, one thing you could do and probably should do is set this up so that you have two different environment variables, one for the direct connection that Alembic uses and one for the pulled connection that our app uses. That way, you don't have to remember to switch these back and forth for future maintenance. But, I'm just going to switch these manually for the tutorial and you can separate create separate variables if you have an app that you want to maintain long-term. But, for now, I'm just going to set that direct connection. And now, let's run our migrations. So, I'm going to open up my terminal here and remember to run our migrations, we can just run Alembic upgrade head. And it looks like our migrations ran successfully there. So, this created all of our tables in the Neon database. So now, if we go back to our Neon dashboard and now, let's go to we can see that we have a tables tab down here. Let's click on that and we should see we have our Alembic version, password reset table, our post table, and our users table here. Okay, so we ran those migrations successfully and our database is created. So now, let me switch the database URL to the pulled connection string since that's the one that we want for actually running our application. So, I'm going to grab that pulled connection string here and let's paste that in. I will save that. Okay, so now, we're ready to build our Docker image. But first, let's do a quick sanity check here and make sure that our app works with this Neon database. This helps us isolate potential issues. So, if this works but then Docker fails, then we'll know that we did something wrong in Docker. But, if this fails, then we know that it's the Neon connection that is the problem and we need to fix it before moving on. So, let me go ahead and run our dev server here. Let's make sure that our application is still running. So, I will reload this and our front-end looks good. Let me check our health endpoint. The health endpoint talks directly to the database and we can see that returns healthy, which means our connection to Neon is working. So, our application is working with Neon. Okay, so now, let me go ahead and stop the server here. All right, so now we're ready to build our Docker image. So, I'll build this and we can test everything locally before deploying. So, again, down here in the terminal, we can say Docker build -t fast API app and then the current directory. Now, that -t flag tags our image with the name fast API app so that we can reference it easily. The dot at the end just means use the current directory as the build context, which is where Docker looks for our Dockerfile and the application code. So, let me go ahead and run this and we'll wait for this to complete. Okay, so I fast-forwarded to the completion of that Docker build. Now, this actually failed here. Let me scroll up and see no interpreter found for Python 12 in managed installations. So, it failed on this line here. I think I know what this is doing. I think that we have So, we can see that we have a Python version file here in our local development directory that is set to 3. 12. We are using the latest 3. 14 in our Dockerfile here. So, let me add this down here. Actually, I'll just add it up here as one of the Docker specific ones. Let's add that Python version. file to our Docker ignore as well. And now, let me try to rebuild it with that in our Docker ignore. So

Segment 8 (35:00 - 40:00)

hopefully, this will work. Let me try to rerun this. Okay, so this output looks a lot better here. So, let's see what it did here. So, we can see it goes through all of the steps. It pulls from the Python base image. It copies the UV binary, installs our dependencies, and then it'll go through the second stage where it copies starts fresh and copies just what it needs and it looks like this was successful. Okay, so that's done. Now, let's run it locally using our. env file, which now points to our Neon database. So, to do this, I can say Docker run and we're going to set the port. We'll set this 8080 8080. And I'm going to go ahead and write these out and then I will discuss all of these after we are done here. So, let me write this out and now, let's go over what this is doing. Now, like I said, I could do an entire series on Docker itself, which I actually do plan to do, but I am not going to go into the weeds of everything in-depth here. But, let me explain as we go. So, Docker run will run an image. This -p and then 8080 here maps port 8080 on our machine to port 8080 in the container. And this -env file option here, that reads all the environment variables from our. env file and injects them into the container at runtime. Now, this part is important. So, the. env file is not in the image itself. It stays on our machine because it's in our Docker ignore file. We're just injecting the variables when we run the container. And then, we just specify the container that we want to run. That is the one that we just built. So, let me go ahead and run this Docker run command. Okay, so now, our container is running, but notice it's on port 8080 now, not 8000 like we when we run it locally with fast API dev. That's because our Dockerfile sets port 8080 by default, which is what Cloud Run uses as well. So, let me test this in the browser. So, instead of port 8000 here, I'm going to do 8080. Let's run that. Okay, awesome. So, this is running on our container. We still don't have any data in here. That's why everything is blank. But, let me check that health endpoint here. We can see that it says status of healthy. All right, awesome. And also, let me just make sure that the docs are working as well. Okay, the fast API documentation is working. So now, from the front-end here, let me go ahead and try registering a user, logging in, creating a post just to make sure that everything works here. So, I will create a user of Corey M. Schafer. I will use my email here. And I will create a password here of just test password one with an exclamation point. Test password one {exclamation point}. Let's register that user. Okay, that worked. And now, let me log in as that user that I just created. Test password one. Okay, login successful. Let's go ahead and create a post running in container. This works. Post that. That is successful and we can see that we have our default image and our first post there. And just to check that Amazon S3 is working within our container as well, let me also change my profile picture here. So, I will change a picture to let's choose my parent's dog Poppy here. So, we will go ahead and upload that. And we can see that now, our profile picture was changed. If I look at the URL, the URL this is kind of hard for you all to see, but it has S3 in the URL here. So, that is coming from Amazon. Awesome. So, all of that still works because we injected our S3 credentials from the. env file into that container. So, if everything works locally in Docker, it should definitely work on Cloud Run. It's the same container, same behavior. And that's why a lot of people decide to use Docker. So, let me go ahead and stop my local container here. All right, and now let's get this deployed to Google Cloud Run. So, first you need a Google Cloud Platform account. So, I have an account here. Now, they have a free tier available, so

Segment 9 (40:00 - 45:00)

you can follow along without paying anything. Just go to console dot cloud dot google. com and create an account if you don't have one. And then create a new project or you can use an existing one. Now, I'm going to go ahead and create a new Google Cloud uh project for this tutorial. Uh so, I will call this fast API dash blog. And I will leave a link in the description section below uh to this link to create a new project if you need to create one as well. So, I will create this project. And then it is going to pull up a dashboard here. Now, I had some other projects as well. And while it was creating that project, it looks like it chose one of my other testing projects that I created. So, this is not the one that I just created. Uh let me select the project that just got done creating here. Okay, and now we can see up here in the left I am on this fast API blog project here. Okay, so we can close everything down. And we also have a project ID and we will need that here in just a bit. But for now, we need the G Cloud CLI. And I am going to uh install this with Homebrew the same as Docker. If you don't use Homebrew, you can download it manually and I'll leave a link to that installation page in the description section below. But to install this on my machine, I'm going to say brew install. And this is a cask and this is G Cloud dash CLI. So, I will install this. Oops, and it looks like I spelled that incorrectly. This is G Cloud. So, let me make sure that I spelled that correctly and now run this. Okay, so it looks like that installed correctly. Uh let me verify that by saying G Cloud dash version and it should give us the version that installed. Okay, good. So, that's working. So, now let's authenticate. We have to authenticate so that it knows that the project is ours and everything like that. So, I'm going to go to Google auth login and this will pull up a page for me to login to my Google account. So, I'll go ahead and allow that. And then I will login with my Google account. Uh I'll probably skip through this part just so I don't show the length of my password or anything, but then I will pick back up once I'm signed in. Okay, now I did want to point out this part. These are the permissions that you are giving here. Uh so, you can see that it you can view and manage your applications deployed on Google App Engine, uh see and confirm uh Google Cloud SQL instances if you are using those, things like that. I'm going to go ahead and allow that. Okay, and then it should take you to this page that says you're now authenticated with G Cloud CLI. Now, I need to set my project and I'll need my project ID for this, which I can find in the Google Cloud Console dashboard. So, I had that pulled up here. Now, it looks like they're moving to something called Cloud Hub here and that the dashboard's no longer going to be updated. Uh but I am not going to worry about that for now. I'm sure in that Cloud Hub it'll be easy to find this stuff as well. But what I'm going to grab here is my project ID. So, I'm going to copy that. And now back in my terminal, let me go ahead and clear my page here. Now, actually before I clear this page out, you can see here that when we did the login, uh it says that okay, we are now logged in. Your current project is none. You can change this by running this. And it gives us uh that command there. So, that's exactly the command that I'm going to run, but I'm going to use my project ID here. So, let me clear this out and that command was G Cloud and I keep spelling that incorrectly. G Cloud config set project. And then we want to paste in that project ID that we got from our Google project. So, let me run that and that's updated. Now, we need to enable the APIs that Cloud Run uses. So, let me try this. So, this is Google or G Cloud services enable uh run. googleapis. com. Let me run this. Now, it looks like this ran successfully for me, but this will likely fail if you haven't enabled billing on the project yet. Even for the free tier, Google requires a billing account to be linked. Uh you won't be charged if you stay within the free tier limits, but if this fails, then you'll have to go to your Google Cloud Platform console and then click on billing. So, we can see here that for my project, it looks like it already connected my billing account here. Uh if it hasn't connected yours, then you'll have to go to billing here and connect that. I won't show that on screen just for, you know, I don't want to show my billing information and stuff. But go there

Segment 10 (45:00 - 50:00)

connect the billing, and then this command here should work. Okay, so there are some other services that we need to enable here. So, instead of just run googleapis, we also need uh that is cloud. build. googleapis. com. Let me run that. Hopefully, I'm not spelling any of this incorrectly. Now, some of these may take a little bit of time, but I'm just fast-forwarding the video to where these are complete. So, now we have run. googleapis, cloud. build. googleapis, and now the last one that we need is going to be artifact registry. And of course, I spell it wrong. Okay, there we go. Okay, now that one didn't give me a success message like the other ones did. Uh let me go ahead and just test this. So, I'll say uh G Cloud services list and I believe we can list enabled like this. Okay, and we can see everything in here. So, we have that artifact registry here. I could have searched these uh independently, but we have run here and Cloud Build was another one that we needed here. Okay, so I'm going to go ahead and clear that out. So, the three APIs that we needed were Cloud Run for running our containers, Cloud Build for building our Docker images in the cloud, and Artifact Registry for storing our Docker images. Okay, so first, let's create an Artifact Registry repository. And this is a one-time setup. So, I'm going to say G Cloud artifacts and we want this to be repositories create and I will call this fast API dash repo. You can call uh this whatever you want for you. Then I'm going to go to a new line here and I'm going to do an option here of repository format and I'm going to set this equal to Docker. And then I'll do another new line here. And then for the location, I looked this up beforehand. I'm going to use US East. So, that is US dash East. And I'm going to use four and that is just a location that I determined was close to our the Neon database that I set up, which is in US East 1. So, keeping your services geographically close minimizes some latency. So, let me run this. If I typed everything correctly, then this should create. Okay, so we can see that it says that it created that repository of fast API repo. So, now let's build our image and push it to Artifact Registry. So, we'll use Cloud Build for this part, which builds the image on Google servers and pushes it directly to our registry. So, this has a longer URL in the command. So, I'm instead going to grab this from my snippets file here. So, let me open up my snippets here and the URL for this. So, let me grab this, go back to our command line here, and I will paste this in. Okay, so the command that we have here is G Cloud builds submit. And then on the next line here, I'm using a tag. Now, this tag URL, you can see that this is pretty long and this is not something that you'd memorize. So, you can find this format in the Google Cloud docs or in the Artifact Registry console after creating the repository. But let me break down what each part is here. So, we first have this US East uh Docker package dev. That's just the registry home name. And then we have our project ID. And then the repository name here. That's the repository that we just created. And then finally, we have the image name, which I am calling fast API app. So, what I need to do here is I need to replace this project ID placeholder with my actual project ID. So, again, let me grab that. And I will go back here and paste in my project ID here. Okay, so now let's run this command. So, what this is doing is this is uploading our source code to Cloud Build and they build the image on their servers using our Dockerfile. So, this is a separate build from the local one that we did earlier. The local build was just for testing on our machine. This one builds it in the cloud and pushes the resulting image to Artifacts directory. And this might take a couple of minutes for the first time. So, let me wait for this build to complete. Okay, so that's done and it looks like it was a success. So, our image is built and stored in the artifact directory. So, now let's deploy it to Cloud Run. And again, I'm going to grab this from my snippets here since we have that long URL in here again. But let me paste this

Segment 11 (50:00 - 55:00)

in and then we'll go over what this does here. So, let me clear out that there. Okay, so here we have gcloud run deploy fastAPI service. fastAPI service is the name that we are giving our Cloud Run service. The image flag tells it which image to use and that is what we just deployed up to our artifacts directory. Or I'm sorry, that's is the image that we just pushed to our artifacts directory. And then we have our region here which was us-east-4. And the allow unauthenticated means that anyone can access our app. So, without it, you'd need Google authentication to access the URL which isn't what we want for a public blog. So, I'm going to replace my project ID here again because I just have a placeholder there. And now let me grab this project ID and paste that in. Okay, and now let me run this and deploy that fastAPI service. And now while this is running, if we think about this, this is probably going to fail and we can see that it just did fail here. Now, that's expected so don't worry. The container needs environment variables like database URL and secret key in order to boot up. Without them, it's going to crash on startup. But the good news is that the Cloud Run service has been created. We just need to add our environment variables. Now, there are a few ways that you can do this. So, you could use the gcloud CLI with the set env vars option which is great for scripting and CI/CD. But for this tutorial, I'm going to use the Cloud Console UI so that we can see what's happening. So, first let me generate a new secret key for production. Just like tutorial 18 if you followed along there, we never want to reuse keys between environments. So, to create a new secret key for our application, I'm just going to use Python here. So, run Python 3 and do a command here. And I'm going to import secrets and I'll put a semicolon there just so we can run this all on one line. And then I will do secrets. token_hex and we will pass in 32 as the value there. Hit enter and we can see that we get a big long random secret key here. So, I'm going to copy that. And now let me go to the Cloud Console here in the browser. And now here within the Google Cloud Console, I'm just going to navigate to Cloud Run. So, I will search for Cloud Run up here and we can see it's the first option. So, I'll click on Cloud Run. And now we should see our service here. That's the one that we just tried to start. Now, we can see that when we tried to deploy this that it says that there are errors here. So, let me click on this service. And now we can see a list of a few errors here. Now, before I go to the settings, let me copy the URL that they've given us here. We can see the URL here and I can copy this to the clipboard. We're going to need that for the front-end URL environment variable. So, I'll go ahead and copy that. And now I'm going to go up here to edit and deploy new revision. So, I'm going to click on this here. And now down here we can see our container. And with our container, you can see that we have an option here of variables and secrets. So, I'm going to open up this variables and secrets here. And now we can see this is where we can add our environment variables. So, I'll add all of our environment variables. Now, for a more hardened production application, you could use Google Secret Manager for sensitive values instead of plain environment variables. But for this tutorial, environment variables work fine. So, I have my. env file open here so that I can reference it. So, just to make this easier on myself, let me actually take myself out of full screen mode here on both of these and then I can have them side by side here so that I can see everything that we need. And I'm also going to turn off word wrap there. Okay. Okay, and now I'm just going to add these one at a time. Now, the first one that I'm going to add is going to be front-end URL and that is the one that we just copied. So, I will paste in that URL. And now the second one that I want to create here is going to be secret key. And also, I don't have this on my clipboard anymore. But this is one that we just created. So, again let me paste this in. And now everything else should be the same as we have in our. env file over here. Now again, remember we are using this pulled connection string for our database URL for that Neon database. So, I'm going to

Segment 12 (55:00 - 60:00)

go through here and I am going to add all of these. I probably won't show me adding all of them since this is going to be a little tedious here. But I will show adding a few here just so you can see exactly what I'm doing. And then once I'm done, we will go ahead and fast forward and I'll show you all of these set. Okay, so I went through and added all of my environment variables here. Now, the only two that were different from what was actually in our. env file here is the front-end URL and we added these at the top. Instead of localhost, we want that to be our actual service URL there. And for the secret key, we generated a new one because we don't want to use the same one that we used in development. All of the other ones are the same that we have. Just make sure that you're using that pulled connection for the Neon database if that's what you're using. I also used port 587 here for our mail port. This is a production port for email and 587 works on Mailtrap as well. So, if you do switch over to something like SendGrid or an actual email service, then you would just have to come in here and update the mail server and the username and password that they give you. But we are using Mailtrap here. That should work fine. I'm going to go ahead and click deploy now that we have all of our environment variables in place. And so, let's click that. And now it should create this and try to start this up again. Okay, awesome. So, it looks like it succeeded this time. So, now let me make this full screen again for both of these. And now let's go back to our container here and our service that's running. So, let me click on the URL that it gives me here and let's see if this is running. We can see that we do have our application and that we still have our database working because it's pulling in the one that we ran on our local machine earlier. Let me make this a little larger so everyone can see. Okay, so we can see the URL up here is for our fastAPI service. And now let me see if the health check works on here. We can see status healthy there. So, that seems to be working. If we go to the docs route, then that seems to be working as well. Great. Okay, so now let's also take a look at some of the Cloud Run logs here. Okay, so right here we can see that we are looking at a specific revision. Let me go back to the overview here and let's look at our service. And now we can see that we have logs here. Let me click on the logs and we can see that our application logs right here in the console. And this is where that Python buffered equal to one in our Dockerfile comes in handy because without it, these logs might be delayed or missing. So, you can view all of your logs here. Now, just like when we deployed in the last video, you probably don't want this big long URL here of this random fastAPI service. You probably want to use a custom domain name instead of what Google provided for you. So, let's go ahead and get that set up as well. So, I'm going to use the same domain as I used in the last tutorial and that is myawesomeapp. com. But first, I want to mention an important caveat. So, Cloud Run's built-in domain mapping is currently labeled as preview and limited availability. Google themselves says it's not recommended for production. For a real production app, they recommend using an external load balancer or Firebase hosting or Cloudflare in front of Cloud Run. But for this tutorial, the built-in domain mapping keeps things simple and lets us see the full process. Plus, I'd expect that it won't be in preview much longer. But obviously, I can't be entirely sure of that. Okay, so the first step is to verify domain ownership in the Google Search Console. So, I have Google Search Console pulled up here already. I'll go ahead and leave a link to this page in the description section below. But whenever you go to the Google Search Console, then it's going to say that we want to add a property here. Now, the property that we want to add is a domain and not a URL prefix. And the domain that I want to add for me is going to be my awesome app. com. Yours will be whatever domain you pick and I will click continue. Okay, now for this step here, this says that ownership was auto verified. I think that this is doing this for me because I have verified this domain on my account in previous tutorials, but what you might

Segment 13 (60:00 - 65:00)

get is Google should give you a TXT record that you would then need to add to your DNS settings. So, if it was to give me that TXT record, what I would do is I would go to whatever domain registrar I am using. Mine is Namecheap. Yours can be whatever it is. You're going to then click on your domain names settings and then you'll want to navigate to your DNS settings. On Namecheap, this is called advanced DNS. On yours, it could be anything. And then what you would do at this point is you would click on add new record and you would want to add a new TXT record and the host would just be an @ symbol there. And then for the value, it would be whatever Google gave you and then you would save that. And then after you save that, you would need to wait a few minutes for DNS propagation and then go back to the search console and click on verify. Uh but it looks like mine was already verified here. Now, once that's verified, then we can create the domain mapping. And this requires using the beta command uh since this is still in preview. But once this is out of preview, then this command will likely be the same as I'm about to use but without the beta part. So, let me go ahead and type all of this out uh just so we can map this URL. So, I'm going to say Google beta run and this is domain mappings and we will create a mapping here. And now I'm going to go to a new line and for the service, we are going to set this equal to fast API service. This is the service that we just created. You would use whatever you named your service. For the domain here, I'm going to set this equal to my awesome app. com. You would use whatever domain you are using. And then again for the region here, my region has been US East 4 for this entire video. You would use whatever you selected. Okay, so let me run that and let's see if that works. Okay, so once that's done, Cloud Run will give us DNS records that we need to add here. So, it'll show four A records for IPV4 and four A records here for IPV6. So, let me go back to Namecheap and add these. So, again, let me make this half screen here and again here. Go back to my Namecheap account here. And sorry, I'm going to make the screen just a little smaller here so that all of these fit on one line. Actually, I still want you to be able to see this. Okay, so I think this is large enough here. Okay, so now we need to add all of these. So, I still have some A records here from the last deployment video where I deployed this onto a VPS. I'm just going to delete those since I no longer want these to point to Linode. Now, I'm getting an error here and it's because this I've probably been inactive for so long that it logged me out. Let me go ahead and log back in here and then I will pick up the video from there. Okay, I have logged back into my account. Now, I can delete these old records that I was using for the last video. We no longer need those. And now we have no DNS records here. So, I'm just going to add these one at a time. We are going to have four A records and of the four A records here. So, I'll go ahead and just add all of these in. And now I will do a couple of these here. So, contents, we want to set all of these to the right IP addresses here. Uh now for the host, we are going to use just an @ symbol for all of these. Now, I probably won't show filling all of these in uh but I will fill in enough to where you can kind of get an idea. Okay, so I filled in all of the records that it gave me. I misspoke earlier. I said that it gave me four of these uh four A records here. It only gave me three. So, now I'm just going to go through and save all of these and then it should allow those to propagate. And then once those are propagated, then that is when we can do the certificate provisioning. So, we need to wait for DNS propagation and for Google to provision an SSL certificate. And this takes longer than it did with the VPS approach in the last video. Uh with the VPS deployment, we ran Certbot immediately after DNS propagated and had an SSL certificate within a minute or so. With Cloud Run, Google's automated

Segment 14 (65:00 - 70:00)

system provisions certificates on their own schedule. So, expect 15 to 45 minutes, sometimes longer uh depending on when that automated system provisions certificates. So, we can actually test this. So, now let me just go ahead and maximize my browser again. Go back here to my terminal console. Now, we can test this here. I doubt that this is going to be provisioned yet, but we can do a gcloud beta and I'm going to run domain mappings and then we are going to click on describe here or type out describe. And then for the domain, we are going to set the domain to my awesome app. com. Sorry, talking and writing at the same time is kind of difficult sometimes. And then for the region here, we're going to set the region equal to US East 4. Now, if I run this, then I would say that this probably isn't done yet. Okay, so we can see here that it is still waiting. So, we have waiting for operation here and waiting for certificate provisioning. You must configure DNS settings for certificate issuance to begin. So, I don't think that is done yet. So, I am going to pause the video here, wait a good bit and then I will rerun this command and I will wait until this command gives us a success. Okay, so I took a good long break there. I believe it was about 50 minutes or so. I was still coming back and this was not telling me that the certificate was provisioned but just over 50 minutes, a little under an hour, that certificate did get provisioned there. So, whenever we run this describe command here, now we can see that we are getting certificate provisioned equal to true. Okay, so let me clear out my terminal here. And now let's go back to the browser. Now, I do have a my awesome app open here in the browser. Before it was saying this site cannot be reached. So, now let me reload this. Okay, and we can see that is now working. So, that's awesome. That's great. So, it looks like our app's running on our custom domain and with HTTPS. So, we do have a secure connection here. So, that is great. Uh now, let me go ahead and walk through here a little bit. So, let me just test that everything is working on our custom domain. So, if I go to our health check, then we can see that is printing out that we are healthy. If I create a new account here, so I'll create Corey M. Schafer 2 instead there. Now, for the testing, I already have a Corey M. Schafer@gmail address registered. So, I'm going to do test@test. com. And for the password, we will do a test password again here. Hopefully I spelled that correctly. Okay, so let's create an account. And now let's log in here. That was test@ @test. com and I was using test password here. So, let's log in here. Login successful. I will create a new post here. I'll say we are deployed and we are deployed on custom domain. All right, so let's post that. That is working there. Now, let's go ahead and make sure that S3 is working with our custom domain. I will choose Let's choose my dog here. Let's upload that. Okay, so it says the profile picture was uploaded successfully and we can see that profile picture is working and it is coming from our S3 URL. Awesome. Okay, so I know that was a lot. So, if you made it this far, then just take a second to feel good about getting to this point and having all of that come together. Okay, so now that we are fully deployed, let me quickly show you how to update the application when you make code changes. So, you make whatever changes that you want to your application and then when you are ready to deploy those changes, this is super simple and easy. It's just two commands. So, first you would rebuild and push the image. And I ran this command earlier, so let me hit up until I find this

Segment 15 (70:00 - 75:00)

command here. So, that is our deploy. Here is our build command. So, we did a GCloud build submit and then this was our tag here. So, we would just run that after we make some code changes and remember our Dockerfile copies our application code into the image during the build. So, that build command, it picks up whatever code changes we've made. It builds a new image with those changes and pushes it to our registry. And once you run that build, we can see that was successful. I'm going to go ahead and clear that out and then you would just deploy that new version with the run deploy command. Now, I will press up here until I find that run deploy command here. So, let me find that. That is right here. So, I can run that. And that's it. If you had made changes to your code and built that and then deployed it, then Cloud Run would handle rolling out the new version with a zero downtime deployment. It spins up the new version, verifies that it's healthy, and then routes traffic to that. If it has health checks that fail, then traffic would stay on the previous version. Now, if you change the database schema, then you'd also need to run migrations. So, the way we have it set up, we would just temporarily swap to the direct connection string and our environments file in our. env file. Then we would run Alembic upgrade head and then swap back. But if you set those up as separate variables, then you could run the migration without even swapping those. And if you wanted to get this down to one command, then Cloud Run actually can deploy directly from source code without running separate build and deploy commands. So, I believe this is GCloud run deploy and we could just do FastAPI service and for the source, we will just set it to our current directory and then we could set the region that is US East 4 for me. And this source flag tells Cloud Run to upload our source code and build it on their servers. Now, if a Dockerfile exists and ours does, it does that automatically. So, this is really just combining the build and deploy steps into one convenient command and that's what just happened here. It used our Dockerfile will use our Dockerfile here. So, I think that would probably use a different repo than the one that we created. I'm just going to cancel that since we have been doing it with different build and deploy steps. Now, if you tried to do that and there was no Dockerfile, then Cloud Run falls back onto something called Buildpacks. So, Buildpacks is Google's tool that tries to auto-detect what language your project uses and build a container for you automatically with no Dockerfile needed. Now, you might be wondering why I went through writing the entire Dockerfile if Buildpacks can handle it for us. Well, there's a couple of reasons for that. First, when I was preparing for this tutorial, Buildpacks didn't even support the version of Python that we've been using for this series. I think Google has since updated it, so it might work for our application, but that's kind of the point. With a Dockerfile, you have full control over the Python version, the package manager, how the app starts, and everything else. You're not waiting on Google to support your specific setup. And second, Docker is a fundamental skill that transfers everywhere. The Dockerfile that we wrote works on Cloud Run, but it will also work on AWS, on Kubernetes, on a CI/CD pipeline, anywhere. Buildpacks is specific to Google and they, you know, they can work for your use case. If it does, it's a great shortcut, but knowing Docker gives you control and portability. Okay, so let's take a step back and compare the costs of deploying to a VPS like we did in the last video and deploying here with Docker and a managed container platform like Cloud Run that we did here. So, Cloud Run's free tier gives you 2 million requests per month. After that, you pay per request and it scales to zero when there's no traffic. So, you're not paying anything when nobody's visiting your application. Neon's free tier, our database, gives you half a gig of storage and plenty of compute hours for a small project and it also scales to zero. So, for a small project, the total cost for what we've set up today is most likely zero dollars. Both services scale to zero when idle. If your app takes off and then gets a lot

Segment 16 (75:00 - 79:00)

of traffic, then you'll start paying, but that's a good problem to have if you've built something that's getting that much traffic. So, compare that to the virtual private server deployment from the last video, Linode costs about $5 a month for their smallest VPS whether anyone visits or not. You manage everything yourself, but the cost is predictable. So, which deployment method should you choose? Well, that depends. So, let me do a quick side-by-side comparison of VPS versus a managed container platform like Cloud Run. So, in terms of control, a VPS gives you full control. A managed platform, you only manage the container. For maintenance, a VPS means that you update the operating system, also Nginx and Postgres yourself. For how we've done it in this video, Google and Neon would handle that. For scaling, on a VPS, that would be manual. You would need to upgrade to a server that can handle your traffic. A managed container platform like we have here scales automatically. Now, in terms of cost, a VPS is fixed and predictable. For ours, it was $5 a month. On a managed platform, it's pay-per-use. For a small app like ours, it's likely going to be zero dollars. For a large app, you would have to look at your metrics and determine what that cost is going to be. And lastly, in terms of the skills that you need, for a VPS, you're going to be doing some fairly advanced Linux and Nginx. For a managed container platform like we used here, you use Docker and you also use your cloud provider's tools. In this example, we were mainly using the GCloud tools. So, in my opinion, I'd say that a VPS is great for predictable traffic and learning the fundamentals, especially with system administration. A managed container platform is great for variable traffic and less ops overhead. So, both are legitimate production choices. It really just depends on your situation. Now, for FastAPI specifically, I really wanted to include their own deployment offering, which is called FastAPI Cloud, but that's still currently in private beta. It's worth keeping an eye on though. Once that's released, perhaps I'll add on to this series and show deployment through that as well. Okay, so stepping back and looking at this whole series, we built a complete blog application from scratch. We have authentication, API documentation, templates, file uploads, email, pagination, database migrations, testing. We did images through AWS S3 and now two production deployments. So, that's a real end-to-end project and if you've made it through, then I think that you're in a really strong spot to build and ship your own applications. And I'll be adding more videos to this series based on what patrons and channel members have been requesting. I've already had requests to cover a couple of topics like rate limiting and also to do a React front-end video. So, I'm going to get to work on those. So, be sure to subscribe if you haven't already done so that you don't miss out on those. But I think that is going to do it for this video. Hopefully now you have a good idea of how to containerize and deploy a FastAPI application with Docker and Google Cloud Run, but if anyone has any questions about what we covered in this video, then feel free to ask in the comment section below and I'll do my best to answer those. And if you enjoy these tutorials and would like to support them, then there are several ways you can do that. The easiest way is to simply like the video and give it a thumbs up. Also, it's a huge help to share these videos with anyone who you think would find them useful. And if you have the means, you can contribute through Patreon or YouTube and there are links to those pages in the description section below. Be sure to subscribe for future videos and thank you all for watching.

Другие видео автора — Corey Schafer

Ctrl+V

Экстракт Знаний в Telegram

Экстракты и дистилляты из лучших YouTube-каналов — сразу после публикации.

Подписаться

Дайджест Экстрактов

Лучшие методички за неделю — каждый понедельник