CircleCI速くした(9分→4分)
環境
- laradockで開発しているLaravelプロジェクト
CIで時間かかる処理
- npmパッケージ取得
- composerパッケージ取得
- dockerイメージビルド
キャッシュによる高速化
- キャッシュの仕組みがある
- CircleCI 2.0からの機能らしい
save_cache
- 依存ライブラリ等に名前を付けて、キャッシュを生成できる
restore_cache
- 名前を指定してキャッシュを読み出す
- 無ければ何もしない
- キャッシュの名づけには、パッケージ管理ファイルのチェックサム等を使用する
- シノニムは考えないことにする
npmパッケージ
.circleci/config.yml
- run: cp ./src/package-lock.json ./src/package-lock.json.bak - restore_cache: keys: - npm-v1-{{ checksum "./src/package-lock.json.bak" }} paths: - ./src/node_modules - run: name: Install JavaScript Packages command: | if [ ! -d ./src/node_modules ]; then pushd ./laradock docker-compose exec workspace npm install fi - save_cache: key: npm-v1-{{ checksum "./src/package-lock.json.bak" }} paths: - ./src/node_modules
package-lock.json
のチェックサムをもってして同一性を検証- ただし、
npm install
でpackage-lock.json
が書き換わるようなのでバックアップを使用している - キャッシュ使用時は
npm install
しない
composerパッケージ
.circleci/config.yml
- run: cp ./src/composer.lock ./src/composer.lock.bak - restore_cache: keys: - composer-v1-{{ checksum "./src/composer.lock.bak" }} paths: - ./src/vendor - run: name: Install PHP Packages command: | if [ ! -d ./src/vendor ]; then pushd ./laradock docker-compose exec workspace composer install fi - save_cache: key: composer-v1-{{ checksum "./src/composer.lock.bak" }} paths: - ./src/vendor
- おなじ
dockerイメージビルド
.circleci/config.yml
- run: name: Archive Build Context (for checksum) command: tar --mtime="2000-01-01 00:00Z" -cvf laradock.tar laradock - restore_cache: keys: - laradock-v1-{{ checksum "./laradock.tar" }} paths: - ~/caches/images.tar - run: name: Docker Image Rebuild command: | if [ ! -f ~/caches/images.tar ]; then pushd laradock docker-compose build workspace php-fpm nginx mysql fi - run: name: Save Docker Images command: | if [ ! -f ~/caches/images.tar ]; then mkdir ~/caches docker image save $(docker image ls --format="{{.Repository}}" | grep laradock_) -o ~/caches/images.tar fi - save_cache: key: laradock-v1-{{ checksum "./laradock.tar" }} paths: - ~/caches/images.tar - run: name: Load Docker Images command: docker image load -i ~/caches/images.tar - run: docker image ls
- 先の例ほど単純ではないので分割
キャッシュ名生成部分
- run: name: Archive Build Context (for checksum) command: tar --mtime="2000-01-01 00:00Z" -cvf laradock.tar laradock
- docker-composeのビルドコンテキストは
laradock/
ディレクトリ全体 - CircleCIの
checksum
は単一ファイルにしか対応していない。はず。 - なので
*.tar
に固めてからchecksum
に渡す必要がある - 下記では駄目:
tar -cvf laradock.tar laradock
tar
コマンドは内容物のタイムスタンプを保存する- CircleCIがGitHubからコードをcloneした時刻によってタイムスタンプは変わるため、
laradock.tar
のチェックサムが毎回変わってしまう - ので、タイムスタンプを固定値にする:
tar --mtime="2000-01-01 00:00Z" -cvf laradock.tar laradock
キャッシュ読み出し部分
- restore_cache: keys: - laradock-v1-{{ checksum "./laradock.tar" }} paths: - ~/caches/images.tar
mkdir ~/caches
はしなくていいみたい
dockerイメージビルド・ファイル書き出し部分
- run: name: Docker Image Rebuild command: | if [ ! -f ~/caches/images.tar ]; then pushd laradock docker-compose build workspace php-fpm nginx mysql fi - run: name: Save Docker Images command: | if [ ! -f ~/caches/images.tar ]; then mkdir ~/caches docker image save $(docker image ls --format="{{.Repository}}" | grep laradock_) -o ~/caches/images.tar fi
- キャッシュを読み出せた場合は何もしない
~/caches/images.tar
の存在により判定
docker-compose build
で必要なイメージをビルドするlaradock_
から始まるイメージのみファイルに書き出すdocker image ls --format="{{.Repository}}"
はイメージ名一覧を得る
- 【issue】
laradock/.env
のCOMPOSE_PROJECT_NAME=laradock
を変えると機能しなくなる
キャッシュ保存
- save_cache: key: laradock-v1-{{ checksum "./laradock.tar" }} paths: - ~/caches/images.tar
- どうってことはない
イメージ読み込み
- run: name: Load Docker Images command: docker image load -i ~/caches/images.tar - run: docker image ls
- キャッシュファイルからイメージ読み込む
- キャッシュミスして1からビルドした場合も通るので効率悪い
- けど判定・分岐が面倒くさい&頻繁なケースではないので手を抜いた
高速化による弊害と対策
docker-compose up -d
でmysqlコンテナ起動後、mysqldの準備完了を待たずして後工程が容赦なく進むようになった- Composeの起動順番を制御
Compose はコンテナの準備が「整う」まで待ちません。 (つまり、特定のアプリケーションが利用可能になるまで待ちません) 単に起動するだけです。
- DBが絡むテストで
SQLSTATE[HY000] [2002] Connection refused
が出てしまうように - wait-for-itを用いてmysqldの準備完了を待つようにした
- run: name: PHP CI (waiting for the invocation of mysqld) command: docker-compose exec workspace /root/etc/wait-for-it.sh mysql:3306 -- composer run ci working_directory: ./laradock