diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index 86b99f50..00000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,70 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL" - -on: - #push: - # branches: [ main ] - #pull_request: - # The branches below must be a subset of the branches above - # branches: [ main ] - schedule: - - cron: "37 10 * * 1" - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: ["javascript", "python"] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - # Learn more about CodeQL language support at https://git.io/codeql-language-support - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - - # ℹī¸ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 diff --git a/content/aws/50001050-cdk-fn-lambda-custom-docker.md b/content/aws/50001050-cdk-fn-lambda-custom-docker.md new file mode 100644 index 00000000..3fc9caa4 --- /dev/null +++ b/content/aws/50001050-cdk-fn-lambda-custom-docker.md @@ -0,0 +1,172 @@ +Title: How to create a Lambda function in a ECR Docker image using AWS CDK in Python +Date: 2024-12-06 +Category: AWS Academy +Series: AWS CDK +series_index: 1040 +Tags: aws, cdk, python +Author: Rehan Haider +Summary: This article provides a walkthrough on how to deploy an AWS Lambda function using a AWS provided ECR Docker image with AWS CDK in Python +Keywords: lambda, cdk, docker, python, aws, ecr + + + +In previous posts we looked at how to create using AWS CDK: + +1. [Default Lambda function]({filename}50001000-cdk-fn-create-lambda.md), +2. [Lambda function with Python dependencies using a Lambda layer]({filename}50001020-cdk-fn-lambda_layers.md) +3. [Lambda function with Python dependencies that uses AWS provided Docker image]({filename}50001030-cdk-fn-lambda-python-deps.md) +4. [Lambda function using a AWS ECR Docker image]({filename}50001040-cdk-fn-lambda-aws-docker.md) + +But what if you need something more custom? We can use a similar approach to the previous post, but it requires a bit more work. + + +## Prerequisites + +1. Ensure that you have [AWS CDK and SAM CLI installed]({filename}00000100-cdk-installing-cdk-sam-cli.md). +2. If needed [create a new CDK application]({filename}50000020-cdk-new-app.md). + + +## Create a Lambda function using a custom Docker image + +We will need to do the following: + + +1. Create the `Dockerfile` +3. Create a `requirements.txt` file to specify the Python packages to be installed. +4. Add AWS Lambda Runtime Interface Client (RIC) to the Dockerfile. +5. Write the lambda function. +6. Create the lambda stack. + + +### 1. Create the Dockerfile + +Let's create a `lambda` directory in `cdk_app` to store the files for this function. + +```Dockerfile +# filename: cdk_app/lambda/Dockerfile + +FROM ubuntu:latest + +ARG FUNCTION_DIR="/function" + +# 👇đŸŊ Install Python and pip +RUN apt update -y +RUN apt install -y python3 python3-pip + +# 👇đŸŊ Copy the rest of the application +RUN mkdir -p ${FUNCTION_DIR} +COPY . ${FUNCTION_DIR} + + +# 👇đŸŊ Set working directory +WORKDIR ${FUNCTION_DIR} + +# 👇đŸŊ Install dependencies +# A target directory is required since latest versions of Ubuntu have implemented PEP 668 +# which prevents pip from installing packages system-wide. +RUN python3 -m pip install --target ${FUNCTION_DIR} -r requirements.txt + +# 👇đŸŊ Install AWS Lambda Runtime Interface Client +RUN python3 -m pip install --target ${FUNCTION_DIR} awslambdaric + +# 👇đŸŊ Define the entrypoint +ENTRYPOINT ["python3", "-m", "awslambdaric"] + +# 👇đŸŊ Set the handler to be used by the Lambda runtime +CMD ["index.handler"] +``` + +Within this image we have: + +1. Used the latest Ubuntu as the base image. This could be changed to a different image if needed. +2. We ensure that Python and pip are installed. +3. Created a directory for the function code. +4. Copied the function code into function directory. +5. Installed the Python packages specified in the `requirements.txt` file in the function directory. +6. Installed the AWS Lambda Runtime Interface Client (RIC) in the function directory. +7. Set the command to be executed when the container starts. + +!!! note + 1. The RIC is required for the Lambda function to communicate with the Lambda runtime. + 2. The packages are installed in the function directory since the latest versions of Ubuntu have implemented PEP 668 which prevents pip from installing packages system-wide. + 3. The `ENTRYPOINT` and `CMD` instructions are used to specify the command to be executed when the container starts. + + +### 2. Create a requirements.txt file + +Create a new file called `requirements.txt` in the `cdk_app/lambda` directory. Any Python packages that you may need to install can be added to this file. + +``` +requests +``` + +### 3. Create the lambda function + +Within the `lambda` directory create a new file called `index.py`. This is the main Python file that will be executed by the Lambda function. + +```python +# filename: cdk_app/lambda/index.py + +import requests + +def handler(event, context): + response = requests.get("https://jsonplaceholder.typicode.com/todos/1") + + return {"statusCode": 200, "body": response.json()} +``` + + +### 4. Create a lambda_stack.py file + +We modify the `lambda_stack.py` file to create the CDK stack. + +```python +# filename: cdk_app/lambda_stack.py + +from aws_cdk import ( + Stack, + aws_lambda as _lambda, +) +from constructs import Construct + +class LambdaStack(Stack): + + def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: + super().__init__(scope, construct_id, **kwargs) + + fn = _lambda.DockerImageFunction( + self, + "LambdaFunction", + code=_lambda.DockerImageCode.from_image_asset("cdk_app/lambda"), + ) +``` + +In the above code we use the `DockerImageFunction` construct to create the Lambda function. It takes the following arguments: + +1. `self`: The construct itself. +2. `id`: The unique identifier for the function. +3. `code`: The Docker image code. In this case we are using the `DockerImageCode.from_image_asset` method to specify the path to the Docker image. +4. `environment`: The environment variables for the function. This is not required but is useful for testing purposes. + +Compared to previous examples, we don't need to identify the handler function as this is specified in the `Dockerfile`. + +Now finally, let's initialise the stack by creating the `app.py` file. + +```python +# filename: app.py + +import aws_cdk as cdk + +from cdk_app.lambda_stack import LambdaStack + +app = cdk.App() +lambda_stack = LambdaStack(app, "LambdaStack") + +app.synth() +``` + +To deploy the stack, run `cdk deploy`. + +When the lambda function is deployed, you can go to the console and test the function. It should show the below output. + +![Lambda function output]({static}/images/aws/50001050-01-aws-lambda-output.png) \ No newline at end of file diff --git a/content/images/aws/50001050-01-aws-lambda-output.png b/content/images/aws/50001050-01-aws-lambda-output.png new file mode 100644 index 00000000..cd20d8d8 Binary files /dev/null and b/content/images/aws/50001050-01-aws-lambda-output.png differ