How to Run a Python Docker Image on AWS Lambda

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Hey everyone. In this video, I'm going to show you how to run a Docker image on AWS Lambda. Docker is a way to put all of your code into a container. That way you won't encounter unexpected problems when you run it on a different machine or a different environment. AWS Lambda is a cloud compute service. We can use this to run our Docker image on demand, just like a function. And we can make it run whenever a user calls our API endpoint. It's completely serverless, so we get billed by millisecond of usage. But it is extremely cheap. Docker and Lambda are amazing together because it means that you can build any type of application you want in any language you want, and then run it on the cloud for a really low cost. Today, we're going to learn how to use this by creating a Python "Hello World" application that we're going to run as a Docker image on AWS Lambda. To follow along effectively with this project, you'll need to have Docker, AWS CLI and AWS CDK installed. And it will be good if you have some experience with them as well. I'm going to start by creating a CDK project for this app. AWS CDK—or "Cloud Development Kit"—is a tool we can use to create our cloud infrastructure. That way, we can define our cloud infrastructure using code instead of having to click things in the console or having to do everything in the command line. Let's make a folder for our CDK project. When you're in the folder, you can run the "cdk init" command to create the CDK application. I'm going to use the language TypeScript for the CDK application. This should finish after about a minute and we can open this directory up in our code editor. Next, we have to create our Docker image folder. That means we'll have our Python app in a folder and a Dockerfile to turn that app into an image with all of its runtime dependencies. Back in our project, I'm going to create a folder called "image". Inside that image folder, I'm going to create another folder called "src". In the "image/src" folder, I'm going to create my Python application file, which I'm going to call "main.py". This Python file is going to be my Lambda function handler. This is going to be the code that executes when my Lambda function is called. And for this, it's just going to be a really basic "hello world" function. It simply returns a status code of 200 (which means it was successful) and a "hello world" message in the body. But if you only wanted to run a simple Python script by itself, then AWS actually has a native Python runtime. So if "hello world" was all you wanted to do, you could just use that. You don't need to use Docker. Where Docker starts to become really useful is if you actually need a lot of packages or dependencies with your Python application. That's because many popular Python packages actually use a lot of platform specific binaries or code behind the scenes. And it can be really difficult to get these binaries installed or working correctly for the Amazon Linux runtime that AWS Lambda uses. That's why a lot of people who develop Python Lambda functions find that they have an error in their AWS Lambda when the same Python code works fine on their machine. With Docker though, this is really easy to fix. Everything inside the image will be run as is. So to demonstrate that, let's also install the "numpy" package and use that in our code. Go to our image folder and in here we're going to create a new file and we're going to call it "requirements.txt". And in here we can use this to list all of the packages or dependencies we need for our project. So here I'm going to add numpy. And now I've gone back to my Python function code and I've included numpy as a dependency. And I've also used it to generate a random matrix so that I can use it as part of my application. And I'll print it out here as well. So now I have a Python hello world application that also uses an external package. And I'm ready to build it into a Docker image. To turn this app into a Docker image, we'll need a Dockerfile. Which is basically just a set of instructions on how to build the image. So go to your image folder and let's create a new file here. We have to call it "Dockerfile". And the name here does matter. It has to be named "Dockerfile" with the capital "D". The first line of our Dockerfile is going to tell us where to base this image on. So we're not building the image from scratch. We're actually going to use this base image, which is an AWS Lambda Python 3.11 image. And then add our stuff into this image to build our own image. And if you want to use a different base image, then the AWS documentation has a list of all the different base images they publish. So you can click in the link below (in the video description) to go to this page and look at all the different Python versions you can choose from. Or if you don't want to use Python, then AWS also provides a bunch of base images in other languages too, such as TypeScript and Java. The next line we need to add to the Dockerfile is to copy this requirements text, which is here. So when we run this Dockerfile, the root directory that it works with is basically wherever this Dockerfile is based. So because the Dockerfile is in the same folder as requirements text, we can just call it requirements text without having to have an absolute path to the file. And we want to copy this into the Lambda "task root". So this is going to be an environment variable that is available to the Dockerfile when it's building. And this is basically where Lambda will consider as the root path for its function. Next, we're going to want to run "pip install" on the requirements text file, which is how we get our numpy dependency installed into the Docker image. My next command is going to copy all the files in this source folder. So that's going to be my main.py application file. And it's also going to put it in the Lambda task root. And the last line is going to set the default command of the Dockerfile to this handler function. This is going to be "main", which is the name of this file, and then "handler", which is the name of the function. So this is what the Lambda function runs when it is used. Now your Dockerfile is ready and you can build an image from it. But before we upload it to AWS, you might want to test it locally. So first go back to your terminal and then navigate to the folder where your Dockerfile is. So that's the "image" folder in this project. And then build your Dockerfile. And you can do that using a command like this. And once you've built your Dockerfile, you have to run it. So you can do that using a command like this. And here I'm going to run it on port 9000. And once the image is running, you can go to another terminal and then send an HTTP request to it like this. And this will actually run the function inside your Dockerfile. So if I run that, you can see that I get my status code 200 and my "hello world" message and even my numpy matrix. Now let's go ahead and create the AWS infrastructure that will have the Lambda function and the API endpoint that we can use to run this image. Go to the "lib" folder in your project and you'll find this AWS stack file here. And it should look something like this. So we're going to delete all this commented code because we don't need that. And at the top we're going to import AWS Lambda. And in here, let's create our Docker image function. I'm going to call this Docker function and it's going to be a Lambda "DockerImageFunction". And here are the parameters. For the code, we're going to use Docker image code from asset. And this is going to be a directory where we have the Dockerfile. When we compile this, CDK will go into this folder and it will use this Dockerfile to create an image. And it's going to upload that image and associate it with this Lambda function so that we can use it. For the memory size, I'm going to put 1024MB and then I'm going to give it a timeout of 10 seconds. By default, I think Lambda has quite a low timeout. Maybe it's like 2 seconds and that might not be enough time for a Docker image to start up and run. And for the architecture, I'm going to put architecture "arm64". Now, most of you probably don't need this. So this is probably going to be fine to have it like this. But because I'm running this on a Mac M1, I need the architecture of the Lambda function to match the architecture that I'm building this image with. So when I run it on this machine, it's going to be built with "arm64". If I don't do this, it's going to fail. But you can choose arm64 or the Intel one if you are using a Windows or if you know that you are using an Intel processor. Or just leave it out completely if you're unsure. Now, to make the Lambda function easily accessible with an API endpoint, I'm also going to add a function URL. So to do that, you can use this add function URL method on your Lambda function to create a URL endpoint that you can just use right away. But I'm going to set the arguments here so that auth type is "NONE" so that we don't need to be authenticated to use it. Anyone with a URL will be able to call it. And I'm also going to set the CORS header to allow all HTTP methods and allow all headers and origins. And finally, to actually see the value of this function URL, we're also going to create an output variable for it. So I'm going to do like that so that when we build our CDK application, we actually get this function URL in a string. So this should be all the infrastructure code we need. And because we also have the Python application file ready and the Docker image file ready, we should be ready to deploy this. Now you're ready to deploy your Docker image to AWS. But before you do that, please make sure that you have your AWS CLI ready and configured because you will need the permissions from that to interact with your AWS account. As a sanity check, you can type `aws sts get-caller-identity`. And if your AWS CLI is configured properly, you should get a response like this. Now let's go back to our project root directory and set up CDK. So in your project root folder, type "cdk bootstrap". And here you can even choose the region you want to bootstrap in or leave it blank if you just want to use your default AWS region. Bootstrapping will create a bunch of resources in your AWS account that CDK will need. But you only need to run it once per account per region. And because I've already run it for this account in this region, nothing happens. And that's fine as well. With bootstrapping completed, we can now run "cdk deploy" to deploy our application. And the first time you run this, you might have to press yes to confirm that you do want to create these resources. And you can see here it's actually building and publishing our image to this private repo. After a couple of minutes, it should finish deploying. And you can find the URL for the function right here in this function value output that we've created. And we can try out the function by just clicking on this URL. And here you can see that our function returns "hello world from Lambda". And it's even returned our numpy matrix for us. If you go to your AWS console, you'll see this function created here. And if you click into it, you'll see that there's a function URL. And it's also using this Docker image that we created. Now if you get up to this point and you can't run the function or it has an error like runtime invalid entry point, then double check what architecture you're using because you could be using the wrong Lambda architecture for the machine that you're built with. So in this one, I used an ARM64 architecture because I'm using an M1 Apple silicon Mac. But if you're using an Intel or a Windows computer, you might need to use the x86 architecture instead. Otherwise, I hope this worked for you and that you have a working Lambda Docker Python function. And you can use this as a basis to start developing your app and use whatever packages and dependencies you want. Now Docker Lambda functions are a little bit slower than native Python Lambda functions on the cold-start. The cold-start is when you first use the function after you haven't used it for 15 minutes because Lambda will have to kind of create the whole runtime again. But it is more reliable if you do need to have runtime dependencies because you don't have to worry about having platform specific bugs or errors appear when you move from your development environment to the Lambda cloud environment. This is especially true if you use packages that are heavy on things like math, cryptography or basically anything that tends to use platform specific binaries to do the heavy lifting. So there is a bit of a trade off, but if you want an easier development experience and you don't mind the slower cold-start, then I do think that Docker functions are the way to go. Anyways, I hope you enjoyed this video. You can check in the comments for the code for this project. And thank you for watching.
Info
Channel: pixegami
Views: 16,651
Rating: undefined out of 5
Keywords: aws, docker, aws lambda, docker aws lambda, python docker lambda, python docker aws, docker on aws, docker on lambda, aws lambda docker, aws lambda tutorial, aws lambda python, python docker tutorial, amazon web services, cloud computing, aws tutorial, docker aws tutorial, docker lambda image, python lambda aws, deploy docker lambda, deploy docker aws
Id: wbsbXfkv47A
Channel Id: undefined
Length: 13min 7sec (787 seconds)
Published: Mon Aug 21 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.