Dockerfileの書き方

はじめに

Dockerfileとはコンテナイメージを作成するためのファイルである
「環境の設計図」や「レシピ」のようなもので、これを書いておくと、誰でも同じ環境を簡単に作れるようになる

また、Dockerfileは、ただのテキストベースのファイルなので、手軽に環境を共有できるというのがメリットである
image.png←Dockerfileのイメージ

Dockerの基本的な関係

PCで例えると…

とっつきにくいと思うので身近なPCで例えてみる

  • イメージ … 「ROM(Read Only Memory)」のようなもの
    一度書き込まれた内容は変更できず、基本的に固定されている
  • コンテナ … 「RAM(メモリ)」のイメージで、電源を切るとこの内容は消えてしまう
    つまり、一時的な作業やインストールしたソフトは、再起動やコンテナの停止とともに失われる
  • ボリューム … 「HDDやSSDのようなストレージ(ボリューム)」をつないでそこに保存する
    そうすれば、コンテナを削除してもデータは残り、次回の起動時に再利用可能になる

 

用語集

イメージレイヤー

  • レイヤーとはイメージを構成する積み重ねられた層
  • イメージレイヤーはコマンド一つ一つが層と思えばいい、RUN、COPY、CMDとかが一つ一つレイヤーということ
  • レイヤーの数が少ないほうがイメージの容量が小さくなる→下記の例なら2レイヤーの書き方の方が容量は小さくできる
--- 1レイヤー ---
RUN apt update && apt install vim
--- 2レイヤー ---
RUN apt update
RUN apt install vim
  • ビルドをしたことがある場合、レイヤー単位でキャッシュされるので、1レイヤーで書いている場合、インストールするものを追加したりするとapt updateから全部やり直しになるのでビルドに時間がかかる

ビルドコンテキスト

  • docker buildで指定したディレクトリやファイルの集合のこと
  • Dockerfileで使用するファイルのこと

 

Dockerfileの例

nginxコンテナのイメージを作成するDockerfileの例

#1 使用するベースイメージを指定
FROM nginx:latest
#2 設定ファイルをイメージ内にコピー
COPY nginx.conf /etc/nginx/nginx.conf
#3 htmlディレクトリの中身をコピー
COPY ./html /usr/share/nginx/html
#4 コンテナ起動時に実行するコマンドを設定
CMD ["nginx", "-g", "daemon off;"]
  • 例のように実行したい処理を箇条書きで書く
  • 処理はプログラムと一緒で上から順番に実行されるので、コピーしたファイルをつかって何かしたい場合などは、その処理の前にCOPYを書いておく必要がある

 

よく使うDockerfileのコマンド

この他にも、コマンドは存在するが、おそらくよく使うものは以下のコマンド

FROM

  • 使用するイメージを指定
FROM イメージ:タグ
ex)FROM ubuntu:latest

ARG

  • イメージの作成時のみに有効な一時的な変数
  • Dockerfileの中でしか生存しない→コンテナの環境変数にはならない
ARG 環境変数 = 値
ex)ARG message_arg="Message"

ENV

  • イメージの環境変数に設定する
ENV 環境変数 = 値 
ex)ENV HOST_IP="10.0.0.1"

RUN

  • ビルド時にコマンドを実行させる
RUN コマンド
ex)RUN apt update

COPY

  • ホストのファイルをコンテナにコピーする
  • Dockerfileのある場所のファイルしかコピーできない
COPY コピー元 コピー先
ex)COPY test.py /usr/bin/

ADD

  • 圧縮ファイルの場合自動で展開
  • URLを指定するとダウンロードしてくれる
ADD コピー元 コピー先
ex)ADD archive.tar.gz /app/
ex)ADD https://example.com/file.txt /app/

WORKDIR

  • コマンドを実行するパスを指定
  • これを書いた以降のコマンド(レイヤー)がそのパスで実行される
  • デフォルトは/ルートになっている
WORKDIR パス
ex)WORKDIR /home/pi

CMD

  • コンテナ起動時にデフォルトで実行されるコマンド
  • 複数書いている場合は最後のもののみ有効
  • execなどでコマンドを指定した場合はそちらが優先される
CMD ["コマンド"]
ex)CMD ["ls","-a"]

ENTRYPOINT

  • docker runなどの際も上書きされず、必ず実行される
ENTRYPOINT ["コマンド"]
ex)ENTRYPOINT ["./test"]

Dockerfileのビルド

基本構文

  • -tオプションでイメージに名前とタグをつける
docker build -t イメージ名:タグ ビルドコンテキストのパス

具体例

  • 以下のコマンドではカレントディレクトリをビルドコンテキストとして、イメージ名がmy-nginx,タグ名が1.0というイメージが作成される
docker build -t my-nginx:1.0 .

小技集

マルチステージビルド(イメージサイズの削減)

最終的に使いたいイメージのサイズを小さくするため、例えばバイナリだけほしい時などは、別のステージでコンパイルをして、その結果だけを最終イメージに持ってくるということができる

  • FROMから次のFROMまでで1ステージ
//ここからステージ0↓
FROM gcc:1.17 AS builder
WORKDIR /app
RUN gcc -o myapp myapp.c

//ここからステージ1↓
FROM ubuntu:latest
COPY --from=builder /app/myapp .
//COPY --from=0 /app/myapp . ←これでも同じ意味
CMD ["./myapp"]
  • ASでステージに名前を付けることができる
  • --fromオプションでコピー元のステージを指定
  • ソースのビルドをステージ0で行う、最終的に出来上がるイメージには最終ステージのみが残る

複数コンテナで共通のビルド部分をまとめる

//ステージ0:共通のパッケージをインストール
FROM ubuntu:20.04 AS base
RUN apt-get update && apt-get install -y \
    curl \
    git \
    vim

//ステージ1:特定のコンテナに必要な追加パッケージをインストール
FROM base AS app1
RUN apt-get install -y nginx

//ステージ2:別のコンテナに必要な追加パッケージ
FROM base AS app2
RUN apt-get install -y apache2

ビルドしたいステージを指定してイメージの作成
.はビルドコンテキストの指定,例ではカレントディレクトリを指定している

docker image build --target app1 .

.dockerignoreで不要ファイル除外

  • 例えば ./app/ の中身をすべてコンテナ内にコピーしたいとかの場合、以下の例のように.dockerignore にコピー不要なファイルを記述しておけば除外できる
.dockerignore
.git
*.log
test.txt

コメント