15
15

More than 3 years have passed since last update.

GitLab CIの基本的な流れ

Last updated at Posted at 2020-02-27

GitLab CI

GitLabから他のツールに連携して、ビルド、テスト、デプロイなどのCI連携ができる機能です。
使ってみると意外と色んなことが出来て面白そうなので、作り方をメモしておきます。

今回の構成と動作の流れ

バージョンなど

OS...Debian 9
GitLab...12.6
GitLab Runner...12.6
Ansible...2.10

流れ

  • Debian_1にDockerがインストールされていて、GitLabがコンテナで動作している。ここにレポジトリがあり、ソースが保存される。
  • 別のDebian_2にGitLab Runner(後述)とAnsibleがインストールされている。
  • Ansibleはさらに別のDebian_3を構築する。

gitlab.png

  1. pushやmergeなどのタイミングでGitLab本体がGitLab runnerに通知を送る
  2. Runnerは実行条件に合致していたら動作を開始する
  3. Runnerはまずgit cloneコマンドでレポジトリの内容をローカルにコピーして、そのレポジトリにcdする
  4. Runnerはそのノード上でansible-playbookコマンドを実行する
  5. Ansibleは普通に実行した時と同じようにdebian_3を構築する
  • 2のところの実行条件と、4で実行するコマンドはジョブの定義として作ってあげる必要があります。
  • また、5のところでAnsibleがちゃんとDebian_3を構築できるようにinventryを設定してあげる必要があります。 環境変数とかを使ってうまくやってください。

GitLab Runnerのセットアップ

上の図でDebian_2にあるGitLab Runnerをインストールします。

Runnerの種類

GitLab Runnerには大きくShared RunnerとSpecific Runnerがあります。
自分もよくわかってないので、詳しくはここを見てください。

Shared Runner

複数のプロジェクトで共通して利用できるRunner。
いつどれが使われるかはRunnerとCIジョブに付けられたタグで決まります。

Specific Runner

特定のプロジェクトでのみ利用されるRunner

Runnnerのインストール

GitLabの公式サイトから.debのバイナリを落としてくることができます。
Debian以外にもRHEL, Windows, Mac, FreeBSDなど複数に対応します。

これだけでインストールが完了します。

root@debian:~# dpkg -i gitlab-runner_amd64.deb

Runnerの初期設定

Runner側でコマンドをいくつか打つことで、GitLabにRunnerとして登録することができます。

root@debian:~# gitlab-runner register
Runtime platform                                    arch=amd64 os=linux pid=4496 revision=1b659122 version=12.8.0
Running in system-mode.

Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
http://10.91.77.8/ #GitLabサーバーのURLを入力
Please enter the gitlab-ci token for this runner:
dx5bFN4PJQ9XNUj_Vxbf #GitLabのadmin画面から取得できるトークンを入力
Please enter the gitlab-ci description for this runner:
[debian]: Ansible runner #このRunnerの説明を入力
Please enter the gitlab-ci tags for this runner (comma separated):
ansible #コンマ区切りでタグを入力
Registering runner... succeeded                     runner=dx5bFN4P
Please enter the executor: docker+machine, docker-ssh+machine, kubernetes, docker, docker-ssh, shell, virtualbox, custom, parallels, ssh:
shell #ジョブの実行方法を入力
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!

ジョブの実行方法はローカルでシェルを実行する、SSHでリモートを操作する、Dockerコンテナを立ち上げるなど複数から選べます。

.gitlab-ci.ymlの作成

環境が完成したら実際にCIを実行する定義.gitlab-ci.ymlを作ります。
このファイルはレポジトリのルートに置いておき、他のソースと同じようにバージョン管理されます。

今回はレポジトリに登録されたAnsible playbookを自動実行するように以下のようなYAMLを書きました。
詳細な文法などはGitLabの公式サイトを見てください。

.gitlab-ci.yml
# ステージ定義
stages:
  - test
  - deploy
  - result

# Pushするたびに文法チェックをする
sanity_check:
  stage: test
  script:
    - "ansible-playbook site.yml --syntax-check"
  only:
    - push
  tags:
    - ansible

# MRを作成したらDRY RUNで実行し、エラーにならないかを確認
run_playbook_dry:
  stage: test
  script:
    - ansible-playbook -i ansible_hosts.ini site.yml --check
  only:
    - merge_requests
  tags:
    - ansible

# develブランチにマージされたタイミングで自動デプロイ
run_playbook:
  stage: deploy
  script:
    - ansible-playbook -i ansible_hosts.ini site.yml
  only:
    - devel
  tags:
    - ansible

# ジョブが失敗したらMRにコメントを残す
send_failure_message:
  stage: result
  script:
    - 'MR_IID=$(curl --request GET --header "Private-Token: $API_PRIVATE_TOKEN" "http://10.91.77.8/api/v4/projects/$CI_PROJECT_ID/repository/commits/$CI_COMMIT_SHA/merge_requests" --insecure | jq --raw-output ".[0].iid")'
    - 'PROJECT_URL=$(curl --request GET --header "Private-Token: $API_PRIVATE_TOKEN" "http://10.91.77.8/api/v4/projects/$CI_PROJECT_ID" --insecure | jq --raw-output ".web_url")'
    - 'curl --request POST --header "Private-Token: $API_PRIVATE_TOKEN" --data "body=CIジョブに失敗しました。<br><a href=$PROJECT_URL/pipelines>パイプラインの詳細</a>から内容を確認してください。" http://10.91.77.8/api/v4/projects/$CI_PROJECT_ID/merge_requests/$MR_IID/notes --insecure'
  when: on_failure
  only:
    - merge_requests
  tags:
    - ansible

まずGitLabから対象のサーバーにレポジトリがgit cloneされます。
前述の通りクローンした後はそのディレクトリにcdされるので、scriptブロックに記載するコマンドはすべてレポジトリのルートから見える相対パスで書きます。

ジョブ

YAMLの一番上の階層に書いてあるもの(予約語以外のもの)がジョブで、この単位でスクリプトや実行条件を指定します。
上のスクリプトでいうとsanity_testrun_playbook_dryとかsend_failure_messageですね。

stages

順序立ててジョブを実行する必要がある場合、stagesを定義してジョブを所属させると順番を決めて実行できます。
同じstageで複数のジョブが定義されている場合はパラレルで実行されます。
上のでいうと、まずtestに所属するジョブが実行され、次にdeploy、終わったらresultが動きます。

only,except

ジョブごとに実行条件を指定できます。(exceptは除外条件)
pushはpushした時、merge_requestはMRを作成した時、ブランチ名を書くとそのブランチが更新された時です。
今回は実際にplaybookを動かすところをonly: develにしているので、develブランチの中身が更新された時だけPlaybookが適用されます。

tag

Runnerのタグを指定します。
ここに指定したRunnerでジョブが実行されます。

APIを使ってコメント投稿

ジョブsend_failure_messageではジョブに失敗した時という条件でMR画面にコメントを書き込んでいます。

scriptに書かれてる内容は普通にRunnerがインストールされているOS上でコマンドを打ってるのと同じなので、GitLab APIを使ってコメント残したり色々できます。
$API_PRIVATE_TOKENというのはgitlab-runnerのconfig.toml内で定義した環境変数的なやつです。変数の中身はGitLabのWeb画面から取ってきたbot用アカウントのプライベートトークンです。

実際に試す

Push

ローカルからpushすると、レポジトリの一番上に緑のチェックがつきます。
YAMLの文法に問題なかったということがわかります。

citest2.png

MR作成

MRを作成するとAnsibleのDRY RUNが走り、不具合が起きないかをチェックできます。
成功したらさっきと同じように緑のチェックが付きます。

citest.png

クリックしないと具体的に何のジョブが実行されたのかわからないのは難点ですね。

マージ

マージされると実際にPlaybookが実行され、サーバーに構成が反映されます。
上の画像の下にもう一つチェックが付きます。

参考:詰まったところ

よくわからんエラーで詰まったのでメモしておきます。
エラーはコピーしてなかったので後からネットで拾ってきました。

HTTP 403

Running with gitlab-ci-multi-runner 9.4.2 (6d06f2ec)
on host-vm (a126d8fa)
Using SSH executor...
Running on host-vm via host-vm...
Cloning repository...
Cloning into 'builds/a126d8fa/0/project/appName'...
fatal: unable to access 'https://gitlab-ci-token:xxxxxxxxxxxxxxxxxxxx@gitlab.my-company.com/project/appName.git/': The requested URL returned error: 403
ERROR: Job failed: Process exited with: 1. Reason was:  ()

→ユーザー権限の問題でした。権限振り直したら直りました。

git fetch-packのエラー

Running with gitlab-runner 11.9.2 (fa86510e)
  on stage-test yMEso5rx
Using SSH executor...
Running on d1.XXXXXX.com via d1.XXXXXX.com...
warning: templates not found builds/yMEso5rx/0/kudja/postel-deluxe.tmp/git-template
Reinitialized existing Git repository in /home/qapd/builds/yMEso5rx/0/XXXX/XXXXXX/.git/
Clean repository
Fetching changes with git depth set to 10...
fatal: remote origin already exists.
fatal: git fetch-pack: expected shallow list
ERROR: Job failed: Process exited with: 1. Reason was:  ()

→Runnerに入ってるGitのバージョンを上げたら直りました。

15
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
15