TL;DR (忙しい方はここだけ読んでください!)
GitLab RunnerをAWS上にデプロイするためのコードを書いたので、是非お使いください!
ご挨拶
開発推進グループのbbrfkr(ビビリフクロウ)こと、斎藤です。
2019年6月、iRidgeにインフラエンジニアとしてジョインしました。コーディングについては初心者で、至らない点も多々ありますが、本ブログ等を通してご指導ご鞭撻いただけると嬉しいです。
開発者としては日が浅い私ですが、開発を進める中でインフラ観点で効率化に寄与できる点はないかと考えました。その結果として、タイトルの通りGitLab Runnerを簡単にデプロイするためのコードを作成しました。今回はこの場を借りて、本コードについて紹介させていただきます。
モチベーション
弊社では開発にGitLab CommunityEditionを活用しており、もちろんCI/CDにはGitLab CIを使っています。GitLab CIにおいてビルド/デプロイジョブを実行するノードを「GitLab Runner」といいますが、私が担当しているプロジェクトで構築されたGitLab Runnerの調子が悪くなり、作り直すことにしました。
既存Runnerの構築時手順は残されていましたが、どうせなら作成手順をコード化し、他プロジェクトでも簡単に使いまわせるようにしたかったため、本コードを作成することにしました。さらにおまけで、CPU負荷に応じてRunnerをオートスケールする機能も付加することにしました。
使い方
準備
以下のURLでコードを公開しておりますので、まずはコードをgit clone
してください。
git clone
したら、pip
コマンドで依存パッケージをインストールします。なお、pythonバージョンは3.7でのみ動作確認しております。
$ pip install -r requirements.txt
次にリポジトリ直下で設定ファイルのサンプルをコピーします。
$ cp variables.yaml.sample variables.yaml
コピーした設定ファイルvariables.yaml
内の変数に値を入力していきます。各変数の意味は以下の通りです。
変数名 | 説明 |
---|---|
runner_region | RunnerをデプロイするAWSリージョン |
runner_vpc | RunnerをデプロイするVPC |
runner_allowed_ip | RunnerにSSHする際の接続許可ソースIP(CIDRで記載。なおパブリックIPが付与されるかはVPCの設定に依存しますので、プライベートサブネットでご利用の場合は、生成されたインスタンスにアクセス可能な踏み台サーバのIPを指定して下さい) |
runner_ami_id | Runnerに利用するAMI ID (Amazon Linux 2で動作確認済み。RedHat系OSのみ利用可能) |
runner_instance_type | Runnerのインスタンスタイプ |
runner_key_pair | Runnerのキーペア |
runner_desired_count | Runnerの初期数 |
runner_min_count | Runnerの最小数 |
runner_max_count | Runnerの最大数 |
runner_subnets | Runnerが所属するサブネットID(カンマ区切りで記載) |
runner_job_concurrency | Runnerが処理するジョブの並列数(0で無限) |
runner_tag_list | RunnerのGitLab上のタグリスト(カンマ区切りで記載) |
runner_register_token | Runnerを登録する際のトークン |
runner_gitlab_url | Runnerが接続するGitLabのURL |
runner_volume_size | Runnerに接続するEBSボリュームのサイズ(GB) |
runner_scalein_threshold | RunnerをスケールインするCPU使用率(%) |
runner_scaleout_threshold | RunnerをスケールアウトするCPU使用率(%) |
runner_scalein_cooldown | Runnerをスケールインしたあとのクールダウン期間(秒) |
runner_scaleout_cooldown | Runnerをスケールアウトしたあとのクールダウン期間(秒) |
また、本コードは内部的にboto3を使用しますので、対象AWSアカウントに対するクレデンシャルを環境変数やAWS CLIのaws configure
コマンドで予め与えておいてください。環境変数で与える場合はリポジトリ直下のファイル.env.sample
を以下のコマンドでコピーし、値を入力します。
$ cp .env.sample .env
その後、source
コマンドで環境変数を読み込ませます。
$ source .env
以上で、GitLab Runnerをデプロイする準備は完了です。
いざ、デプロイ!
依存パッケージと変数の準備が完了していれば、GitLab Runnerのデプロイは以下のコマンドを実行するだけです!
本コードではsceptreとtroposphereというツールを利用して、CloudFormationスタックを作成することでデプロイを実現しています。
$ sceptre --var-file ./variables.yaml launch runners
sceptreとtroposphereについて簡単に説明させていただきますと、sceptreはCloudFormationスタックをAWS CLIに代わって操作するラッパーで、troposphereはCloudFormationテンプレートをpythonコードから生成可能なライブラリです。この2つを組み合わせて利用すると、troposphereを用いて記述したpythonコードからsceptreにてCloudFormationスタックをシームレスに生成することができます。
単純にCloudFormationテンプレート単体で利用するよりも動的なリソース生成、条件に応じたデプロイリソースのスイッチングといった柔軟なスタック生成が行えるメリットがあります。例えば前者ですと、生成するインスタンス数をパラメータで外出しすることが、for文のループによって簡単に実現できます。後者ですと、if文を用いることで本番環境ではAutoScaling Groupを作成するが、開発環境ではAutoScaling Groupを作らずに、単一インスタンスのみ作成する、といったパラメータだけでは吸収しきれない環境差異も単一コードで表現可能です。
不要になったら…
本コードで作成した環境が不要になった際は、まずAutoScaling Groupの必要数を0にして、インスタンスが削除されたことを確認した後、以下のコマンドでクリーンアップすることができます。
$ sceptre --var-file ./variables.yaml delete runners
構成
本コードを実行すると、お使いのAWSアカウント上に、概ね以下のリソースが作成されます。(詳しい作成内容についてはソースコードをご覧ください)
オートスケーリンググループ
Runnerの実体を作成するオートスケーリンググループです。ユーザデータにGitLab RunnerのインストールとGitLabへの登録を行うスクリプトが仕込まれるため、本コードを実行するだけで、すぐに使用可能なGitLab Runnerがプロビジョニングされ、GitLabに自動的に登録されます。スケールアウト/スケールイン用のCloudWatchアラーム
オートスケーリンググループのCPU使用率を監視し、指定した閾値でアラートをあげるCloudWatchアラームです。このアラームのもと、GitLab Runnerはスケールアウトおよびスケールインします。登録解除用のLambda関数
GitLab Runnerがスケールインする際、GitLabから当該Runnerを登録解除する必要があります。こちらはその際に発火するLambda関数です。本関数はAWS Systems ManagerからRunCommand機能を呼び出して、GitLab Runnerに登録解除用のスクリプトを実行させます。
まとめ
GitLab RunnerをAWSにデプロイするときはEC2インスタンスを利用することが一般的かと思います。EC2インスタンスは仮想マシンですので、DockerコンテナやLambda関数と異なりステートフルに扱うことが容易で、運用が属人化しやすいリソースです。このため、GitLab Runnerのようにステートレスに扱うことのできるEC2インスタンスは、設定をコード化することも容易ですので、属人化を防ぐために可能な限りコードに落とし込んでおくことをおすすめします。
なお、Docker ExcecuterをRunnerに利用しなくても良い場合、Fargate上にRunnerをデプロイするという荒業も可能なようです。この場合、RunnerはShell Excecuterとして動作するため、Docker Excecuterのようにserviceの概念が使えません。このためDBに接続してのCIといったユースケースには活用できず利用シーンは限られてくるかと思いますが、要件を満たすシーンでは積極的に活用していきたいと思います。