CI
docker
drone.io
docker-compose

drone.ioでdrone-volume-cacheを使ってビルドを高速化する

概要

drone.ioでは、毎回コンテナが生成され、終わると破棄されるため、
bundler、composer、npmなどを使っていると、
毎回インストールが発生するためビルドに時間がかかってしまいます。

そこで、 drillster/drone-volume-cache というpluginを使い、
そのような毎回インストールが発生するパッケージをキャッシュとして保存し、
ビルドに時間がかからないようにします。

環境

  • drone 0.7.3
  • docker-compose 1.8.1

まずはじめに

drone-volume-cacheを使うためには、
drone.ioの画面の各レポジトリの [Settings]で 、[Trusted]を[on]にする必要があります。
OFFのままビルドをしようとすると、
ERROR: Insufficient privileges to use volumes
というエラーが出ます。

そしてまた、[Trusted]を[on]にするためには、ADMINユーザーである必要があります。

ネットワークによっては下記のようなことが起きるかも。。
参考:Trustedオプションの設定

Drone.ioのSETTINGSの変更

現象:Drone.ioで該当リポジトリのSETTINGSを変更しても反映されない。
原因:SETTINGSの変更はPATCHメソッドで実行されていたがプロキシが対応しておらず400でエラーになっていた(ブラウザのネットワークの通信を見てわかった)。
対応:一時的に外部からのアクセスを許可してプロキシを利用しないで設定変更、、、

まず、ADMINユーザーを設定するため、
drone.ioのホストOS上のdocker-compose.ymlで、 DRONE_ADMIN に、ADMINにするユーザーを指定します。
GITのユーザー名をカンマ区切りで複数指定することができます。
参考:http://readme.drone.io/0.5/install/authorization/

docker-compose.yml
version: '2'

services:
  drone-server:
    image: drone/drone:0.7.3
    ports:
      - 80:8000
    volumes:
      - ./drone:/var/lib/drone/
    restart: always
    # カンマ区切りで複数指定可能
    DRONE_ADMIN=GITのユーザー名, GITのユーザー名

# *snip*

次に、drone.ioの画面で、対象のレポジトリの[Settings]で[Trusted]を[on]にします。

drone_trusted.png

ADMINユーザー以外で操作をすると、
Error updating repository settings
というエラーが表示され、 [Trusted] の設定を変更することができません。

.drone.ymlの作成

各レポジトリの.drone.ymlに、restore-cacherebuild-cacheを追記します。

.drone.yml
pipeline:
  restore-cache:
    image: drillster/drone-volume-cache
    restore: true
    mount:
      - ./vendor
    volumes:
      - /tmp/cache:/cache
    ttl: 7
    when:
      branch: [ master, staging ]
      event: push

  build:
    image: ruby:2.3.1
    commands:
      - git clone https://github.com/user/appname.git /tmp/appname
      - bundle install --path vendor/bundle
      - cp .env.drone .env
      - bundle exec rake db:migrate
      - bundle exec rspec spec
    when:
      branch: [ master, staging ]
      event: push

  rebuild-cache:
    image: drillster/drone-volume-cache
    rebuild: true
    mount:
      - ./vendor
    volumes:
      - /tmp/cache:/cache
    ttl: 7
    when:
      branch: [ master, staging ]
      event: push

services:
  drone_postgresql:
    image: postgres:9.5
    environment:
      - POSTGRES_DB=appname_test
      - POSTGRES_USER=postgres

restore-cache で、ホストOSからビルドコンテナへファイルをコピーします。
rebuild-cache で、ビルドコンテナからホストOSへファイルをコピーします。

build前に、キャッシュされているファイルを展開し、
build後に、ファイルをキャッシュし直します。
こうすることで、buildによって差分が生まれたファイルもキャッシュされることになります。

その他の設定については以下の通りです。

name desc
mount キャッシュする各レポジトリのディレクトリを指定します。配列で複数指定も可能です。
volumes ホストOSの/tmp/cacheとビルドコンテナの/cacheを同期します。
ttl キャッシュファイルを何日残すか、日数を指定します。

これで、droneのホストマシンの/tmp/cacheの下に以下のようなキャッシュファイルが作成され、ビルドする際に参照されるようになります。
/tmp/cache/username/appname/1/vendor/

参考: http://plugins.drone.io/drillster/drone-volume-cache/

キャッシュクリア方法、キャッシュを利用しない方法

GITのコミットメッセージに以下を含めると、それぞれ特定の挙動をします。

message desc
[CLEAR CACHE] キャッシュをクリアしてからビルドする
[NO CACHE] キャッシュを使用せずにビルドする(rebuildもされなくなる)

参考:https://github.com/Drillster/drone-volume-cache/blob/master/DOCS.md

課題

初回実行時のみ、
restore-cache で、以下のエラーが発生します。

find: ‘/cache/username/appname/1’: No such file or directory

初回は、ホストOS上に、/cache/username/appname/1 が作成されていないことが原因のようです。
rebuild-cache が実行されたタイミングでディレクトリが作成されるようです。
手動で、ディレクトリを作成しておけばエラーにはなりませんが、
今のところ良い解決方法はまだ見つかっていません。

暫定対応案

とりあえず、下記のいずれかで対応する。

  • 手動でdroneのホストOSに mkdir /cache/username/appname/1 をする
  • appleboy/drone-ssh のpluginを使って、droneサーバーにsshで入り、 /cache/username/appname/1がなければ作成する。(一番イケてない)

追記 - 解決 2017/07/12

drone-volume-cacheのプラグインに問題があることが発覚しました。
最初に、古いキャッシュを消そうとする処理があるのですが、キャッシュが存在していなくても、削除処理を走らせようとしていて、そこでエラーになっていました。

問題の箇所はこちらです。
https://github.com/Drillster/drone-volume-cache/blob/master/cacher.sh#L43
43 - 44行目

42            echo "Removing files and (empty) folders older than $PLUGIN_TTL days..."
43            find "/cache/$DRONE_REPO_OWNER/$DRONE_REPO_NAME/$DRONE_JOB_NUMBER" -type f -ctime +$PLUGIN_TTL -delete
44            find "/cache/$DRONE_REPO_OWNER/$DRONE_REPO_NAME/$DRONE_JOB_NUMBER" -type d -ctime +$PLUGIN_TTL -empty -delete

なので、 該当箇所を下記のように修正し、自作イメージ化して使うことにしました。

42            if [ -d "/cache/$DRONE_REPO_OWNER/$DRONE_REPO_NAME/$DRONE_JOB_NUMBER" ]; then
43              echo "Removing files and (empty) folders older than $PLUGIN_TTL days..."
44              find "/cache/$DRONE_REPO_OWNER/$DRONE_REPO_NAME/$DRONE_JOB_NUMBER" -type f -ctime +$PLUGIN_TTL -delete
45              find "/cache/$DRONE_REPO_OWNER/$DRONE_REPO_NAME/$DRONE_JOB_NUMBER" -type d -ctime +$PLUGIN_TTL -empty -delete
46            fi

修正したものを、DockerHubに公開しました!
https://hub.docker.com/r/esfahan/drone-volume-cache/
[追記 2017/07/13] オリジナルのものが修正されたのでprivateにしました。

今回私は、DockerHubにイメージ公開しましたが、
公開しなくても、droneのホストOSにイメージが存在していればOKです。
参考:DockerHubに自作イメージを公開する

オリジナルのプラグインには、現在プルリクを出しています。
https://github.com/Drillster/drone-volume-cache/pull/9

追記 2017/07/13

オリジナルのプラグインには、現在プルリクを出しています。
https://github.com/Drillster/drone-volume-cache/pull/9

こちら、マージされました!
動作も問題ありませんでした。
https://hub.docker.com/r/drillster/drone-volume-cache/

以上

関連