docker-compose で複数サービスを起動する際に時間を要するのが、Docker イメージのダウンロードと展開です。この時間を削減するために、ベースイメージを共通化する方法を試してみました。
本エントリでは、開発環境や CI 環境に docker-compose を利用することを想定しています。
改善前
ここでは、dokcer-compose up(pull) の時間を削減できるかを確認するだけなので、下記のように dynamodb, elasticmq, elasticsearch のみを docker-compose.yml に含めています。
version: "2.0" services: dynamodb: image: amazon/dynamodb-local:1.12.0 ports: - 8000:8000 elasticmq: image: softwaremill/elasticmq:0.15.7 ports: - 9324:9324 elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:7.6.2 environment: - discovery.type=single-node ports: - 9200:9200
この docker-compose.yml を CircleCI で起動すると、55s を要します。
問題点
上記の 3 イメージは別々のベースイメージからビルドされており、それぞれ別のレイヤを持ちます。つまり、docker-compose up 実行時には全てのレイヤをダウンロードし、さらに展開する必要があります。この処理に時間を要するので、削減します。
$ docker inspect -f '{{json .RootFS.Layers}}' amazon/dynamodb-local:1.12.0 | jq . [ "sha256:9a1290d6039b7d2456bc035d687e9753e85b78647095a2f43f882b2975b20a0b", "sha256:7ca537ddeb95cbd49208e26cbb64225b915c39cf7b94ba210fe3ed5a6da9339d", "sha256:7d832d77ed1b80c4d3ccb546cf8488df25e8b7a6ea7985e6f5655e2a6f43a3c8" ]
$ docker inspect -f '{{json .RootFS.Layers}}' softwaremill/elasticmq:0.15.7 | jq . [ "sha256:e2a8a00a83b20c88b81952f81e6cfc2e2dd5aa7f00a23b067e6342c70602a567", "sha256:15210a41d4ee66fef9f6917804a00d44f72517c8ed8feee1c97e08a35be52ad6", "sha256:392f356944ff70fa41f6dbf6e6d207beef060f0869e584edb58ca8cd343b341f", "sha256:a4e797bc3f155d8be8dcd6bb565fb41e07cc4febdba63efdf7a8dcb6ac10444e", "sha256:c6465287316203e0732c16b7a1834a28e1fd5a3916789f18f72dba74aea151cd", "sha256:7955da51da828051722b0bbdcba0307130e064f518cf341b4cf8caa748c8aede", "sha256:a4e7d1c2f08d0d8420a077c391372e7a366cbe3d2cc78f095950ebaba64ec9e1", "sha256:4861ed836e7651a543d3fbf2ee5de5f15acc40a881eecbfa3d31c41b8d2fbd5c", "sha256:68e8576c229676e395ba11c57c45d0068e8f67fd362ed693c5add5b941862eab", "sha256:a6a7b41a96061209ee4548cb012c0bffd2c39f26cad80ee47fb70a63f8fdbe09", "sha256:9e4f8dd8b1f3573419b6e7b41d44522c2a6a56298a19ddea3b94d2daf3fb137a", "sha256:c08329398ff9d7d02d65945c4e8a70f715e3fe102b2d0612a6195bdc3528ef44", "sha256:be3f840efe299226b292a3ec70b28faa31f9fe93609616b6d5ca5469a8e4915f" ]
$ docker inspect -f '{{json .RootFS.Layers}}' docker.elastic.co/elasticsearch/elasticsearch:7.6.2 | jq . [ "sha256:77b174a6a187b610e4699546bd973a8d1e77663796e3724318a2a4b24cb07ea0", "sha256:7712f32688d1bef330aa3b4fac2683cec1d7339335ce403483b329423debffb6", "sha256:1a090720e70c88e61053c89d3ff01932943b198644f4a7e86426e576b721d2e3", "sha256:0535424758bd9ab49a3d03af52a9fa5447b807198fadc35e9f80123a0929402e", "sha256:4d2f8f4a58623431cca0ee321bbee273b87070f9e381b3147e4293e83dc146d7", "sha256:77c5267605c2c7cf2426242d5df50af78931e66403e9d0d06f2b9fd7adc3adc9", "sha256:537370aeea86be07f79bbcd25464a1df23f347bb5313e0ff7ca15d6aad70e074" ]
改善案
今回起動するサービスはいずれも JVM で実行するものなので、OS と JVM 環境を含む同一のイメージをベースに利用し、その上に個別に必要な内容を含めるようにします。
ベースイメージ
ベースイメージは、OS と JVM 環境を含む adoptopenjdk:8-jre-hotspot
イメージを利用します。
https://hub.docker.com/_/adoptopenjdk
各サービスイメージ
各サービスでは、ベースイメージを FROM で指定し、必要な内容を追加します。
- dynamodb - Dockerfile
FROM adoptopenjdk:8-jre-hotspot RUN mkdir /opt/dynamodb \ && cd /opt/dynamodb \ && curl -O https://s3.ap-northeast-1.amazonaws.com/dynamodb-local-tokyo/dynamodb_local_latest.tar.gz \ && tar zxvf dynamodb_local_latest.tar.gz \ && rm dynamodb_local_latest.tar.gz WORKDIR /opt/dynamodb ENTRYPOINT ["java"] CMD ["-Djava.library.path=./DynamoDBLocal_lib", "-jar", "DynamoDBLocal.jar", "-inMemory"]
- elasticmq - Dockerfile
FROM adoptopenjdk:8-jre-hotspot RUN mkdir /opt/elasticmq \ && cd /opt/elasticmq \ && curl -o elasticmq-server.jar https://s3-eu-west-1.amazonaws.com/softwaremill-public/elasticmq-server-0.15.7.jar ADD custom.conf /opt/elasticmq/custom.conf WORKDIR /opt/elasticmq ENTRYPOINT ["java"] CMD ["-Dconfig.file=custom.conf", "-jar", "elasticmq-server.jar"]
elasticmq - custom.conf
include classpath("application.conf")
- elasticsearch - Dockerfile
FROM adoptopenjdk:8-jre-hotspot RUN mkdir -p /opt \ && cd /opt \ && curl -L -o elasticsearch.tar.gz https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.6.2-linux-x86_64.tar.gz \ && tar zxvf elasticsearch.tar.gz \ && rm -f elasticsearch.tar.gz \ && mv elasticsearch-7.6.2 elasticsearch \ && chown -R nobody elasticsearch USER nobody WORKDIR /opt/elasticsearch ENTRYPOINT ["./bin/elasticsearch"] CMD []
それぞれのイメージは docker build でビルドして、Docker Hub 等の Docker Registry に push しておきます。push したイメージのサンプルは下記です。
- https://hub.docker.com/r/shin1x1/test-elasticmq
- https://hub.docker.com/r/shin1x1/test-dynamodb
- https://hub.docker.com/r/shin1x1/test-elasticsearch
docker-compose.yml の変更
docker-compose.yml ではビルドしたイメージを利用するように変更します。
version: "2.0" services: dynamodb: image: shin1x1/test-dynamodb ports: - 8000:8000 elasticmq: image: shin1x1/test-elasticmq ports: - 9324:9324 elasticsearch: image: shin1x1/test-elasticsearch environment: - discovery.type=single-node ports: - 9200:9200
結果
この改善策にて、docker-compose up を実行すると、25s に短縮できました。つまり、30s 短縮できました。
ビルドしたイメージのレイヤを確認すると、3 つのイメージで上から 6 つのレイヤ(b7f7d2967507ba709dbd1dd0426a5b0cdbe1ff936c131f8958c8d0f910eea19e
から 105be441f2caa7d1b332f89e227cabd6652dc9257174735562c9e76c93d1632b
)が一致していることが分かります。
$ docker inspect -f '{{json .RootFS.Layers}}' shin1x1/test-dynamodb | jq . [ "sha256:b7f7d2967507ba709dbd1dd0426a5b0cdbe1ff936c131f8958c8d0f910eea19e", <--- "sha256:a6ebef4a95c345c844c2bf43ffda8e36dd6e053887dd6e283ad616dcc2376be6", <--- "sha256:838a37a24627f72df512926fc846dd97c93781cf145690516e23335cc0c27794", <--- "sha256:28ba7458d04b8551ff45d2e17dc2abb768bf6ed1a46bb262f26a24d21d8d7233", <--- "sha256:55c91231ac46fdd63c3cf84b88b11f8a04c1870482dcff033029a601bc50e1ab", <--- "sha256:105be441f2caa7d1b332f89e227cabd6652dc9257174735562c9e76c93d1632b", <--- "sha256:ecf2bae03f590766d77542cc1aa36603c4af4a61dc88786cbfe8974d05ca98eb" ]
$ docker inspect -f '{{json .RootFS.Layers}}' shin1x1/test-elasticmq | jq . [ "sha256:b7f7d2967507ba709dbd1dd0426a5b0cdbe1ff936c131f8958c8d0f910eea19e", <--- "sha256:a6ebef4a95c345c844c2bf43ffda8e36dd6e053887dd6e283ad616dcc2376be6", <--- "sha256:838a37a24627f72df512926fc846dd97c93781cf145690516e23335cc0c27794", <--- "sha256:28ba7458d04b8551ff45d2e17dc2abb768bf6ed1a46bb262f26a24d21d8d7233", <--- "sha256:55c91231ac46fdd63c3cf84b88b11f8a04c1870482dcff033029a601bc50e1ab", <--- "sha256:105be441f2caa7d1b332f89e227cabd6652dc9257174735562c9e76c93d1632b", <--- "sha256:3d77653fa44c3b902d9c8d107493b5277f59b88b152a904174f9324c2489d40c", "sha256:b090447c7a50d5fe331abc7aef4fd6d81a2722342408444a98ca2d5e82cc21af" ]
$ docker inspect -f '{{json .RootFS.Layers}}' shin1x1/test-elasticsearch | jq . [ "sha256:b7f7d2967507ba709dbd1dd0426a5b0cdbe1ff936c131f8958c8d0f910eea19e", <--- "sha256:a6ebef4a95c345c844c2bf43ffda8e36dd6e053887dd6e283ad616dcc2376be6", <--- "sha256:838a37a24627f72df512926fc846dd97c93781cf145690516e23335cc0c27794", <--- "sha256:28ba7458d04b8551ff45d2e17dc2abb768bf6ed1a46bb262f26a24d21d8d7233", <--- "sha256:55c91231ac46fdd63c3cf84b88b11f8a04c1870482dcff033029a601bc50e1ab", <--- "sha256:105be441f2caa7d1b332f89e227cabd6652dc9257174735562c9e76c93d1632b", <--- "sha256:136ecb5b062dfe72bade3a1467843f092f76c8cbec1c7b3ca8d84b34264e5848" ]
イメージサイズの変化
3 イメージサイズは、改善前と改善後で以下のようになりました。
- 改善前: 1,923MB(3イメージ合算。)
- 改善後: 758MB(3イメージ合算。重複分は除外。)
- 差分: -1,165MB
差分のうち、512MB がベースイメージを共通化して削減した分です(206MB*2)。残りの 653MB は、イメージを自作し、内容を必要最低限なものに絞ったことで削減できました。これは特に、dynamodb と elasticmq で顕著で、両イメージではそれぞれ 383MB、283MB をカットしています。
直接的にベースイメージの共通化だけが削減の要因ではありませんが、イメージサイズを減らすことで docker-compose up の起動時間が短縮できることがあらためて実感できました。
改善前
Service | Image | Size |
---|---|---|
dynamodb | amazon/dynamodb-local | 611 MB |
elasticmq | softwaremill/elasticmq | 521 MB |
elasticsearch | docker.elastic.co/elasticsearch/elasticsearch | 791 MB |
計 | 1923 MB |
改善後
Service | Image | Size | 改善前との差分 |
---|---|---|---|
dynamodb | shin1x1/test-dynamodb | 228 MB | -383MB |
elasticmq | shin1x1/test-elasticmq | 238 MB | -283MB |
elasticsearch | shin1x1/test-elasticsearc | 704 MB | -87MB |
重複分を削除 | adoptopenjdk:8-jre-hotspot(206MB) * 2 | -512 MB | |
Total | 758 MB | -1165MB |
さいごに
30s 短縮の効果をどう見るかは状況によるでしょう。
改善前、改善後にはそれぞれ pros/cons があり、改善前は実行時間はかかりますが、公開されているイメージをそのまま利用するので構築は容易です。さらにイメージのメンテナンスも不要です。一方、改善後は実行時間はかかりますが、イメージの構築、メンテナンスが必要になります。
どちらを選ぶかは状況によりますが、改善できる方法を知っておくのは大切ですね。