この記事はチームラボエンジニアリングアドベントカレンダー 18日目です!
アドベントカレンダー初投稿なので、広い心で見ていただけば、嬉しいです(ついでに、いいね!なんてしてくれると泣いて喜びます)
はじめに
ある日、こんなツイートが流れてきた
なんだこれは。Dockerfile書きたくないでござる https://t.co/d6cqF0FS7M
— pospome (@pospome) December 1, 2019
気になって色々調べたり、Cloud Native Buildpackについての記事で、試してみたら、意外と便利じゃん!!ってなったので、紹介したいなと思います
Cloud Native Buildpackとは??
そもそもBuildpackは、PaaS上で、任意の言語やフレームワークを実行できるようになった仕組みです
歴史的背景として、Herokuによって作られ、Heroku内で提供していたが、徐々に、CloudFoundryやGitLabなどでも採用されています
そして、PivovalとHerokuによって開始されたプロジェクトが、CloudNativeBuildPacksです
CloudNativeBuildpacksの登場によって、Buildpacksの仕様が統一され、DockerやKubernetesでも対応されるようになりました
対応言語は、複数あり「Java, .NET, NodeJS, Python, Golang, PHP」に対応しています
Provide a balance of control that reduces the operational burden on developers and supports enterprise operators who manage apps at scale.
Ensure that apps meet security and compliance requirements without developer intervention.
Provide automated delivery of both OS-level and application-level dependency upgrades, efficiently handling day-2 app operations that are often difficult to manage with Dockerfiles.
Rely on compatibility guarantees to safely apply patches without rebuilding artifacts and without unintentionally changing application behavior.
Buildpacksはプラグイン可能なモジュラー化されたツールであり、ソースコードをコンテナ対応の成果物へと変換する。しかもDockerfileと比べてより高度な抽象化を実現してくれる。これにより本番投入にかかる時間を最小化するなど開発者のさまざまな手間を省く一方、企業において大規模なアプリケーション展開を行う運用者も支援し、両者を適切なバランスで実現する。
こんな経験無いですか??
- Dockerfileを書いてたら、半日過ぎてた
- Dockerfileを書いてたら、実行順番が効率的でないと指摘を受けた
- Dockerfileを書いてたら、怪物イメージが出来上がり、ゴミイメージと呼ばれた
- Dockerfileのベースイメージに脆弱性があって、ベースイメージ移行で夜があけた
辛い。。。。Dockerfile辛い。。。。。
そんなToilを削減できるのが、Buildpacksです!!!!
とりあえず試してみよう
前提:Dockerのインストールとイメージ化したいプロジェクトは用意しておいてください
サンプルのプロジェクトも作ったので、使ってください!!!!
https://github.com/adachishohei/buildpack-java-sample
Buildpacksのインストール
- Mac
brew tap buildpack/tap
brew install pack
- Linux
wget https://github.com/buildpack/pack/releases/download/v0.5.0/pack-v0.5.0-linux.tgz
tar xvf pack-v0.5.0-linux.tgz
rm pack-v0.5.0-linux.tgz
./pack --help
- Windows
実行
# Dockerfileが無いことを確認する
$ls
HELP.md build.gradle docker-compose.yml gradlew.bat springboot-practice.iml
README.md config gradle out src
build db gradlew settings.gradle
# buildを実行
$pack build --path . springboot-practice --builder cloudfoundry/cnb:bionic
cflinuxfs3: Pulling from cloudfoundry/cnb
Digest: sha256:8d3e130dac4627022aeb654d601ba8e09f2c7c143f3cc001141340175402722f
Status: Image is up to date for cloudfoundry/cnb:cflinuxfs3
full-cnb: Pulling from cloudfoundry/run
0e1cf81986c5: Pull complete
Digest: sha256:85a5b90046f87cbf1c8d4a75a2a7dac14982000e30ef0d836bc94e4486bcd4e3
Status: Downloaded newer image for cloudfoundry/run:full-cnb
--- 中略 ---
===> CACHING
[cacher] Reusing layer 'org.cloudfoundry.openjdk:2f08c469c9a8adea1b6ee3444ba2a8242a7e99d87976a077faf037a9eb7f884b'
[cacher] Reusing layer 'org.cloudfoundry.openjdk:6dd0c9c8a740e6c19149e98034fba8e368fd9aa16ab417aa636854d40db1a161'
[cacher] Reusing layer 'org.cloudfoundry.openjdk:openjdk-jdk'
[cacher] Caching layer 'org.cloudfoundry.buildsystem:build-system-cache'
[cacher] Reusing layer 'org.cloudfoundry.jvmapplication:executable-jar'
[cacher] Reusing layer 'org.cloudfoundry.springboot:spring-boot'
[cacher] Reusing layer 'org.cloudfoundry.springautoreconfiguration:46ab131165317d91fd4ad3186abf755222744e2d277dc413def06f3ad45ab150'
Successfully built image springboot-practice
# イメージの確認
$docker image -ls
springboot-practice latest d5d4aafb5733 2 minutes ago 246MB
以上で、Docker imageの完成です
イメージサイズも軽くて、良いですね!
さらに、ベースイメージに脆弱性があった時の乗せ替え作業は、rebaseコマンドで代替え可能です
$ pack rebase my-app:my-tag
実行速度
実際の業務で使うためには、実行速度も一つの観点だと思うので、buildの実行速度も計測してみました
初回実行
項目 | 時間 |
---|---|
user | 1.60s |
system | 2.09s |
total | 4:41.93s |
2回目以降
項目 | 時間 |
---|---|
user | 1.68s |
system | 2.15s |
total | 1:39.87s |
初回の実行でも、少し重いかな?って印象を受けますが、十分に使える速度だと思います
さらに、2回目以降は、キャッシュが聞いてくれるので、かなり早くなりましたね
CIについて考えてみた
コンテナイメージをbuildするのは、ローカルではなくCI環境のはずなので、CI環境の構築もやってみました
今回は、GithubActionsを使ったCI環境の構築をしてみます!
と言っても、めちゃくちゃ簡単でした
Buildpackを使うために必要なものは、単純に、Linuxのインストール手順を実行するだけです!
今回は、Springbootで試してみました。
以下の手順で、Buildpackのインストールからビルド、ECRへのPushまで実現可能でした
あとは、うまくキャッシュを聞かせてあげれば、ビルド時間の短縮にも繋がるので、より良くなりそうだと思いました!
サンプルのGitHubActionsのテンプレートは、以下にも置いています
https://github.com/adachishohei/buildpack-java-sample/blob/master/.github/workflows/image_build_for_ecr.yml
on:
push:
branches:
- master
name: buildImageforECR
jobs:
imageBuild:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- name: Get Cloud Native Build
run: wget https://github.com/buildpack/pack/releases/download/v0.5.0/pack-v0.5.0-linux.tgz
- name: Unzip file
run: tar xvf ./pack-v0.5.0-linux.tgz
- name: Remove pack
run: rm pack-v0.5.0-linux.tgz
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
- name: Build, tag, and push image to Amazon ECR
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
ECR_REPOSITORY: ${{ secrets.AWS_ECR_REPO_NAME }}
run: |
IMAGE_TAG=$(echo ${{ github.ref }} | sed -e "s#refs/tags/##g")
./pack build --path . $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG --builder cloudfoundry/cnb:bionic
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
所感
Buildpacksを採用した場合、オリジナルのbuilderを作成することも可能なので、会社として、builderを管理し、それを使ってプロジェクト側でDockerfileを書かずにコンテナイメージを作るのが良いかなと思いました。
そうすることで、脆弱性の対応に関しても、builderのアップデートだけで済むので、プロジェクト単位では、rebaseコマンドを実行するだけで済むので、かなりの運用コストの削減もできます!
あとは、今回Buildpacksの内部の仕組みにまで触れてないのですが、そこに触れるともっと面白そうだなと思ったので、別の機会で記事にできたら良いなと思います
まとめ
- Buildpacksは、コンテナイメージを作る工程と管理を楽にしてくれる(Toilの削減になる)
- Buildpacksは、Java, .NET, NodeJS, Python, Golang, PHPなど複数の言語に対応してる
- Builderの自作が可能で、脆弱性の対応やイメージの一元管理が可能
Buildpacksは神