DEV Community

Wesley Cheek
Wesley Cheek

Posted on

Python AWS CDK Pipelines with NodeJS Dependencies

AWS CDK Pipelines are a fantastic way to deploy your infrastructure using CI/CD practices.

The pipeline, using AWS CodeBuild and CodePipeline, can reproducibly build and deploy both your front-end and back-end applications. But how can we use Python to build the pipeline, but then deploy Lambda Functions written in JavaScript or TypeScript?

This has been a bit of a tricky problem for me, because most examples found online are for AWS CDK projects written in TypeScript. We need to add an additional step to our pipelines if we want our NodeJS Lambda Functions to get built with dependencies.

TLDR: Simply run npm i in your shell step and your dependencies detailed in your root package.json file will be available when CodeBuild is building your NodeJS functions.

With AWS CDK Pipelines, there is no need to specify dependencies in each individual function folder. Instead, specify all of them at the root of your project in a package.json file. When npm i is run in the pipeline's shell step, these dependencies become available for all of your NodeJS functions to build with.

I provide a full example below.

Let's build our stack, stage, and pipeline in Python flavored AWS CDK!

STACK WITH NODEJS LAMBDA FUNCTION

# stacks/backend_stack.py
from constructs import Construct
from aws_cdk import aws_lambda_nodejs as _lambda_nodejs
from aws_cdk import Stack

class BackendStack(Stack):
    def __init__(
        self, scope: Construct, construct_id: str, **kwargs
    ) -> None:
        super().__init__(scope, construct_id, **kwargs)

        self.backend_lambda = self.build_backend_lambda()

    def build_backend_lambda():
            """
            Example NodeJS lambda
            """
            # Here I instantiate a lambda function which is written in Javascript or Typescript. The file app.js exports a function called handler.
            backend_lambda = _lambda_nodejs.NodejsFunction(
                scope=self,
                id="backendLambda",
                runtime=_lambda.Runtime.NODEJS_16_X,  # type: ignore
                entry="lambda_funcs/backend/app.js",
                handler="handler",
            )


Enter fullscreen mode Exit fullscreen mode

STAGE

# app.py
from constructs import Construct
from stacks.backend_stack import BackendStack

class BackendStage(Stage):
    def __init__(self, scope: Construct, id: str, **kwargs):
        super().__init__(scope, id, **kwargs)
        )
        self.backend = BackendStack(
            scope=self, construct_id="Backend"
        )
Enter fullscreen mode Exit fullscreen mode

PIPELINE

# app.py
from aws_cdk import aws_secretsmanager as secretsmanager
from aws_cdk.aws_codebuild import (
    BuildEnvironment,
    ComputeType,
    LinuxBuildImage,
)
from aws_cdk.aws_codepipeline_actions import GitHubTrigger
from constructs import Construct

class PipelineStack(cdk.Stack):
    def __init__(
        self,
        scope: Construct,
        construct_id: str,
        **kwargs,
    ) -> None:
        super().__init__(scope, construct_id, **kwargs)
        github_secret = secretsmanager.Secret.from_secret_name_v2(
            scope=self,
            id="github_secret",
            secret_name="Github_Personal_Access_Token",
        )
        code_build = pipelines.CodeBuildOptions(
            build_environment=BuildEnvironment(
                build_image=LinuxBuildImage.STANDARD_5_0,
                compute_type=ComputeType.SMALL,
            )
        )
        # This pipeline deploys a cdk stack
        pipeline = pipelines.CodePipeline(
            scope=self,
            id="Pipeline",
            code_build_defaults=code_build,
            synth=pipelines.ShellStep(
                id="Synth",
                input=pipelines.CodePipelineSource.git_hub(
                    repo_string="USERNAME/REPOSITORY",
                    branch="dev",
                    authentication=github_secret.secret_value_from_json(
                        key="github_access_token"
                    ),
                    trigger=GitHubTrigger.WEBHOOK,
                ),
                commands=[
                    "pip install -r requirements.txt",
                    "npm i",  # This is the essential step for this article
                    "npm install -g aws-cdk",
                    "cdk synth",
                ],
            ),
            docker_enabled_for_synth=True,
        )

        pipeline.add_stage(
            BackendStage(scope=self, id="backend"),
        )
Enter fullscreen mode Exit fullscreen mode

Good luck!

Top comments (0)