クイック エンジニアリングブログ

株式会社クイック Web事業企画開発本部のエンジニアリングチームが運営する技術ブログです。

実践!GitLab CI/CDでのジョブ実行基盤改善

こんにちは。2019/8月入社SREチームのくぼっきーです。
今回は弊社のCI/CD環境周りをGitLab CI/CDでスマートに!という内容でお送りします。

前提

  • AWS × Jenkins × GitLabCE on EC2 な環境

課題

  1. 業務バッチとCI/CDジョブが混在していて止まってはいけないジョブがどれなのか担当者じゃないとわからない。(仮に把握してもその後ジョブはどんどん生まれていく
  2. ジョブ間の依存関係がよくわからない。(Jenkinsのpipelineは敷居高い、、、
  3. Jenkinsのジョブ定義をバージョン管理できていない。いつの間にか動かなくなったなんてこともざらにある。
  4. 影響範囲を限定するためプロジェクト毎に専用のJenkinsスレーブを立てているが、スレーブノード自体の管理&認知負荷が辛い。(ノード毎にタグ管理とかしたくない、そして分けても過負荷で止まる
  5. Gitリポジトリとの連携はServer hooks使い始めたけど、ここの作りこみをやっていくと辛い未来が待っている。

GitLab CI/CDの良いとこ

  • ☞ 1.の課題解消 止まるとサービス影響のある業務バッチ(Jenkins)と、止まっても直接的にサービス影響が生じないビルド/デプロイジョブ(GitLab CI/CD)とで棲み分けがされていくことが期待できる。
  • ☞ 2.の課題解消 ジョブとリポジトリが紐づく & 強制的にパイプライン表現になるので依存関係がわかりやすい。 f:id:aimstogeek:20200227172829p:plain
  • ☞ 3&5.の課題解消 Gitリポジトリとの連携が非常にスマートになる。特につくりこまなくても様々な開発フロー要件にフィットさせられる。
  • ☞ 4.の課題解消 ジョブ実行ノードをオートスケールアウト・インさせれるので一度作ってしまえば基本的に放置でおk。ジョブ実行基盤をプロジェクト毎に管理することから解放される。

  • Jenkinsリモートビルド機能を活用すれば既存Jenkinsジョブを流用しつつ柔軟に開発フローを組むのも簡単。
    参考:JenkinsでJobを起動して、終了まで待つシェルスクリプト
  • スポットインスタンス運用&営業時間内外でインスタンスのアイドリング数を変更出来たりとコスパ最強!!
  • その他まだまだ魅力満載\(^_^)/(機能多過ぎで触りきれない
    参考:GitLab機能一覧

構成概要

f:id:aimstogeek:20200228104843p:plain

  • GitLab:gitリポジトリサーバ。
  • GitLab Runnerベースマシン: ジョブ実行制御用ノード。リクエスト数に応じてスポットインスタンスでジョブ実行ノードをスケーリング。
  • GitLab Runnerジョブ実行ノード: 実際に処理が実行されるインスタンス

全体の流れ

※既にGitLabサーバが立っていることを前提としてます

  1. GitLab Runnerジョブ実行ノード用AMIを用意
  2. GitLab Runnerベースマシンセットアップ
  3. CI/CDジョブを実行してみる
    ※とりあえずCI/CD機能だけ試してみたい!って人はgitlab.comを利用すれば3のステップだけでお試しできます

Let's try

1. GitLab Runnerジョブ実行ノード用のAMIを用意

概要

ベースマシンがジョブ実行ノード起動時に使用するAMIを用意します。起動処理はdocker-machineで行われ、ジョブ実行ノードで自動的にdockerがセットアップされます。

動作要件

  • GitLab Runnerベースマシンから、22番ポートを使用してパスフレーズ無し公開鍵認証でsshログイン出来ること
  • GitLab Runnerベースマシンから2376番ポートで通信出来ること(docker socket通信で使用)

docker-machineがデフォルトだとubuntuユーザでsshログインしにいくため、今回の検証ではAMIストアパブリックイメージのUbuntu 19.04(ami-0b50bf6a426e13bf9)を利用しました。デフォルトのままであればSSH鍵も自動生成してくれるのでお手軽です。


2. GitLab Runnerベースマシンセットアップ

概要

下記動作要件を満たすコンテナを立ち上げ、GitLab Runnerの設定をします。

動作要件

  • GitLabサーバとSSH、HTTP or HTTPS通信が出来ること
  • dockerコマンドが動作すること
  • docker-machineコマンドが動作すること
  • gitlab-runnerコマンドが動作すること

セットアップ

  • 下記のdockerfileを作成し、コンテナを起動します。

Dockerfile

FROM gitlab/gitlab-runner:latest
RUN apt update -y && apt install -y \
    apt-transport-https \
    ca-certificates \
    curl \
    software-properties-common
RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - && \
    add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
RUN apt update -y && apt install docker-ce -y && \
    apt-get clean && rm -rf /var/lib/apt/lists/*

docker build -t gitlab-runner-base "Dockerfileを配置したディレクトリ"
docker run -d -t --name gitlab-runner-base -i gitlab-runner-base
  • 下記コマンドを環境に合わせパラメーター設定し、実行

各パラメーターはこちらを参考に設定してください https://docs.gitlab.com/ee/ci/runners/README.html
https://docs.gitlab.com/runner/configuration/runner_autoscale_aws/
https://docs.gitlab.com/runner/executors/docker_machine.html
http://docs.docker.jp/machine/drivers/aws.html
※docs.docker.jpのページは記載されてるオプションの一部でスペル間違いがありハマったので、正確なスペルはdocker-machineコマンドのhelpを確認することお勧めします

Command

docker exec -it gitlab-runner-base gitlab-runner register \
 --non-interactive \
 --name autoscaler \
 --limit 10 \
 --url https://gitlab.com/ \
 --registration-token XXXX \
 --executor docker+machine \
 --tag-list sample_runner \
 --custom_build_dir-enabled \
 --docker-image docker:stable \
 --docker-privileged \
 --docker-volumes "/var/run/docker.sock:/var/run/docker.sock" \
 --docker-volumes "/builds:/builds" \
 --docker-pull-policy "if-not-present" \
 --machine-max-builds 0 \
 --machine-idle-nodes 1 \
 --machine-idle-time 1800 \
 --machine-machine-driver amazonec2 \
 --machine-machine-name=runner-default-%s \
 --machine-machine-options "amazonec2-ami=ami-0b50bf6a426e13bf9" \
 --machine-machine-options "amazonec2-access-key=XXXX" \
 --machine-machine-options "amazonec2-secret-key=XXXX" \
 --machine-machine-options "amazonec2-instance-type=t2.micro" \
 --machine-machine-options "amazonec2-region=ap-northeast-1" \
 --machine-machine-options "amazonec2-root-size=16" \
 --machine-machine-options "amazonec2-security-group=gitlab-runner" \
 --machine-machine-options "amazonec2-ssh-user=ubuntu" \
 --machine-machine-options "amazonec2-tags=Name,gitlab-runner" \
 --machine-machine-options "amazonec2-vpc-id=vpc-XXXX" \
 --machine-machine-options "amazonec2-subnet-id=subnet-XXXX" \
 --machine-machine-options "amazonec2-zone=a" \
 --machine-machine-options "amazonec2-private-address-only" \
 --machine-machine-options "amazonec2-request-spot-instance" \
 --machine-machine-options "amazonec2-spot-price=" \
 --cache-type s3 \
 --cache-path gitlab-runner/cache \
 --cache-shared=true \
 --cache-s3-server-address s3.amazonaws.com \
 --cache-s3-access-key XXXX \
 --cache-s3-secret-key XXXX \
 --cache-s3-bucket-name "s3bucket_name" \
 --cache-s3-bucket-location ap-northeast-1 \
 --machine-off-peak-periods "* * * * * sat,sun *" \
 --machine-off-peak-periods "* * 0-9,18-23 * * mon-fri *" \
 --machine-off-peak-timezone Asia/Tokyo \
 --machine-off-peak-idle-count 0 \
 --machine-off-peak-idle-time 60

ログを確認し下記のように最終的に "Machine created" と出力されていればOK

Log

# docker logs -f gitlab-runner-base

~~~
~~~
Configuration loaded                                builds=0
WARNING: Failed to process runner                   builds=0 error=failed to update executor: no free machines that can process builds executor=docker+machine runner=39148577
Running pre-create checks...                        driver=amazonec2 name=runner-39148577-runner-default-1582858635-dce88b79 operation=create
Creating machine...                                 driver=amazonec2 name=runner-39148577-runner-default-1582858635-dce88b79 operation=create
(runner-39148577-runner-default-1582858635-dce88b79) Launching instance...  driver=amazonec2 name=runner-39148577-runner-default-1582858635-dce88b79 operation=create
(runner-39148577-runner-default-1582858635-dce88b79) Waiting for spot instance...  driver=amazonec2 name=runner-39148577-runner-default-1582858635-dce88b79 operation=create
WARNING: Failed to process runner                   builds=0 error=failed to update executor: no free machines that can process builds executor=docker+machine runner=39148577
WARNING: Failed to process runner                   builds=0 error=failed to update executor: no free machines that can process builds executor=docker+machine runner=39148577
(runner-39148577-runner-default-1582858635-dce88b79) Created spot instance request sir-3mdrb6sg  driver=amazonec2 name=runner-39148577-runner-default-1582858635-dce88b79 operation=create
WARNING: Failed to process runner                   builds=0 error=failed to update executor: no free machines that can process builds executor=docker+machine runner=39148577
WARNING: Failed to process runner                   builds=0 error=failed to update executor: no free machines that can process builds executor=docker+machine runner=39148577
WARNING: Failed to process runner                   builds=0 error=failed to update executor: no free machines that can process builds executor=docker+machine runner=39148577
WARNING: Failed to process runner                   builds=0 error=failed to update executor: no free machines that can process builds executor=docker+machine runner=39148577
WARNING: Failed to process runner                   builds=0 error=failed to update executor: no free machines that can process builds executor=docker+machine runner=39148577
Waiting for machine to be running, this may take a few minutes...  driver=amazonec2 name=runner-39148577-runner-default-1582858635-dce88b79 operation=create
Detecting operating system of created instance...   driver=amazonec2 name=runner-39148577-runner-default-1582858635-dce88b79 operation=create
Waiting for SSH to be available...                  driver=amazonec2 name=runner-39148577-runner-default-1582858635-dce88b79 operation=create
WARNING: Failed to process runner                   builds=0 error=failed to update executor: no free machines that can process builds executor=docker+machine runner=39148577
WARNING: Failed to process runner                   builds=0 error=failed to update executor: no free machines that can process builds executor=docker+machine runner=39148577
WARNING: Failed to process runner                   builds=0 error=failed to update executor: no free machines that can process builds executor=docker+machine runner=39148577
WARNING: Failed to process runner                   builds=0 error=failed to update executor: no free machines that can process builds executor=docker+machine runner=39148577
WARNING: Failed to process runner                   builds=0 error=failed to update executor: no free machines that can process builds executor=docker+machine runner=39148577
Detecting the provisioner...                        driver=amazonec2 name=runner-39148577-runner-default-1582858635-dce88b79 operation=create
WARNING: Failed to process runner                   builds=0 error=failed to update executor: no free machines that can process builds executor=docker+machine runner=39148577
Provisioning with ubuntu(systemd)...                driver=amazonec2 name=runner-39148577-runner-default-1582858635-dce88b79 operation=create
WARNING: Failed to process runner                   builds=0 error=failed to update executor: no free machines that can process builds executor=docker+machine runner=39148577
WARNING: Failed to process runner                   builds=0 error=failed to update executor: no free machines that can process builds executor=docker+machine runner=39148577
WARNING: Failed to process runner                   builds=0 error=failed to update executor: no free machines that can process builds executor=docker+machine runner=39148577
WARNING: Failed to process runner                   builds=0 error=failed to update executor: no free machines that can process builds executor=docker+machine runner=39148577
Installing Docker...                                driver=amazonec2 name=runner-39148577-runner-default-1582858635-dce88b79 operation=create
Copying certs to the local machine directory...     driver=amazonec2 name=runner-39148577-runner-default-1582858635-dce88b79 operation=create
Copying certs to the remote machine...              driver=amazonec2 name=runner-39148577-runner-default-1582858635-dce88b79 operation=create
WARNING: Failed to process runner                   builds=0 error=failed to update executor: no free machines that can process builds executor=docker+machine runner=39148577
Setting Docker configuration on the remote daemon...  driver=amazonec2 name=runner-39148577-runner-default-1582858635-dce88b79 operation=create
WARNING: Failed to process runner                   builds=0 error=failed to update executor: no free machines that can process builds executor=docker+machine runner=39148577
Checking connection to Docker...                    driver=amazonec2 name=runner-39148577-runner-default-1582858635-dce88b79 operation=create
WARNING: Failed to process runner                   builds=0 error=failed to update executor: no free machines that can process builds executor=docker+machine runner=39148577
Docker is up and running!                           driver=amazonec2 name=runner-39148577-runner-default-1582858635-dce88b79 operation=create
To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env runner-39148577-runner-default-1582858635-dce88b79  driver=amazonec2 name=runner-39148577-runner-default-1582858635-dce88b79 operation=create
Machine created                                     duration=1m0.152015073s name=runner-39148577-runner-default-1582858635-dce88b79 now=2020-02-28 02:58:15.978711696 +0000 UTC m=+86584.947166950 retries=0

  • ジョブ同時実行数を設定
    デフォルトではジョブ同時実行数が1となっているため、必要に応じて同時実行数を増やす
docker exec -it gitlab-runner-base bash
vi /etc/gitlab-runner/config.toml

先頭行にあるconcurrentの値を希望の数に設定

concurrent = xx
~~~

3. CI/CDジョブを実行してみる

参考:GitLab CI/CD Pipeline Configuration Reference

.gitlab-ci.ymlサンプル

stages:
  - codecheck
  - build_container
  - deploy_feature
  - e2etest
  - deploy_develop
  - deploy_production

variables:
    GIT_CLONE_PATH: ${CI_BUILDS_DIR}/${CI_PROJECT_NAME}/${CI_COMMIT_REF_SLUG}

static_code_analysis:
  stage: codecheck
  image: docker/compose:latest
  script:
    - echo static_code_analysis

code_test:
  stage: codecheck
  image: docker/compose:latest
  script:
    - echo code_test

build_container:
    stage: build_container
    image: docker:stable
    script:
      - echo build_container

deploy_feature:
    stage: deploy_feature
    image: docker:stable
    script:
      - echo deploy_feature
    environment:
      name: feature/${CI_COMMIT_REF_SLUG}
      url: https://${CI_COMMIT_REF_SLUG}.example.com

e2etest:
    stage: e2etest
    image: docker:stable
    script:
      - echo e2etest

deploy_develop:
    stage: deploy_develop
    image: docker:stable
    script:
      - echo deploy_develop
    only:
      - develop
    when: manual
    environment:
      name: develop
      url: https://dev-example.com

deploy_production:
    stage: deploy_production
    image: docker:stable
    script:
      - echo "deploy_production"
    only:
      - master
    when: manual
    environment:
      name: production
      url: https://prd-example.com

  • GitLabのPipelinesページでパイプラインが実行されてることを確認 f:id:aimstogeek:20200228123312p:plain

    f:id:aimstogeek:20200228132753p:plain

  • MR画面にパイプラインの実行結果が表示&レビュー用環境へのリンクが自動付与(Review Apps機能)されレビュー効率が大幅アップ\(^_^)/ f:id:aimstogeek:20200228174802p:plain

以上!

コメント

本記事上では一部機能にしか触れてませんが、その他機能含め感触としてGitLabとてもおすすめです!
やはりGitLabはリポジトリとCI/CDが同じサービス内で統合されているという点で利点が大きく、CI/CDでやりたいおおよそのことがスマートに実装出来る印象を持ちました。
またプロジェクト管理機能が充実しているので、この点も上手く使いこなせればよりスマートなDevOpsに近づくのではないかと思います。

世の中ではGitHubのほうが人気ですが、今回色々と触ってみたことで個人的にはGitLab推しになりました!ぜひ皆さんもGitLab使ってみてください。

Enjoy develop!



\\『真のユーザーファーストでマーケットを創造する』「ありがとう」で溢れる仲間を募集中です!! // 919.jp