Fortran を AWS Lambda のCustom Runtime で実行する

# シリーズ目次

- [AWS Lambda 関数を Docker コンテナを使ってビルド & デプロイ](https://qiita.com/sasaco/items/b65ce36c05c50a74ac3e)
- Fortran を AWS Lambda のCustom Runtime で実行する


# 概要

記事 [AWS Lambda Custom Runtimesを利用してFortranで数値計算 #reinvent](https://dev.classmethod.jp/articles/lambda-custom-runtimes-fortran/) を参考に
**Fortran** を **AWS Lambda** の **Custom Runtime** で実行する方法を書きました


### AWS Lambda のCustom Runtime とは、

>AWS Lambda ランタイムは、どのプログラミング言語でも実装できます。
ランタイムは、関数が呼び出されたときに Lambda 関数のハンドラメソッドを実行するプログラムです。


### カスタムランタイムを使用するには、

![スクリーンショット 2021-09-21 13.26.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142847/01e11aa6-3c6c-1ac9-1ac4-c1f68bfc618f.png)

と、Docker から生成したファイル(今回は**hello**)
を用いて実行します。

AWS Lambda 関数を 作成するには以下の３ステップが必要です

1.**Docker イメージ**を作成する
2.Docker イメージから 実行ファイルを生成
3.**圧縮ファイル(.zip)**を Amazon Lambda にアップロード


# 前提条件

### Docker Desktop がインストールされていること

この記事は Mac 上で Docker を用いて操作しています。

この記事の作業はローカル環境に Docker Desktop がインストールされていることを前提で進めます。インストールされていない場合は、インストールしてから進めてください。

### Amazon CLI がインストールされていること

Amazon CLI
https://aws.amazon.com/jp/cli/

aws configure (初期化) が済んでいること

```powershell
> aws configure
AWS Access Key ID [None]: ATI********CS
AWS Secret Access Key [None]: ***erg***sdfg***bs1sderg**
Default region name [None]: ap-northeast-1
Default output format [None]: json
```

### gfortran がインストールされていること

[Mac (macOS Catalina, 10.15.2)にgfortranとPGI Fortran 19.10をインストールしたときの手順](https://qiita.com/implicit_none/items/2f84dafc62e1ada9862a)

```bash
% brew install gcc
```

インストールが完了したら，そのままターミナルで`gfortran --version`コマンドを実行してください．以下のようなメッセージが表示されれば，インストールは成功しています．

```bash
% gfortran --version
GNU Fortran (Homebrew GCC 11.2.0) 11.2.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
```

# 実装

## 手順1: 4つのテキストファイルを用意する

作業するフォルダを決めて
以下の4つのテキストファイルを作成しましょう

![スクリーンショット 2021-09-21 15.27.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142847/0232ec5d-f5ce-d47e-a9fd-e55a8b5bb0cf.png)


それぞれのファイルの中身は以下の通りとします。

### hello.f90

```fortran:hello.f90
program hello
  implicit none
  write(*,*) 'Hello World!'
  stop
end program hello
```
【解説】
今回の Fortran コードは、ただ 'Hello World!' を出力するだけ

### Dockerfile
```Dockerfile:Dockerfile
FROM amazonlinux:latest
RUN yum -y install gcc-gfortran glibc-static
COPY hello.f90 /
RUN gfortran -c hello.f90
RUN gfortran -static -o hello hello.o
CMD /bin/bash
```
【解説】
FROM 命令で amazonlinux の AWS 公式の公開イメージを指定しています.
amazonlinux に gfortran をインストールしています。
COPY コマンドでローカルに配置されている Lambda 関数本体である hello.f90 ファイルをイメージにコピーしています。そして CMD で Lambda 関数のハンドラーを渡しています。
gfortran で hello.f90 をコンパイルして、配置しています。

### bootstrap
```sh:bootstrap
#!/bin/sh
set -euo pipefail
LM=$(echo "$_HANDLER" | cut -d. -f2)
while true; do
  HEADERS="$(mktemp)"
  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)
  RESPONSE="$(./$LM "$EVENT_DATA")"
  curl -X POST "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/$REQUEST_ID/response" -d "$RESPONSE"
done
```
【解説】
ほぼ[公式チュートリアル](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/runtimes-walkthrough.html)のものと変わりませんが、実行バイナリの名前をハンドラ（環境変数$_HANDLER）から指定するようにしています。

### Makefile
```Makefile:Makefile
TARGET=hello
IMAGE=temp:latest

all: $(TARGET).zip

$(TARGET).zip: $(TARGET) bootstrap
	zip $(TARGET).zip bootstrap $(TARGET)

$(TARGET): hello.f90
	docker build -t $(IMAGE) .
	docker run -it --rm -v `pwd`:/tmp -w /tmp --entrypoint=cp $(IMAGE) /$(TARGET) /tmp
```
解説
なんだかよくわかりませんが、なにやら Docker にイメージをビルドして bootstrap ファイルと一緒に
圧縮しているみたい


## 手順2: make コマンドの実行


```shell
$ make
```

なにやらコマンドが走ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142847/29fedd86-f2f8-eef6-9216-d90e5c63115a.png)

hello というファイルと **hello.zip** というファイルが生成されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142847/869ac71b-6c1d-2ab6-8ae2-52acfa01abfb.png)


## 手順3.Lambda関数に アップロードする手順

### AWS Lambda ダッシュボードから 関数作成 ボタンをクリックする

![スクリーンショット 2021-09-21 16.08.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142847/b6abfc58-2208-bbeb-f97c-f8a859670755.png)

- 一から作成
- ランタイムを　`Amazon Linux2 でユーザー独自のブートストラップを提供する`

を選択します。


### ランタイム設定を変更

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142847/65012e11-b73b-3e54-e865-b38ecc99d5d6.png)

ハンドラを `fortran.hello` に変更してくださ

### hello.zip ファイルをアップロード

アップロードボタンから　.zipファイルを選択し、 生成しておいた`hello.zip` を選択してください

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142847/ba14dda8-f7d4-640d-15f7-2b17b3291893.png)


## 手順4:作成された関数を実行確認

そしていよいよ実行することができます。作成された関数を実行してみましょう。

```powershell
> aws lambda invoke --function-name fortran_hello output ; cat output                                                   
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142847/f651706b-dbed-0a36-3d32-0afa82f22c36.png)


正常に返ってきました！！