GCP の Cloud Shell を触ってみて、ふとどんな環境で動いてるんだろう?と気になったのでちょっと調べてみた。
Cloud Shell とは
Cloud Shell はブラウザから shell にアクセス可能な Linux コンテナ環境で多くの言語 (Java, Go, Python, Node.js, Ruby, PHP, .NET Core) と gcloud や gsutil などはもちろん他にも 多くのツール(Emacs も Vim も入ってる)を含んでおり、イメージは毎週更新されるようです。
Linux Distribution は debian で、apt でパッケージを追加することも可能。常に必要なら後述の ~/.customize_environment に書いておく。
$ cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 9 (stretch)"
NAME="Debian GNU/Linux"
VERSION_ID="9"
VERSION="9 (stretch)"
VERSION_CODENAME=stretch
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
root 権限あるし、任意の Docker コンテナ実行できるしファイルのアップロード、ダウンロードもできるしエディタとして VS Code みたいな Theia も使える便利環境です。インスタンスは通常 g1-small (0.5 vCPU, 1.7GB メモリ)ですが、ブーストモードで n1-standard-1 (1 vCPU, 3.75GB メモリ)にすることも可能。ブーストモードの詳細は知らない。
Open in Cloud Shell
Open in Cloud Shell 機能を使えばワンクリックで指定の Docker コンテナ環境に git repository を clone してブラウザ内のエディタで開くことが出来ます。
Cloud Shell を立ち上げて次のコマンドを実行するのと同じした。
cloudshell_open --repo_url "https://github.com/yteraoka/flask-sample.git" --page "editor" --open_in_editor "app/app.py"
ちなみに alias edit='cloudshell edit-files'
が設定されているため edit some-exist-file
とするだけで Theia で開くことが出来ます。dl
という alias もあって簡単にファイルをダウンロード出来ます。
Web Preview
Cloud Shell 内で 8080/tcp を listen したサーバーを起動させて Web Preview 機能を使えばブラウザでアクセスすることが出来ます。
ドキュメントにあるようにアプリを書いて実行することもできるし、次のように docker container で 8080 をマップすることでも対応可能。
docker run -d -p 8080:80 nginx
ストレージ
5GB ある /home 配下は永続化され、新しいコンテナに切り替わってもデータは引き継がれます。120日間アクセスが無いとこのストレージは削除されます。
料金
無料らしい。
プロセスを見てみる
さて、どんな環境かということで ps コマンドで確認してみると次のようになっていました。
username@cloudshell:~ (project-id)$ ps auxwwf
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 17976 2876 ? Ss 12:23 0:00 /bin/bash /google/scripts/onrun.sh sleep infinity
root 8 4.6 0.1 250116 2200 ? Ssl 12:23 0:00 /usr/sbin/rsyslogd
root 81 0.0 0.1 69960 3172 ? S<s 12:23 0:00 /usr/sbin/sshd -p 22 -o AuthorizedKeysFile=/etc/ssh/keys/authorized_keys
root 294 0.0 0.3 86552 6476 ? S<s 12:23 0:00 \_ sshd: username [priv]
username 298 0.0 0.2 86552 4352 ? S< 12:23 0:00 \_ sshd: username@pts/0
username 299 0.0 0.1 11176 3044 pts/0 S<s+ 12:23 0:00 \_ bash -c if [ -f /google/devshell/start-shell.sh ]; then /google/devshell/start-shell.sh 38771 'project-id' '' '1363912993' false else touch /var/run/google/devshell/38771 && bash --login fi
username 301 0.0 0.1 11192 2896 pts/0 S<+ 12:23 0:00 | \_ /bin/bash /google/devshell/start-shell.sh 38771 project-id 1363912993 false
username 306 0.0 0.1 19332 3064 pts/0 S<+ 12:23 0:00 | \_ tmux new-session -A -D -n cloudshell -s 1363912993
username 300 0.0 0.0 12688 1724 ? S<s 12:23 0:00 \_ /usr/lib/openssh/sftp-server
root 156 1.6 3.8 376044 66772 ? Sl 12:23 0:00 /usr/bin/dockerd -p /var/run/docker.pid --mtu=1460 --registry-mirror=https://asia-mirror.gcr.io
root 170 0.5 2.4 496136 42304 ? Ssl 12:23 0:00 \_ containerd --config /var/run/docker/containerd/containerd.toml --log-level info
username 289 3.6 1.1 58580 20368 ? S 12:23 0:00 /usr/bin/python /usr/bin/supervisord -n -c /google/devshell/supervisord.conf -u username --pidfile=/var/run/supervisor.pid --logfile=/var/log/supervisord.log
username 365 2.2 0.9 43128 17304 ? S 12:23 0:00 \_ /usr/bin/python /google/devshell/send_heartbeats.py
root 290 0.0 0.0 25384 1504 ? S 12:23 0:00 logger -t supervisord
root 293 0.0 0.0 4188 612 ? S 12:23 0:00 sleep infinity
username 308 0.0 0.1 27940 3280 ? S<s 12:23 0:00 tmux new-session -A -D -n cloudshell -s 1363912993
username 309 1.8 0.3 23080 6712 pts/1 S<s 12:23 0:00 \_ -bash
username 383 0.0 0.1 38304 3200 pts/1 R<+ 12:24 0:00 \_ ps auxwwf
username@cloudshell:~ (project-id)$
PID 1 で onrun.sh が実行されており何らかのコンテナで実行されてるっぽい。sleep コマンドの引数に infinity なんて使い方ができるんですね。(sleep infinity で無限に待つ - @tmtms のメモ)
onrun.sh の中では rsyslogd を実行した後に環境変数 ONRUM で指定されたコマンドを順に実行し、その後、引数で指定されたコマンド(sleep infinity)が実行されます。環境変数 ONRUN には /google/devshell/startup.sh /google/scripts/wrapdocker.sh /google/devshell/start-supervisord.sh が入っていました。(以下、環境変数による細かい振る舞いは省略)
startup.sh
- ログイン関連で必要となるファイルを vmtouch コマンドでキャッシュに乗っける
~/.customize_environment
が存在すれば実行する(これは初回起動時のみ)
Environment customization- useradd コマンドでユーザーを作成する(docker, adm, sudo グループに所属)
- sshd の起動
AuthorizedKeysFile=/etc/ssh/keys/authorized_keys
と指定されており、ここには Theia 用とおぼしき公開鍵も入っていました - /etc/environment への環境変数の設定
- Google Cloud SDK 設定
wrapdocker.sh
環境変数 DISABLE_DIND
が空でなければ何もしない。
- stdin / stdout / stderr 以外の file descripter を閉じる(fork で引き継いだやつとかかな?)
DOCKER_OPTS
を /etc/default/docker に追記- service docker start で docker daemon を起動させる
start-supervisord.sh
- supervisord を起動させる
supervisord では /google/devshell/send_heartbeats.py
を実行する。send_heartbeats.py は1分おきに ssh.cloud.google.com にあるエンドポイントに対してハートビートリクエストを送る。
その他
/google/devshell/start-shell.sh ってどこから実行してるのかな?って悩んでたのだけれどこれは単に ssh してから実行してるのかな。
まとめ
セッションは最長12時間であるとか、いくつかの制限はありますが、ブラウザさえあれば使える便利な環境が無料で使えるんです。もちろん GCP 関係ない作業にも使える。
調査することで sleep に infinity が指定可能であるとか vmtouch や mountpoint コマンドというものがあるということを知ることができました。やったね!