@making's memo

All Categories All Tags Premium (Beta)


Cloud Foundryのbuildpackを使ってDockerイメージを作成しKubernetesにデプロイ

Edit History

目次

BuildpackとDockerfile

Cloud Foundryのbuildpackは便利で、"Source Code to Container Image"を実現してくれます。

Dockerを用いてアプリケーションをデプロイする場合は、一般的に

  1. ソースコード作成/修正
  2. Dockerfile作成/修正
  3. Dockerイメージの作成
  4. Dockerイメージのデプロイ
  5. Dockerイメージを使ってアプリケーション(コンテナ)をデプロイ

ですが、Cloud Foundryではbuildpackを使うことにより

  1. ソースコード作成/修正
  2. cf pushコマンドでアプリケーション(コンテナ)をデプロイ

で完了します。

Dockerの場合、通常Dockerfileを作ることになりますが、これをメンテナンスするということは、アプリケーションコードのメンテナンスの他に

  • OSイメージ(opensshの脆弱性対応など)
  • ランタイム/ミドルウェア(Javaの場合JDKやTomcat、PHPの場合Apache HTTPやmod_phpなど)

のメンテナンスもしなくてはなりません。Dockerfileは自由度が高い反面、ケアすべき点も多いです。

一方、buildpackではrootfsとしてcflinuxfs2というUbuntu14.04の派生のイメージを使用します。定期的にセキュリティパッチがあてられています。
また各言語ごとにランタイム/ミドルウェアがメンテナンスされており、原則としてCVE(Common Vulnerabilities and Exposures)公開後48時間以内にパッチがリリースされます。
これにより、基本的にアプリケーションコードにのみ集中することができます。

個人的には、アプリケーションデプロイの観点ではDockerfileの作成はあまりやりたい作業でありません。Buildpack方式のほうが好みです。

CF Local Plugin

CF Local Pluginを使用することで、前述のbuildpackによるメリットをDockerイメージ作成にも適用できます。
CF LocalはLaptop内でcf pushをエミュレートするプラグインですが、DockerイメージへのExportに対応しています。

これを使うことにより、Dockerを用いてアプリケーションをデプロイする場合も、

  1. ソースコード作成/修正
  2. CF LocalでDockerイメージの作成
  3. Dockerイメージのデプロイ
  4. Dockerイメージを使ってアプリケーション(コンテナ)をデプロイ

になり、Dockerfileのメンテナンスから解放されます。

これでBuildpackのメリットを活かしつつ、DockerイメージをKubernetesにデプロイするといったことが可能になります。

CF Localの利用

では実際にCF Localで"Source Code to Docker Image"を行い、アプリケーションをk8sにデプロイしてみます。

Cloud Foundry CLIのインストール

まずはcfコマンドが必要です。golangの実行可能バイナリなので、インストールは容易です。

CF CLIのインストールはこちらを参照してください。

Macの場合は、

brew install cloudfoundry/tap/cf-cli

でインストールできます。

CF Local Pluginのインストール

CF Local Pluginのバイナリはこちらからダウンロード可能です。

Macの場合は、

curl -L -J -O https://github.com/sclevine/cflocal/releases/download/v0.13.0/cflocal-0.13.0-macos
cf install-plugin cflocal-0.13.0-macos

でインストールできます。

コンテナイメージの作成

今回は次の簡単なJavaアプリケーション(ただのサーブレット)を題材に使用します。
https://github.com/making/hello-servlet

git clone [email protected]:making/hello-servlet.git
cd hello-servlet
./mvnw package

target/ROOT.warファイルが作成されます。

その後、cf local stageコマンドでステージングを行い、コンテナイメージ(Droplet)を作成します。

cf local stage hello-servlet -p ./target/ROOT.war

次のようなログが出力されます。JDKやTomcatがダウンロードされていることがわかります。またコンテナのメモリサイズ(デフォルトで1GB)に合わせて、JVMのメモリの設定が行われていることもわかります。メモリサイズは-mで変更可能です。

Buildpack: will detect                                                         
[hello-servlet] 2017-08-21T04:32:48.695440393Z -----> Java Buildpack Version: v3.17 | https://github.com/cloudfoundry/java-buildpack.git#87fb619
[hello-servlet] 2017-08-21T04:32:51.033834076Z -----> Downloading Open Jdk JRE 1.8.0_141 from https://java-buildpack.cloudfoundry.org/openjdk/trusty/x86_64/openjdk-1.8.0_141.tar.gz (2.1s)
[hello-servlet] 2017-08-21T04:32:51.977072148Z        Expanding Open Jdk JRE to .java-buildpack/open_jdk_jre (0.9s)
[hello-servlet] 2017-08-21T04:32:52.094011807Z -----> Downloading Open JDK Like Memory Calculator 2.0.2_RELEASE from https://java-buildpack.cloudfoundry.org/memory-calculator/trusty/x86_64/memory-calculator-2.0.2_RELEASE.tar.gz (0.1s)
[hello-servlet] 2017-08-21T04:32:52.117972916Z        Memory Settings: -Xss349K -Xmx681574K -XX:MaxMetaspaceSize=104857K -Xms681574K -XX:MetaspaceSize=104857K
[hello-servlet] 2017-08-21T04:32:52.223085215Z -----> Downloading Container Security Provider 1.8.0_RELEASE from https://java-buildpack.cloudfoundry.org/container-security-provider/container-security-provider-1.8.0_RELEASE.jar (0.1s)
[hello-servlet] 2017-08-21T04:32:53.174939975Z -----> Downloading Tomcat Instance 8.0.46 from https://java-buildpack.cloudfoundry.org/tomcat/tomcat-8.0.46.tar.gz (0.9s)
[hello-servlet] 2017-08-21T04:32:53.278926558Z        Expanding Tomcat Instance to .java-buildpack/tomcat (0.1s)
[hello-servlet] 2017-08-21T04:32:53.436115761Z -----> Downloading Tomcat Lifecycle Support 2.5.0_RELEASE from https://java-buildpack.cloudfoundry.org/tomcat-lifecycle-support/tomcat-lifecycle-support-2.5.0_RELEASE.jar (0.1s)
[hello-servlet] 2017-08-21T04:32:53.668302543Z -----> Downloading Tomcat Logging Support 2.5.0_RELEASE from https://java-buildpack.cloudfoundry.org/tomcat-logging-support/tomcat-logging-support-2.5.0_RELEASE.jar (0.2s)
[hello-servlet] 2017-08-21T04:32:53.747964428Z -----> Downloading Tomcat Access Logging Support 2.5.0_RELEASE from https://java-buildpack.cloudfoundry.org/tomcat-access-logging-support/tomcat-access-logging-support-2.5.0_RELEASE.jar (0.0s)
Successfully staged: hello-servlet

Gifアニメも貼っておきます。

cflocal

Java以外の場合、-pは不要で、カレントディレクトリからステージングが行われます。

作成されたコンテナイメージはcf local runコマンドで実行できます。

$ cf local run hello-servlet
Running hello-servlet on port 54921...                                         
[hello-servlet] 2017-08-21T04:51:20.509802947Z [CONTAINER] org.apache.coyote.http11.Http11NioProtocol         INFO    Initializing ProtocolHandler ["http-nio-8080"]
[hello-servlet] 2017-08-21T04:51:20.517556491Z [CONTAINER] org.apache.catalina.startup.Catalina               INFO    Initialization processed in 371 ms
[hello-servlet] 2017-08-21T04:51:20.524758060Z [CONTAINER] org.apache.catalina.core.StandardService           INFO    Starting service Catalina
[hello-servlet] 2017-08-21T04:51:20.525311765Z [CONTAINER] org.apache.catalina.core.StandardEngine            INFO    Starting Servlet Engine: Apache Tomcat/8.0.46
[hello-servlet] 2017-08-21T04:51:20.539589930Z [CONTAINER] org.apache.catalina.startup.HostConfig             INFO    Deploying web application directory /home/vcap/app/.java-buildpack/tomcat/webapps/ROOT
[hello-servlet] 2017-08-21T04:51:20.815559712Z [CONTAINER] org.apache.jasper.servlet.TldScanner               INFO    At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
[hello-servlet] 2017-08-21T04:51:20.869397279Z [CONTAINER] org.apache.catalina.startup.HostConfig             INFO    Deployment of web application directory /home/vcap/app/.java-buildpack/tomcat/webapps/ROOT has finished in 329 ms
[hello-servlet] 2017-08-21T04:51:20.874792454Z [CONTAINER] org.apache.coyote.http11.Http11NioProtocol         INFO    Starting ProtocolHandler ["http-nio-8080"]
[hello-servlet] 2017-08-21T04:51:20.880862674Z [CONTAINER] org.apache.tomcat.util.net.NioSelectorPool         INFO    Using a shared selector for servlet write/read
[hello-servlet] 2017-08-21T04:51:20.889905003Z [CONTAINER] org.apache.catalina.startup.Catalina               INFO    Server startup in 371 ms

この例ではlocalhostの54921ポートにアクセスすると、コンテナ内の8080ポートにフォワードされます。

$ curl localhost:54921

██╗     █████╗ ███╗   ███╗    ███████╗████████╗██╗██╗     ██╗          █████╗ ████████╗    ██╗    ██╗ █████╗ ██████╗ 
██║    ██╔══██╗████╗ ████║    ██╔════╝╚══██╔══╝██║██║     ██║         ██╔══██╗╚══██╔══╝    ██║    ██║██╔══██╗██╔══██╗
██║    ███████║██╔████╔██║    ███████╗   ██║   ██║██║     ██║         ███████║   ██║       ██║ █╗ ██║███████║██████╔╝
██║    ██╔══██║██║╚██╔╝██║    ╚════██║   ██║   ██║██║     ██║         ██╔══██║   ██║       ██║███╗██║██╔══██║██╔══██╗
██║    ██║  ██║██║ ╚═╝ ██║    ███████║   ██║   ██║███████╗███████╗    ██║  ██║   ██║       ╚███╔███╔╝██║  ██║██║  ██║
╚═╝    ╚═╝  ╚═╝╚═╝     ╚═╝    ╚══════╝   ╚═╝   ╚═╝╚══════╝╚══════╝    ╚═╝  ╚═╝   ╚═╝        ╚══╝╚══╝ ╚═╝  ╚═╝╚═╝  ╚═╝

DockerイメージへExport

ここまででCloud FoundryのコンテナイメージフォーマットであるDropletファイルが作成されました。これをcf local exportコマンドでDockerイメージのフォーマットにエクスポートできます。

cf local export hello-servlet -r making/hello-servlet

making/hello-servletという名前のDockerイメージが作成できました。

$ docker images
REPOSITORY                TAG                 IMAGE ID            CREATED              SIZE
making/hello-servlet      latest              61d311f1bd06        3 seconds ago        951MB
<none>                    <none>              74a5658980c7        About a minute ago   951MB
cflocal                   latest              79e3268df4cf        5 minutes ago        953MB
cloudfoundry/cflinuxfs2   latest              a7adacf72d2a        3 days ago           893MB

もちろん、このイメージはdocker runで実行可能です。

$ docker run -p 8080:8080 making/hello-servlet
[CONTAINER] org.apache.coyote.http11.Http11NioProtocol         INFO    Initializing ProtocolHandler ["http-nio-8080"]
[CONTAINER] org.apache.catalina.startup.Catalina               INFO    Initialization processed in 416 ms
[CONTAINER] org.apache.catalina.core.StandardService           INFO    Starting service Catalina
[CONTAINER] org.apache.catalina.core.StandardEngine            INFO    Starting Servlet Engine: Apache Tomcat/8.0.46
[CONTAINER] org.apache.catalina.startup.HostConfig             INFO    Deploying web application directory /home/vcap/app/.java-buildpack/tomcat/webapps/ROOT
[CONTAINER] org.apache.jasper.servlet.TldScanner               INFO    At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
[CONTAINER] org.apache.catalina.startup.HostConfig             INFO    Deployment of web application directory /home/vcap/app/.java-buildpack/tomcat/webapps/ROOT has finished in 410 ms
[CONTAINER] org.apache.coyote.http11.Http11NioProtocol         INFO    Starting ProtocolHandler ["http-nio-8080"]
[CONTAINER] org.apache.tomcat.util.net.NioSelectorPool         INFO    Using a shared selector for servlet write/read
[CONTAINER] org.apache.catalina.startup.Catalina               INFO    Server startup in 458 ms
$ curl localhost:8080

██╗     █████╗ ███╗   ███╗    ███████╗████████╗██╗██╗     ██╗          █████╗ ████████╗    ██╗    ██╗ █████╗ ██████╗ 
██║    ██╔══██╗████╗ ████║    ██╔════╝╚══██╔══╝██║██║     ██║         ██╔══██╗╚══██╔══╝    ██║    ██║██╔══██╗██╔══██╗
██║    ███████║██╔████╔██║    ███████╗   ██║   ██║██║     ██║         ███████║   ██║       ██║ █╗ ██║███████║██████╔╝
██║    ██╔══██║██║╚██╔╝██║    ╚════██║   ██║   ██║██║     ██║         ██╔══██║   ██║       ██║███╗██║██╔══██║██╔══██╗
██║    ██║  ██║██║ ╚═╝ ██║    ███████║   ██║   ██║███████╗███████╗    ██║  ██║   ██║       ╚███╔███╔╝██║  ██║██║  ██║
╚═╝    ╚═╝  ╚═╝╚═╝     ╚═╝    ╚══════╝   ╚═╝   ╚═╝╚══════╝╚══════╝    ╚═╝  ╚═╝   ╚═╝        ╚══╝╚══╝ ╚═╝  ╚═╝╚═╝  ╚═╝

そして、docker pushでDocker Registryへデプロイします。

docker push making/hello-servlet

k8sへのデプロイ

Docker Registryにデプロイした後は、普通にk8sにデプロイできます。

$ kubectl run hello-servlet --image=making/hello-servlet --port=8080
deployment "hello-servlet" created

$ kubectl expose deployment hello-servlet --type=NodePort
service "hello-servlet" exposed

$ kubectl get service hello-servlet -o wide
NAME            CLUSTER-IP   EXTERNAL-IP   PORT(S)          AGE       SELECTOR
hello-servlet   10.0.0.61    <nodes>       8080:32271/TCP   20s       run=hello-servlet

$ curl `minikube ip`:32271

██╗     █████╗ ███╗   ███╗    ███████╗████████╗██╗██╗     ██╗          █████╗ ████████╗    ██╗    ██╗ █████╗ ██████╗
██║    ██╔══██╗████╗ ████║    ██╔════╝╚══██╔══╝██║██║     ██║         ██╔══██╗╚══██╔══╝    ██║    ██║██╔══██╗██╔══██╗
██║    ███████║██╔████╔██║    ███████╗   ██║   ██║██║     ██║         ███████║   ██║       ██║ █╗ ██║███████║██████╔╝
██║    ██╔══██║██║╚██╔╝██║    ╚════██║   ██║   ██║██║     ██║         ██╔══██║   ██║       ██║███╗██║██╔══██║██╔══██╗
██║    ██║  ██║██║ ╚═╝ ██║    ███████║   ██║   ██║███████╗███████╗    ██║  ██║   ██║       ╚███╔███╔╝██║  ██║██║  ██║
╚═╝    ╚═╝  ╚═╝╚═╝     ╚═╝    ╚══════╝   ╚═╝   ╚═╝╚══════╝╚══════╝    ╚═╝  ╚═╝   ╚═╝        ╚══╝╚══╝ ╚═╝  ╚═╝╚═╝  ╚═╝

Buildpackの更新

デフォルトのBuildpackのバージョンはCF Local Pluginに依存するため、Buildpackのバージョンを更新したい場合は、-bで明示する必要があります。
Java Buildpackのバージョンを、執筆時点で最新の4.5にあげてみます。

$ cf local stage hello-servlet -p ./target/ROOT.war -b https://github.com/cloudfoundry/java-buildpack.git#v4.5
Buildpack: https://github.com/cloudfoundry/java-buildpack.git#v4.5             
[hello-servlet] 2017-08-21T05:23:44.725841336Z -----> Java Buildpack v4.5 | https://github.com/cloudfoundry/java-buildpack.git#36205c5
[hello-servlet] 2017-08-21T05:23:45.153024223Z -----> Downloading Jvmkill Agent 1.10.0_RELEASE from https://java-buildpack.cloudfoundry.org/jvmkill/trusty/x86_64/jvmkill-1.10.0_RELEASE.so (0.2s)
[hello-servlet] 2017-08-21T05:23:45.201490613Z -----> Downloading Open Jdk JRE 1.8.0_141 from https://java-buildpack.cloudfoundry.org/openjdk/trusty/x86_64/openjdk-1.8.0_141.tar.gz (found in cache)
[hello-servlet] 2017-08-21T05:23:46.099868077Z        Expanding Open Jdk JRE to .java-buildpack/open_jdk_jre (0.8s)
[hello-servlet] 2017-08-21T05:23:46.937437172Z -----> Downloading Open JDK Like Memory Calculator 3.9.0_RELEASE from https://java-buildpack.cloudfoundry.org/memory-calculator/trusty/x86_64/memory-calculator-3.9.0_RELEASE.tar.gz (0.8s)
[hello-servlet] 2017-08-21T05:23:47.235578582Z        Loaded Classes: 9742, Threads: 300
[hello-servlet] 2017-08-21T05:23:47.359764715Z -----> Downloading Client Certificate Mapper 1.2.0_RELEASE from https://java-buildpack.cloudfoundry.org/client-certificate-mapper/client-certificate-mapper-1.2.0_RELEASE.jar (0.1s)
[hello-servlet] 2017-08-21T05:23:47.416043793Z -----> Downloading Container Security Provider 1.8.0_RELEASE from https://java-buildpack.cloudfoundry.org/container-security-provider/container-security-provider-1.8.0_RELEASE.jar (found in cache)
[hello-servlet] 2017-08-21T05:23:48.042413872Z -----> Downloading Tomcat Instance 8.5.20 from https://java-buildpack.cloudfoundry.org/tomcat/tomcat-8.5.20.tar.gz (0.6s)
[hello-servlet] 2017-08-21T05:23:48.153498196Z        Expanding Tomcat Instance to .java-buildpack/tomcat (0.1s)
[hello-servlet] 2017-08-21T05:23:48.211211569Z -----> Downloading Tomcat Access Logging Support 3.0.0_RELEASE from https://java-buildpack.cloudfoundry.org/tomcat-access-logging-support/tomcat-access-logging-support-3.0.0_RELEASE.jar (found in cache)
[hello-servlet] 2017-08-21T05:23:48.253126051Z -----> Downloading Tomcat Lifecycle Support 3.0.0_RELEASE from https://java-buildpack.cloudfoundry.org/tomcat-lifecycle-support/tomcat-lifecycle-support-3.0.0_RELEASE.jar (found in cache)
[hello-servlet] 2017-08-21T05:23:48.300813949Z -----> Downloading Tomcat Logging Support 3.0.0_RELEASE from https://java-buildpack.cloudfoundry.org/tomcat-logging-support/tomcat-logging-support-3.0.0_RELEASE.jar (found in cache)
Successfully staged: hello-servlet

これでソースコードや設定ファイルを変更することなく、イメージが更新され、Tomcatが8.5系に上がりました。また、JVMのMemory Calculatorの仕様も変わりました
メモリ設定をBuildpackにお任せできて楽です。k8sにJavaアプリケーションをデプロイする場合も、Buildpackの恩恵に与ることができます。

$ cf local run hello-servlet
Running hello-servlet on port 55383...                                         
[hello-servlet] 2017-08-21T05:25:36.151338888Z JVM Memory Configuration: -XX:CompressedClassSpaceSize=15326K -Xss1M -Xmx394118K -XX:MaxDirectMemorySize=10M -XX:MaxMetaspaceSize=75931K -XX:ReservedCodeCacheSize=240M
[hello-servlet] 2017-08-21T05:25:36.663399060Z [CONTAINER] org.apache.coyote.http11.Http11NioProtocol         INFO    Initializing ProtocolHandler ["http-nio-8080"]
[hello-servlet] 2017-08-21T05:25:36.674031978Z [CONTAINER] org.apache.catalina.startup.Catalina               INFO    Initialization processed in 373 ms
[hello-servlet] 2017-08-21T05:25:36.681052927Z [CONTAINER] org.apache.catalina.core.StandardService           INFO    Starting service [Catalina]
[hello-servlet] 2017-08-21T05:25:36.681435114Z [CONTAINER] org.apache.catalina.core.StandardEngine            INFO    Starting Servlet Engine: Apache Tomcat/8.5.20
[hello-servlet] 2017-08-21T05:25:36.709458734Z [CONTAINER] org.apache.catalina.startup.HostConfig             INFO    Deploying web application directory [/home/vcap/app/.java-buildpack/tomcat/webapps/ROOT]
[hello-servlet] 2017-08-21T05:25:37.030274533Z [CONTAINER] org.apache.jasper.servlet.TldScanner               INFO    At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
[hello-servlet] 2017-08-21T05:25:37.097099849Z [CONTAINER] org.apache.catalina.startup.HostConfig             INFO    Deployment of web application directory [/home/vcap/app/.java-buildpack/tomcat/webapps/ROOT] has finished in [387] ms
[hello-servlet] 2017-08-21T05:25:37.101279358Z [CONTAINER] org.apache.coyote.http11.Http11NioProtocol         INFO    Starting ProtocolHandler ["http-nio-8080"]
[hello-servlet] 2017-08-21T05:25:37.110166410Z [CONTAINER] org.apache.tomcat.util.net.NioSelectorPool         INFO    Using a shared selector for servlet write/read
[hello-servlet] 2017-08-21T05:25:37.126321558Z [CONTAINER] org.apache.catalina.startup.Catalina               INFO    Server startup in 451 ms

CF Local PluginはもともとはCloud Foundryを使った開発において、ローカル環境でのイテレーションを円滑に行うためのプラグインですが、
これを使って、Dockerfileを作ることなくBuildpackからDockerイメージを作成し、k8sにデプロイできることを確認しました。

CF Local Pluginはまだ、Stephen Levineさんの個人プロジェクト扱いですが、Cloud Foundry Summit 2017のKeynoteで紹介されていたので、
Cloud Foundry公式プロジェクトになることを期待しています。

このエントリーをはてなブックマークに追加