Edited at

GithubにGoで書いたDockerをTravisでCIする

あまり他人のソフト使うのが上手くないので、色々とハマりポイントがあったもので

Git履歴よりハマりポイントのおさらい


目指すもの

GithubにTravisCIを連携させることで、PushやPullRequestした時などに

自動的にTestやLintを行い、コードカバレッジを行う事ができる

大手の開発では一般的なスタイルではなかろうか?

個人的に勉強ついでに作っていた SlackBotのプログラムを使って勉強してみた

https://github.com/YukiMiyatake/GOSICK

SlackBotである。プラグインを入れる事で機能拡張を行う事ができる

とりあえず勉強用テストプロジェクトである

これからリファクタリングしたり interface化して、LintなりTestなり色々な改造を行う予定

(現在 gomodule導入テストのためプラグインもecho以外動かないはず)


dockerファイルを修正

今までDockerfileにて go buildして実行ファイルを起動させていたが

TravisやローカルでTestをまわすために

また、コード修正のたびに docker-compose buildしたくないので

Dockerでは何もせず、シェルスクリプトでビルド実行やテストを行うように変更した


Dockerファイル


dockerfile

WORKDIR /build

COPY src .
CMD ./build.sh
CMD ls

CMD ./GOSICK


この辺りを削除した。ぶっちゃけ Goのイメージそのまま使うのでDockerfileは不要で

docker-composeにimage指定するだけでいいけど

今後なにかインストールする可能性もあるので Dockerファイルはのこした


build.sh

今回はプラグインのビルドなども入るので、ワンライナーで書かず

ビルドをシェルスクリプトでわけたかった

(最終的にはMakefile等にしたいなあ)


build.sh

if [ $TEST = "test" ]; then

cd plugins/echo
go test -v ./... --buildmode=plugin
cd ../..

go test -v ./...
else
cd plugins/echo
go build --buildmode=plugin
cd ../..

go build
fi


テストと通常ビルドを分けるため $TEST環境変数で分けることにした


Script


docker_app_build

docker-compose up -d

docker-compose exec gosick_app bash -C '/app/build.sh'


docker_app_test

docker-compose up -d

docker-compose exec -e TEST=test gosick_app bash -C '/app/build.sh'

テストと実行でファイルを分けたが、環境変数以外はかわらないので、まとめてもいいなあ

docker-compose up も別にすべきかなあ

等色々考えているが、しばらく使って考える予定


GithubにTravisを連携させバッヂをつける

https://qiita.com/hoshimado/items/4090d8e64beb8a7f95e1

例えばこの辺を参考に、バッヂまでつける


Travisの設定

とっても苦労したTravisの設定

とりあえずはどのリポジトリをPushしても通知が入るようにしている

プロジェクトのルートに .travis.yml ファイルを作成してPush


最初の設定


.travis.yaml

sudo: required

services:
- docker

before_install:
# - docker-compose up -d

install:

before_script:

script:
- scripts/docker_app_run
# - docker-compose exec golang go test -v ./...

after_script:

notifications:


いろんなサイトをみて上記の設定ファイルを書いたが、色々なエラーが出てダメ

なので色々と


language設定

TravisのページをみるとRubyと判断されていたのでlanguageを設定


.travis.yaml

language: go


ただ、Goのバージョンが古かったのでちゃんとバージョン指定してみた


.travis.yaml

language: go

go:
- 1.12.x


GO111MODULE

ログをみていると GO111MODULE=autoになっていた

今回はgo module使いたいので onにしたいので下記のようにかいてみた


.travis.yaml

script:

- env GO111MODULE=on scripts/docker_app_test

ところがログをみても GO111MODULE=autoのままだった

どうやらenvセクションに書く必要があった


.travis.yaml

env:

- GO111MODULE=on


go_import_path

githubのアドレスを加えた


.travis.yaml

go_import_path: github.com/YukiMiyatake/GOSICK



スクリプトパーミッション

Windowsで開発を行っていたため、ファイルのパーミッションがおかしくなっていた

Travis内でパーミッションを設定してもいいが、根本的な解決としてスクリプトファイルにパーミッションをあたえPushした

https://qiita.com/maosanhioro/items/aaade68cdca591232159

この辺をみて、パーミッションを正しく設定したら動いた


DockerComposeのバージョンが古い

docker-composeのバージョンが古かったので念のためバージョンアップを行った

まず、TravisのDockerやDockerComposeバージョンは例えば下記で調べられる


.travis.yml

before_install:

- docker-compose -v
- docker -v

これによると


$ docker-compose -v

docker-compose version 1.17.1, build 6d101fb

before_install.3

$ docker -v

Docker version 17.09.0-ce, build afdb6d4


Dockerはとりあえず今回はバージョンはいいとします

DockerComposeだけ 1.24.1にバージョン上げます


.travis.yml

env:

- GO111MODULE=on
- DOCKER_COMPOSE_VERSION=1.24.1

before_install:
- sudo rm /usr/local/bin/docker-compose
- curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
- chmod +x docker-compose
- sudo mv docker-compose /usr/local/bin


Travis公式のドキュメント通りです。

ところが色々不可解なエラーが出ます


Yamlの罠

yamlじたいほとんど書かないのでよくわかってませんが、気になるポイントをみつけた


.travis.yml

env:

- GO111MODULE=on
- DOCKER_COMPOSE_VERSION=1.24.1

結論からいうと

GO111MODULE:on

だとGO111MODULEは定義されずautoになる

GO111MODULE: on

だとGO111MODULEはtrueが定義されてしまう

GO111MODULE= on

だとGO111MODULEは空文字が定義される

よって

GO111MODULE=on

以外はダメ

DOCKER_COMPOSE_VERSION = 1.24.1

DOCKER_COMPOSE_VERSION:1.24.1

DOCKER_COMPOSE_VERSION :1.24.1

は共に定義されない

DOCKER_COMPOSE_VERSION: 1.24.1

DOCKER_COMPOSE_VERSION=1.24.1

はOK

:の場合は前にスペースNG、後ろにスペース必須

=の場合は 前も後ろもスペースNG

GO111MODULEには=しか使えない

DOCKER_COMPOSE_VERSIONは上記ルールを守っているなら:でも=でもOK

細かい事はおいといて


.travis.yml

  - GO111MODULE=on

- DOCKER_COMPOSE_VERSION=1.24.1

とするとちゃんと定義されるようになった


並列実行問題


.travis.yml

env:

- GO111MODULE=on
- DOCKER_COMPOSE_VERSION=1.24.1

で両方の環境変数は定義されたが、なぜか2つ実行されているっぽい

その2つの環境変数は

GO111MODULE=on, DOCKER_COMPOSE_VERSION定義なし

GO111MODULE定義なし, DOCKER_COMPOSE_VERSION=1.24.1

の2つ

どう考えても並列実行されている

ドキュメント見た感じだと globalに設定すればよさそう


.travis.yml

env:

global:
- GO111MODULE=on
- DOCKER_COMPOSE_VERSION=1.24.1

これで、すべての実行環境において上記のフラグが立つようになった

今回は使用していないが metrix: に環境変数配列を列挙すると並列で実行できるので

テストの高速化を行う時は使ってみよう

(ただし無料版だとたぶん2並列までしかできない)


DBのbind問題

下記の謎エラーが出て結構悩まされた

ERROR: for gosick_mysql  Cannot start service gosick_mysql: driver failed programming external connectivity on endpoint gosick_mysql (cb76f17f3761214c04ca3c4ca03fe4b993e65b0ca14b76b711606651d40c8a8c): Error starting userland proxy: listen tcp 0.0.0.0:3306: bind: address already in use

ERROR: for gosick_mysql Cannot start service gosick_mysql: driver failed programming external connectivity on endpoint gosick_mysql (cb76f17f3761214c04ca3c4ca03fe4b993e65b0ca14b76b711606651d40c8a8c): Error starting userland proxy: listen tcp 0.0.0.0:3306: bind: address already in use

BindAddressが使われている。3306なのでMySQLが既に立ち上がっているようだが、いくら見渡してもそれらしいものがない・・

ので困った

MySQLのDockerは今は使ってないので消せば解決はするが、ちゃんと解決させたいので調べたら、まさかの! TravisでMySQLが立ち上がっていた・・・

ので、実行前にTravisのMySQLを落とす


.travis.yml

before_install:

- sudo /etc/init.d/mysql stop

やった!できた!


まとめ

色々な罠があったが、とりあえずTravisCIを動かすことができた

一通り自分の陥った罠をリストアップしたので、誰かの役にたてば幸いです

なぜかすべてのテストが通ってないので問題は残ってるけど、TravisCIの問題は解決したということで。

最終的な設定ファイル(不要な設定もあるかもしれないけど)


.travis.yml

language: go

go:
- 1.12.x

go_import_path: github.com/YukiMiyatake/GOSICK

env:
global:
- GO111MODULE=on
- DOCKER_COMPOSE_VERSION=1.24.1

services:
- docker

before_install:
- sudo /etc/init.d/mysql stop
- docker-compose -v
- docker -v
- sudo rm /usr/local/bin/docker-compose
- curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
- chmod +x docker-compose
- sudo mv docker-compose /usr/local/bin
- docker-compose build

install:

before_script:

script:
- scripts/docker_app_test

after_script:

notifications: