🚀

LambdaのEFSマウントを調べてみた

2022/04/29に公開

業務でLambdaでEFSを利用するケースがあり、マウントオプションに関して調べた備忘録。

Lambda,EFS

言わずもがなのAWSサービス。サービス詳細の内容は公式ドキュメントへ。
※1 Lambda デベロッパーガイド
※2 EFS ユーザガイド

マウントに関して

EFSファイル操作を扱う機能を実装していた際に、読み込み・書き込み処理のリトライってアプリ内で実装するの?マウントオプションで実現されてるのか?が気になり色々と調べてみた。

EFSのマウントは、NFSが利用されている。

出典:Red Hat Enterprise Linux 4: システム管理入門ガイド

またAWS公式から、NFSマウントオプションの推奨デフォルト値が提示されている。
※3 マウントに関する追加の考慮事項

LambdaとEFSのマウントでも、hardオプションが設定されているのか否かが当初の疑問を解消すると思い、AWS公式のドキュメントを漁りまくったが、該当するドキュメントを発見することができなかった。(ドキュメントご存知の方教えてください…)

「まあ推奨しているし、内部実装でもそのように処理されているだろう」と思ったが、気になってしまった手前諦めることができず、AWSサポートに問い合わせてみた。

「大変申し訳ございませんが、該当の内容でお客様にご提示できる情報はございません。」

なんだって!?!? 絶望。。(対応いただいた方、拙い質問に対してありがとうございました)

じゃあ実装するかと思い、SAMでEFSをマウントしたLambdaをデプロイしてみて、内部状態を調べてみた。

実装

LambdaにEFSマウントする場合は、SAMテンプレートではLambdaの設定項目に以下を追加する必要がある。

  • VpcConfig
  • FileSystemConfigs

また私はSAMでマウントターゲットも作成しているため、DependsOnも利用。
SAM Template (抜粋)

CmdFunction:
    Type: AWS::Serverless::Function 
    DependsOn: MountTarget
    Properties:
      CodeUri: cmd/
      Handler: cmd
     // ommited
     
      VpcConfig:
        SecurityGroupIds:
          - !Ref LambdaSecurityGroup
        SubnetIds:
          - !Ref Subnet
      FileSystemConfigs:
        - Arn: !GetAtt AccessPoint.Arn
          LocalMountPath: /mnt/efs

Lambdaは大好きなGoで実装。実装が雑なのは、ご愛嬌で。。
色々調べてみたかったので、コマンドを引数とする形で実装。
Lambda

package main

import (
	"context"
	"fmt"
	"log"
	"os/exec"

	"github.com/aws/aws-lambda-go/lambda"
)

type MyEvent struct {
	Cmd string `json: cmd`
}

func HandleRequest(ctx context.Context, evt MyEvent) {

	res, err := exec.Command("sh", "-c", evt.Cmd).Output()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(res))
}

func main() {
	lambda.Start(HandleRequest)
}

結果

まずは実行ユーザを調べた。(whoami)

sbx_user1051

ルートのディレクトリを一覧。(ls -l /)

total 34
dr-xr-xr-x  2 root         root  1024 Mar 16 15:39 bin
dr-xr-xr-x  2 root         root  1024 Jan  6  2012 boot
drwxr-xr-x  2 root         root  4096 Apr 29 01:11 dev
drwxr-xr-x 50 root         root  3072 Apr 11 23:46 etc
drwxr-xr-x  2 root         root  1024 Jan  6  2012 home
dr-xr-xr-x  5 root         root  1024 Mar 16 15:39 lib
dr-xr-xr-x  5 root         root  6144 Mar 16 15:39 lib64
drwxr-xr-x  2 root         root  1024 Jan  6  2012 media
drwxr-xr-x  3 root         root  4096 Apr 29 01:22 mnt
drwxr-xr-x  2 root         root  1024 Mar 16 15:39 opt
dr-xr-xr-x 78 root         root     0 Apr 29 01:22 proc
dr-xr-x---  2 root         root  1024 Jan  6  2012 root
dr-xr-xr-x  2 root         root  1024 Mar 16 15:39 sbin
drwxr-xr-x  2 root         root  1024 Jan  6  2012 selinux
drwxr-xr-x  2 root         root  1024 Jan  6  2012 srv
drwxr-xr-x  2 root         root  1024 Jan  6  2012 sys
drwx------  2 sbx_user1051   990 4096 Apr 29 01:22 tmp
drwxr-xr-x 13 root         root  1024 Mar 16 15:38 usr
drwxr-xr-x  1        12569 users 1024 Mar 21 14:14 var

使用可能なコマンド一覧。(ls -l /bin)

total 4483
-rwxr-xr-x 1 root root  28448 Feb 25  2016 arch
lrwxrwxrwx 1 root root      4 Mar 16 15:38 awk -> gawk
-rwxr-xr-x 1 root root  28128 Feb 25  2016 basename
-rwxr-xr-x 1 root root 939200 Jun 16  2020 bash
-rwxr-xr-x 1 root root  48000 Feb 25  2016 cat
-rwxr-xr-x 1 root root  57216 Feb 25  2016 chgrp
-rwxr-xr-x 1 root root  52992 Feb 25  2016 chmod
-rwxr-xr-x 1 root root  58496 Feb 25  2016 chown
-rwxr-xr-x 1 root root 145760 Feb 25  2016 cp
-rwxr-xr-x 1 root root 129912 Oct  8  2014 cpio
-rwxr-xr-x 1 root root  40672 Feb 25  2016 cut
-rwxr-xr-x 1 root root  59584 Feb 25  2016 date
-rwxr-xr-x 1 root root  69416 Feb 25  2016 dd
-rwxr-xr-x 1 root root  95280 Feb 25  2016 df
-rwxr-xr-x 1 root root  44976 Dec  4  2020 dmesg
-rwxr-xr-x 1 root root  27904 Feb 25  2016 echo
-rwxr-xr-x 1 root root    290 Aug 17  2017 egrep
-rwxr-xr-x 1 root root  28128 Feb 25  2016 env
-rwxr-xr-x 1 root root  24416 Feb 25  2016 false
-rwxr-xr-x 1 root root    290 Aug 17  2017 fgrep
-rwxr-xr-x 1 root root 234512 Jan 17  2011 find
-rwxr-xr-x 1 root root  58352 Dec  4  2020 findmnt
-rwxr-xr-x 1 root root 373632 Oct 14  2012 gawk
-rwxr-xr-x 1 root root 150600 Aug 17  2017 grep
lrwxrwxrwx 1 root root      3 Mar 16 15:39 gtar -> tar
-rwxr-xr-x 1 root root   2253 Aug 17  2017 gunzip
-rwxr-xr-x 1 root root  93576 Aug 17  2017 gzip
-rwxr-xr-x 1 root root  28320 Dec  4  2020 kill
-rwxr-xr-x 1 root root  25472 Feb 25  2016 link
-rwxr-xr-x 1 root root  53352 Feb 25  2016 ln
-rwxr-xr-x 1 root root  32728 Dec  4  2020 login
-rwxr-xr-x 1 root root 113440 Feb 25  2016 ls
-rwxr-xr-x 1 root root  74880 Dec  4  2020 lsblk
-rwxr-xr-x 1 root root  77728 Feb 25  2016 mkdir
-rwxr-xr-x 1 root root  61184 Feb 25  2016 mknod
-rwxr-xr-x 1 root root  36512 Feb 25  2016 mktemp
-rwxr-xr-x 1 root root  36952 Dec  4  2020 more
-rwxr-xr-x 1 root root 124168 Feb 25  2016 mv
-rwxr-xr-x 1 root root  28896 Feb 25  2016 nice
-rwxr-xr-x 1 root root  85384 Aug 14  2018 ps
-rwxr-xr-x 1 root root  28672 Feb 25  2016 pwd
-rwxr-xr-x 1 root root  10992 Dec  4  2020 raw
-rwxr-xr-x 1 root root  37344 Feb 25  2016 readlink
-rwxr-xr-x 1 root root  57216 Feb 25  2016 rm
-rwxr-xr-x 1 root root  40480 Feb 25  2016 rmdir
-rwxr-xr-x 1 root root  15936 Jun 29  2021 rpm
-rwxr-xr-x 1 root root  66168 Jul  7  2012 sed
lrwxrwxrwx 1 root root      4 Mar 16 15:38 sh -> bash
-rwxr-xr-x 1 root root  28032 Feb 25  2016 sleep
-rwxr-xr-x 1 root root 109696 Feb 25  2016 sort
-rwxr-xr-x 1 root root  65120 Feb 25  2016 stty
-rwxr-xr-x 1 root root  25120 Feb 25  2016 sync
-rwxr-xr-x 1 root root 344648 Oct  7  2014 tar
-rwxr-xr-x 1 root root  27696 Dec  4  2020 taskset
-rwxr-xr-x 1 root root  55872 Feb 25  2016 touch
-rwxr-xr-x 1 root root  24416 Feb 25  2016 true
-rwxr-xr-x 1 root root  28448 Feb 25  2016 uname
-rwxr-xr-x 1 root root  25344 Feb 25  2016 unlink
-rwxr-xr-x 1 root root   1941 Aug 17  2017 zcat

いよいよお目当てのマウント状態を調べるぞ!

マウント状態を調べる方法は以下の3つがある。

  1. /etc/mtab を表示する
  2. /proc/mounts を表示する
  3. df コマンドを発行する

1の結果 (cat /etc/mtab)

/mnt/root-rw/opt/amazon/asc/worker/tasks/rtfs/go1.x-rapid-amzn-201803 / overlay ro,nosuid,nodev,relatime,lowerdir=/tmp/es2091527754/17769c2694755799:/tmp/es2091527754/51696035961324 0 0
/dev/vdb /dev ext4 rw,nosuid,noexec,noatime,data=writeback 0 0
/dev/vdd /tmp ext4 rw,relatime,data=writeback 0 0
none /proc proc rw,nosuid,nodev,noexec,noatime 0 0
/dev/vdb /proc/sys/kernel/random/boot_id ext4 ro,nosuid,nodev,noatime,data=writeback 0 0
/dev/root /etc/passwd ext4 ro,nosuid,nodev,relatime,data=ordered 0 0
/dev/root /var/rapid ext4 ro,nosuid,nodev,relatime,data=ordered 0 0
/dev/vdb /etc/resolv.conf ext4 ro,nosuid,nodev,noatime,data=writeback 0 0
/dev/vdb /mnt ext4 rw,noatime,data=writeback 0 0
/dev/vdc /var/task squashfs ro,nosuid,nodev,relatime 0 0
127.0.0.1:/ /mnt/efs nfs4 rw,relatime,vers=4.1,rsize=1048576,wsize=1048576,namlen=255,hard,noresvport,proto=tcp,port=20252,timeo=600,retrans=2,sec=sys,clientaddr=127.0.0.1,local_lock=none,addr=127.0.0.1 0 0

2の結果 (cat /proc/mounts)

/mnt/root-rw/opt/amazon/asc/worker/tasks/rtfs/go1.x-rapid-amzn-201803 / overlay ro,nosuid,nodev,relatime,lowerdir=/tmp/es2091527754/17769c2694755799:/tmp/es2091527754/51696035961324 0 0
/dev/vdb /dev ext4 rw,nosuid,noexec,noatime,data=writeback 0 0
/dev/vdd /tmp ext4 rw,relatime,data=writeback 0 0
none /proc proc rw,nosuid,nodev,noexec,noatime 0 0
/dev/vdb /proc/sys/kernel/random/boot_id ext4 ro,nosuid,nodev,noatime,data=writeback 0 0
/dev/root /etc/passwd ext4 ro,nosuid,nodev,relatime,data=ordered 0 0
/dev/root /var/rapid ext4 ro,nosuid,nodev,relatime,data=ordered 0 0
/dev/vdb /etc/resolv.conf ext4 ro,nosuid,nodev,noatime,data=writeback 0 0
/dev/vdb /mnt ext4 rw,noatime,data=writeback 0 0
/dev/vdc /var/task squashfs ro,nosuid,nodev,relatime 0 0
127.0.0.1:/ /mnt/efs nfs4 rw,relatime,vers=4.1,rsize=1048576,wsize=1048576,namlen=255,hard,noresvport,proto=tcp,port=20252,timeo=600,retrans=2,sec=sys,clientaddr=127.0.0.1,local_lock=none,addr=127.0.0.1 0 0

3の結果 (df -h)

Filesystem                                                             Size  Used Avail Use% Mounted on
/mnt/root-rw/opt/amazon/asc/worker/tasks/rtfs/go1.x-rapid-amzn-201803  8.0G  6.5G  1.6G  81% /
/dev/vdb                                                               1.5G   14M  1.4G   1% /dev
/dev/vdd                                                               526M  872K  514M   1% /tmp
/dev/root                                                              9.8G  538M  9.2G   6% /var/rapid
/dev/vdc                                                               4.5M  4.5M     0 100% /var/task
127.0.0.1:/                                                            8.0E     0  8.0E   0% /mnt/efs

おお〜しっかり指定したローカルマウントパスでEFSマウントされてる!!!(当然)
マウントオプションも提示されている推奨値で行われている。

ってことは、アプリ側でEFS上のファイルの読み込み・書き込みのリトライ処理は入れなくていいんかなというのが現在の結論。
ちゃんとLinuxとかコンテナの勉強しなきゃな〜〜と思う今日この頃。

PS. AWSあるある ルートユーザのログインのセキュリティチェックの文字列入力、大体1回間違えがち

参考

Discussion