MyRefer Tech Blog

株式会社MyReferの技術チームブログです。

gitlab runnerをAmazon EC2スポットインスタンス+docker in dockerで実現する

はじめましてMyReferでエンジニアとして主にバックエンドとインフラを担当している籔下です。
MyReferのエンジニアチームにてtech blogを始めることにしました。
よろしくお願いします。

MyReferは国内初のリファラル採用活性化サービスとして2015年9月にリリースしており、元々パーソルキャリアという企業内の新規事業として立ち上がったサービスでしたが、2018年8月にパーソルキャリアからスピンアウトベンチャーとして法人化し、現在株式会社MyReferとして運営しています。

jp.techcrunch.com

ことの発端

企業の紹介は以上として、本記事の本題です。
MyReferではgitlab runnerを利用し、日々テストを回していたのですが、ある日急に動かなくなってしまいました。
理由はgitlab runnerを構築した担当者のアカウント権限をgitlab runner内の処理で利用しており、その担当者が退職したため権限を削除したのが原因でした。
さらにgitlab runnerはAWS EC2上で動いており、キーペアを共有してもらうことを忘れたまま退職されてしまいました。1
ということでこれを機に再構築したついでにMyReferで動かしているgitlab runnerの構成などについて紹介します。

構成

ざっくり構成は以下のようになってます。 f:id:myrefer:20190225103909p:plain

現在MyReferは国内のクラウドサービス上でサービスを展開していて、Gitlab等の社内ツールも同クラウド上にオンプレで構築して運用しています。
今後は利用しているインフラ全てAWSへ移行する計画があり、現在進行形で一部サービスから徐々に移行作業を実施しています。
今回紹介するGitlab runnerもEC2のスポットインスタンスを活用して構築しています。

今回構成したgitlab runnerのジョブの動作概要

以下のような流れでgitlab runnerのジョブが実行されます。

1. git pushする
2. gitlab runner起動
3. docker-machineでEC2のスポットインスタンスを起動
4. EC2上にdocker:dindでコンテナ立ち上げ
5. 立ち上がったコンテナ内でgitlab runnerのジョブが走る

以下今回設定したgitlab runner内のジョブの流れです。

1. git cloneでリポジトリを取得
2. docker hubからdocker imageを取得(事前に必要なOS/OSSがインストールされているものを登録しています)
3. 各種設定
4. テスト実行

各種設定

gitlab runner インストール

EC2インスタンス上にgitlab runnerを導入します。

$ curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh | bash

$ yum install gitlab-runner-11.3.1 -y

docker-machine インストール

同じくEC2インスタンス上にdocker-machineを導入します。

$ curl -L https://github.com/docker/machine/releases/download/v0.15.0/docker-machine-`uname -s`-`uname -m` >/tmp/docker-machine

$ chmod +x /tmp/docker-machine

$ cp /tmp/docker-machine /usr/local/bin/docker-machine

$ ln -s /usr/local/bin/docker-machine /usr/bin/docker-machine

gitlab runner 登録

gitlab runnerを登録します。
事前にgitlabのUIからRunner tokenを取得してください。
Runner tokenは「Setting」→「CI / CD」→「General pipelines settings」→「Runner token」から取得できます。
今回の構築では以下のようなコマンドで登録しました。

$ gitlab-runner register -n \
  --url="[gitlabのURL]" \
  --registration-token="[Runner token]" \
  --executor="docker+machine" \
  --limit=0 \
  --docker-tlsverify=false \
  --docker-image="docker:18.03.1-ce" \
  --docker-privileged=true \
  --docker-disable-cache=false \
  --docker-volumes="/cache" \
  --docker-shm-size=0 \
  --cache-type="s3" \
  --cache-s3-server-address="s3-ap-northeast-1.amazonaws.com" \
  --cache-s3-access-key="[アクセスキー]" \
  --cache-s3-secret-key="[シークレットキー]" \
  --cache-s3-bucket-name="[s3バケット名]" \
  --cache-s3-insecure=false \
  --machine-idle-nodes=0 \
  --machine-idle-time=600 \
  --machine-machine-driver="amazonec2" \
  --machine-machine-name="runner-%s" \
  --machine-machine-options="amazonec2-instance-type=m4.large" \
  --machine-machine-options="amazonec2-region=ap-northeast-1" \
  --machine-machine-options="amazonec2-vpc-id=[vpcのID]" \
  --machine-machine-options="amazonec2-subnet-id=[subnetのID]" \
  --machine-machine-options="amazonec2-private-address-only=0" \
  --machine-machine-options="amazonec2-request-spot-instance=true" \
  --machine-machine-options="amazonec2-spot-price=0.04" \
  --machine-machine-options="amazonec2-security-group=[セキュリティグループ名]" \
  --machine-machine-options="amazonec2-tags=environment,runner-public" \
  --machine-machine-options="amazonec2-monitoring=0" \
  --machine-machine-options="amazonec2-root-size=16" \
  --machine-off-peak-timezone="Asia/Tokyo" \
  --machine-off-peak-idle-count=0 \
  --machine-off-peak-idle-time=60 \
  --machine-off-peak-periods="* * 0-9,17-23 * * mon-fri *" \
  --machine-off-peak-periods="* * * * * sat,sun *"

成功した場合はGitlabの「Setting」→「CI / CD」→「Runners settings」→「Runners activated for this project」で確認できます。

gitlab runnerのジョブ設定

実際にgitlab runnerで実施するジョブは.gitlab-ci.ymlで設定します。 このファイルはリポジトリのルートディレクトリに配置しておきます。

.gitlab-ci.yml(一部抜粋)

image: docker:latest

variables:
  DOCKER_DRIVER: overlay2
  GIT_STRATEGY: none

services:
  - docker:dind

before_script:
  - hogehoge
  - fugafuga

lint:
  script:
    - do lint
    - etc

unittest:
  script:
    - do unittest
    - etc

imageは利用するdocker imageを指定します。
ここで何も指定しない場合は、gitlab-runner registerコマンドの--docker-imageオプションで指定しているイメージがデフォルトで選択されます。

variablesDOCKER_DRIVERはDockerコンテナが接続するストレージ・ドライバを指定します。

GIT_STRATEGYはgitリポジトリからcloneするかfetchするかを選択するオプションですが、noneを指定することでcloneもfetchも実施しないように振舞うことが出来ます。
今回構成の関係でgitlab runnerが動作しているEC2上にproxyを立ててそこを経由してcloneしたりした関係でbefore_scriptの中でcloneするような処理を呼んでいるため、noneを指定しています。

servicesdocker:dindを指定することで、docker in dockerの構成を取ることができます。
imagedocker:dindが対応していないカーネルを含むイメージファイルを指定してしまうと外側のコンテナの中の処理でこけてしまうので要注意です。
外側のコンテナで何かOSに依存するようなツールをまわすなどでなければdocker:latestで良いと思います。

before_scriptでは全体(上記でいうとlintとunittest)のジョブ実行前に実施する処理を定義します。
lintunittestは自由に(gitlab runnerの予約語除いて)定義が可能で、この単位でタスクが実行されます。実行したい内容はscriptで定義します。

以上で各種設定・構築は完了です。

(補足)
今回、既に開発環境で利用しているコンテナや、コンテナに対して開発環境設定するスクリプトを丸々流用した結果このような構成になっており一部強引な構成になっています。

最後に

今回の再構築は、まだエンジニア組織として諸々のルールが整備されていないことが発端となり、チームとしては旧パーソル時代から構成されていたものの、新会社としての組織づくりがまだまだ追いついていないことが露骨となってしまいました。
これらの組織づくりに加えて、MyReferはリリース以降徐々に利用いただいている企業様が増えており、それに伴い、インフラ整備が急務となっています。

また、インフラに限らず、フロントエンドやバックエンドの開発に関しても現在様々な技術的負債を抱えており、サービスのアップデートを行いながらもこれらの負債の解消に向け日々技術的なチャレンジを模索しています。
まだまだエンジニアが足りず、募集中ですのでご興味ある方はカジュアル面談からでもウェルカムなので下記よりご応募お待ちしております!

myrefer.co.jp


  1. 本来あるまじき状況ですが、社内でAWSを使うのは初ということもあり完全に個人で対応し、諸々ルールなども整備できていなかったというのが実際のところです。。