見出し画像

XcodeCloudの基本と社内導入に向けて

こんにちは、光るグラフィックボードです。ナビタイムジャパンでiOSのアプリケーション開発を担当しています。
本記事では、Apple公式のCIサービスであるXcodeCloudの概要と、社内導入に向けての経緯などについてお話させていただきます。

CIってそもそも何?

本題に入る前に、CIについて簡単に…
CIとはContinuous Integrationの略語で、継続的インテグレーションとも言われるものです。
CD(Continuous Delivery)とセットでCI/CDと扱われる事が多いです。これらの2つの違いについてここでは触れませんが、アプリケーション開発におけるCI/CDの役割について一言で表現するなら「リリースやテストの自動化」になります。

About continuous integration and delivery with Xcode Cloud 「Overview」

なんのためにCIを使うのか

CIを利用することでどんな良いことがあるのか、代表的なものをあげると…

  • 作業コストの削減

  • 開発・運用の安定化

  • 各種作業の属人化・専門化の防止

  • ヒューマンエラーの防止

などなど、チームでアプリケーション開発を進める上で非常に恩恵が多く、欠かせないものであることがわかります。

アプリケーション開発向けのCIサービスには多くの種類があります。
代表的なものではBitrise, CircleCi, GitHub Actionsなどがあり、多くのエンジニアの方々が利用しているかと思います。

ナビタイムジャパンのiOSのCI環境について

元々当社では、セキュリティ上の観点から課題があったため外部CIサービスの利用を見送っていました。そのため社内に専用のMacを設け、Jenkinsを構築してCIとして利用するという方法をとっていました。

この環境では、非常に多くのプロジェクトのワークフローが混在し、同時実行される運用となっています。結果として、同時実行中のワークフロー同士の処理が干渉するなど、環境が不安定になることもしばしばありました。
また、入っているプラグインも把握・管理されていないもが多く、Jenkins本体のバージョンアップも困難な状況でした。
そのため、問題解決やメンテナンスのための運用コストが非常に高く、何かしら新しい環境が必要だと感じていました。

そのような状況だったため、これらの問題を解決し、運用コストを下げつつCIを安定化させる方法を切望していました。

具体的には以下のように、課題を解決できる環境・運用方法を探していました。

  • ビルド環境が独立していること

  • 安定して運用できること

  • 運用コストが高くないこと

  • 学習コストが高くないこと

  • 将来的な運用が可能なこと

各プロジェクト用にそれぞれMacを用意するというパワフルなプランもあったのですが、それぞれのプロジェクトでJenkinsやMacの保守・運用を行うと非常にコストが高くなるほか、会社全体としてのサポートや管理が難しくなることもあり見送りとなりました。

XcodeCloudの登場

そのような中、2021年6月に開催されたWWDC2021で、XcodeCloudがついに発表され、同時にβ版のサービス開始の案内も行われました。Apple公式のCIサービスということで、注目したエンジニアの方も多くいたのではないかと思います。

β版の情報公開後、サービスの概要などを確認した結果、XcodeCloudを利用することで現在抱えているいくつかの問題を解決できるかもしれないと考えました。
そうして、当社のセキュリティ担当と協議した結果、社内で利用が可能という判断になりました。
とはいえ、社内の全てのプロジェクトが現在の運用からXcodeCloudへ、すぐに移行できるわけではありません。上記に挙げた特徴や環境を踏まえて実際に社内で利用・運用が可能なのか、技術的な確認・保証が必要になります。そうして、いくつかのプロジェクトに協力してもらいながら調査を兼ねて試験的に利用を開始しました。

翌年のWWDC2022のタイミングでプランや料金に関しても詳細な情報が公開され、XcodeCloudは正式なサービスとしてリリースされました。この時点では懸念していたいくつかの不具合も修正され、サービスの社内利用も現実的に視野に入り始めました。

XcodeCloudについて

XcodeCloudはどのようなCIサービスなのか、使用感も含めて簡単にまとめました。

XcodeCloudを触った感想としては、AppleらしいシンプルなIFとなっており、カスタマイズ性は高いとは言えないものの、CIサービスにおいても後発なだけあってCIに必要な要点は抑えられているサービスといった印象でした。Apple公式だからこその有用な特徴も備えています。
もちろん、いい所だけではなく運用や構成によっては検討・対応が必要になる点もあります。

良い点

■シンプルで簡単
設定が簡潔で非常にシンプルです。「CI = ごちゃごちゃして難しい」というイメージを持つ人も多いかと思いますが、構成によってはGUI上で指定された設定を埋めていくだけでワークフローを完成させることも可能です。

AppStoreConnect:ワークフロー設定画面の例

■証明書の紐付けが自動
AppStoreConnectに組み込まれたサービスであるため、証明書の紐付けも自動で行われ、設定や証明書ファイルのアップロードなどは一切不要です。
CIを運用した事があれば、一度は証明書関連でハマった経験があるかと思います。これだけでも使う価値があると思う人もいるのではないでしょうか。

■Testflightへのデプロイが楽
Testflightへのデプロイも、外部テスト/内部テストや、Testerを任意に設定するだけで行うことが可能です。

AppStoreConnect:ワークフロー設定画面の例

■Xcode / AppStoreConnectどちらからでも設定・実行が可能
Xcode / AppStoreConnectで設定状態や実行状況が同期されていて、常にどちらからでも操作・確認が可能です。ログに関してもXcode上から確認できるため、ビルドエラーなどに関しては普段のデバッグと同じような感覚で確認することができます。

惜しい点、仕方がない点

■ビルドキャッシュが使いにくい
XcodeCloudではキャッシュ機能はあるものの、その対象はDerivedData配下のみとなっていて、任意のパスやフォルダなどの指定はできません。
具体的にはXcodeのビルド時キャッシュと、SwiftPackageManagerで取得・ビルドされたライブラリが対象となります。
そのため、CarthageやCocoaPodsの成果物などをキャッシュにして利用することができません。

XcodeCloudでは、プロジェクトに設定されているSwiftPackageManagerの依存関係の解決は自動で行われます。
ライブラリの取得をSwiftPackageManagerへまとめることで、スクリプトで処理を行う部分が減って運用がシンプルになるだけでなく、XcodeCloudの実行時間も改善させることができます。

■カスタマイズ性が低い
全ての依存関係をSwiftPackageManagerにまとめ、Testflightへのデプロイのみを行うような、XcodeCloudが公式にサポートしている運用方法を前提とした設定は非常に扱いやすくできています。
反面、それ以外の作業に関しては、自前でshell scriptを用意する必要があります。

■設定ファイルがない
作成したXcodeCloudのワークフローにはAppStoreConnect内で管理されているらしく、YAMLファイルなど、何らかのファイルへのエクスポートができません。
幸い、ワークフローの複製は可能で、現状GUI上での設定は非常にシンプルなためそこまで困るシーンはなさそうですが、今後のアップデートで設定項目が増える事があればそういったニーズも高まりそうです。

環境について

環境に関しては、2023年2月時点は全てIntelCPUの環境となっているようでした。詳細なスペックやメモリなどに関しては、GUI上から確認する場所はなかったものの、実行時にコマンドを叩くことで取得することができました。

Software:
System Software Overview:
System Version: macOS 13.1 (22C65)
Kernel Version: Darwin 22.2.0
Boot Volume: Macintosh HD
Boot Mode: Normal
User Name: local (local)
Secure Virtual Memory: Enabled
System Integrity Protection: Enabled
Time since boot: 6 minutes, 56 seconds

Hardware:
Hardware Overview:
Model Name: Mac
Model Identifier: MacVM1,1
Processor Name: Unknown
Processor Speed: 2 GHz
Number of Processors: 8
Total Number of Cores: 8
L2 Cache (per Processor): 4 MB
L3 Cache (per Processor): 16 MB
Memory: 16 GB
System Firmware Version: AVM11.88Z.0003.D00.2110230656
OS Loader Version: 564.40.4~55
SMC Version (system): 1.13f3

料金などについて

料金プランに関しては非常にシンプルなものとなっていて、利用時間に応じた4段階の設定があるのみです。ストレージ容量の制限もなく、利用するOSなども料金に関わらないため、安心して使うことができそうです。
2023年の12月までの間は、25Hまで無料で利用できるので是非試してみてください。

Xcode Cloud 「サブスクリプションが利用可能に」

ワークフローの構成

XcodeCloudではワークフローを作成する際、主に専用のGUIを使ってAppStoreConnect / Xcodeから設定を行っていきます。ビルド対象のprojectファイルや、環境変数、開始条件の設定などはここで行います。また、環境構築や成果物の処理のため特定のタイミングで任意のshell scriptを実行することが可能です。
これらの設定と、shell scriptを組み合わせてワークフローを作っていくことになります。

Writing custom build scripts 「Create a custom build script」

XcodeCloudのワークフローは8つのブロックに分かれています。
この内、緑色の「Post-clone」「PreXcodebuild」「Post-XcodeBuild」の3箇所で指定されたパスのshファイルを配置しておくことで、任意のshell scriptを実行することが可能です。他の青色の箇所は、GUI上から設定を行うことで自動で処理が進む部分になります。

  1. 🟦 Create temporary environment

    • ワークフロー実行のための、一時的な環境が用意されます。

    • 環境は、HomeBrewのみがinstallされた状態が用意されます。

  2. 🟦 Clone Git repository

    • ビルド対象のリポジトリのクローンを行います。

    • Git LFSで大きなサイズのファイルを扱っている場合でも、ここで一緒に取得されます。

  3. 🟩 Post-clone(ci_post_clone.sh)

    • クローン完了後のタイミングで、任意のshell scriptの実行が可能です。

    • ここでは、ビルド前の環境構築やライブラリのビルドなどを行います。HomeBrewのみしか用意されていないため、諸々必要なもののinstallも必要になります。

  4. 🟦 Resolve dependencies(ci_pre_xcodebuild.sh)

    • SwiftPackageManagerの依存性の解決が行われます

  5. 🟩 Pre-XcodeBuild

    • ビルド直前のタイミングで、任意のshell scriptの実行が可能です。

    • ここでは、追加の依存関係のコンパイルなどが可能です。

  6. 🟦 Run xcodebuild command

    • 設定されているアクションの実行が行われます。

      • Archiveが指定されていた場合、ipaの出力までここで行われます。

      • 証明書の紐付けなども自動で行われます。

  7. 🟩 Post-Xcodebuild(ci_post_xcodebuild.sh)

    • ビルド完了後のタイミングで、任意のshell scriptの実行が可能です。

    • この時点で成果物が揃っているため、外部へアップロードする場合はここで行います。

  8. 🟦 Save artifacts

    • 成果物の保存が行われ、ポストアクションで指定された内容が実行されます。

    • 成果物は30日間保存されます。

実際にワークフローを作成してみて

当社の多くのプロジェクトでは、社内ライブラリだけでなくサードパーティ製のライブラリなども利用している他、チームによる開発効率を上げるためのためBundlerや各種パッケージを利用しているため、shell scriptによる追加の環境構築が必要でした。

XcodeCloudでワークフローを作るにあたって、特別カスタマイズする箇所があるとすれば、ci_post_clone.shとci_post_xcodebuild.shの2箇所になることが多くなるかと思います。

一例として、試験的に運用を行ったプロジェクトのci_post_clone.sh(クローン後の環境構築)の内容は以下のようになりました。

# 社内ライブラリを取得するための諸々の設定
xxxxx.....
xxxxx.....

# AWS CLI / Romeなどに必要
xcode-select --install

# setup Rome
brew tap tmspzz/tap https://github.com/tmspzz/homebrew-tap.git
brew install tmspzz/homebrew-tap/rome

# setup Bundler
# そのままgem installを行うと書き込み権限がないため、Gemのインストールパスを変更する
export GEM_HOME=$CI_PROJECT_FILE_PATH/.gem
export PATH=$GEM_HOME/bin:$PATH
gem install bundler
bundle config set path bundler/ --local
bundle install
bundle exec fastlane add_plugin rome

# setup Carthage
brew install carthage

# setup AWS CLI
brew install awscli

# pod install
bundle exec pod install --no-repo-update

# run rome(CarthageのキャッシュをS3経由で取得)
bundle update fastlane
bundle exec fastlane install_library_rome

# run carthage
sh ./carthage.sh bootstrap --platform iOS --cache-builds

当社では、アプリケーション開発で利用する社内の共通ライブラリをS3にデプロイし、プロジェクト側でそれらをCarthage経由で取得する方法が採用されています。
また、試験のためCocoaPodsで取得しているライブラリもSwiftPackageManagerへ移行させず、そのままの状態で実行可能かを確認しました。

結果、取得するライブラリが多いこともあり、このスクリプトだけで概ね30分前後の実行時間がかかりました。特に、初回のキャッシュのない状態からのpod installと、aws cliのインストールでそれぞれ10分ほどかかってしまっています。
今後、用意される環境がM1/M2になるなどすれば改善の可能性もありますが、やはり極力SwiftPackageManagerへ一本化したほうが良さそうです。

社内利用へ向けて

現在、XcodeCloudの社内利用へ向けてドキュメントの整備やサポート体制の整理を行っています。社内へ展開を行う際、XcodeCloudは独自のルールやフォーマットといったものが少ないため、利用時の学習コストはそこまで高くなく、属人化もしにくい利点が生きてくると思います。

ただ、ipaさえ作成できれば良いというわけではなく、それぞれのプロジェクトでこれまでの運用に合わせた移行のサポートが必要になりそうです。そういったノウハウも都度ドキュメント化していきつつ、将来的にはサポートがいらない状態を目指していきたいですね。

終わりに

以上、XcodeCloudの概要と導入に向けた取り組みについて書いてみました。
どんなサービスなのか気になっていた方の参考になれば幸いです。