Now that you have a project configured to use AWS, we can create the thumbnailer. We’ll use the AWS Lambda Containers for this.
Create a new directory within your Pulumi project called app
mkdir app
Next, create a Dockerfile within the app directory and use it to build ffmpeg into the image:
FROM amazon/aws-lambda-nodejs:12
ARG FUNCTION_DIR="/var/task"
# Install tar and xz
RUN yum install tar xz unzip -y
# Install awscli
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" -s
RUN unzip -q awscliv2.zip
RUN ./aws/install
# Install ffmpeg
RUN curl https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz -o ffmpeg.tar.xz -s
RUN tar -xf ffmpeg.tar.xz
RUN mv ffmpeg-4.4-amd64-static/ffmpeg /usr/bin
# Create function directory
RUN mkdir -p ${FUNCTION_DIR}
# Copy handler function and package.json
COPY index.js ${FUNCTION_DIR}
# Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile)
CMD [ "index.handler" ]
You’ll notice you’re specifying an index.handler as the command, but we haven’t defined it yet.
Inside the app/ directory, let’s create index.js which becomes your Lambda entrypoint.
'use strict';
const { execSync } = require('child_process');
function run(command) {
    console.log(command);
    const result = execSync(command, {stdio: 'inherit'});
    if (result != null) {
        console.log(result.toString());
    }
}
exports.handler = async (event) => {
    console.log("Video handler called");
    if (!event.Records) {
        return;
    }
    for (const record of event.Records) {
        const fileName = record.s3.object.key;
        const bucketName = record.s3.bucket.name;
        const thumbnailFile = fileName.substring(0, fileName.indexOf("_")) + ".jpg";
        const framePos = fileName.substring(fileName.indexOf("_")+1, fileName.indexOf(".")).replace("-", ":");
        
        run(`aws s3 cp s3://${bucketName}/${fileName} /tmp/${fileName}`);
        run(`ffmpeg -v error -i /tmp/${fileName} -ss ${framePos} -vframes 1 -f image2 -an -y /tmp/${thumbnailFile}`);
        run(`aws s3 cp /tmp/${thumbnailFile} s3://${bucketName}/${thumbnailFile}`);
        console.log(`*** New thumbnail: file ${fileName} was saved at ${record.eventTime}.`);
    }    
};
The app directory should now look like this:
.
├── Dockerfile
└── index.js
Back inside your Pulumi program (index.ts in the directory above the app directory) we now need to build this Docker image and create a place to push it.
We’ll use Pulumi Crosswalk to build the image and push it to the ECR repository. Add the following to index.ts:
const image = awsx.ecr.buildAndPushImage("thumbnailer", {
    context: "./app",
});
The index.ts file should now look like this:
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";
const image = awsx.ecr.buildAndPushImage("thumbnailer", {
    context: "./app",
});
This Pulumi component takes care of creating an ECR repository and building the local container image and pushing it.
Run your Pulumi program and inspect the resources it’ll create:
Previewing update (dev)
View Live: https://app.pulumi.com/jaxxstorm/thumbnailer/dev/previews/4a0d6e8e-1b71-4c97-8aae-5bfb5c10d419
     Type                           Name             Plan
 +   pulumi:pulumi:Stack            thumbnailer-dev  create
 +   └─ awsx:ecr:Repository         thumbnailer      create
 +      ├─ aws:ecr:Repository       thumbnailer      create
 +      └─ aws:ecr:LifecyclePolicy  thumbnailer      create
Resources:
    + 4 to create
Hit yes when you’re ready, you should see some output while the image builds in the background (this may take a few minutes):
Updating (dev)
View Live: https://app.pulumi.com/jaxxstorm/thumbnailer/dev/updates/1
     Type                           Name             Status       Info
 +   pulumi:pulumi:Stack            thumbnailer-dev  creating
 +   └─ awsx:ecr:Repository         thumbnailer      created      Executing ' docker build ./app -t 12fda807-container'
 +      ├─ aws:ecr:Repository       thumbnailer      created
 +      └─ aws:ecr:LifecyclePolicy  thumbnailer      created