2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

mac環境でSAM CLIと仮想環境LinuxのDockerを使用してLambdaをローカル実行する

Posted at

AWS Serverless Application Model(SAM)のローカル実行時のコンテナ実行環境として、mac上のLinux仮想環境にインストールしたDocker エンジンを使用する手順を検証します。

なぜ、このような環境が必要か

  • 手元mac端末でvscodeとAmazon Q develoerを使ったlambda開発がしたい
  • サクサク開発/デバッグするためSAMのローカル実行を使用したい
  • SAMのローカル実行にはコンテナエンジンが必要だが諸事情によりmacで直接稼働するDocker(Docker Desktop)は使用したくない

環境

  • 手元mac端末
    • m1 macbook air sonoma 14.7.1
  • 仮想環境
    • UTM 4.5.4
  • 仮想環境用 Linux
    • ubuntu 24.04.1 LTS(ARM64)
  • Docker
    • Docker CE 5.27.4.0
  • SAM CLI
    • 1.125.0

実現したいアーキテクチャ

全体イメージ図です。

image.png

今回検証するのは「macのターミナルでsam invokeを実行すると、仮想環境LinuxのDockerでLambdaが実行される」の部分だけです。

図中に「sam code」とある箱の部分ですが、後述するようにmacでSAMを実行して作成されるファイルを、Dockerエンジンが稼働するLinuxから直接参照できるようにする必要があります。NFSやSambaなど参照のやり方はいろいろありますが、今回はUTMの共有ディレクトリ機能を使用しています。

検証手順

SAM CLI、UTMのインストール

SAM CLIのインストール、UTMのインストールに関しては一般的な話のため詳細割愛します。

UTMはhomebrewでインストールしました。

UTM仮想マシン作成

母艦となるmacのディスク残量が厳しいため、ubuntuを最小構成でインストールします。Dockerを動かすだけなのでDesktop環境など追加のパッケージは不要です。

UTMの仮想マシンは「仮想化」で作成します。インストールするLinuxはARM版が必要です。

image.png

メモリー2GB、ディスク8GBで構成しました。
image.png
image.png

「共有ディレクトリ」を設定します。
image.png

後段でsamの実行ディレクトリとなるディレクトリを含むようにパスを指定します。
私はvscodeのワークスペース用に作ったフォルダを指定しました。

Ubuntu 導入

導入オプションとしてUbuntu server(minimized)を選択します。
image.png

ネットワークやディスク構成はデフォルトのまま進めます。

ログインユーザとしては"user01"を作成しました
パスワードなどは適宜設定します。

image.png

インストーラで選択できるDockerはインストールしませんでした。Dockerは個別にインストールします

image.png

インストールが完了したらインストールイメージのISOをドライブから外して再起動します。
image.png

Linuxの初期導入が完了しました。

Linuxの設定

Docker CEインストール

Docker CEをインストールします。手順は公式手順に従います。
https://docs.docker.jp/engine/installation/linux/docker-ce/ubuntu.html

ログインユーザuser01のDokcerグループへの追加

グループへの追加
$ usermod -aG docker user01

設定ファイル編集用にvimインストール

vimインストール
$ apt-get -y install vim

Dockerの設定

Dockerにリモートのmacから接続できるように設定します。設定ファイルは/usr/lib/systemd/system/docker.serviceです。

/usr/lib/systemd/system/docker.service(更新前)
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

ExecStartの行に-H tcp://(linux仮想マシンのIPアドレス)を追記します。
私の環境では192.168.64.12でした。

/usr/lib/systemd/system/docker.service(更新後)
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://192.168.64.12 --containerd=/run/containerd/containerd.sock

カーネルモジュールの設定

UTMの共有フォルダは9pという仕組みを使っているようです。
https://docs.getutm.app/guest-support/linux/#virtfs

9pのマウントに必要な機能はUbuntuの場合カーネルモジュールになっていました。

UTMの共有フォルダを自動マウントできるように、カーネルモジュールの自動ロード設定をします。
設定ファイルは/etc/modules-load.d/modules.confです。

/etc/modules-load.d/modules.conf
# /etc/modules is obsolete and has been replaced by /etc/modules-load.d/.
# Please see modules-load.d(5) and modprobe.d(5) for details.
#
# Updating this file still works, but it is undocumented and unsupported.
9pnet_virtio
9p

9pnet_virtio9pを追記します。

UTMの共有フォルダ自動マウント

UTMの共有フォルダのマウントパスを作成します。ここは何でもよいですが、/mnt/utmshareとしました。

$ mkdir /mnt/utmshare

OS起動時の自動マウントを設定します。
以下を/etc/fstabに追記します。

/etc/fstab
share	/mnt/utmshare	9p	trans=virtio,version=9p2000.L,rw,_netdev,nofail	0	0

設定が終わったら再起動します。

設定確認

dockerdが設定した引数(-H tcp://192.168.64.12)で起動していることを確認します。

user01@ubuntu01:~$ ps -ef | grep docker
root         706       1  0 03:41 ?        00:00:00 /usr/bin/dockerd -H fd:// -H tcp://192.168.64.12 --containerd=/run/containerd/containerd.sock
user01      1043     807  0 03:41 pts/0    00:00:00 grep --color=auto docker

UTMの共有ディレクトリ/mnt/utmshareがマウントされていることを確認します

user01@ubuntu01:~$ df
Filesystem                        1K-blocks      Used Available Use% Mounted on
tmpfs                                200340      1036    199304   1% /run
efivarfs                                256        25       232  10% /sys/firmware/efi/efivars
/dev/mapper/ubuntu--vg-ubuntu--lv   5813344   2639876   2857260  49% /
tmpfs                               1001684         0   1001684   0% /dev/shm
tmpfs                                  5120         0      5120   0% /run/lock
/dev/vda2                           1768056    100636   1559288   7% /boot
/dev/vda1                            549804      6508    543296   2% /boot/efi
share                             239362432 192441088  46921344  81% /mnt/utmshare
tmpfs                                200336        12    200324   1% /run/user/1000

macの設定

Linux側の準備ができたので、mac側の設定を行います。

DOCKER_HOSTの設定

まずSAM CLIを実行するターミナルで以下を設定します。
export DOCKER_HOST=(Linux仮想マシンのIPアドレス):2375
私の環境ではLinux仮想マシンのIPアドレスは192.168.64.12なので、以下のように設定します。

% export DOCKER_HOST=192.168.64.12:2375

SAMのテンプレート作成

samで使用するディレクトリで以下を実行し、SAMの必要ファイルを作成します。
m1 macのarmアーキテクチャの仮想環境で動かすので、-a arm64が必要になります。

% sam init -a arm64

今回は検証なので、Hello Worldのサンプルを使用します。言語はPythonとし、サンプルのコードも特に変更しません。

sam init実行結果
% sam init -a arm64
Which template source would you like to use?
1 - AWS Quick Start Templates
2 - Custom Template Location
Choice: 1

Choose an AWS Quick Start application template
1 - Hello World Example
2 - Data processing
3 - Hello World Example with Powertools for AWS Lambda
4 - Multi-step workflow
5 - Scheduled task
6 - Standalone function
7 - Serverless API
8 - Infrastructure event management
9 - Lambda Response Streaming
10 - Serverless Connector Hello World Example
11 - Multi-step workflow with Connectors
12 - GraphQLApi Hello World Example
13 - Full Stack
14 - Lambda EFS example
15 - DynamoDB Example
16 - Machine Learning
Template: 1

Use the most popular runtime and package type? (Python and zip) [y/N]: 

Which runtime would you like to use?
1 - dotnet8
2 - dotnet6
3 - go (provided.al2)
4 - go (provided.al2023)
5 - graalvm.java11 (provided.al2)
6 - graalvm.java17 (provided.al2)
7 - java21
8 - java17
9 - java11
10 - java8.al2
11 - nodejs20.x
12 - nodejs18.x
13 - nodejs16.x
14 - python3.9
15 - python3.8
16 - python3.12
17 - python3.11
18 - python3.10
19 - ruby3.3
20 - ruby3.2
21 - rust (provided.al2)
22 - rust (provided.al2023)
Runtime: 16

What package type would you like to use?
1 - Zip
2 - Image
Package type: 1

Based on your selections, the only dependency manager available is pip.
We will proceed copying the template using pip.

Would you like to enable X-Ray tracing on the function(s) in your application?  [y/N]: 

Would you like to enable monitoring using CloudWatch Application Insights?
For more info, please view https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch-application-insights.html [y/N]: 

Would you like to set Structured Logging in JSON format on your Lambda functions?  [y/N]: 

Project name [sam-app]: 

    -----------------------
    Generating application:
    -----------------------
    Name: sam-app
    Runtime: python3.12
    Architectures: arm64
    Dependency Manager: pip
    Application Template: hello-world
    Output Directory: .
    Configuration file: sam-app/samconfig.toml
    
    Next steps can be found in the README file at sam-app/README.md
        

Commands you can use next
=========================
[*] Create pipeline: cd sam-app && sam pipeline init --bootstrap
[*] Validate SAM template: cd sam-app && sam validate
[*] Test Function in the Cloud: cd sam-app && sam sync --stack-name {stack-name} --watch

SAMビルド実行

sam buildを実行します

% sam build
(略)                                     

Build Succeeded

Built Artifacts  : .aws-sam/build
Built Template   : .aws-sam/build/template.yaml

Commands you can use next
=========================
[*] Validate SAM template: sam validate
[*] Invoke Function: sam local invoke
[*] Test Function in the Cloud: sam sync --stack-name {{stack-name}} --watch
[*] Deploy: sam deploy --guided

"Built Artifacts"のディレクトリ配下にテンプレートやアプリケーションコード(app.py)が出力されます。このパスをローカル実行時の引数で使用します。

% ls .aws-sam/build
HelloWorldFunction	template.yaml
% ls .aws-sam/build/HelloWorldFunction 
__init__.py				charset_normalizer-3.4.0.dist-info	requirements.txt
app.py					idna					urllib3
certifi					idna-3.10.dist-info			urllib3-2.2.3.dist-info
certifi-2024.8.30.dist-info		requests
charset_normalizer			requests-2.32.3.dist-info

SAM ローカル実行

ローカル実行のコマンドを実行します

sam local invoke --container-host 192.168.64.12 --container-host-interface 0.0.0.0 --docker-volume-basedir /mnt/utmshare/test01/sam-app/.aws-sam/build

--docker-volume-basedirには 「Linux仮想マシン側から見えるBuilt Artifactsのディレクトリ」 を指定します。samを実行するmac側のディレクトリではないことに注意です。

--container-host--container-host-interfaceはローカルマシンで稼働していないDockerを使用する場合に必要なようです。

sam local invoke実行結果
% sam local invoke --container-host 192.168.64.12 --container-host-interface 0.0.0.0 --docker-volume-basedir /mnt/utmshare/test01/sam-app/.aws-sam/build
Invoking app.lambda_handler (python3.12)                                                                                                       
Local image was not found.                                                                                                                     
Removing rapid images for repo public.ecr.aws/sam/emulation-python3.12                                                                         
Building image................................................................................................................................................................................................................................................................................................................................................................................................................................................................
Using local image: public.ecr.aws/lambda/python:3.12-rapid-arm64.                                                                              
                                                                                                                                               
Mounting /mnt/utmshare/test01/sam-app/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated, inside runtime container                    
START RequestId: 12113ae4-b112-4d6a-853d-0e9564d2bfed Version: $LATEST
END RequestId: 21972317-d3d8-41c6-abf8-b1ec673ee401
REPORT RequestId: 21972317-d3d8-41c6-abf8-b1ec673ee401 Init Duration: 0.02 ms Duration: 54.31 ms Billed Duration: 55 ms Memory Size: 128 MB Max Memory Used: 128 MB 
{"statusCode": 200, "body": "{\"message\": \"hello world\"}"}

無事仮想環境LinuxのDockerを使ってローカル実行のLambdaが実行されました。

Linux側のdocker psでコンテナが実行されていることが確認できます。

$ docker ps
CONTAINER ID   IMAGE                                           COMMAND                  CREATED        STATUS                  PORTS                    NAMES
1c4533c23445   public.ecr.aws/lambda/python:3.12-rapid-arm64   "/var/rapid/aws-lamb…"   1 second ago   Up Less than a second   0.0.0.0:6708->8080/tcp   distracted_joliot

最後に

本稿では、macからリモートのDockerを使用してSAMローカル実行を行う手順を検証しました。

今回は検証なので簡易に実装できる方法として仮想環境のLinuxを使用しましたが
同様の手順で別物理PCで稼働しているDocker環境を仕様し、コードの共有にsamba/NFSを使ったSAMローカル実行も可能と考えます。

同じようなケースで困っていることは少ないかもしれませんが、ぜひお役立てください。

2
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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?