はじめに
Dockerfileを書くことなく、ソースコードからDockerイメージを作ることができると言うCloud Native Buildpacksという存在を知りました。
Dockerfileを色々と調べながら書くのはあんまり好きじゃなく、できれば楽できたらなと思ったところに知ったものなので、早速試してみました。
pack
コマンドのインストール
まず、pack
コマンドのインストールを行います。やり方は公式サイトにドキュメントがあるので、それを参考に。
私が試した時には、0.26.0
というバージョンでした。
azureuser@myVM:~$ pack --version 0.26.0 azureuser@myVM:~$
また、Docker環境も整えておきます。
Javaのサンプルアプリを動かす
チュートリアルが用意されているので、それに従ってやってみます。
サンプルリポジトリをcloneして、pack
コマンドを実行します。
azureuser@myVM:~/work/samples/apps/java-maven$ pack build myapp --builder cnbs/sample-builder:bionic bionic: Pulling from cnbs/sample-builder (省略) ===> ANALYZING ===> DETECTING [detector] samples/java-maven 0.0.1 ===> RESTORING [restorer] Restoring metadata for "samples/java-maven:jdk" from app image [restorer] Restoring metadata for "samples/java-maven:maven_m2" from cache [restorer] Restoring data for "samples/java-maven:jdk" from cache [restorer] Restoring data for "samples/java-maven:maven_m2" from cache ===> BUILDING [builder] ---> Java buildpack [builder] ---> Installing JDK [builder] ---> Running Maven Wrapper [builder] [INFO] Scanning for projects... [builder] [INFO] [builder] [INFO] --------------------< io.buildpacks.example:sample >-------------------- [builder] [INFO] Building sample 0.0.1-SNAPSHOT [builder] [INFO] --------------------------------[ jar ]--------------------------------- [builder] [INFO] (省略) [builder] [INFO] ------------------------------------------------------------------------ [builder] [INFO] BUILD SUCCESS [builder] [INFO] ------------------------------------------------------------------------ [builder] [INFO] Total time: 2.827 s [builder] [INFO] Finished at: 2022-05-29T08:05:21Z [builder] [INFO] ------------------------------------------------------------------------ ===> EXPORTING [exporter] Reusing layer 'samples/java-maven:jdk' [exporter] Adding 1/1 app layer(s) [exporter] Reusing layer 'launcher' [exporter] Reusing layer 'config' [exporter] Reusing layer 'process-types' [exporter] Adding label 'io.buildpacks.lifecycle.metadata' [exporter] Adding label 'io.buildpacks.build.metadata' [exporter] Adding label 'io.buildpacks.project.metadata' [exporter] Setting default process type 'web' [exporter] Saving myapp... [exporter] *** Images (d8a7e88bd822): [exporter] myapp [exporter] Reusing cache layer 'samples/java-maven:jdk' [exporter] Adding cache layer 'samples/java-maven:maven_m2' Successfully built image myapp azureuser@myVM:~/work/samples/apps/java-maven$
Mavenによるビルドが実行され、Dockerイメージが作成されました。
azureuser@myVM:~/work/samples/apps/java-maven$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE heroku/pack 20 187818685cd8 8 hours ago 602MB cnbs/sample-stack-run bionic 0aa0fb9222a5 5 months ago 70.2MB hello-world latest feb5d9fea6a5 8 months ago 13.3kB buildpacksio/lifecycle 0.13.1 76412e6be4e1 42 years ago 16.4MB heroku/buildpacks 20 51904c87109f 42 years ago 1.56GB cnbs/sample-builder bionic 83509780fa67 42 years ago 181MB myapp latest d8a7e88bd822 42 years ago 300MB ## ← 作られたDockerイメージ azureuser@myVM:~/work/samples/apps/java-maven$
アプリを動かしてみます。
azureuser@myVM:~/work/samples/apps/java-maven$ docker run --rm -p 8080:8080 myapp |'-_ _-'| ____ _ _ _ _ _ | | | | _ \ (_)| | | | | | (_) '-_|_-' | |_) | _ _ _ | | __| | _ __ __ _ ___ | | __ ___ _ ___ |'-_ _-'|'-_ _-'| | _ < | | | || || | / _` || '_ \ / _` | / __|| |/ // __| | | / _ \ | | | | | | |_) || |_| || || || (_| || |_) || (_| || (__ | < \__ \ _ | || (_) | '-_|_-' '-_|_-' |____/ \__,_||_||_| \__,_|| .__/ \__,_| \___||_|\_\|___/(_)|_| \___/ | | |_| :: Built with Spring Boot :: 2.1.18.RELEASE 2022-05-29 08:09:28.225 INFO 1 --- [ main] i.b.example.sample.SampleApplication : Starting SampleApplication v0.0.1-SNAPSHOT on c6e7f160ad2c with PID 1 (/workspace/target/sample-0.0.1-SNAPSHOT.jar started by cnb in /workspace) 2022-05-29 08:09:28.229 INFO 1 --- [ main] i.b.example.sample.SampleApplication : No active profile set, falling back to default profiles: default 2022-05-29 08:09:29.912 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2022-05-29 08:09:29.975 INFO 1 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2022-05-29 08:09:29.976 INFO 1 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.39] 2022-05-29 08:09:30.096 INFO 1 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2022-05-29 08:09:30.097 INFO 1 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1766 ms 2022-05-29 08:09:30.377 INFO 1 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2022-05-29 08:09:30.463 INFO 1 --- [ main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index 2022-05-29 08:09:30.635 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2022-05-29 08:09:30.639 INFO 1 --- [ main] i.b.example.sample.SampleApplication : Started SampleApplication in 3.089 seconds (JVM running for 3.708)
ブラウザでアクセスしてみると、以下のような画面が出てきました。
Rubyのサンプルアプリを試す
サンプルリポジトリにはruby-bundler
というSinatraで作られたアプリがあるので、これを試してみます。
Javaの時と同じようにpackコマンドを使ってDockerイメージを作成します。
azureuser@myVM:~/work/samples/apps/ruby-bundler$ pack build myapp-ruby --builder cnbs/sample-builder:bionic bionic: Pulling from cnbs/sample-builder Digest: sha256:f9aa933450900df3a91a5f405c4a55ed3bb9decc9ee503b2dd85ff728db75e22 Status: Image is up to date for cnbs/sample-builder:bionic bionic: Pulling from cnbs/sample-stack-run Digest: sha256:7b0946aa031f1ddd30bda8963eb33431458a25a576208646348ce89536fef59a Status: Image is up to date for cnbs/sample-stack-run:bionic 0.13.1: Pulling from buildpacksio/lifecycle Digest: sha256:f2cb410c8e204e6d2c6d86b1a171862595d8dccefc35197804eff09ab9221219 Status: Image is up to date for buildpacksio/lifecycle:0.13.1 ===> ANALYZING ===> DETECTING [detector] samples/ruby-bundler 0.0.1 ===> RESTORING [restorer] Restoring metadata for "samples/ruby-bundler:bundler" from app image [restorer] Restoring metadata for "samples/ruby-bundler:ruby" from app image [restorer] Restoring data for "samples/ruby-bundler:bundler" from cache ===> BUILDING [builder] ---> Ruby Buildpack [builder] ---> Downloading and extracting Ruby 2.5.0 [builder] ---> Installing bundler [builder] Successfully installed bundler-2.3.14 [builder] 1 gem installed [builder] ---> Reusing gems [builder] Your RubyGems version (2.7.6.2) has a bug that prevents `required_ruby_version` from working for Bundler. Any scripts that use `gem install bundler` will break as soon as Bundler drops support for your Ruby version. Please upgrade RubyGems to avoid future breakage and silence this warning by running `gem update --system 3.2.3` [builder] Your RubyGems version (2.7.6.2) has a bug that prevents `required_ruby_version` from working for Bundler. Any scripts that use `gem install bundler` will break as soon as Bundler drops support for your Ruby version. Please upgrade RubyGems to avoid future breakage and silence this warning by running `gem update --system 3.2.3` ===> EXPORTING [exporter] Reusing layer 'samples/ruby-bundler:bundler' [exporter] Reusing layer 'samples/ruby-bundler:ruby' [exporter] Adding 1/1 app layer(s) [exporter] Reusing layer 'launcher' [exporter] Reusing layer 'config' [exporter] Reusing layer 'process-types' [exporter] Adding label 'io.buildpacks.lifecycle.metadata' [exporter] Adding label 'io.buildpacks.build.metadata' [exporter] Adding label 'io.buildpacks.project.metadata' [exporter] Setting default process type 'web' [exporter] Saving myapp-ruby... [exporter] *** Images (360bd2e06828): [exporter] myapp-ruby [exporter] Reusing cache layer 'samples/ruby-bundler:bundler' Successfully built image myapp-ruby azureuser@myVM:~/work/samples/apps/ruby-bundler$
docker run
コマンドを使って動かします。
azureuser@myVM:~/work/samples/apps/ruby-bundler$ docker run --rm -p 8080:8080 myapp-ruby Hello from .profile Your RubyGems version (2.7.6.2) has a bug that prevents `required_ruby_version` from working for Bundler. Any scripts that use `gem install bundler` will break as soon as Bundler drops support for your Ruby version. Please upgrade RubyGems to avoid future breakage and silence this warning by running `gem update --system 3.2.3` [2022-05-29 08:18:51] INFO WEBrick 1.4.2 [2022-05-29 08:18:51] INFO ruby 2.5.0 (2017-12-25) [x86_64-linux] == Sinatra (v2.0.7) has taken the stage on 8080 for development with backup from WEBrick [2022-05-29 08:18:51] INFO WEBrick::HTTPServer#start: pid=1 port=8080
ブラウザでアクセスしてみます。大変簡素な画面ですが、無事動きました。
Rubyサンプルアプリのバージョンアップを行う
サンプルアプリのRubyのバージョンは2.5だったので最新バージョンである3.1.2で動かすことにします。
最初は.ruby-version
を変更すれば良いだけでしょと思っていたのですが、それだけではうまく動きませんでした。
まずはローカルで動かす
まずはローカルで動かしてみます。ruby app.rb
を実行すると、以下のようなメッセージが出てうまく動きません。
azureuser@myVM:~/work/samples/apps/ruby-builder3$ ruby app.rb /home/azureuser/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/rack-2.2.3.1/lib/rack/handler.rb:45:in `pick': Couldn't find handler for: thin, puma, reel, HTTP, webrick. (LoadError) from /home/azureuser/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/base.rb:1503:in `run!' from /home/azureuser/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/sinatra-2.2.0/lib/sinatra/main.rb:45:in `block in <module:Sinatra>' azureuser@myVM:~/work/samples/apps/ruby-builder3$
これはwebrick
が最近のRubyでは標準ではインストールされないために起こる問題です。gem "webrick"
をGemfileに追加してbundle install
します。また、bundle update --bundler
やbundle update
を実行して、大量に出てくるdeprecatedを消しておきます。これでローカルで動かすことができます。
azureuser@myVM:~/work/samples/apps/ruby-builder3$ ruby app.rb [2022-05-29 08:37:43] INFO WEBrick 1.7.0 [2022-05-29 08:37:43] INFO ruby 3.1.2 (2022-04-12) [x86_64-linux] == Sinatra (v2.2.0) has taken the stage on 8080 for development with backup from WEBrick [2022-05-29 08:37:43] INFO WEBrick::HTTPServer#start: pid=34563 port=8080
Dockerイメージを作成する
続いてpackコマンドでDockerイメージを作成してみます。これまでと同じようにイメージ名だけ変えて動かしてみたら以下のメッセージが出てDockerイメージは作られませんでした。
azureuser@myVM:~/work/samples/apps/ruby-builder3$ pack build myapp-ruby3 --builder cnbs/sample-builder:bionic bionic: Pulling from cnbs/sample-builder (省略) Status: Image is up to date for buildpacksio/lifecycle:0.13.1 ===> ANALYZING [analyzer] Previous image with name "myapp-ruby3" not found ===> DETECTING [detector] samples/ruby-bundler 0.0.1 ===> RESTORING ===> BUILDING [builder] ---> Ruby Buildpack [builder] ---> Downloading and extracting Ruby 3.1.2 [builder] ---> Installing bundler [builder] <internal:/layers/samples_ruby-bundler/ruby/lib/ruby/3.1.0/rubygems/core_ext/kernel_require.rb>:85:in `require': libyaml-0.so.2: cannot open shared object file: No such file or directory - /layers/samples_ruby-bundler/ruby/lib/ruby/3.1.0/x86_64-linux/psych.so (LoadError) (省略) [builder] ERROR: failed to build: exit status 1 ERROR: failed to build: executing lifecycle. This may be the result of using an untrusted builder: failed with status code: 51 azureuser@myVM:~/work/samples/apps/ruby-builder3$
これを解決するには--builder
で指定した値を変えます。どの値を指定していいかわかりませんでしたが、以下のマニュアルにあるようにpack builder suggest
コマンドで提示されたものを指定してみます。
今回は、heroku/buildpacks:20
を指定してみることにします。
azureuser@myVM:~/work/samples/apps/ruby-builder3$ pack build myapp-ruby3 --builder heroku/buildpacks:20 20: Pulling from heroku/buildpacks (省略) Status: Image is up to date for heroku/pack:20 ===> ANALYZING Previous image with name "myapp-ruby3" not found ===> DETECTING 1 of 2 buildpacks participating heroku/ruby 0.1.3 ===> RESTORING ===> BUILDING -----> Installing bundler 2.2.21 -----> Removing BUNDLED WITH version in the Gemfile.lock -----> Compiling Ruby/Rack -----> Using Ruby version: ruby-2.7.4 -----> Loading Bundler Cache -----> Installing dependencies using bundler 2.2.21 Running: BUNDLE_WITHOUT='development:test' BUNDLE_PATH=/layers/heroku_ruby/gems/vendor/bundle BUNDLE_BIN=vendor/bundle/bin BUNDLE_DEPLOYMENT=1 bundle install -j4 Fetching gem metadata from https://rubygems.org/ Fetching gem metadata from https://rubygems.org/.... (省略) -----> Detecting rake tasks ###### WARNING: You have not declared a Ruby version in your Gemfile. To declare a Ruby version add this line to your Gemfile: ``` ruby "2.7.4" ``` For more information see: https://devcenter.heroku.com/articles/ruby-versions ===> EXPORTING (省略) Saving myapp-ruby3... *** Images (163a27f2364c): myapp-ruby3 Adding cache layer 'heroku/ruby:gems' Successfully built image myapp-ruby3
今度はうまくDockerイメージが作られましたが、Rubyのバージョンが2.7.4になっています。ログの警告にあるようにGemfile
にRubyのバージョンが書かれていないのが原因のようです。このため、Gemfile内にruby "3.1.2"
と書いておきます。bundle update
もして再度pack build
してみます。
azureuser@myVM:~/work/samples/apps/ruby-builder3$ pack build myapp-ruby3 --builder heroku/buildpacks:20 20: Pulling from heroku/buildpacks (省略) ===> BUILDING -----> Installing bundler 2.2.21 -----> Removing BUNDLED WITH version in the Gemfile.lock -----> Compiling Ruby/Rack -----> Using Ruby version: ruby-3.1.2 -----> Loading Bundler Cache -----> Installing dependencies using bundler 2.2.21 Running: BUNDLE_WITHOUT='development:test' BUNDLE_PATH=/layers/heroku_ruby/gems/vendor/bundle BUNDLE_BIN=vendor/bundle/bin BUNDLE_DEPLOYMENT=1 bundle install -j4 (省略) Successfully built image myapp-ruby3 azureuser@myVM:~/work/samples/apps/ruby-builder3$
無事イメージが作られました。
あとはdocker run
すればいいだけと思っていたのですが、まだ動きません。
azureuser@myVM:~/work/samples/apps/ruby-builder3$ docker run --rm -p 8080:8080 myapp-ruby3 Hello from .profile configuration /workspace/config.ru not found azureuser@myVM:~/work/samples/apps/ruby-builder3$
動かすためには、Procfile
を作成します。Procfile
については以下を参照。
今回は次のような内容にします。
web: ruby app.rb
Procfile
を作成後、再度pack build
を実行し、docker run
すると無事動かすことができました。
azureuser@myVM:~/work/samples/apps/ruby-builder3$ docker run --rm -p 8080:8080 myapp-ruby3 Hello from .profile [2022-05-29 08:57:06] INFO WEBrick 1.7.0 [2022-05-29 08:57:06] INFO ruby 3.1.2 (2022-04-12) [x86_64-linux] == Sinatra (v2.2.0) has taken the stage on 8080 for production with backup from WEBrick [2022-05-29 08:57:06] INFO WEBrick::HTTPServer#start: pid=1 port=8080