BuildなどSaaS形式でユーザー側で保守する必要のないCIが盛り上がっているが、まだまだJenkinsのオンプレ運用も需要も高い。Unityアプリの場合、iOSはMacでのビルドが必須だし、iOSをMacでやってるんだからAndroidもついでにMacでビルドしたほうがメンテコストが安い。大きいアセット素材(画像や動画)をビルドするマシンまで転送するのもいろいろ工夫が必要であり、自分たちの需要に合わせたインフラを作る必要がある。なるとSaaS型のCIは需要に耐えられるか不安でなかなかすべて置き換えるのは難しそうだ。最近はポストJenkinsとしてdrone.ioが登場しているがUnityがdocker上で微妙1なのでiOSビルドの需要に耐えない。結果、オンプレMacにJenkinsを建てることになる。やっかいなことに、そのJenkinsは設定が管理されてないことが多く、Jenkinsが吹っ飛ぶと開発が止まる。commitするなどしてバックアップをとり、安全性を確保するだろう。次に問題になってくるのは、設定の再構築方法がわからなくなることだ。Jenkinsは基本的にGUIでポチポチ設定をすることを前提にしているので設定に再現性が生まれにくい。CIは開発者にとってのインフラになるので1度1から再構築をするなんてことはできない。結果、長年積もった設定変更の積み重ねにより、秘伝のJenkinsが出来上がる。どの設定を変えるとどこに影響が生まれるのかはその設定をした管理者しかわからない。Jenkinsおじさんの完成だ。pocketsJenkinsおじさんの育て方https://slides.com/sakamoto_desu/jenkins_expertJenkinsおじさんの育て方Jenkins設定のコード化Jenkinsはこの問題に対し、解答を用意している。codeはyamlでJenkinsの設定を書き、GUIからワンボタンで再起動なしで変更を適用することができる。ユーザーアカウントやプラグインも記述可能で、サポートされていればプラグインの設定も管理可能だ。本来のJenkinsの設定自体は複数のxmlだが、1つのyamlになることで設定を一望できるし、変更すべき場所もわかりやすい。このyamlをgit管理することによってJenkinsが吹っ飛んでも初期状態から再構築できる。PipelineはJenkinsfileという名のgroovyでジョブの設定を書くことができる。ジョブに必要なパラメータや呼び出すべきbashスクリプトなどを記述できる。Pipelineに関しては、git連携が非常に便利だ。設定すれば、リモートのgitリポジトリに存在するJenkinsfileを実行時にフェッチして反映することができる。この機能のおかげで、複数人でgit管理されたジョブスクリプトを編集、管理することができる。Pipelineで間違いなく保守性は上げることができた。Jenkinsが吹っ飛んでも(多少の手間はかかるが)復元できるし、設定やコードはgit上で共同管理できる。かゆいところに手が届かない状況が存在する。codeでyamlに書くことで管理できると述べた。yamlで記述したプラグインがインストールされるのはyamlを適用した後である。いうことが起こるかというと、yamlにプラグインの設定を書き、その設定を適用しようとすると「プラグインが存在しない」と言われて適用できないのだ。プラグインをインストールするためにyamlを書いてるのにyamlを適用するためにプラグインが必要になるというデッドロックが発生する2。codeのインストールはyamlに書くことはできない。結局、自分はこの問題が解決できなかったので、プラグインの設定はyamlに書き、プラグインのリストとインストールは別の方法で管理している。3段階を踏む必要がある(まあ普段ジョブを作る頻度はそんなに高くないので良いのだが...)。この問題は、GitHubOrganizationFolderを使うことで解決できるのだが、こいつはこいつで厄介なのだ。Pipelineジョブ(後述)を自動で作成してくれます。https://www.kaizenprogrammer.com/entry/2017/03/20/130721つまり、ジョブ1つに対して、リポジトリ1つが対応することになる。管理する必要があるリモートリポジトリなどなるべくなら増やしたくはない。CIはジョブがたくさん必要なので1つのリモートリポジトリに複数のJenkinsfileを置いて運用するのが良い。するとOrganizationFolderは使えず、先程述べたジョブ設定が必要になる3。Oneというよりは自分に必要なPluginを選んで使う思想なのでPlugin間の連携ができなかったりするのはまあ仕方ない。ポータビリティも上げて、どこでも実行できるし、いつでも再構築&改修が楽にできる状態にしたい。garicchi/p-jenkinsdocker-composeでシュッっと立ち上げることができるし、1つのジョブを実行するだけでgithub上の設定やジョブを同期できるし、なんならs3へのバックアップ機能もあるので各々の需要に合わせて使ってほしい。upでシュッと立ち上がるのは便利だ。dockerさえ入っていればローカルマシンですら動くのでJenkinsをアップデートするのが怖い時も、すぐにローカルで動かして確認&改修ができる。イメージはjenkinsの公式イメージから引っ張ってきている。JenkinsAdminアカウントはjenkins.yamlに書くのでセットアップウィザードもスキップしている。「CASC_JENKINS_CONFIG」環境変数で示しているディレクトリにyamlをコピーしておけば適用してくれる。codeのyamlに変更があった場合、必要に応じてyaml設定をJenkinsに適用しなければならない。それを担当しているスクリプトが以下だ。garicchi/p-jenkins単純にスクリプトから相対パスにあるjenkins.yamlを$CASC_JENKINS_CONFIGにdiffをとってコピーしているだけだ。Pipelineのgit連携によって自動フェッチされるので、最新のjenkins.yamlを適用することができる。codeはコピーしただけでは設定を反映できない。CONFIGURATION」ボタンを手動で押さなければならない4。削除ジョブはGitHub上の特定のフォルダと同期することで追加と削除を行う。実行しているスクリプトは以下だ。garicchi/p-jenkins下記コードでリポジトリのjobsディレクトリとjenkins_home内のjobsディレクトリのdiffをとる。IS_UPDATE_JOB=truedoneもしdiffがあって、リポジトリのjobsディレクトリのほうが多ければ、jenkins-cliを用いて足りないジョブを作る。ジョブのconfig.xmlは自分で用意しなければならないのでテンプレートっぽいものを用意して使う。garicchi/p-jenkinsもしリポジトリのjobsディレクトリよりjenkins_homeのjobsディレクトリが多かったなら削除しなければならないので削除する。これもまたjenkins-cliで行うことができる。上記のインフラを整えることで、Jenkinsのジョブを追加したい時はリポジトリにJenkinsfileを置いてスクリプトを実行するだけでよくなる。プラグインの更新プラグインは上述のとおり、jenkins.yamlにはかかない。Jenkinsをdockerで構築すると、install-plugin.shというプラグインインストールのためのスクリプトが標準で用意されている。これを使用してリポジトリのplugin.txtに差分があればinstall-plugin.shを実行する。------"fiこれでプラグインを更新したい場合もgit上のplugin.txtを編集し、スクリプトを実行することで再起動なしで反映される。リストアjenkins.yamlに構築方法が書いてあるとはいえ、jenkins_homeのバックアップを取らないのは不安だ。jenkins_homeはtar圧縮してs3へとアップロードをする。\e[m"自己設定同期するJenkinsp-jenkinsでは上記までで紹介した機能はすべて自身のジョブとして実行することができる。ジョブを実行するだけでs3へとバックアップできるし、github上のjenkins設定と同期することができる。upしたばかりのときはupdate-configジョブしか無いのだが、update-configジョブを実行すると、以下のようにgithub上のジョブ設定と同期を行うことができる。持ったJenkinsの完成だ。おわりにJenkinsが保守できなくなるのを恐れて設定を同期する仕組みを作ってしまったがこの仕組みもまた保守されなくなる未来が見える気がする..やはり最初から設定はコードで書くことが可能で、ジョブスクリプトもgithubから取ってくるようなもので、オンプレでも動くようなCIがあれば今ならわりとすんなり天下を取れるかも知れない。linux版はpreview。