How to make a Docker build image for the Python flavor of AWS CDK, for people who don't like NPM
Tags: python, cdk, aws, docker
Published: 2022-11-23 23:36:38

This is going to rub a lot of people the wrong way, but here was my initial thought process when I first encountered AWS CDK:

_Oh wow, it's got a Python flavor! I can actually write all of my AWS infrastructure as code in Python and ditch Terraform? It transpiles to Cloudformation so I can use Cloudformation drift detection and I don't have to worry about state files? This is incredible!_

:grimacing: _It's actually all written in typescript? I have to install a bunch of NPM dependencies just to run CDK? The Python transpiles to typescript which transpiles to Cloudformation? This seems messy._

:bulb: _Maybe I can sweep all this messiness under the rug by installing NPM and the CDK CLI into a Docker image, and then I won't have to have NPM and all the dependencies installed locally! Then I can just instantiate a build container every time I need to update my AWS resources with CDK!_

So that's what I did, and it works great. Here are all the requirements for Python CDK that need to be installed:

1. Python, obviously. You can start from a Docker image that already has Python installed, or install it yourself. I'm going to do the latter for completeness.
2. pip, in order to install the python packages you need.
3. tar and xz, to unzip the node installation package that you'll download.
4. npm
5. The aws-cdk npm package
6. Python libraries for CDK: aws-cdk-lib and constructs
7. The AWS CLI

So if we put all that stuff together in a Dockerfile, we get:

```
FROM public.ecr.aws/amazonlinux/amazonlinux:2

RUN yum -y install python39
RUN curl -O https://bootstrap.pypa.io/get-pip.py
RUN python3 get-pip.py
WORKDIR /deploy
RUN yum -y install tar
RUN yum -y install xz
RUN curl https://nodejs.org/dist/v16.14.2/node-v16.14.2-linux-x64.tar.xz | tar -xJf -
ENV PATH="/deploy/node-v16.14.2-linux-x64/bin:${PATH}"
RUN npm install -g aws-cdk
RUN yes | pip --no-cache install aws-cdk-lib constructs
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
RUN yum -y install unzip
RUN unzip awscliv2.zip
RUN ./aws/install

COPY . /deploy/
ENV LANG=C.UTF-8
WORKDIR /deploy
CMD [ "/bin/bash" ]
```

That's it! Now you can keep all that garbage in a Docker image instead of on your local development environment. You never have to think about NPM again, you can just write your Python code in peace.

You'll notice that the Dockerfile also has a COPY to move all the code in your local deploy folder into the Docker image. That's where you'll locally develop all your CDK code, following the guide here: https://docs.aws.amazon.com/cdk/v2/guide/work-with-cdk-python.html. Your app.py, cdk.json, etc files will be there. Thus to deploy via CDK, you first build the image:

`docker build -t cdk_deploy .`

And then you temporarily instantiate the Docker container and run cdk deploy:

`docker run -v $HOME/.aws/:/root/.aws/ --rm cdk_deploy cdk deploy --require-approval never`

You can see there that I mount my local .aws dir so that I don't have to hardcode my AWS credentials there.

Finally, I should point out that I usually wrap this whole docker command in some kind of devops pipeline. I'm not an animal. This pattern is versatile enough to use with many different kinds of wrappers.

That's it, take care, until next time!

Joe