morimura-tech

DockerFileの書き方

2025-04-27

ボリュームには二種類ある。ホストのディレクトリと、dockerのリソースとしてのボリューム。

要は、ホストにあるものをそのままマウントしたものとと、docker create volumeで作ったボリューム

data volume containerというものがあるが、これはdockerのオプションに—volume-formを逆に利用したやり方だと推測する。—volume-fromで指定したコンテナと同じ位置に同じものをマウントできる。多数のコンテナを同じ位置にマウントしたい場合、data用のコンテナを一つ用意して、それと同じようにマウントさせていく方法。volumeを制作するだけだと、マウント位置を書かなければならないので、data volume container が使われる。(現在調査中)

docker volume inspect で保存場所を確認できる

Docker Desktop for Macを使っている場合、Docker環境はHyperKitというVM(バーチャルマシン)上で実行されているためMacからは参照できないようです。

nsenter1というコマンドでVMに入って確認することができます。

また、詳しくは違うページに書く。

ocker Desktop for Macを使っている場合、Docker環境はHyperKitというVM(バーチャルマシン)上で実行されているためMacからは参照できないようです。

ボリュームとは、Docker コンテナーにおいて生成され利用されるデータを、永続的に保持する目的で利用される仕組みです。他にバインドマウントという機能も存在する。割とバインドマウントを使う機会が多い(個人的体感)。

ボリュームはホストマシン上に新たなディレクトリが生成され、そこが Docker の保存ディレクトリとなります。ホストマシンとは切り離されていて、完全に Docker によって管理されます。

つまり、編集するときにdockerを使わなかえればならない。コンテナを経由して編集する前提となる。

バインドマウントとは

バインドマウントとは、ボリュームに比べると機能は制限されるが、ホストマシン上のファイルやディレクトリがコンテナ内にマウントされる。

そのファイルやディレクトリは、Docker ホストに存在している必要がなくなります。 存在してなかったとしても、必要とされるときには生成されます。

バインドマウントは、絶対パス(full path)によって参照される。そして、ホストマシンで直接触れる。バインドマウントを管理するために Docker CLI コマンドを直接利用することはできなくなります。

ただしホストマシンのファイルシステムに依存するものとなり、利用可能な特定のディレクトリ構造に従ったものになります。

要するに、ホストマシンのディレクトリを、そのままdockerコンテナ内の指定したディレクトリの下にマウントできるということ。

tmpfs マウントとは

コンテナに一時的に保存したい場合、かつ、コンテナレイヤーにも書き込みたくないデータをマウントするさいに使用される。コンテナが作成され削除されるまでの間に、非永続的な状態または機密情報を保存することができます。ホストマシンのメモリ上にのみ存在します。

• この機能は Docker on Linux を稼動させている場合にのみ利用可能です。

使用例

  • tmpfsマウントはデータをホストマシンかコンテナ内でも保持したくない場合。
    • これはセキュリティ上の理由か、大量の非永続化データを書き込む必要がある場合にコンテナのパフォーマンスを保護するためです。

バインドマウントよりボリュームが優れている点

  • ボリュームはバインドマウントよりも、バックアップや移行が容易です。
  • ボリュームは Docker CLI コマンドや Docker API を利用して管理することができます。
  • ボリュームは Linux と Windows 上のコンテナーにおいて動作します。
  • ボリュームは複数コンテナー間にて安全に共有できます。
  • ボリュームドライバーを用いると、リモートホスト上、あるいはクラウドプロバイダー上のボリュームに保存できるようになります。保存の際にはボリューム内データを暗号化することができ、その他にも種々の機能を利用することができます。
  • ボリュームを新たに生成すると、その内容はコンテナーがあらかじめ用意していた内容になります。
  • Docker Desktop 上のボリュームは、Mac や Windows ホストからのバインドマウントに比べて、より高い性能を実現します。

ボリュームの使い方

全般に--mountの方がわかりやすいものですが、記述は増えます。 両者の最大の違いは、-vの文法がオプション指定のすべてを 1 項目にとりまとめるものであるのに対して、--mountの文法はそれを 1 つずつ個別に分けている点です。

要するに—mountはわかりやすいけど、打つ量が多い。-v—volumeは打つのが短い。

はじめて利用する方は--mountを利用してください。 上級ユーザーは-v--volumeを用いることに慣れているかもしれませんが、--mountを利用するように心がけてください。 --mountの方が簡単に利用することができるとの調査もあります。

  • -vまたは—volumeの場合
    • vまたは-volume: 3 つの項目から構成され、それぞれをコロン(:)で区切ります。 各項目は正しい順に記述する必要があります。 各項目の意味は、そのときどきによって変わります。
      • 名前つきボリュームの場合、1 つめの項目は、そのボリューム名です。 指定されるホストマシン上において固有の名称であるものです。 匿名ボリュームの場合、1 つめの項目は省略されます。
      • 2 つめは、コンテナー内にマウントされるファイルまたディレクトリのパスです。
      • 3 つめは任意の指定項目であり、オプション指定をカンマ区切りで指定します。 指定内容にはroなどがあります。 このオプションに関しては後に説明しています。
  • —mountの場合
    • -mount: 複数のキーバリューペアを指定し、各ペアはカンマにより区切ります。 そしてそれぞれのペアは<key>=<value>という記述を行います。 -mountにおける記述はv-volumeにおけるものよりも長くなります。 しかしキーの並び順に意味はなく、このフラグに与えられたキーバリューの内容は容易に理解することができます。
      • typeはマウントのタイプであり、bindvolumetmpfs といった値を指定します。 ここで説明しているのはボリュームであるため、常にvolumeであるものとします。
      • sourceはマウント元です。 名前つきボリュームの場合は、そのボリューム名です。 匿名ボリュームの場合、この項目は省略します。 sourceあるいはsrcといった指定がよく用いられます。
      • destinationには、コンテナー上にてマウントするファイルまたはディレクトリのパスを指定します。 destinationdsttargetといった指定がよく用いられます。
      • オプションreadonlyが指定されると、そのボリュームが コンテナーにおける読み込み専用マウント としてマウントされます。 これはreadonlyまたはroとして指定が可能です。
      • volume-optオプションは複数の指定が可能です。 オプション名とその値からなるキーバリューペアを指定します。

v-mountの動作の違い

バインドマウントの場合とは違い、ボリュームのオプションは、--mount-vフラグの両方においてすべて利用できます。

サービスにおいてボリュームを利用する場合は--mountのみがサポートされます。

ボリュームの生成と管理

バインドマウントとは異なり、ボリュームの生成と管理はコンテナーの外部から行います。

ボリュームの生成

Terminal window
docker volume create my-vol

ボリュームの一覧表示

Terminal window
docker volume ls

ボリュームの確認

Terminal window
docker volume inspect test
[
{
"CreatedAt": "2023-05-04T01:20:43Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/test/_data",
"Name": "test",
"Options": {},
"Scope": "local"
}
]

ボリュームの削除

Terminal window
docker volume rm test

ボリュームを使ったコンテナの起動

ボリュームがまだ存在していない状態で、そのボリュームを使ったコンテナーを起動すると、Docker はその際にボリュームを生成します。

--mount-vによるそれぞれの例は、同一の結果になります。 ただし 2 つの例を同時に実行することはできません。

Terminal window
docker run -d --name devtest --mount source=myvol2,target=/var/www httpd

docker composeでのボリューム利用

ボリュームを利用する単一の Compose サービスは、たとえば以下のようなものです。

version: "3.9" services: frontend: image: node:lts volumes: - myapp:/home/node/app volumes: myapp:

ocker-compose upの初回実行時に、そのボリュームが生成されます。 このボリュームが、それ以降の実行時においても再利用されます。

service外に記述(volumeを事前に作成している場合)

volumeを事前に作成した上でvolumeをバインドさせることもできます。

まずはexternal-test-volumeという名前のvolumeを事前に作成します。

Terminal window
% docker volume create external-test-volume
external-test-volume

docker-compose.ymlのvolumesにexternalオプションを追記します。

Terminal window
version: "3.8"
services:
app:
build:
context: ./dockerfile_dir
dockerfile: Dockerfile
volumes:
- "external-test-volume:/volume_dir"
volumes:
external-test-volume:
external: **true**

externalオプションによってdocker-composeの外で既に作成済みのvolumeを使うことができるようになります。

services > app > volumesで指定するvolume名をexternal-test-volumeに修正しdocker-composeを実行すると、事前に作成したvolumeが有効であることが確認できます。

volumesを複数行で書く

こちらの記事でvolumesを複数行に分けて書ける(long syntax)ことを知りました。

Terminal window
version: "3.8"
services:
app:
build:
context: .
dockerfile: Dockerfile
volumes:
- type: bind
source: ./volumes_test_dir
target: /volume_dir

typeには、Docker上のvolumeを使う場合はvolumeを、ホストのディレクトリをコンテナにバインドさせる場合はbindを指定します。(他にもtmpfs, npipeアリ)

bindのsourceにはホストのディレクトリを、targetにはコンテナのディレクトリを記述します。

volumeのsourceにはvolume名を、targetにはコンテナのディレクトリを記述します。

単行(short syntax)だと自動でディレクトリを作成され予期せぬエラーが発生してしまうことがあるので、基本的にはlong syntaxで記述しておけば良いようです。

まだまだ機能はあるがとりあえず一旦ここまで()

バインドの使い方

全般に--mountの方がわかりやすいものですが、記述は増えます。 両者の最大の違いは、-vの文法がオプション指定のすべてを 1 項目にとりまとめるものであるのに対して、--mountの文法はそれを 1 つずつ個別に分けている点です。 以下に両フラグにおける文法を比較します。

要するに、—mountがわかりやすくて書く行が多い、-v—volumeは書く行が少ない

はじめて利用する方は--mountを利用してください。 上級ユーザーは-v--volumeを用いることに慣れているかもしれませんが、--mountを利用するように心がけてください。 --mountの方が簡単に利用することができるとの調査もあります。

  • -vまたは—volume—mountの違い

    • vまたは-volume: 3 つの項目から構成され、それぞれをコロン(:)で区切ります。 各項目は正しい順に記述する必要があります。 各項目の意味は、そのときどきによって変わります。
      • バインドマウントの場合、1 つめの項目は ホストマシン 上のファイルまたはディレクトリへのパスです。
      • 2 つめは、コンテナー内にマウントされるファイルまたディレクトリのパスです。
      • 3 つめは任意の指定項目であり、オプション指定をカンマ区切りで指定します。 指定内容にはrozZなどがあります。 このオプションに関しては後に説明しています。
    • -mount: 複数のキーバリューペアを指定し、各ペアはカンマにより区切ります。 そしてそれぞれのペアは<key>=<value>という記述を行います。 -mountにおける記述はv-volumeにおけるものよりも長くなります。 しかしキーの並び順に意味はなく、このフラグに与えられたキーバリューの内容は容易に理解することができます。
      • typeはマウントのタイプであり、bindvolumetmpfsといった値を指定します。 ここで説明しているのはバインドマウントであるため、常にbindであるものとします。
      • sourceはマウント元です。 バインドマウントにおいては、Docker デーモンホスト上のファイルまたはディレクトリへのパスになります。 sourceあるいはsrcといった指定がよく用いられます。
      • destinationには、コンテナー上にてマウントするファイルまたはディレクトリのパスを指定します。 destinationdsttargetといった指定がよく用いられます。
      • オプションreadonlyが指定されると、そのバインドマウンドが コンテナーにおける読み込み専用マウント としてマウントされます。
      • オプションbind-propagationが指定されると、バインドプロパゲーション(bind propagation)の設定変更を行います。 rprivateprivatersharedsharedrslaveslaveのいずれかを指定します。
      • -mountフラグは、selinux ラベルを修正するためのzまたはZオプションには対応していません。

    v-mountの動作の違い

    • vおよび-volumeフラグは、長らく Docker の一部分として実現してきているため、その動作を今さら変更することはできません。 このことがつまり、v-mountの動作の違いの 1 つ になります。
    • vまたは-volumeを使ってファイルやディレクトリをバインドマウントした際に、そのファイルやディレクトリが Docker ホスト上にまだ存在していなかった場合、vはそのマウントエンドポイントを生成します。 その場合には常にディレクトリとして生成されます。
    • -mountを使ってファイルやディレクトリをバインドマウントした際に、そのファイルやディレクトリが Docker ホスト上に存在していなかった場合、Docker はそのファイルやディレクトリを自動的に生成することはしません。 かわりにエラーが出力されます。

    これはdocker composeのshort syntaxとlong syntaxにも言えることである。

    —mount,-vは相対パスで指定できない

    docker compose だと相対パスで指定できる。

    コンテナー上の空ではないディレクトリへのマウント

    バインドマウントする先のコンテナー内ディレクトリが空でなかったとします。 このときそのディレクトリ内にはじめからあった内容は、バインドマウントによって見えなくなってしまいます。 そうであっても、このことを便利に利用できる場合もあります。 たとえばアプリケーションの新バージョンをテストする際に、新たなイメージをビルドせずに実現するような場合です。 ただしそういった状況には驚くかもしれません。 またこの動きは Docker ボリューム とは異なるものです。

    以下は極端な例です。 コンテナーの/usr/ディレクトリをホストマシン上の/tmp/ディレクトリに置き換えてしまうものです。 おそらくこのコンテナーは使いものにならなくなります。

    • -mountvによるそれぞれの例は、同一の結果になります。
    • -mount
    • v
    Terminal window
    $ docker run -d \
    -it \
    --name broken-container \
    --mount type=bind,source=/tmp,target=/usr \
    nginx:latest
    docker: Error response from daemon: oci runtime error: container_linux.go:262:
    starting container process caused "exec: \"nginx\": executable file not found in $PATH".

    コンテナーは生成されましたが、起動はされませんでした。 コンテナーはここで削除します。

    Terminal window
    $ docker container rm broken-container

参照

【図解】Dockerの全体像を理解する -中編- - Qiita

https://numb86-tech.hatenablog.com/entry/2022/04/24/221235#:~:text=Docker の volume は、コンテナ,ができるようになる。

Dockerでvolumesを設定する

ボリュームの利用

バインドマウントの利用

Dockerのマウント3種類についてわかったことをまとめる - Qiita

【Docker】ボリューム・バインド・一時メモリ(tmpfs)マウントの概要・違いを徹底解説

docker-composeでvolumesを設定する

docker-compose の bind mount を1行で書くな