GitLabでCIを動かす

はじめに

Gitと連携させCIを動かす事が増えて来た。GitHubと連携させTravis CIもいいし、Circle CIもいいだろう。GitLab CIのいいところは、自前で環境さえ準備できさえすれば非常に低コスト(IaaSの運用コストのみ)で動かす事ができるのが魅力だ

設定方法

前提条件

GitLabが動作できていること

本手順は、GitLab 10.3.7を前提としている

GitLabの設定

GitLabの左メニューで Settings -> CI/CDを選択する

General piplines settingsで
「Instance default」を選択し、Runner Tokenをひかえる

 

CIサーバ側の設定

GitLab CIサーバでGitLab runnerの設定をいれる

# sudo gitlab-runner register

Running in system-mode.

Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
https://git.sumito.jp/
Please enter the gitlab-ci token for this runner:
SJxxxxxxxxxxxx
Please enter the gitlab-ci description for this runner:
[server]: projectA
Please enter the gitlab-ci tags for this runner (comma separated):

Whether to lock the Runner to current project [true/false]:
[true]: true
Registering runner... succeeded runner=xxxxxxx
Please enter the executor: parallels, ssh, virtualbox, docker+machine, docker-ssh+machine, docker, docker-ssh, shell, kubernetes:
shell
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!

 

automatically reloaded!と表示されれば設定は問題ない

.gitlab-ci.ymlの設定

.gitlab-ci.yml 
variables:
AMI_ID_KUSANAGI: "ami-123456"
INSTANCE_NAME: "${CI_COMMIT_REF_NAME}_${CI_COMMIT_SHA}_${CI_PIPELINE_ID}"
TMP_ANSIBLE_DIR: "/tmp/gitlab/${CI_COMMIT_SHA}/${CI_PIPELINE_ID}"
DEPLOY_SITE: "wordpress"
SSH_KEY_NAME: "ssh-key"
INSTANCE_LOG: "/tmp/gitlab/${CI_COMMIT_SHA}/${CI_PIPELINE_ID}/run-instances.json"
ALLOCATE_ADDRESS_LOG: "/tmp/gitlab/${CI_COMMIT_SHA}/${CI_PIPELINE_ID}/allocate-address.json"

stages:
- initial
- build
- test
- deploy
- cleanup

########################################################
# STAGE:ANCHORS #
########################################################

# These are hidden jobs that contain the anchors
.server_group_1:
only: &kusanagi_servers
/^(wordpress).*$/

########################################################
# STAGE:INITIAL #
########################################################
make_tmp_directory:
stage: initial
script:
- mkdir -p ${TMP_ANSIBLE_DIR}

# デプロイテスト用インスタンスを作成@kusanagi& t2.medium
run_aws_server_kusanagi:
stage: build
only:
- *kusanagi_servers
script:
# インスタンスを作成
- aws ec2 run-instances --key-name ${SSH_KEY_NAME} --image-id ${AMI_ID_KUSANAGI} --count 1 --instance-type t2.medium --security-group-ids sg-12345678 --subnet-id subnet-12345678> ${INSTANCE_LOG}
# インスタンスにタグ付け
- instance_id=`jq -r .Instances[].InstanceId ${INSTANCE_LOG}`
- aws ec2 create-tags --resources $instance_id --tags Key=Name,Value=${INSTANCE_NAME}
# ElasticIPを払い出してタグ付け
- aws ec2 allocate-address --domain vpc > ${ALLOCATE_ADDRESS_LOG}
- allocation_id=`jq -r .AllocationId ${ALLOCATE_ADDRESS_LOG}`
- aws ec2 create-tags --resources $allocation_id --tags Key=Name,Value=${INSTANCE_NAME}
# インスタンスのステータスがrunningになるまで待つ
- i=1; while [ $i -le 120 ]; do sleep 3; if [ "\"running\"" = `aws ec2 describe-instances --instance ${instance_id} | jq '.Reservations[].Instances[].State.Name'` ]; then break; fi; i=$(expr $i + 1); done
# ElasticIPをインスタンスに紐付け
- aws ec2 associate-address --allocation-id ${allocation_id} --instance ${instance_id}

# Ansible Playbookをgit clone
setup_git:
stage: build
script:
- cd ${TMP_ANSIBLE_DIR}
- git clone git@git.sumito.jp:sumito/projectA.git
- cd projectA
- git checkout ${CI_COMMIT_REF_NAME}

########################################################
# STAGE:TEST #
########################################################
# 全てのAnsible Playbookの構文チェック
check_syntax_ansible:
stage: test
before_script:
- sed -e s%__ROLES_PATH__%${TMP_ANSIBLE_DIR}/projectA/Ansible/roles%g /home/gitlab-runner/.ansible_template.cfg > /home/gitlab-runner/.ansible.cfg
- cd ${TMP_ANSIBLE_DIR}/projectA/Ansible
script:
- ansible-playbook -i inventories/staging/hosts sites/staging/wordpress.yml --syntax-check

########################################################
# STAGE:DEPLOY #
########################################################
# Ansible Deployを実行
execute_ansible:
stage: deploy
only:
- *kusanagi_servers
before_script:
- elastic_ip=`jq -r .PublicIp ${ALLOCATE_ADDRESS_LOG}`
- cd ${TMP_ANSIBLE_DIR}/projectA/Ansible
- sed -si -e s/__IP__/${elastic_ip}/g -e s%__KEY__%/home/gitlab-runner/.ssh/${SSH_KEY_NAME}%g inventories/staging/hosts
- sleep 20
script:
- ansible-playbook -i inventories/staging/hosts sites/staging/${DEPLOY_SITE}.yml -u sumito --limit ${DEPLOY_SITE} --vault-password-file=/home/gitlab-runner/.vault_password

########################################################
# STAGE:CLEANUP #
########################################################
# Deployテストしたサーバリソースを削除@on_success
remove_aws_server_success:
stage: cleanup
only:
- *kusanagi_servers
before_script:
- instance_id=`jq -r .Instances[].InstanceId ${INSTANCE_LOG}`
script:
- sh /home/gitlab-runner/bin/aws/terminate-instance.sh $instance_id
after_script:
- rm -rf ${TMP_ANSIBLE_DIR}

# Deployテストしたサーバリソースを削除@on_failure
remove_aws_server_manual:
stage: cleanup
only:
- *kusanagi_servers
before_script:
- instance_id=`jq -r .Instances[].InstanceId ${INSTANCE_LOG}`
script:
- sh /home/gitlab-runner/bin/aws/terminate-instance.sh $instance_id
after_script:
- rm -rf ${TMP_ANSIBLE_DIR}
when: manual

どのように動くか

今回実施したPipelineは

“`
stages:
– initial
– build
– test
– deploy
– cleanup
“`

の順番で処理が行われるよう骨格を作った。

AWSのインスタンスをたちあげ、環境をセットアップし、ansibleを流す。最後にはテストで使ったイメージを削除するPipeline
gitにpushする度にCIが動くようになり、品質が担保できるようになった。