0
0

AWS上で Swift の Lambda を動かしてみる

Last updated at Posted at 2024-06-08

サーバー系は苦手なのに、必要に迫られて AWS で APIを実装する必要性に迫られた。別に、Node.jsやJavaを使えば、もっと簡単に実装できるかもしれないけれど、やはり Swift での実装にこだわってみた。

情報収集

まずは「aws、lambda、swift」くらいで検索してみる。このあたりがトップででてくる。

このあたりも気になる。

Projectを作成

mkdir mylambda
cd mylambda

次の構造のようにファイルを構成します。

$ tree .
.
├── Package.swift
└── Sources
    └── mylambda
        └── main.swift
Package.swift
// swift-tools-version:5.2
 // The swift-tools-version declares the minimum version of Swift required to build this package.
    
 import PackageDescription
    
 let package = Package(
   name: "mylambda",
   products: [
     .executable(name: "mylambda", targets: ["mylambda"]),
   ],
   dependencies: [
     .package(url: "https://github.com/swift-server/swift-aws-lambda-runtime.git", .upToNextMajor(from:"0.3.0")),
   ],
   targets: [
     .target(
       name: "mylambda",
       dependencies: [
         .product(name: "AWSLambdaRuntime", package: "swift-aws-lambda-runtime"),
       ]
     ),
   ]
 )

今回の lambda は JSON の name を取得して、"Hello" に続けて名前をつけて返すだけのシンプルな仕様とします。

main.swift
import AWSLambdaRuntime

struct Input: Codable {
  let name: String
}

struct Output: Codable {
  let message: String
}

Lambda.run { (context, input: Input, callback: @escaping (Result<Output, Error>) -> Void) in
  callback(.success(Output(message: "Hello \(input.name)!")))
}

Xcode で Package.swiftを開きます。そして、Edit Scheme..からEnvironment Variables
LOCAL_LAMBDA_SERVER_ENABLEDtrueを設定します。

これで、実行すると、コンソールに以下のような表示がされ、呼び出しを待っている状態になります。AWS上ではありませんが、まずはローカルで簡単な動作の確認を行います。

2024-06-08T01:21:49-0400 info LocalLambdaServer : [AWSLambdaRuntimeCore] LocalLambdaServer started and listening on 127.0.0.1:7000, receiving events on /invoke
2024-06-08T01:21:49-0400 info Lambda : [AWSLambdaRuntimeCore] lambda lifecycle starting with Configuration
  General(logLevel: info))
  Lifecycle(id: 41133856746458, maxTimes: 0, stopSignal: TERM)
  RuntimeEngine(ip: 127.0.0.1, port: 7000, requestTimeout: nil

Postman などで、JSON を POST してみます。URLはログから拾い出したアドレスに、ログに記載のあるinvoke をつけます。

127.0.0.1:7000/invoke

こんなかんじになります。

出力した結果は以下の通りです。ローカルでの動作が確認できました。

{"message":"Hello John Doe"}

パッケージング

SwiftはAWSのコンソールで編集して動作させる事ができないので、アップロードできるようにパッケージングする必要があります。

Xcode から Archive します。すると Organizer ウィンドウの Archives に mylambda が現れます。

Dockerを使いイメージを作成します。私は普段Dockerなど使わないので、Dockerの知識はあまりないのですが、この場合は Dockerfile を用意する必要はないようです。

実はここに辿り着くまで、結構いろいろな古い情報に踊らされて、結構しんどかったのですが、この方法でイメージを作れるのは良かったです。ちなみに、元ネタは「swift:5.3.1」だったのですが、これもうまくいかず、「5.9.2」でうまくいきましたが、将来はわかりませんね。

$ docker run \
    --rm \
    --volume "$(pwd)/:/src" \
    --workdir "/src/" \
    swift:5.9.2-amazonlinux2 \
    swift build --product mylambda -c release -Xswiftc -static-stdlib 
$ docker run \
    --rm \
    --volume "$(pwd)/:/src" \
    --workdir "/src/" \
    swift:5.9.2-amazonlinux2 \
    swift build --product mylambda -c release -Xswiftc -static-stdlib 
Fetching https://github.com/apple/swift-nio.git
Fetching https://github.com/apple/swift-system.git
Fetching https://github.com/apple/swift-atomics.git
...snip...
[58/59] Compiling mylambda main.swift
[59/60] Linking mylambda
Build complete! (49.28s)

そして、以下のように package.sh を用意します。

$ tree ../mylambda\ copy 
.
...snip...
├── Package.swift
├── Sources
│   └── mylambda
│       └── main.swift
└── scripts
    └── package.sh
package.sh
#!/bin/bash

set -eu

executable=$1

target=.build/lambda/$executable
rm -rf "$target"
mkdir -p "$target"
cp ".build/release/$executable" "$target/"
cd "$target"
ln -s "$executable" "bootstrap"
zip --symlinks lambda.zip *

実行できるようにします。

$ chmod +x scripts/package.sh

そして、package.sh を実行します。mylambdaを自分の利用する名前に変える事を忘れないでください。

$ scripts/package.sh mylambda     
  adding: bootstrap (stored 0%)
  adding: mylambda (deflated 66%)

上手くできたら、以下のファイルが生成されているはずです。この「lambda.zip」をAWSのポータルでアップロードします。他にも方法があるようですが、ここではこの方法で進めます。

$ ls .build/lambda/mylambda 
bootstrap       lambda.zip      mylambda

AWS上で動かしてみる

AWSのポータルにログインして、ダッシュボードにアクセスします。

Functiion を作ります。AWSのポータルから Lambda に入ります。Scratchから作成して。「Amazon Linux 2023」を選びます。「Architecture」は「Arm64」を選びます。

こんなかんじになります、で、ここから「Upload from」から「Zip File」を選びます。

ここで、先ほどの「Lambda.zip」を指定してアップロードします。

API Gateway から「Create API」を選びます。

image.png

「New API」で API の名前の指定します。分かりやすい名前をつけましょう。今回は「mylambda_api」としてみました。

image.png

パス「/」を選んで、「Create Method」を選びます。

image.png

Method type で「POST」を選び「Lambda function」を選択します。そして、先ほど作った Lambda を選びます。

image.png

次にステージを選びます。実はいろいろ試行錯誤していてこれが必要かどうかは確信がないのですが、今回は作成します。「Create Stage」を選びます。

image.png

Stage の名前に今回は「develop」とします。「Create Stage」を選びます。

image.png

Depoloy します。

image.png

「develop」が作られたかんじは、こんなふうです。「invoke URL」をコピペして、POSTMANなどから、APIを叩いてあげます。

image.png

JSON を編集して、送信すると、AWS上の Lambda が動作し、レスポンスが帰ってくる事が確認できました。

image.png

悪戦苦闘

実は、ここに来るまでにスッタモンダしました。将来の自分がこのページを見て同じ問題に遭遇しないように、上手くいかなかった場合も記録に残しておく事にします。

さて、Lambdaの画面からトリガーを作り、API Gatewayを設定しても、「Missing Authentication Token」に遭遇して、解決する方法がわかりませんでした。よって、API Getway側から Lambda を指定するようにしました。

image.png

Screenshot 2024-06-08 at 4.05.31.png

image.png

{
    "message": "Missing Authentication Token"
}

次の課題

次の課題は、Lambda から S3 のストーレージにアクセスしたり。より高度な機能を提供する事です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0