Cloud Functions実行環境について学ぶためにOSコマンドを色々実行してみた

Cloud Functions実行環境であんなこと、こんなことしてみました
2021.12.02

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

MAD事業部@大阪の岩田です。

本エントリは クラスメソッド Google Cloud Advent Calendar 2021 の 2日目 の記事です。

個人的にマネージドサービスの裏側を想像するのが好きなので、FaaS実行環境でOSコマンドを実行して出力を見ながらニヤニヤするアレをやってみました。

やってみる

ということで早速やっていきます。

  • トリガーはHTTP
  • ランタイムはNode.js14

を指定して以下のソースコードを準備します。

const execSync = require('child_process').execSync;
exports.helloWorld = (req, res) => {
  const cmd = 'ここに実行したいOSコマンドを設定'
  const result =  execSync(cmd).toString();
  res.status(200).send(result);
};

あとは変数cmdの中身に実行したいOSコマンドを設定して実行、出力を確認していきます。実行したいコマンドをクエリストリングで渡そうかとも思ったのですが、検証とはいえOSコマンドインジェクションバリバリな実装をするのはどうかと思い留まりました。

実行するOSコマンドについては既に先人がパスの通っているコマンド一覧を調査されていたので、こちらを参考にさせて頂きました。

では諸々のコマンドの実行結果を見ていきましょう。

pwd

/workspace

/workspaceなんてディレクトがあるんですね

ls -al /

total 0
drwxr-xr-x 2 root     root     0 Nov 30 13:55 .
drwxr-xr-x 2 root     root     0 Nov 30 13:55 ..
drwxr-xr-x 2 root     root     0 Oct 21 03:26 bin
drwxr-xr-x 2 root     root     0 Jan  1  2000 boot
dr-xr-xr-x 2 www-data www-data 0 Nov 30 13:56 cloudsql
drwxr-xr-x 2 root     root     0 Jan  1  1980 cnb
dr-xr-xr-x 1 root     root     0 Nov 30 13:56 dev
drwxr-xr-x 2 root     root     0 Nov 25 05:26 etc
lrwxrwxrwx 1 root     root     0 Oct 21 03:28 home -> /tmp
drwxr-xr-x 2 www-data www-data 0 Jan  1  1980 layers
drwxr-xr-x 2 root     root     0 Oct 21 03:27 lib
drwxr-xr-x 2 root     root     0 Jan  1  2000 lib64
drwxr-xr-x 2 root     root     0 Jan  1  2000 media
drwxr-xr-x 2 root     root     0 Jan  1  2000 mnt
drwxr-xr-x 2 root     root     0 Jan  1  2000 opt
dr-xr-xr-x 2 root     root     0 Nov 30 13:56 proc
lrwxrwxrwx 1 root     root     0 Oct 21 03:28 root -> /tmp
lrwxrwxrwx 1 root     root     0 Oct 21 03:28 run -> /tmp/run
drwxr-xr-x 2 root     root     0 Oct 21 03:26 sbin
lrwxrwxrwx 1 root     root     0 Oct 21 03:28 serve -> /usr/bin/serve
lrwxrwxrwx 1 root     root     0 Nov 10 05:57 srv -> /workspace
drwxr-xr-x 2 root     root     0 Nov 10 05:54 staging
lrwxrwxrwx 1 root     root     0 Oct 21 03:28 start -> /usr/bin/start
dr-xr-xr-x 1 root     root     0 Nov 30 13:56 sys
drwxrwxrwt 1 www-data www-data 0 Nov 30 13:56 tmp
drwxr-xr-x 2 root     root     0 Jan  1  2000 usr
drwxr-xr-x 2 root     root     0 Nov 28 15:42 var
drwxr-xr-x 2 www-data www-data 0 Jan  1  1980 workspace
drwxr-xr-x 2 www-data www-data 0 Nov 10 05:57 www-data-home

pwdより先にこっちを実行しとけば良かったですね。/homeや/rootが/tmpにリンクしてるのが面白いところです。

ps aux

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
www-data     1  2.0  3.0 644488 63476 ?        Ssl  13:10   0:03 node /layers/google.nodejs.functions-framework/functions-framework/node_modules/.bin/functions-framework
www-data    15  0.0  0.1  12688  3520 ?        S    13:13   0:00 /bin/sh -c ps aux
www-data    16  0.0  0.1  42464  3748 ?        R    13:13   0:00 ps aux

ナルホドPID:1の /layers/google.nodejs.functions-framework/functions-framework/node_modules/.bin/functions-frameworkが関数のプロセスなんですね

uname -a

Linux localhost 4.4.0 #1 SMP Sun Jan 10 15:06:54 PST 2016 x86_64 x86_64 x86_64 GNU/Linux

カーネルは4.4を使っているようです

whoami

www-data

これはHTTPトリガーを指定したからユーザーがwww-dataなのかな?と思い、GCSバケットからトリガーする関数でも試してみましたが、ユーザーは変わらずwww-dataでした

node -v

v14.17.6

2021/11/30時点のNode.jsのランタイムはv14.17.6が動作しているようです

printenv

GCF_BLOCK_RUNTIME_nodejs6=410
S2A_ACCESS_TOKEN=なにかのトークンらしき文字列
NO_UPDATE_NOTIFIER=true
K_REVISION=15
SHLVL=1
HOME=/root
PORT=8080
NODE_OPTIONS=--max-old-space-size=192
FUNCTION_SIGNATURE_TYPE=http
GCF_BLOCK_RUNTIME_go112=410
_=/layers/google.nodejs.functions-framework/functions-framework/node_modules/.bin/functions-framework
PATH=/workspace/node_modules/.bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
FUNCTION_TARGET=helloWorld
DEBIAN_FRONTEND=noninteractive
NODE_PATH=/workspace/node_modules
K_SERVICE=os-cmd
PWD=/workspace
GAE_RUNTIME=nodejs14
NODE_ENV=production

S2A_ACCESS_TOKENが何者なのか気になりますね。S2AはSecure Session Agentの略でしょうかね?

https://github.com/google/s2a-core

df -h

Filesystem      Size  Used Avail Use% Mounted on
none            8.0E     0  8.0E   0% /tmp

Availableが8.0E?!こんなの初めて見ました

lscpu

Architecture:        x86_64
CPU op-mode(s):      32-bit, 64-bit
Byte Order:          Little Endian
CPU(s):              2
On-line CPU(s) list: 0,1
Vendor ID:           GenuineIntel
CPU family:          6
Model:               85
Model name:          unknown
Stepping:            unknown
CPU MHz:             2679.843
BogoMIPS:            2679.84
Virtualization:      VT-x
Flags:               fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm cqm mpx rdt_a avx512f avx512dq rdseed adx smap clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves pku

安定のIntel製

lsblk

Error: function terminated. Recommended action: inspect logs for termination reason. Additional troubleshooting documentation can be found at https://cloud.google.com/functions/docs/troubleshooting#logging Details:
Command failed: lsblk
lsblk: failed to access sysfs directory: /sys/dev/block: No such file or directory

ダメでした!

findmnt

TARGET       SOURCE FSTYPE    OPTIONS
/            none   overlayfs rw
|-/dev       none   overlayfs rw
| `-/dev/shm none   tmpfs     rw
|-/proc      none   proc      rw
|-/sys       none   sysfs     rw
|-/tmp       none   tmpfs     rw
|-/cloudsql  none   9p        rw
`-/var/log   none   overlayfs rw

注目したいのは/cloudsql none 9p rwの部分です。9p filesystemなんてのがあるんですね。恥ずかしながら初めて知りました。

dmesg

[    0.000000] Starting gVisor...
[    0.384209] Letting the watchdogs out...
[    0.720865] Consulting tar man page...
[    0.868943] Checking naughty and nice process list...
[    1.279663] Creating process schedule...
[    1.535912] Daemonizing children...
[    1.683496] Searching for socket adapter...
[    2.025663] Adversarially training Redcode AI...
[    2.468126] Conjuring /dev/null black hole...
[    2.827750] Segmenting fault lines...
[    2.832743] Granting licence to kill(2)...
[    2.939954] Ready!

おお、gVisorの出力が!Cloud FunctionsはgVisor上で動いていると聞いていましたが、こうやってログから確認できるとナルホドとなりますね

まとめ

Cloud Functionsの実行環境について少し詳しくなれました。やはりマネージド・サービスの裏側を想像するのは楽しいですね!

明日12/3は小倉功一 さんです。よろしくお願いします!