ちょっと話題の記事

AWS LambdaのCustom RuntimeでCOBOLを動かしてみた #reinvent

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

一時期Twitterで騒然となった、AWSのCOBOL対応ですが、実際にやってみたいと思います。

Dockerとdocker-composeの環境を整える

まずは、EC2でAmazon Linuxのインスタンスを立ち上げてsshでログインします。そして次の手順でDocker環境を整えます。dockerコマンドで環境情報が表示されれば成功です。

$ sudo yum -y update
$ sudo amazon-linux-extras -y install docker
$ sudo service docker start
$ sudo chkconfig docker on
$ sudo usermod -a -G docker ec2-user
$ sudo gpasswd -a $USER docker
$ sudo systemctl restart docker
$ exit
# もう1回ログインする
$ docker info
Containers: 0
 Running: 0
 Paused: 0
 Stopped: 0
....

次に、docker-composeの環境を整えます。

$ sudo curl -L "https://github.com/docker/compose/releases/download/1.23.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

$ sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose --version
docker-compose version 1.23.1, build b02f1306

COBOLをコンパイルする環境を整える

Dockerにインストールするライブラリなどを指定します。

Dockerfile

FROM amazonlinux:1

# install tools
RUN yum -y groupinstall "Development tools"

# install GnuCOBOL 2.2
RUN yum -y install gmp-devel ncurses-devel db4-devel
RUN curl -L -o gnucobol-2.2.tar.gz https://sourceforge.net/projects/open-cobol/files/gnu-cobol/2.2/gnucobol-2.2.tar.gz/download
RUN tar zxf gnucobol-2.2.tar.gz
RUN cd gnucobol-2.2 && ./configure --prefix=/usr --libdir=/usr/lib64 && make && make install

# build lambda function package
RUN mkdir -p /cobol/lib
COPY bootstrap /cobol
COPY hello.cob /cobol
RUN cp /usr/lib64/libcob.so.4 \
       /lib64/libm.so.6 \
       /usr/lib64/libgmp.so.10 \
       /lib64/libncursesw.so.5 \
       /lib64/libtinfo.so.5 \
       /usr/lib64/libdb-4.7.so \
       /lib64/libdl.so.2 \
       /lib64/libc.so.6 \
       /lib64/libpthread.so.0 \
       /lib64/ld-linux-x86-64.so.2 \
       /cobol/lib
RUN cd /cobol && \
      COB_LDFLAGS="-Wl,--rpath=./lib -Wl,--dynamic-linker=./lib/ld-linux-x86-64.so.2" cobc -x hello.cob
RUN cd /cobol && zip -r /lambda-cobol-hello.zip ./bootstrap ./hello ./lib

CMD /bin/bash

Lambdaのサンプルそのままです。

bootstrap

#!/bin/sh
 
set -euo pipefail
 
LM=$(echo "$_HANDLER" | cut -d. -f2)

# 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
  export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$LAMBDA_TASK_ROOT/lib
  RESPONSE="$(./$LM "$EVENT_DATA")"
  echo $RESPONSE
 
  # Send the response
  curl -X POST "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/$REQUEST_ID/response" -d "$RESPONSE"
done

Dockerを起動してLambda向けのファイルをコピーします。

bash.sh

#!/bin/bash
docker build -t lambda-cobol:latest .
docker run -it --rm -v `pwd`:/tmp lambda-cobol cp /lambda-cobol-hello.zip /tmp/

hello.cob

       IDENTIFICATION DIVISION.
       PROGRAM-ID. SAMPLE-01.
       ENVIRONMENT DIVISION.
       DATA DIVISION.
       PROCEDURE DIVISION.
       MAIN.
       DISPLAY "Hello world!" UPON CONSOLE.
       STOP RUN.

ビルドする

Lambdaにデプロイするために必要なファイルが揃いましたので、セットアップとコンパイルを行います。

$ ./build.sh
Successfully built 912ab7f887a4
Successfully tagged lambda-cobol:latest

$ ls
Dockerfile  bootstrap  build.sh  hello.cob  lambda-cobol-hello.zip

ビルド済みのファイルが圧縮されて保存されていることが分かります。

Lambdaにデプロイ

出来上がったZIPを下記のコマンドでデプロイします。

$ export LAMBDA_EXEC_ROLE=arn:aws:iam::XXXXXXXXXXXX:role/exe-lambda

$ aws lambda create-function --function-name hello-cobol --runtime provided --role $LAMBDA_EXEC_ROLE --handler cobol.hello --zip-file fileb://lambda-cobol-hello.zip --region ap-northeast-1

{
    "TracingConfig": {
        "Mode": "PassThrough"
    },
....

作成したLambda関数を動かしてみる

まとめ

当初、Amazon Linux 2上で環境を作ろうとして、ライブラリ関連の相性が悪くてなかなかできませんでした。社内に相談したところ、そのままズバリの解決策を教えてもらえまして、どうにか動作確認まですることができました。山下さんありがとうございました!!

参考資料

サンプルソース一式