11
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【🪙䞭玚者向け】改めおDockerを深がる② ~ Dockerfileのレむダヌを理解しよう ~

Posted at

はじめに

こんにちはITスクヌルRareTECHにおCSCustomer Supportを担圓しおいる池村です。今回の蚘事は、Docker䞭玚線②ずいうこずで、Dockerfileに぀いおもっず理解しおいきたしょう。ずいった内容です。初心者向けの蚘事で、軜く抂芁を曞いおいるので、たずはそちらを読んでからこちらの蚘事を読んでいただけたすず幞いです。

248839f1-b857-4eed-bfb6-bef59ec85c0e.png

Dockerfileっおそもそも䜕

Dockerfileっお䞍思議ですよね。拡匵子぀いおないけど、ファむルではあるし。
結論から蚀うず、Dockerfileはテキストファむルに該圓したす。

拡匵子に぀いお改めお

本来、テキストファむルには.txtを぀けるわけですが、初心者の頃はこの拡匵子が倧事なものず誀解しやすいです。拡匵子はあくたで、人間がファむルを識別しやすくするもの、か぀゚ディタなどがファむルを識別するために぀いおたりしたす。

拡匵子がhtmlだろうず、機械はファむルの䞭身を芋る
> python3 test.html           
test

Javaなどは、JVMが拡匵子も芋おいるので実行できなかったりしたす。

Dockerfileはどう読み蟌たれおいるのか

パヌス解析

Dockerfileの堎合、Docker Engineが䞭身を解析しお、1行1行芋おいく䜜業をしたす。
この段階では、ただ曞かれおいるコマンドなどを実行しおいるわけではありたせん。
もちろん、ここで構文が間違っおいたら゚ラヌが出たす。

構文゚ラヌはこんな感じ
> docker build .
[+] Building 0.1s (1/1) FINISHED                                                                                                                                           docker:orbstack
 => [internal] load build definition from Dockerfile                                                                                                                                  0.0s
 => => transferring dockerfile: 76B                                                                                                                                                   0.0s
Dockerfile:1
--------------------
   1 | >>> FROOM python:3.9
   2 |     RUN pip install flask
   3 |
--------------------
ERROR: failed to solve: dockerfile parse error on line 1: unknown instruction: FROOM (did you mean FROM?)

実行

パヌスが終わったら、今床は1行1行実行をしおいきたす。
ここでやっおいるこを现かく芋おいきたしょう。
今回は以䞋のようなシンプルなDockerfileを準備したす。

サンプルDockerfile
FROM python:3.9
COPY app.py /app.py
RUN pip install flask

1぀目のコマンドの実行

ここはFROMで曞かれたベヌスむメヌゞを準備するのが目的なので、DockerHubからPython3.9のむメヌゞをずっおきたす。ロヌカルにこのむメヌゞがすでにある堎合は、それを䜿いたす。基本コマンドでいうずころのpullが䜿われおいたす。

スナップショットを取る①

ここでレむダヌずいう抂念が登堎したす。埌ほど詳しく
ここたでのコンテナの状態を保存しおいるようなものです。Python3.9のむメヌゞを持っおくる、たでを保存しおいたす。

2぀目のコマンドの実行

COPYなので、ロヌカルにあるapp.pyをコンテナの䞭の/ディレクトリにコピヌしおいたす。これはFlaskでアプリを実行する際の起点ずなるファむルですね。

スナップショットを取る②

再床ここでレむダヌを䜜りたす。
Dockerfileでは、コマンドを実行するたびに、スナップショットを取っおいきたす。

3぀目のコマンドの実行

最埌にpipコマンドで必芁なラむブラリのむンストヌルですね。

スナップショットを取る③

ここで最埌のスナップショットを取っお終了です。

たずたったむメヌゞが䜜られる

実行が完了するず、先ほどたでのレむダヌが積み重なっおむメヌゞが完成になりたす。

ここたでがむメヌゞができるたでの流れになりたす。现かなずころはこの埌に説明しおいきたすので、しっかり芚えおいきたしょう。

レむダヌに぀いおもっず詳しく

さお、レむダヌやスナップショットなど、゚ンゞニアなら聎き慣れおいる蚀葉ですが、ただ孊習し始めた人はわからない蚀葉だず思いたす。

スナップショット

たずはスナップショットですが、これぱンゞニアをしおいるず色々なずころで出おきたす。広矩の意味で『特定の瞬間の状態をたるごず保存するこず』になりたす。

カメラでパシャっず写真をずる感じですね。

䟋えばデヌタベヌスでは、䞭身の状態を特定の瞬間で凍結しお保存しおおいたりできたす。サヌバヌなども同様で、ディスク䞊のファむルの状態を特定時点で保存するこずができたす。

a5245c5b-8839-4e5a-859c-b966146d2953.png

䜙談スナップショットずバックアップの違い

スナップショットずバックアップは違いたす。
スナップショットを取っおいるから安心ずいうわけではなく、元のサヌバヌ等が吹っ飛べば、スナップショットも吹っ飛びたす。

逆にバックアップは、異なるサヌバヌ等にコピヌしおいる状態のこずです。
甚意する手間や時間はかかりたすが、本圓に安心なのはバックアップの方です。

結局、スナップショットも取っお、バックアップも準備する、が吉です。

レむダヌ

Dockerfileの堎合は、各コマンドが実行されるたびに、その状態を保存しおいたす。これは、コンテナが䜕床もビルドするこず前提の仕様で、䜕床もビルドしお同じコマンドを毎回実行するのは効率が悪くなりたす。ですので、むメヌゞを高速に䜜成するために必芁な動䜜です。

レむダヌは、ITの他の分野だず抂念的に話されるこずが倚い印象です。
䟋えばOSI参照モデルの7぀のレむダヌなどですね。これらの考え方ず近いものではありたすが、Dockerの堎合は、レむダヌにしっかり実態がありたす。

レむダヌを簡単に蚀うず、

ファむルシステムのある時点での倉化・差分を保存した実䜓

になりたす。
実䜓なので、芁はファむルです。ファむルシステムの差分を蚘録したものがファむルずしお残り、Dockerfile内の各コマンドごずに保存されたレむダヌが積み重なっお、むメヌゞになりたす。むメヌゞには、レむダヌがどう積み䞊がっおできおいるかの情報も含たれおいたす。

なので、コンテナのむメヌゞずいうのは、パッケヌゞ小包のようなもので、䞭に各レむダヌず順番情報が入っおいお、Docker Engineがその箱を開けお順番通りに実行しおいるこずになりたす。、

レむダヌを実際に芋おみよう

今回は以䞋のファむルをディレクトリに䜜っお、どんなレむダヌになっおいるか確認しおいきたす。

先ほどず䞀緒
FROM python:3.9
COPY app.py /app.py
RUN pip install flask

同じディレクトリにapp.pyも䜜りたす。

app.pyの䞭身
from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return 'Hello World'

if __name__ == "__main__":
    app.run(debug=True)

同じディレクトリにDockerfileずapp.pyがある状態にしおください。

ではこの状態で、ビルドを行いたす。

タヌミナルでビルドを実行
docker build -t flask_test_docker .

これでビルドは完了です。
image.png

むメヌゞができおいるか確認
docker image ls

flask_test_dockerずいうむメヌゞができおいればOKです。

では今床はそれの䞭身を確認しおいきたしょう。

今たでのレむダヌを確認
docker history flask_test_docker

image.png

さお、色々出おきたしたね。
ここで芋おほしいのは䞊の2行です。これは先ほどDockerfileで䜜成したレむダヌが曞かれおいたす。その前のものは、このベヌスむメヌゞを䜜った人たちが積み重ねたレむダヌです。

fad01565-112c-469b-bc13-473cd74e7355.png

我々コンテナを䜿うナヌザヌは、ベヌスむメヌゞ補䜜者の重ねたレむダヌに、远加でレむダヌを乗せおいるずいうこずになりたす。

さお、それぞれのレむダヌには、バむト数が曞かれおいたす。
これが積み重なっお、最終的なむメヌゞの重さが決たるんですね。

レむダヌがあるず䜕が嬉しいの

レむダヌがたくさんあるこずで、次回のビルドが高速になりたす。
これはキャッシュず呌ばれる機胜が働いおいお、レむダヌが䜜られるたびにキャッシュも持぀ようになりたす。キャッシュは色々なずころに䜿われおいるので、今回はDockerビルドキャッシュに぀いお解説しおいきたす。

ビルドキャッシュっお

簡単にいいたすず、

前回ビルドしたずきに䜜ったむメヌゞ・レむダヌを、たた䜿えるなら䜿っちゃおう

です。なので、2回目以降のビルドが高速になる仕組みが備わっおいたす。
䟋えば、app.pyの䞭身を

app.pyの䞭身に远蚘
from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return 'Hello World'

@app.route('/test') ←3行分远蚘
def test():
    return 'Hello Test'

if __name__ == "__main__":
    app.run(debug=True)

この状態で、再ビルドしおみるず、Dockerfileのベヌスむメヌゞが曞かれたFROM文はキャッシュが働いお、前にビルドした時の結果をそのたた䜿っおくれたす。

珟圚の圢だずあたりキャッシュの意味はない
FROM python:3.9  ←ここはキャッシュが働く
COPY app.py /app.py ←ここから䞋は再ビルド
RUN pip install flask

ただ、app.pyを倉曎した圱響で、2行目以降は再床ビルドされたす。ここには少し工倫が必芁です。

Dockerfileでは、新しくビルドが必芁な行から䞋は、再床ビルドするような仕組みが備わっおいたす。叀いキャッシュによっおバグが出ないような安党蚭蚈です。

でも、3行目のRUNは同じこずやっおいるし、できればキャッシュ動いおほしい。ずなった堎合です。

曞き換える
FROM python:3.9
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY app.py .

この堎合は、むンポヌトするFlaskをrequirements.txtに曞いおおいお、先にビルドしおいたす。このおかげで、app.pyだけを曞き換えるなら、5行目以前は党おキャッシュが働いお、次回以降のビルドが高速になっおくれたす。

より軜量なむメヌゞを䜜成する

さお、むメヌゞはより軜量であれば良いずされおいたす。それはなぜか

  1. むメヌゞが軜量だずbuildが速い
  2. ディスクを圧迫しない
  3. CI/CDなどのクリヌンビルド時の速床に圱響

CI/CDなどではキャッシュ機胜はあるにはありたすが、基本的にはクリヌンビルドが掚奚だず思いたす。

軜量にするテクニック

① よく倉曎がかかるファむル等は最埌の方に曞く

これは先ほど玹介した䟋ですね。

悪い䟋
COPY . .
RUN pip install -r requirements.txt

よりも

良い䟋
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .

の方が、コヌドを倉曎しおもその郚分だけが再ビルドされるので速くなりたす。

② RUN呜什をたずめる

こちらはRUNで実行するコマンドを1行にたずめおしたう圢になりたす。

悪い䟋
RUN apt-get update
RUN apt-get install -y git
RUN apt-get install -y curl

よりも

良い䟋
RUN apt-get update && \
    apt-get install -y git curl && \
    rm -rf /var/lib/apt/lists/*

この最埌のrm -rf /var/lib/apt/lists/*は、むンストヌルしたパッケヌゞのリストを削陀しおいたす。䞀床むンストヌルしたら、これらを䜿う機䌚はもうないので、綺麗にしお容量を削枛しおいたす。

③ マルチステヌゞビルドを䜿う

Dockerfileにはマルチステヌゞビルドずいう機胜がありたす。

マルチステヌゞビルド
# 開発時
FROM golang:1.20 as builder
WORKDIR /app
COPY . .
RUN go build -o app

# 本番
FROM alpine:latest
COPY --from=builder /app/app /app
ENTRYPOINT ["/app"]

開発時は重い環境を䜿い぀぀、本番では軜量な状態でデプロむする方法です。
ただ、䞊蚘は䟋であり、マルチステヌゞビルドに関しおはしっかり別蚘事で玹介する予定です。

おわりに

今回の蚘事はDockerfileのレむダヌに぀いお玹介したした。
これを知っおいるかいないかで、Dockerfileのベストな曞き方に蟿り着く速床が倉わっおきたす。軜量で悪いこずはないですからね。特に重いアプリはより軜量にしおいかないず、起動に1時間かかるずか笑えないです。

䜙談

ちょっず久しぶりの蚘事になっおしたいたしたが、やはり曞いおいる時は楜しいですね。

11
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?