DockerイメージはDistrolessを使えということだったので

じゃあ具体的にどうする?どうした?っていう話。
言語はNode.js.



変更前のDockerfile(alpine)



FROM node:12-alpine
COPY example /example
COPY app.js .
COPY package*.json ./
RUN apk add git
RUN npm install --production
RUN apk update \
  && apk add --no-cache curl fontconfig \
  && curl -O https://noto-website.storage.googleapis.com/pkgs/NotoSansCJKjp-hinted.zip \
  && mkdir -p /usr/share/fonts/NotoSansCJKjp \
  && unzip NotoSansCJKjp-hinted.zip -d /usr/share/fonts/NotoSansCJKjp/ \
  && rm NotoSansCJKjp-hinted.zip \
  && fc-cache -fv

EXPOSE 3000

CMD node app.js

実際に運用する場合あまりシンプルなDockerfileにはならないんじゃないだろうか?
上記例だとnode_moduleにgitに依存しているものがある + 実行に日本語フォントが必要で追加でインストールしている。


変更前のDockerfile(distroless)



FROM node:12 as builder
WORKDIR /work
COPY example /example
COPY app.js .
COPY package*.json ./
RUN npm install
RUN apt-get update \
  && apt-get install curl fontconfig \
  && curl -O https://noto-website.storage.googleapis.com/pkgs/NotoSansCJKjp-hinted.zip \
  && mkdir -p /usr/share/fonts/NotoSansCJKjp \
  && unzip NotoSansCJKjp-hinted.zip -d /usr/share/fonts/NotoSansCJKjp/ \
  && rm NotoSansCJKjp-hinted.zip \
  && fc-cache -fv

FROM gcr.io/distroless/nodejs:12
COPY example /example
COPY app.js .
COPY package*.json ./
COPY --from=builder /work/node_modules /node_modules
COPY --from=builder /usr/share/fonts/NotoSansCJKjp /usr/share/fonts/NotoSansCJKjp

EXPOSE 3000

CMD ["app.js"]


distrolessはShellやaptなどがないため追加でモジュールのインストール等が出来ない(正確には出来ないこともないかもしれないが面倒)
マルチステージビルドを使用してビルド後の必要なファイルをコピーするといったアプローチを取る。
マルチステージビルドについて少しざっくり説明するとas hogehogeで名前を付けたDockerイメージは後で使用することができる。最終的なイメージサイズには影響がない。
COPY --from=builder builderのパス 実行環境のパスでコピーができる。

最初ビルド用のDockerをnode:12-alpineにしていたがどうもdistrolessとベースイメージが異なるらしく(互換性がない)場合によっては実行時にエラーになる。
具体的にはSharpでエラーが発生した。
Error: 'linuxmusl-x64' binaries cannot be used on the 'linux-x64' platform. Please remove the 'node_modules/sharp' directory and run 'npm install' on the 'linux-x64' platform.

node:12-alpine → node:12に変更した場合、apkをaptに変更する必要がある(gitはデフォルトで入っているらしい)
CMDはデフォルトでnode.jsなのでアプリの起動はファイル名を指定するだけで良い。CMD node app.js は動作しない。


ビルドイメージのサイズについて



node:12-alpine+α
214MB
↓
gcr.io/distroless/nodejs:12 
221MB
それなりに増えると思っていたが思ったほどでもなかった。
対応が面倒で放置していた軽微なセキュリティリスクも0件になっている。



参考


https://blog.inductor.me/entry/alpine-not-recommended

2021年3月10日水曜日