Go
GitLab
Ansible
GitLab-CI

gitlab-ciとansibleでgolangのデプロイ環境を作る

この記事は 富士通クラウドテクノロジーズ Advent Calendar 2017の17日目の記事です。

16日目は@clutterさんの「OK, Google. サーバーをスペックアップして」でした。
最近はやりの音声アシスタントをサーバのスペックアップに使うという発想面白くていいですね。

今回私はgitlab-ciとansibleでgolangのデプロイ環境を整えるお話をしたいと思います。

gitlab-ciとは

  • gitlab バージョン8以降にデフォルトで付いているCIツールです。
  • 特別な設定が不要で、リポジトリに.gitlab-ci.ymlを追加するだけで利用できます。

デプロイ環境の概要

image.png

  • gitlabにpushするとgitlab runnerが動き出します。
  • gitlab runnerがデプロイのため以下の動作をするように.gitlab-ciを作成します。
    1. ソースをビルドしgitlab上に保存
    2. ビルドでできたバイナリをvmへ転送
    3. AnsibleでVMにinit.dでサービス登録

ディレクトリ構成

gitlab.com/UminoShohei05/go-gitlabci
├── .gitlab-ci.yml
├── ansible
│   ├── inventories
│   └── roles
└── server/
  • .gitlab-ciはビルドからAnsibleの実行まで行うジョブが定義されています。
  • ansibleにはgoのバイナリをserviceとして登録するplay-bookが入っています。
  • serverにはHelloWorld!を返すだけのgo+echoでできたAPIが入っています。
  • OSはCentos6.7で試しています。

やってみる

まずはビルドジョブの作成

build_jobではserver/にあるソースをビルドし、できたバイナリをgitlab上に保存します。
ビルドジョブは以下のようになります。

.gitlab-ci.yml
build_job:
  image: golang:1.8
  stage: build
  script:
    - mkdir -p $GOPATH/src/gitlab.com/UminoShohei05/go-gitlabci/server
    - mv $CI_PROJECT_DIR/server/* $GOPATH/src/gitlab.com/UminoShohei05/go-gitlabci/server
    - cd $GOPATH/src/gitlab.com/UminoShohei05/go-gitlabci/server/
    - go get -u github.com/golang/dep/cmd/dep
    - dep ensure
    - go build -o test-api
    - cp test-api $CI_PROJECT_DIR
  artifacts:
    paths:
    - test-api

ジョブの内容を解説していきます。

image

使いたいdockerイメージを指定します。

script

実行したい命令を記述していきます。
今回はビルドするため一度GOPATHに移動し、ビルドでできた成果物をartifactsで使うために$CI_PROJECT_DIRにコピーしています。
$CI_PROJECT_DIRは、CI実行時にリポジトリがクローンされるディレクトリを表しています。
これはPredefined variablesというCI上で使うために元から定義されている変数で、詳細はこちらで確認することができます。

artifacts

ジョブの中で作成した成果物などをpathで指定してgitlab上に保存できます。
pathは$CI_PROJECT_DIRからの相対パスとなっています。
今回artifactsではpathのみ指定していますが、成果物の名前を変更したり、保存期間を指定することもできます。(何も指定しないと無限に残り続けます)
保存されたartifactsは画像のようにgitlab上からzip形式でダウンロードすることもできます。

Repository
artifacts1

CI/CD -> Pipeline
artifacts2

デプロイジョブの作成

deploy_jobではbuild_jobでできたバイナリのサーバへの転送と、Ansibleを使いバイナリをinit.dでサーバにサービス登録します。
デプロイジョブは以下のようになります。

.gitlab-ci.yml
deploy_job:
  image: webdevops/ansible
  stage: deploy
  before_script:
    - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client git -y )'
    - eval $(ssh-agent -s)
    - echo "$SSH_KEY" | tr -d '\r' | ssh-add - > /dev/null
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - ssh-keyscan $SERVER_IP  >> ~/.ssh/known_hosts
    - chmod 644 ~/.ssh/known_hosts
  script:
    - scp test-api root@$SERVER_IP:/opt/api/bin/release
    - cd ansible
    - ansible-playbook -i inventories/production.yaml deploy-api.yaml

before script

scriptを実行する前の準備を記述していきます。
今回のデプロイジョブではscpやAnsibleでSSH keyを使うためssh-agentへの鍵の登録を行い、known_hostsへホストの登録をしています。

また、SSH keyはリポジトリに入れることが憚られるため、gitlabのSecret variablesという機能を使い参照できるようにしています。
画像のようにgitlab上でKeyとValueを入れ登録すると、CI上で$Keyで参照することができます。
APIのアクセスキーやシークレットキーの登録などもこちらで行うと安全に使えます。
secret_variables

script

scpコマンドを見てもらうとわかるように、前のジョブでartifactsに保存したtest-apiをそのまま使っています。このように前のジョブの成果物を引き継ぎたい時にartifactsは便利です。
デプロイのジョブは最後にserviceにtest-apiを登録するansibleを流して終了です。
Ansibleの内容については今回使ったリポジトリを貼っておくので、こちらで確認をしてみてください。

動作確認

ちゃんとデプロイされているか一応動作確認をしてみます。
動作確認

さいごに

今回はデプロイをするだけの簡単なgitlab-ciですが、実際に仕事で使うにはbuildの前にlintやtestを追加するとより良いと思います。
また、今回は最低限の機能しか使っていませんが、指定されたブランチのpush時のみジョブを指定するonlyやジョブの障害時や失敗した場合に実行されるジョブを定義するwhenなど様々な機能があります。
一方で、gitlab-ciはpassphraseのついたssh keyが使えなかったり、パラメータを取るようなジョブの場合は向いていなかったりもします。
個人的にはgitlab-ciの機能面だけでなく、設定いらずで管理するツールも増えない部分にメリットを感じているので、gitlab-ciをこれからもっと使っていきたいなと思います。

あしたは@cooの「ニフクラの物理ネットワークを支える人たち」です。宜しくお願いします!