Dockerの基本を学ぶ

目次

Dockerとは?

キーワード

Docker

  • DockerはLinuxのコンテナ技術を使ったもの。

Dockerエンジン

  • 様々なOSで実行可能なコンテナランタイム。

コンテナーイメージ(通称イメージ, Image)

  • アプリケーションコードと、その実行に必要な環境全てを含むスタンドアローンパッケージ

コンテナ

  • イメージをDockerエンジンで動かしたもの。

Hub

  • イメージを共有するための場所。
  • Docker Hubや様々なホストサービスが存在する。

Dockerfile

  • イメージを構築するための設定ファイル

概要

  • 特定のホストマシンに依存したアプリケーション開発から、任意の環境で動かすために生まれた技術が仮想化
  • 仮想化には仮装マシンやコンテナがある。
  • 仮装マシンはホストマシン上でハイパーバイザーを動かし、ハイパーバイザー上でゲストOSを動かし、ゲストOS上でミドルウェアを動かし、アプリケーションを動作させていた。
  • それに対し、コンテははホストマシン上でDockerエンジンを動かし、Dockerエンジン上でコンテナを動かすのみ。
  • 仮装マシンとコンテナを比較した時、確保するデータ容量、動作パフォーマンス、環境構築コストでコンテナが優位となる。

Dockerと仮想マシンの比較

イメージ

  • Dockerイメージは、レイヤーの組み合わせである。
  • レイヤーはDockerfile内の命令に相当し、1つの命令を実行するたびに既存のレイヤーの上に新しいレイヤーを追加します。(例外あり)
  • イメージは全てのレイヤーを持ちます。これをイメージレイヤーと言い、読み込み専用となります。
  • コンテナとして動作するとき、イメージレイヤーに書き込み可能なレイヤーを追加します。これをコンテナレイヤーと言います。

イメージとレイヤー

ビルド

  • DockerはDockerfileに書かれた命令を読み込み、自動的にイメージを構築します。
  • 構築を始めるには以下のコマンドを実行します。すると Dockerfileコンテキストを用いてイメージを作成します。
docker build .

コンテキスト

docker buildコマンドを実行する際に引数として渡されるパスまたはURLのこと。

  • 例えば、docker build .を実行した場合は、実行時のカレントディレクトリ配下とその全てのサブディレクトリを指します。

  • また、URLを指定する場合はGitリポジトリを指定します。

docker build https://github.com/microsoft/docker/blob/master
  • 指定されたパスは構築時にDockerデーモンに送信されます。
  • Dockerデーモンに送信されたファイルやディレクトリは後述するDockerfileで参照できます。

tips

Dockerfile

FROM

FROM [--platform=<プラットフォーム>] <イメージ名>[:<タグ>] [AS <名前>]
  • FROM命令は構築の初期状態とするイメージを指定します。基本的にDockerfileはFROM命令から始まります。
    • これを初期ステージと呼ぶ。
  • 複数のイメージを作成したり、ある構築ステージを他レイヤーの依存関係に含めるために複数のFROM命令を書くことが可能。
  • FROM命令にAS 名前を追加することで構築ステージに名前をつけられます。以降のFROM命令またはCOPY --from=<名前>命令で、その構築ステージを参照できます。
  • タグを省略するとデフォルトでlatestタグと解釈されます。
  • 特定のプラットフォーム向けにイメージを構築する場合は--platformフラグを用いて行います。

RUN

  • RUN命令は、既存のレイヤに新しいレイヤを追加し、コマンドを実行後、結果をコミットします。
  • コミットされたレイヤは次のステップで使われます。
  • RUN命令はGitのコミットのようなもので、手軽にコミットでき、その履歴のどこからでもコンテナを作成できます。
RUN <コマンド> # シェル形式. linuxであれば /bin/sh -c, windowsなら cmd /S /C

または、

RUN ["実行ファイル", "パラメータ1", "パラメータ2"] # 実行形式
  • シェル形式で使うシェルを変更する場合はSHELL命令を利用します。
  • 実行形式でシェルを変える場合は RUN ["/bin/bash", "-c", "echo hello"] のようにシェルを指定します。

CMD

  • CMD命令はDockerfile中で一度しか使えない。複数のCMD命令がある場合は、最後の命令のみ有効です。
  • CMD命令の目的は、コンテナ実行時のデフォルト動作を確定させるためです。
  • もし実行ファイルを含めない場合はENTRYPOINT命令の指定が必要です。

RUN命令は3通りの形式があります。

CMD ["実行ファイル","パラメータ1","パラメータ2"] # exec 形式、こちらが望ましい

CMD ["パラメータ1", "パラメータ2"] # ENTRYPOINT 命令に対するデフォルトのパラメータとして扱う

CMD コマンド パラメータ1 パラメータ2 #シェル形式
  • exec形式はコマンドとしてのシェルを実行しません。例えばCMD [ "echo", "$HOME" ] では、$HOME を変数展開しません。
  • もしシェルとしての処理を行いたい場合はシェル形式を使うか、CMD [ "sh", "-c", "echo $HOME" ]のように、直接シェルを実行します。
  • シェル形式、exec形式のCMD命令は、対象イメージの起動時に処理するコマンドを指定しています。
  • docker runで引数を指定すると、CMD命令を上書きできます。

COPY

  • COPY命令は、コンテキスト上のファイルやディレクトリを、イメージのファイルシステム上にコピーするためのものです。
COPY [--chown=<ユーザ>:<グループ>] <コピー元>... <コピー先>
  • 複数のコピー元が指定できます。
  • コピー元は(ややこしいですが)ビルド時のコンテキストパスをカレントディレクトリとみなします。
  • それぞれのパスはコンテキストのコピー先に対する相対パスとして解釈されます。

ENV

  • ENV命令は、環境変数に値を設定します。
  • この値は以降の構築ステージ中で保持されますが、ENV命令で書き換え可能です。
ENV <キー>=<値> ...
  • ENV命令で設定した環境変数はコンテナでも維持されます。その値はdocker inspectで確認できます。

  • 環境変数は予期せぬ影響を与える可能性があります。作成したイメージをベースとした時に、ベースで設定した環境変数が引き継がれ、その後の挙動に影響を与えるためです。

回避策としては、以下のように宣言して使うか、 ARG命令を使えば最終イメージでは保持されません。

RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y ...
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y ...

tips

  • Dockerfileで定義したイメージによって生成するコンテナは再現性があり最小構成でいつでも破棄可能であるべきです。

Getting started

以下の流れで進める。

  1. Dockerfileを定義
  2. Imageの作成
  3. Imageを動かす(コンテナ化する)

Dockerfileを定義

作業ディレクトリを作成し、Dockerfile を作成する。

mkdir docker_hello_world
cd docker_hello_world

touch Dockerfile

Dockerfileに以下の内容を記述する。

# syntax=docker/dockerfile:1
FROM ubuntu
CMD ["echo", "hello world!"]
  • docker build コマンドでイメージを構築します。
  • -fオプションで、Dockerfileを使ってビルドを行うよう指定しています。
  • また、-tオプションでイメージにリポジトリ名: hello_world, タグ名: latestを設定しています。
  • 最後の.で、現在のディレクトリである docker_hello_world のファイル・サブディレクトリをデーモンに送信しています。
docker build -t hello_world:latest -f Dockerfile .

作成したイメージを確認します。

docker images

# REPOSITORY    TAG       IMAGE ID       CREATED          SIZE
# hello_world   latest    xxxxx          5 minutes ago    7.73MB

さっそく動かしてみましょう。 このコマンドはコンテナを起動した後、即座にコンテナを破棄します。

docker run --rm hello_world:latest

# hello world!

無事にHello world!できましたでしょうか?

一般的なDockerfile

# syntax=docker/dockerfile:1
FROM ubuntu:18.04
LABEL org.opencontainers.image.authors="org@example.com"
COPY . /app
RUN make /app
CMD python /app/app.py
  • 解説
    • FROM命令文ではubuntu:18.04イメージからレイヤーを作成します。
    • LABEL命令は、イメージのメタデータを変更するのみでレイヤーは作成されません。
    • COPY命令は、Dockerクライアントが現在いるカレントディレクトリにあるファイルを追加します。
    • RUN命令は、makeコマンドでアプリを構築し、結果を新しいレイヤーに書き込みます。
    • CMD命令で、そのコンテナ内で何のコマンドを実行するのかを指定しますが、メタデータを変更するのみなので新しいレイヤーは作成されません。