[DOCKER] Run C binaries on AWS Lambda

It's a trivial matter, but I tried running C with Lambda's custom runtime.

Directory structure

.
├── bin
│   ├── bootstrap
│   └── lambda_function
├── docker-compose.yml
├── Dockerfile
└── src
    ├── lambda_function.c
    └── Makefile

A set of code can be found at https://github.com/tsubasaogawa/lambda-with-c.

procedure

Overview

  1. Write the C source
  2. Compile the source in the same execution environment as Lambda
  3. Fix bootstrap
  4. Upload to Lambda

Details

Write C source

Write the source as usual. This time, I made a simple one that just "outputs the standard input contents".

lambda_function.c


#include <stdio.h>

int main(void) {
  char buf[512];

  while(1) {
    /* Obtain from Stdin https://qiita.com/mpyw/items/aff12a6ff2c7726ed1d8 */
    if(scanf("%511[^\n]%*[^\n]", buf) != 1) {
      break;
    }
    /* Ignore linefeed */
    scanf("%*c");

    printf("%s\n", buf);
  }

  return 0;
}

Makefile


PROGRAM = lambda_function
CC = gcc
CFLAGS = -Wall
OBJS = $(PROGRAM).o

$(PROGRAM): $(OBJS)
	$(CC) $(CFLAGS) -o $(PROGRAM) $(OBJS)

$(OBJS): $(PROGRAM).c
	$(CC) -c $(PROGRAM).c

.PHONY: clean
clean:
	rm -f $(PROGRAM) $(OBJS)

.PHONY: clean_obj
clean_obj:
	rm -f $(OBJS)

Compile the source in the same execution environment as Lambda

It runs on Lambda, so you need to compile it in the same environment as Lambda. According to Lambda runtime environment and available libraries, I am using Amazon Linux (2019/02) Now that we know), we'll compile it on an Amazon Linux container.

Dockerfile


FROM amazonlinux:2
MAINTAINER tsubasaogawa

WORKDIR /usr/local/src/lambda-with-c

RUN set -x && yum install -y gcc make

# ADD ./bootstrap .
COPY ./src/lambda_function.c .
COPY ./src/Makefile .

RUN make && make clean_obj

I managed to switch to Amazon Linux 2. docker-compose is below.

docker-compose.yml


version: '3'
services:
  lambda-with-c-compiler:
    build: .
    volumes:
      - ./bin:/var/tmp
    command: /bin/bash -c 'cp -r /usr/local/src/lambda-with-c/lambda_function /var/tmp'

The binary created by make at the time of container build is copied to the mounted directory. Also, when the container is executed, a binary is created under bin / on the host.

$ docker-compose build
$ docker-compose up -d
$ ls -l bin/lambda_function
-rwxr-xr-x 1 root root 8232 Feb 11 12:49 bin/lambda_function

Fix bootstrap

The custom runtime runs a file called bootstrap. It's like running a binary via bootstrap. In Tutorial, bootstrap is written in a shell script. This is partly (or almost) diverted.

bootstrap


#!/bin/sh

set -euo pipefail

# Processing
while true
do
  HEADERS="$(mktemp)"
  # Get an event
  EVENT_DATA=$(curl -sS -LD "$HEADERS" -X GET "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next")
  REQUEST_ID=$(grep -Fi Lambda-Runtime-Aws-Request-Id "$HEADERS" | tr -d '[:space:]' | cut -d: -f2)

  # Execute the handler function from the script
  EXEC="$LAMBDA_TASK_ROOT/$(echo "$_HANDLER" | cut -d. -f1)"
  RESPONSE=$(echo "$EVENT_DATA" | $EXEC)

  # Send the response
  curl -X POST "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/$REQUEST_ID/response"  -d "$RESPONSE"
done

Upload to Lambda

Zip the artifact and upload it to Lambda. Please prepare an appropriate Role in advance.

Upload to Lambda


$ cd bin
$ zip ../lambda_function.zip ./*
$ cd ..
$ ls -l lambda_function.zip 
-rw-rw-r-- 1 vagrant vagrant 3032 Feb 11 12:55 lambda_function.zip

$ aws lambda create-function --function-name lambda-with-c \
    --zip-file fileb://lambda_function.zip --handler lambda_function.handler \
    --runtime provided --role arn:aws:iam::***:role/role_name

I will try it.

Run


$ aws lambda invoke --function-name lambda-with-c \
    --invocation-type RequestResponse \
    --payload '{ "test1": "value1" }' \
    /tmp/lambda-with-c.log
{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}

Execution result


$ cat /tmp/lambda-with-c.log 
{
    "test1": "value1"
}

Looks good. Now that we have the arguments, we can parse them freely and use them.

in conclusion

--I tried running a binary made in C using Lambda's custom runtime. --Reliable to compile on Amazon Linux --When using a custom runtime, a file called bootstrap is executed first --Run binaries via bootstrap ――In addition, C ++ has a convenient library, so you can be happy if you use it.

Recommended Posts

Run C binaries on AWS Lambda
Run mruby / c on PSoC 5
Is Java on AWS Lambda slow?
Hello World on AWS Lambda + Java
Run GPU-required batch processing on AWS
Try running Word2vec model on AWS Lambda
How to deploy a container on AWS Lambda
Run STS4 on Mac
AWS Lambda timezone change
Lambda on Terraform Container
Test run on rails
Run PostgreSQL on Java
Run Processing on Ant
Run tiscamera on Ubuntu 18.04
Run phpunit on Docker
Regularly post imaged tweets on Twitter with AWS Lambda + Java
AWS Lambda says Container Image Support, so pseudo Cloud Run
Run VS Code on Docker
Run openvpn on Docker (windows)
Run chromium-mir-kiosk on Ubuntu Core
Run java applet on ubuntu
Update RVM on AWS Cloud9
Install docker on AWS EC2
Run Eclipse CDT on Ubuntu
Build AWS Lambda with Quarkus
Try running SlackBot made with Ruby x Sinatra on AWS Lambda
Run (provisionally) a Docker image with ShellCommandActivity on AWS Data Pipeline