💮

Fuchsia を GCE でビルドしてみた

2021/08/11に公開

Fuchsia のビルド、Zircon カーネルデバッグを GCE で行った際の記録です。
ビルド時間を計測しました。

自宅環境の問題

  • ローカルリポジトリ更新(jiri update)が遅い
  • ビルド(fx build)が遅い

これを GCE で解決できないか、検討してみます。
予算は、月 500 円前後。

自宅環境

Chromebox 上の Linux で開発しています。

  • OS:Debian 10(on Crostini)
  • CPU:Celeron 3865U(vCPUx2)
  • メモリ:18GB
  • ストレージ:SSD 337GB

方針

費用削減のため、作業用途によって VM の構成を変えます。

  • VM 最小構成(e2-micro)

    • ソースコード編集(VSCode Remote SSH でリモート接続)
    • fx qemu & gdb デバッグ(ssh でリモート接続)
  • VM ビルド構成(e2-standard-8)

    • fuchsia リポジトリ更新(ssh でリモート接続)
    • fx build ビルド(ssh でリモート接続)

    (追記 e2-standard-4 で十分)

事前準備

https://cloud.google.com/compute/docs/quickstart-linux?hl=ja

  • Google Cloud Platform アカウント登録
  • Google Cloud Platform プロジェクト作成
  • gcloud インストール
    VM をコンソールから操作するのに必要

VM 作成

https://cloud.google.com/sdk/gcloud/reference/compute/instances/create
https://cloud.google.com/sdk/gcloud/reference/compute/instances/set-machine-type

  • 最小構成(e2-micro)で VM 作成

    @local
    gcloud compute instances create instance-test \
    --machine-type=e2-micro \
    --zone=us-west1-b \
    --boot-disk-size=100GB \
    --boot-disk-type=pd-standard \
    --image-family=debian-10 \
    --image-project=debian-cloud \
    --preemptible \
    --no-restart-on-failure \
    --maintenance-policy=TERMINATE
    
    • --machine-type=e2-micro
      vCPUx2、メモリ 1GB 構成
    • --zone=us-west1-b
      us-west1-b(オレゴン)で動作(無料枠の条件)
    • --boot-disk-size=100GB、--boot-disk-type=pd-standard
      永続ブートディスクに 100GB HDD を使用
    • --image-family=debian-10, --image-project=debian-cloud
      Debian 10 の最新イメージを使用。
      (追記)Debian 11 がリリースされました。11 に変更する予定です
    • --preemptible、--no-restart-on-failure、--maintenance-policy=TERMINATE
      プリエンプティブルに必要な設定(自動再起動オフ、メンテナンス時に VM 停止)
  • ビルド構成(e2-standard-8)へ VM 変更

    最小構成をビルド構成に更新する。
    これを実行したあとで、ビルド、リポジトリ更新する。

    @local
    gcloud compute instances set-machine-type instance-test \
    --machine-type e2-standard-8
    
    • --machine-type=e2-standard-8
      vCPUx8、メモリ 32GB 構成
  • 最小構成(e2-micro)へ VM 変更

    ビルド構成を最小構成に更新する。
    これを実行したあとで、ソースコード変更、デバッグする。

    @local
    gcloud compute instances set-machine-type instance-test \
    --machine-type e2-micro
    

料金

  • 無料部分

  • 有料部分

    • e2-standard-8(vCPUx8、メモリ 32GB)、プリエンプティブル

      なるべく安くしたいので、割安になるプリエンプティブルにする。
      0.08041 ドル/時
      1 時間可動した場合、1 ドル 110 円で約 9 円

    • 標準永続ディスク(HDD)100GB

      fuchsia のリポジトリ、ビルド成果物に必要なストレージは、50GB 〜 80GB ほど。

      30GB まで無料。超えた 70GB が課金対象のはず。秒単位で課金。
      追記:秒単位の課金が 30GB * 0.04 * 110 = 132円 を超えるまでは無課金、超えると 100GB を対象に課金された。

    • 外部 IP アドレス(エフェメラル

      • 0.004 ドル/時
        1 時間可動した場合、1 ドル 110 円で 0.44 円

      • エフェメラル 外部 IP アドレスは VM 停止中は課金されない

        エフェメラル IP アドレスについては、関連付けられた VM インスタンスが実行中のときに限り、Google Cloud はそのアドレスを使用中であると見なします。インスタンスが停止または削除されると、Google Cloud はエフェメラル IP アドレスを解放し、このアドレスを使用中と見なしません

SSH でリモート接続

https://cloud.google.com/sdk/gcloud/reference/compute/ssh?hl=ja

@local
gcloud compute ssh instance-test

今回は、VM の外部 IP アドレス宛に SSH で接続します。

fuchsia リポジトリ更新

https://fuchsia.dev/fuchsia-src/get-started/get_fuchsia_source?hl=en

以下、SSH でログインした VM 内での作業です。

@VM(e2-standard-8)
cd ~
sudo apt install -y curl git unzip gcc  # fuchsiaビルドに必要
sudo apt install -y tmux                # 回線切断時の備え
tmux                                    # 以下の作業は tmux 内
curl -s "https://fuchsia.googlesource.com/fuchsia/+/HEAD/scripts/bootstrap?format=TEXT" | base64 --decode > bootstrap.sh
chmod u+x ./bootstrap.sh

計測結果

VM 時間
e2-micro 125m 23s
e2-standard-8 5m 41s
(参考)自宅 65m 55s

計測方法

@VM(e2-micro, e2-standard-8)
time ./bootstrap.sh

fuchsia リポジトリサイズ

@VM
cd ~/fuchsia
du -sm ./
22239

リポジトリサイズは約 22GB でした。

環境変数のセット

@VM
export PATH="/home/{ユーザ名}/fuchsia/.jiri_root/bin:$PATH"

fx コマンドへのパスを通します。

ビルド

計測結果

VM PRODUCT.BOARD ビルド時間 成果物(MB) リポジトリ+成果物(MB)
e2-micro bringup.x64 N/A N/A
e2-micro core.x64 N/A N/A
e2-micro terminal.x64 N/A N/A
e2-micro workstation.x64 N/A N/A
e2-standard-8 bringup.x64 41m 12s 23,983 46,151
e2-standard-8 core.x64 66m 34s 41,620 63,771
e2-standard-8 terminal.x64 81m 2s 50,818 72.923
e2-standard-8 workstation.x64 80m 54s 56,334 78,428
(参考)自宅 workstation.x64 512m 25s - -

計測方法

@VM(e2-standard-8)
time ( fx set bringup.x64 && fx build ) # ビルド時間
du -sm ./out                            # 成果物のサイズ
du -sm ./                               # リポジトリ+成果物のサイズ

備考

  • e2-microではメモリが足りずfx setが終了するため、計測不能

  • 試行回数は設定ごとに 1 回
    terminal.x64workstation.x64がほぼ同じ時間なのは違和感があるが、大まかな時間がわかったので良しとする

  • 試行ごとにrm -rf ./outで成果物を削除した(キャッシュを使用しないため)

  • ./out 以下に成果物(中間成果物を含む)が生成される
    今回は、必要な永続ディスクのサイズを確かめるために、全成果物のサイズを知りたい

  • 今回は費用削減のため、永続ディスクをHDDにしてる。割高なSSDに変更するとより早くなるかもしれない

  • 自宅計測は、並行して別の作業をしていたので、その分遅くなっているはず
    普段の環境でもビルドと並行して作業は行う。今回の趣旨(普段の自宅環境と GCE の比較)に沿っているため問題ない

(参考)e2-micro の結果

@VM(e2-micro)
$ fx set bringup.x64
ERROR: error running gn gen: signal: killed
@VM(e2-micro) カーネルログ
$ sudo dmesg | tail -n 3
[  241.838718] Out of memory: Kill process 625 (gn) score 812 or sacrifice child
[  241.847841] Killed process 625 (gn) total-vm:942816kB, anon-rss:818768kB, file-rss:0kB, shmem-rss:0kB
[  241.881940] oom_reaper: reaped process 625 (gn), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB

メモリが足りず、OOM(Out Of Memory)でプロセスが終了していました。

VSCode でソースコード編集

SSH 設定の準備

https://cloud.google.com/sdk/gcloud/reference/compute/config-ssh?hl=ja

gcloud compute instances start instance-test
gcloud compute config-ssh

VSCode Remote SSH で使用する、~/.ssh/config のホストを生成します。

  • Q. 次回の VM 起動時に、外部 IP アドレス変わったときはどうなる?
    A. VM 起動ごとに、gcloud compute config-ssh を実行する。~/.ssh/config の当該ホストの IP アドレスが更新される

VSCode Remote SSH

https://code.visualstudio.com/docs/remote/ssh-tutorial

  • コード編集は全く重くない、快適

Zircon カーネルデバッグ

QEMU と gdb で Zircon カーネルデバッグを行います。

https://fuchsia.dev/fuchsia-src/development/debugging/qemu?hl=en#debugging_the_kernel_with_gdb

準備

@VM
sudo apt install -y gdb

カーネルイメージのロード時にベースアドレスをランダム化する KASLR(Kernel Address Space Layout Randomization) の影響で、zircon.elf に記載のアドレスは GDB で使用できないです。
(2021 年 7 月時点でランダム化はまだされてないですが、zircon.elf に記載のアドレスとは異なるアドレス(決め打ち)にロードされるようには実装されています)

これを解決するために、zircon.elf-gdb.pyが必要です。
.gdbinitに下記を追加します。

∼/.gdbinit @VM
add-auto-load-safe-path /home/{ユーザ名}/fuchsia/out/default/kernel_x64/zircon.elf-gdb.py

修正パッチをプルリクエスト中です。

デバッグ

  • コンソール

    @VM
    fx qemu -- -s -S
    

    -s -Sオプションで gdb のアタッチを待ちます

  • 別のコンソール

    @VM(e2-micro)
    cd out/default                      # デバッグ時ソースコード表示のために移動が必要
    gdb ./kernel_x64/zircon.elf
    ...
    (gdb) target extended-remote :1234  # qemuにアタッチ
    (gdb) b lk_main
    (gdb) c
    

    fx qemu では、multiboot、physboot ブートローダと Zircon カーネルが動作します。
    上記例では、zircon.elf のlk_main()にブレークポイントをセットしています。
    continue することで、multiboot、physboot の実行、カーネルのロード、_start を実行し、lk_main()で停止します

わかったこと

  • GCE(e2-standard-8)は自宅に比べて、リポジトリ更新で 11 倍、ビルド時間で 6 倍、早い
  • fuchsia のリポジトリ+成果物のサイズは、46GB〜78GB(ただし、PRODUCT.BOARD 依存)
    システム領域と合わせても、永続ストレージは 100GB あれば足りる
  • 費用は 652 円/月 程度と予想
    週 3 日(月 12 日)、5 時間/日(最小構成 3 時間、ビルド構成 2 時間)と仮定する。
    • e2-standard-8:318 円
      • e2-standard-4 の場合:159 円
    • 永続ディスク:308 円
    • 外部 IP アドレス:26 円

おわりに

GCE を使って、ローカルリポジトリ更新、ビルド時間が遅い問題を解決できました。
GCE のビルド時間は想像以上に高速でした。また、リモートでのソースコード編集・デバッグもまったく問題なかったです。
この用途では、自宅に高速なマシンは不要と言えそうです。

自宅で組み込み機器のデバッグをするさいには、GCE から成果物をダウンロードする必要があります。
「GCE → 自宅」向きの通信は課金対象なので、これも検討が必要です。

費用についてはe2-standard-8と、安価(1.1 円/時)なe2-meduimを組み合わせることで、さらに安くできそうです。
(ローカルリポジトリ更新後の 1 回のみ強力なe2-standard-8でビルドし、ソースコード編集後は安価なe2-meduimでビルドするなど)

付録

試行錯誤中に気づいたことです。

非プリエンプティブル → プリエンプティブルは可能だが、逆は不可能

https://cloud.google.com/sdk/gcloud/reference/compute/instances/set-scheduling

  • 非プリエンプティブル → プリエンプティブル

    gcloud compute instances set-scheduling instance-test \
    --preemptible \
    --no-restart-on-failure \
    --maintenance-policy=TERMINATE
    成功
    
  • プリエンプティブル → 非プリエンプティブル

    gcloud compute instances set-scheduling instance-test \
    --restart-on-failure \
    --maintenance-policy=MIGRATE
    失敗
    

最小構成は無料枠(Always Free 枠)なので、割安になるが動作制限のかかるプリエンプティブルにはしない予定でした。
しかし、一度プリエンプティブルにすると、非プリエンプティブルに変更できなくなることから、最小構成時もプリエンプティブルにしました。

永続ディスクサイズ変更

https://cloud.google.com/sdk/gcloud/reference/compute/disks/resize?hl=ja

ビルド成果物が確保したサイズで収まらないときに、ディスクサイズを大きくするために利用しました。

gcloud compute disks resize instance-test --size=100GB

ブート用の永続ディスクの名前instance-testは、インスタンス名と同じ。
上記は 100GB にリサイズする例です。
検討時に、60GB→80GB→100GB と増やしていきました。

config-ssh は 対象インスタンスを可動させた状態で実行する

  • インスタンス停止中はエラー

    # インスタンス停止中
    $ gcloud compute config-ssh
    WARNING: No host aliases were added to your SSH configs because you do not have any running instances. Try running this command again after running some instances.
    
  • インスタンス起動中は成功

    $ gcloud compute instances start instance-test
    $ gcloud compute config-ssh
    You should now be able to use ssh/scp with your instances.
    For example, try running:
    
      $ ssh instance-test.us-west1-b.{プロジェクト名}
    

scripts/gce/

リポジトリ中に、GCE で fuchsia を動作させるスクリプトを発見しました。

https://cs.opensource.google/fuchsia/fuchsia/+/main:scripts/gce/;bpv=1

cd $FUCHSIA_ROOT
fx set core.x64 --release
fx build                      # ... 1
fx gce create-fuchsia-image   # ... 2
fx gce create-instance        # ... 3
sleep 60
fx gce serial                 # ... 4
fx gce delete-instance        # ... 5
  1. ローカル環境でビルドを行う
  2. GCE で動作させる fuchsia のイメージファイルを作成
  3. VM を起動し fuchsia を動作
  4. (仮想的な)シリアル通信で接続する
  5. VM を削除

Discussion