Kekeの日記

エンジニア、読書なんでも

Dockerコンテナの脆弱性、コストを抑えてパフォーマンスを上げるBuilding Small Containers

f:id:bobchan1915:20181004230126p:plain

本記事

以下のようになんとなくコンテナイメージを使っていませんか。

FROM golang:1.9

...

しかし、これはセキュリティ的に脆弱性をアプリケーションに持ち込むだけでなく。Google Cloud Registryを使っているならコストがより多くかかるなどいいことがないので、今回はベストプラクティスとしてDockerコンテナイメージの作り方を紹介しようと思います。

目次

Building Small Containers

コンテナのボリュームの違い

たとえばGolangだと以下のようなtagで用意されています。

f:id:bobchan1915:20181003135717p:plain

実際に1.111.11-strech1.11-aplineをpullしてみます。

確認すると以下のようになっています。

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
golang              1.11-alpine         95ec94706ff6        12 hours ago        310MB
golang              1.11                be13d0c67b75        12 hours ago        777MB
golang              1.11-stretch        be13d0c67b75        12 hours ago        777MB

このように同じバージョンでもコンテナサイズが異なることがわかります。

セキュリティの脆弱性

デフォルトのgolang:1.11やこれにポインタをもつgolang:latestは大きな容量です。

アプリケーションの大きなはせいぜい数MBですから、セキュリティの脆弱性やバグが紛れ込みやすくなります。

小さなイメージにする方法

以下の二つの方法でイメージの小型化します。

1. 小さなイメージを使う方法

例えばNode.jsだとさらに顕著になります。

f:id:bobchan1915:20181003140953p:plain

しかし、コードを入れて、依存環境をインストールしなければならないですが、あまり難しい作業ではありません。

2. Builderパターンを使う

コンパイル型言語では、コンパイル済みコードに変換されます。

f:id:bobchan1915:20181003141232p:plain

コンテナ内でコンパイルするとコンパイラなど余分なものがあります。

以下のようなBuilderパターンと呼ばれるようなパターンを使って小型化をすることができます。

f:id:bobchan1915:20181003141351p:plain

2.1 ビルドコンテナ

まず、ビルドコンテナを用意します。

ここではユニットテスト、コンパイラ、開発のための依存関係のためのツールを持ちます。

コンパイルしたものをランタイムコンテナに格納します。

まず、以下のようなコンテナをつくります。

2.2 ランタイムコンテナ

実際にプロダクションで使われるコンテナのことです。

コンパイル済みのコンテナしかありません。

2.3 実際のDockerfile

以下のようなアプリケーションを書いているかもしれません。

FROM golang:1.8-apline
LABEL MAINTAINER=KeisukeYamashita

WORKDIR /app
ADD . ./app
RUN cd /app && go build -o goapp

EXPOSE 8080

CMD ["./goapp"]

これをBuilderパターンに合致させます。

FROM golang:1.8-apline AS build-env
LABEL MAINTAINER=KeisukeYamashita

WORKDIR /app
ADD . ./app
RUN cd /app && go build -o goapp

FROM alpine
RUN apk update && apk add ca -
WORKDIR /app
COPY --from=build-env /app/goapp /app

EXPOSE 8080
ENTRYPOINT ./goapp

二つ目のFROMはlinuxはaplineであります。

これによって最後のFROMで構成されているコンテナで構築することもできます。

Small Imageの恩恵

1. パフォーマンス

以下の項目でパフォーマンスの向上が見られた。

例: 項目: B:Big Imageでの値 S: Small Imageでの値

  • ビルド時間: B: 54s S: 28s
  • Push時間: B: 48s S: 16s
  • Pull時間: B:52s S: 6s

これによってGoogle Cloud EngineやKubernetesのデプロイメントタイムを大幅に向上することができる。

2. セキュリティ

一般的には小さいイメージの方が脆弱性は低いことが知られている。

Google Cloud Registryでは自動的にコンテナの脆弱性をスキャンしてくれる。

3. コスト

3.1 Cloud Container Registry

以下が公式ページです。

Container Registry の料金  |  Container Registry  |  Google Cloud

システムによって Cloud Storage バケットが作成され、すべてのイメージが保存されます。このストレージに対して料金が課金されます。

また、Container Registry ストレージ バケットに使用されるデフォルトの Cloud Storage クラスは、Multi-Regional であり、Multi-Regional バケットの月額料金は、約 $0.026/GB です。

容量が小さければ小さいほどStorageコストが抑えられることがわかります。

3.2 Cloud Builder

2節でビルド時間が大幅に小さくなることがわかりました。

1日あたり120分のビルドまでは無料です。

しかし、それを超過するとビルド時間に対して$0.0034/ビルド分だけお金がかかってしまいます。

この様にビルド時間を削減できると、コストを抑えられることができます。

まとめ

Small Imageにするしかないし、今までしてこなかった自分に反省です。

参考文献

www.youtube.com