

# Amazon ECS でのバインドマウントの使用
<a name="bind-mounts"></a>

バインドマウントでは、ホスト (Amazon EC2 インスタンスなど) 上のファイルまたはディレクトリがコンテナにマウントされます。バインドマウントは、Fargate インスタンスと Amazon EC2 インスタンスの両方でホストされているタスクでサポートされています。バインドマウントは、それらを使用するコンテナのライフサイクルに紐付けられています。タスクが停止するなど、バインドマウントを使用するすべてのコンテナが停止すると、データが削除されます。Amazon EC2 インスタンスでホストされているタスクの場合、タスク定義で `host` とオプションの `sourcePath` 値を指定することにより、ホスト側 Amazon EC2 インスタンスのライフサイクルにデータを紐付けすることができます。詳細については、Docker ドキュメントの「[Bind mounts](https://docs.docker.com/engine/storage/bind-mounts/)」を参照してください。

バインドマウントの一般的なユースケースは以下のとおりです。
+ 1 つ以上のコンテナにマウントするための空のデータボリュームを提供する。
+ 1 つ以上のコンテナにホストデータボリュームをマウントする。
+ ソースコンテナのデータボリュームを、同じタスク内の他のコンテナと共有する。
+ Dockerfile から 1 つ以上のコンテナにパスとその内容を公開する。

## バインドマウントを使用するときの考慮事項
<a name="bind-mount-considerations"></a>

バインドマウントを使用する際には、以下の点を考慮してください。
+ プラットフォームバージョン `1.4.0` 以降 (Linux) または `1.0.0` 以降 (Windows) を使用して AWS Fargate でホストされているタスクの場合、デフォルトでは、バインドマウント用に最低 20 GiB の一時ストレージが割り当てられます。タスク定義で `ephemeralStorage` パラメータを指定することによって、一時ストレージの総量を最大 200 GiB まで増やすことができます。
+ タスクの実行時に Dockerfile のファイルをデータボリュームに公開するために、Amazon ECS データプレーンが `VOLUME` ディレクティブを探します。`VOLUME` ディレクティブで指定された絶対パスが、タスク定義で指定された `containerPath` と同じである場合、`VOLUME` ディレクティブパス内のデータがデータボリュームにコピーされます。次の Dockerfile の例では、`/var/log/exported` ディレクトリにある `examplefile` という名前のファイルがホストに書き込まれ、その後でコンテナ内にマウントされます。

  ```
  FROM public.ecr.aws/amazonlinux/amazonlinux:latest
  RUN mkdir -p /var/log/exported
  RUN touch /var/log/exported/examplefile
  VOLUME ["/var/log/exported"]
  ```

  デフォルトでは、ボリューム許可は `0755` に設定され、所有者は `root` に設定されます。これらのアクセス許可は Dockerfile でカスタマイズできます。次の例では、ディレクトリの所有者を `node` として定義しています。

  ```
  FROM public.ecr.aws/amazonlinux/amazonlinux:latest
  RUN yum install -y shadow-utils && yum clean all
  RUN useradd node
  RUN mkdir -p /var/log/exported && chown node:node /var/log/exported
  RUN touch /var/log/exported/examplefile
  USER node
  VOLUME ["/var/log/exported"]
  ```
+ Amazon EC2 インスタンスでホストされているタスクで、`host` 値と `sourcePath` 値が指定されていない場合には、Docker デーモンがバインドマウントを自動的に管理します。このバインドマウントを参照するコンテナが存在しない場合、このマウントは、Amazon ECS コンテナエージェントのタスククリーンアップサービスによって最終的に削除されます。デフォルトでは、この処理はコンテナが終了してから 3 時間後に実行されま。また、この期間は `ECS_ENGINE_TASK_CLEANUP_WAIT_DURATION` エージェント変数により設定することも可能です。詳細については、「[Amazon ECS コンテナエージェントの設定](ecs-agent-config.md)」を参照してください。コンテナのライフサイクルを通じてこのデータを永続化する必要がある場合は、バインドマウントの `sourcePath` 値を指定します。
+ Amazon ECS マネージドインスタンスでホストされているタスクの場合、ルートファイルシステムの一部が読み取り専用になっています。読み取り/書き込みバインドマウントは、永続データに `/tmp`、一時データに `/var` といった書き込み可能なディレクトリを使用する必要があります。他のディレクトリに読み取り/書き込みバインドマウントを作成しようとすると、以下のようなエラーでタスクの起動が失敗します。

  ```
  error creating empty volume: error while creating volume path '/path': mkdir /path: read-only file system
  ```

  読み取り専用バインドマウント (`mountPoints` パラメータの `"readOnly": true` で設定) は、ホスト上にある任意のアクセス可能なディレクトリをポイントできます。

  書き込み可能なパスの完全なリストを表示するには、Amazon ECS マネージドインスタンスでタスクを実行し、それを使用してインスタンスのマウントテーブルを検査できます。ホストファイルシステムにアクセスするには、以下の設定を使用してタスク定義を作成します。

  ```
  {
      "pidMode": "host",
      "containerDefinitions": [{
          "privileged": true,
          ...
      }]
  }
  ```

  次に、コンテナ内から以下のコマンドを実行します。

  ```
  # List writable mounts
  cat /proc/1/root/proc/1/mounts | awk '$4 ~ /^rw,/ || $4 == "rw" {print $2}' | sort
  
  # List read-only mounts
  cat /proc/1/root/proc/1/mounts | awk '$4 ~ /^ro,/ || $4 == "ro" {print $2}' | sort
  ```
**重要**  
`privileged` 設定は、ホスト上でルートアクセスに相当する拡張機能をコンテナに付与します。この例では、診断目的でホストのマウントテーブルを検査するために使用されます。詳細については、「[コンテナを特権として実行することは避けてください (Amazon EC2)](security-tasks-containers.md#security-tasks-containers-recommendations-avoid-privileged-containers)」を参照してください。

  コンテナ内でのコマンドのインタラクティブな実行に関する詳細については、「[ECS Exec を使用して Amazon ECS コンテナをモニタリングする](ecs-exec.md)」を参照してください。

# Amazon ECS タスク定義でバインドマウントを指定する
<a name="specify-bind-mount-config"></a>

Fargate または Amazon EC2 インスタンスでホストされている Amazon ECS タスクについて、以下のタスク定義 JSON スニペットにタスク定義向け `volumes`、`mountPoints`、`ephemeralStorage` オブジェクトの構文を示します。

```
{
   "family": "",
   ...
   "containerDefinitions" : [
      {
         "mountPoints" : [
            {
               "containerPath" : "/path/to/mount_volume",
               "sourceVolume" : "string"
            }
          ],
          "name" : "string"
       }
    ],
    ...
    "volumes" : [
       {
          "name" : "string"
       }
    ],
    "ephemeralStorage": {
	   "sizeInGiB": integer
    }
}
```

Amazon EC2 インスタンスでホストされる Amazon ECS タスクで、タスクボリュームの詳細を指定する場合は、オプションの `host` パラメータおよび `sourcePath` を使用できます。これを指定すると、バインドマウントはコンテナではなくタスクのライフサイクルに紐付けされます。

```
"volumes" : [
    {
        "host" : {
            "sourcePath" : "string"
        },
        "name" : "string"
    }
]
```

以下では、各タスク定義パラメータについて詳しく説明します。

`name`  
タイプ: 文字列  
必須: いいえ  
ボリュームの名前。最大 255 文字の英字 (大文字と小文字の区別あり)、数字、ハイフン (`-`)、アンダースコア (`_`) を使用できます。この名前は、コンテナ定義 `mountPoints` オブジェクトの `sourceVolume` パラメータで参照されます。

`host`  
必須: いいえ  
`host` パラメーターは、バインドマウントのライフサイクルを、タスクではなくホスト Amazon EC2 インスタンスと、それが格納されている場所に関連付けるために使用されます。`host` パラメーターが空の場合、Docker デーモンはデータボリュームのホストパスを割り当てますが、関連付けられたコンテナの実行が停止した後にデータが保持されるとは限りません。  
Windows コンテナは `$env:ProgramData` と同じドライブに全部のディレクトリをマウントできます。  
`sourcePath` パラメータは、Amazon EC2 インスタンスまたは Amazon ECS マネージドインスタンスでホストされているタスクを使用する場合にのみサポートされます。  
`sourcePath`  
タイプ: 文字列  
必須: いいえ  
`host` パラメータを使用する場合は、`sourcePath` を指定して、コンテナに表示されるホスト Amazon EC2 インスタンスのパスを宣言します。このパラメータが空の場合は、Docker デーモンによってホストパスが割り当てられます。`host` パラメータに `sourcePath` の場所が含まれている場合、データボリュームは手動で削除するまでホスト Amazon EC2 インスタンスの指定された場所に保持されます。`sourcePath` の値がホスト Amazon EC2 インスタンスに存在しない場合は、Docker デーモンによって作成されます。その場所が存在する場合は、ソースパスフォルダの内容がエクスポートされます。

`mountPoints`  
タイプ: オブジェクト配列  
必須: いいえ  
コンテナでのデータボリュームのマウントポイント。このパラメータは creat-container Docker API の `Volumes` にマッピングされ、docker run の `--volume` オプションにマッピングされます。  
Windows コンテナは `$env:ProgramData` と同じドライブに全部のディレクトリをマウントできます。Windows コンテナは、別のドライブにディレクトリをマウントすることはできません。また、マウントポイントは複数のドライブにまたがることはできません。Amazon EBS ボリュームを Amazon ECS タスクに直接アタッチするには、マウントポイントを指定する必要があります。    
`sourceVolume`  
タイプ: 文字列  
必須: はい (`mountPoints` を使用する場合)  
マウントするボリュームの名前。  
`containerPath`  
タイプ: 文字列  
必須: はい (`mountPoints` を使用する場合)  
ボリュームをマウントするコンテナ内のパス。  
`readOnly`  
タイプ: ブール値  
必須: いいえ  
この値が `true` の場合、コンテナはボリュームへの読み取り専用アクセスを許可されます。この値が `false` の場合、コンテナはボリュームに書き込むことができます。デフォルト値は `false` です。  
Windows オペレーティングシステムを実行している EC2 インスタンスで実行されるタスクの場合、 値をデフォルト の `false` のままにします。

`ephemeralStorage`  
タイプ: オブジェクト  
必須: いいえ  
タスクに割り当てるエフェメラルストレージの容量(GB)。このパラメータは、AWS Fargate プラットフォームバージョン `1.4.0` 以降 (Linux) または `1.0.0` 以降 (Windows) を使用してホストされているタスクの場合、利用可能なエフェメラルストレージの総量をデフォルト容量を超えて拡張するために使用されます。  
コパイロットCLI、CloudFormation、AWSSDK または CLI を使用して、バインドマウントのエフェメラルストレージを指定します。

# Amazon ECS のバインドマウントの例
<a name="bind-mount-examples"></a>

以下の例では、コンテナにバインドマウントを使用する場合の一般的なユースケースについて説明します。

**Fargate タスク用の一時ストレージ容量の増加を割り当てるには**

プラットフォームバージョン `1.4.0` 以降 (Linux) または `1.0.0` (Windows) を使用して Fargate でホストされる Amazon ECS タスクの場合、使用するタスク内のコンテナに対して、デフォルト容量を超えるエフェメラルストレージを割り当てることができます。この例は、他の例に組み込むことで、Fargate タスクに一時ストレージを割り当てることができます。
+ タスク定義で、`ephemeralStorage`オブジェクトを定義します。`sizeInGiB` は `21`および`200` の値の間にある整数である必要があり、GiB に表されます。

  ```
  "ephemeralStorage": {
      "sizeInGiB": integer
  }
  ```

**1 つまたは複数のコンテナに空のデータボリュームを提供する**

場合によっては、タスク内のコンテナにスクラッチスペースを提供することがあります。例えば、タスクの実行中に同じスクラッチファイルの保存場所にアクセスする必要のある、2 つのデータベースコンテナがあるとします。これは、バインドマウントを使用して実現できます。

1. タスク定義の `volumes` セクションで、名前を `database_scratch` としてバインドマウントを定義します。

   ```
     "volumes": [
       {
         "name": "database_scratch"
       }
     ]
   ```

1. `containerDefinitions` セクションで、データベースのコンテナ定義を作成します。これにより、ボリュームがマウントされます。

   ```
   "containerDefinitions": [
       {
         "name": "database1",
         "image": "my-repo/database",
         "cpu": 100,
         "memory": 100,
         "essential": true,
         "mountPoints": [
           {
             "sourceVolume": "database_scratch",
             "containerPath": "/var/scratch"
           }
         ]
       },
       {
         "name": "database2",
         "image": "my-repo/database",
         "cpu": 100,
         "memory": 100,
         "essential": true,
         "mountPoints": [
           {
             "sourceVolume": "database_scratch",
             "containerPath": "/var/scratch"
           }
         ]
       }
     ]
   ```

**Dockerfile 内のパスとその内容をコンテナに公開する**

この例には、コンテナ内にマウントするデータを書き込む Dockerfile があります。この例は、Fargate または Amazon EC2 インスタンスでホストされているタスクで機能します。

1. Dockerfile を作成します。次の例では、パブリックな Amazon Linux 2 コンテナイメージを使用して、コンテナ内にマウントする `/var/log/exported` ディレクトリに `examplefile` という名前のファイルを作成します。`VOLUME` ディレクティブは絶対パスを指定する必要があります。

   ```
   FROM public.ecr.aws/amazonlinux/amazonlinux:latest
   RUN mkdir -p /var/log/exported
   RUN touch /var/log/exported/examplefile
   VOLUME ["/var/log/exported"]
   ```

   デフォルトでは、ボリューム許可は `0755` に設定され、所有者は `root` に設定されます。これらのアクセス許可は Dockerfile で変更できます。以下の例では、`/var/log/exported` ディレクトリの所有者が `node` に設定されています。

   ```
   FROM public.ecr.aws/amazonlinux/amazonlinux:latest
   RUN yum install -y shadow-utils && yum clean all
   RUN useradd node
   RUN mkdir -p /var/log/exported && chown node:node /var/log/exported					    
   USER node
   RUN touch /var/log/exported/examplefile
   VOLUME ["/var/log/exported"]
   ```

1. タスク定義の `volumes` セクションで、名前を `application_logs` としてボリュームを定義します。

   ```
     "volumes": [
       {
         "name": "application_logs"
       }
     ]
   ```

1. `containerDefinitions` セクションで、アプリケーションのコンテナ定義を作成します。これにより、ストレージがマウントされます。`containerPath` 値は、Dockerfile の `VOLUME` ディレクティブで指定された絶対パスと一致する必要があります。

   ```
     "containerDefinitions": [
       {
         "name": "application1",
         "image": "my-repo/application",
         "cpu": 100,
         "memory": 100,
         "essential": true,
         "mountPoints": [
           {
             "sourceVolume": "application_logs",
             "containerPath": "/var/log/exported"
           }
         ]
       },
       {
         "name": "application2",
         "image": "my-repo/application",
         "cpu": 100,
         "memory": 100,
         "essential": true,
         "mountPoints": [
           {
             "sourceVolume": "application_logs",
             "containerPath": "/var/log/exported"
           }
         ]
       }
     ]
   ```

**ホスト Amazon EC2 インスタンスのライフサイクルに紐付けされているコンテナに、空のデータボリュームを提供するには**

Amazon EC2 インスタンスでホストされているタスクの場合、バインドマウントを使用して、ホスト Amazon EC2 インスタンスのライフサイクルにデータを紐付けすることができます。これは、`host` パラメータを使用して `sourcePath` 値を指定することで設定できます。`sourcePath` に存在するファイルはすべて、`containerPath` の値でコンテナに表示されます。`containerPath` に書き込まれたファイルは、ホストの Amazon EC2 インスタンス上の `sourcePath` 値に書き込まれます。
**重要**  
Amazon ECS は、Amazon EC2 インスタンス間でストレージを同期しません。永続的ストレージを使用するタスクは、使用可能なキャパシティーのあるクラスター内の Amazon EC2 インスタンスに配置できます。タスクを停止して再び開始した後に永続的ストレージが必要な場合は、タスクの開始時に毎回 AWS CLI の [start-task](https://docs.aws.amazon.com/cli/latest/reference/ecs/start-task.html) コマンドを使用して、同一の Amazon EC2 インスタンスを指定し直す必要があります。永続ストレージに Amazon EFS ボリュームを使用することもできます。詳細については、「[Amazon ECS での Amazon EFS ボリュームの使用](efs-volumes.md)」を参照してください。

1. タスク定義の `volumes` セクションで、`name` および `sourcePath` 値を使用して、バインドマウントを定義します。次の例では、ホスト Amazon EC2 インスタンスはコンテナ内にマウントしたい `/ecs/webdata` のデータを含めます。

   ```
     "volumes": [
       {
         "name": "webdata",
         "host": {
           "sourcePath": "/ecs/webdata"
         }
       }
     ]
   ```

1. `containerDefinitions` セクションで、定義したバインドマウントの名前を参照する `mountPoints` 値と、コンテナにバインドマウントをマウントするための `containerPath` 値を使用して、コンテナを定義します。

   ```
     "containerDefinitions": [
       {
         "name": "web",
         "image": "public.ecr.aws/docker/library/nginx:latest",
         "cpu": 99,
         "memory": 100,
         "portMappings": [
           {
             "containerPort": 80,
             "hostPort": 80
           }
         ],
         "essential": true,
         "mountPoints": [
           {
             "sourceVolume": "webdata",
             "containerPath": "/usr/share/nginx/html"
           }
         ]
       }
     ]
   ```

**定義したボリュームを異なる場所にある複数のコンテナにマウントする**

タスク定義でデータボリュームを定義し、そのボリュームをさまざまなコンテナのさまざまな場所にマウントできます。例えば、ホストコンテナの `/data/webroot` に、ウェブサイトのデータフォルダがあるとします。そのデータボリュームを、異なるドキュメントルートを持つ 2 つの異なる Web サーバーに、読み取り専用としてマウントしたい場合があります。

1. タスク定義の `volumes` セクションで、名前を `webroot`、ソースパスを `/data/webroot` としてデータボリュームを定義します。

   ```
     "volumes": [
       {
         "name": "webroot",
         "host": {
           "sourcePath": "/data/webroot"
         }
       }
     ]
   ```

1. `containerDefinitions` セクションで、各ウェブサーバーのコンテナを定義しています。各コンテナの `mountPoints` で、`webroot` ボリュームを、そのコンテナのドキュメントルートを参照する `containerPath` 値に関連付けます。

   ```
     "containerDefinitions": [
       {
         "name": "web-server-1",
         "image": "my-repo/ubuntu-apache",
         "cpu": 100,
         "memory": 100,
         "portMappings": [
           {
             "containerPort": 80,
             "hostPort": 80
           }
         ],
         "essential": true,
         "mountPoints": [
           {
             "sourceVolume": "webroot",
             "containerPath": "/var/www/html",
             "readOnly": true
           }
         ]
       },
       {
         "name": "web-server-2",
         "image": "my-repo/sles11-apache",
         "cpu": 100,
         "memory": 100,
         "portMappings": [
           {
             "containerPort": 8080,
             "hostPort": 8080
           }
         ],
         "essential": true,
         "mountPoints": [
           {
             "sourceVolume": "webroot",
             "containerPath": "/srv/www/htdocs",
             "readOnly": true
           }
         ]
       }
     ]
   ```

**`volumesFrom` を使用して別のコンテナからボリュームをマウントするには**

Amazon EC2 インスタンスでホストされているタスクの場合、あるコンテナに 1 つ以上のボリュームを定義し、(同じタスクの) 異なるコンテナ定義で `volumesFrom` パラメータを使用して、`sourceContainer` のすべてのボリュームを、最初に定義されていたマウントポイントにマウントできます。`volumesFrom` パラメータは、タスク定義で定義されたボリューム、および Dockerfile でイメージに組み込まれたボリュームに適用されます。

1. (オプション) イメージに組み込まれているボリュームを共有するには、Dockerfile の `VOLUME` 命令を使用します。次の Dockerfile の例では、`httpd` イメージを使用しボリュームを追加して、それを Apache ドキュメントルートの `dockerfile_volume` にマウントしています。これは、`httpd` ウェブサーバーが使用するフォルダーです。

   ```
   FROM httpd
   VOLUME ["/usr/local/apache2/htdocs/dockerfile_volume"]
   ```

   この Dockerfile を使用してイメージを構築し、Docker ハブなどのレポジトリにプッシュして、タスク定義で使用できます。以下のステップで使用する `my-repo/httpd_dockerfile_volume` イメージ例は、上記の Dockerfile から構築したものです。

1. コンテナの他のボリュームとマウントポイントを定義するタスク定義を作成します。この例の `volumes` セクションでは、Docker デーモンによって管理される空のボリューム `empty` を作成します。また、`host_etc` と呼ばれるホストボリュームも定義されています。これは、ホストコンテナインスタンス上の `/etc` フォルダをエクスポートします。

   ```
   {
     "family": "test-volumes-from",
     "volumes": [
       {
         "name": "empty",
         "host": {}
       },
       {
         "name": "host_etc",
         "host": {
           "sourcePath": "/etc"
         }
       }
     ],
   ```

   コンテナ定義セクションで、先ほど定義したボリュームをマウントするコンテナを作成します。この例では、`web` コンテナが `empty` および `host_etc` ボリュームをマウントします。このコンテナは、Dockerfile 内のボリュームでビルドされたイメージを使用しています。

   ```
   "containerDefinitions": [
       {
         "name": "web",
         "image": "my-repo/httpd_dockerfile_volume",
         "cpu": 100,
         "memory": 500,
         "portMappings": [
           {
             "containerPort": 80,
             "hostPort": 80
           }
         ],
         "mountPoints": [
           {
             "sourceVolume": "empty",
             "containerPath": "/usr/local/apache2/htdocs/empty_volume"
           },
           {
             "sourceVolume": "host_etc",
             "containerPath": "/usr/local/apache2/htdocs/host_etc"
           }
         ],
         "essential": true
       },
   ```

   `volumesFrom` を使用して、`web` コンテナに関連付けられているすべてのボリュームをマウントする、別のコンテナを作成します。`web` コンテナ上にあるすべてのボリュームは、同様に `busybox` コンテナにもマウントされます。これには、`my-repo/httpd_dockerfile_volume` イメージのビルドに使用された Dockerfile で指定されたボリュームも含まれます。

   ```
       {
         "name": "busybox",
         "image": "busybox",
         "volumesFrom": [
           {
             "sourceContainer": "web"
           }
         ],
         "cpu": 100,
         "memory": 500,
         "entryPoint": [
           "sh",
           "-c"
         ],
         "command": [
           "echo $(date) > /usr/local/apache2/htdocs/empty_volume/date && echo $(date) > /usr/local/apache2/htdocs/host_etc/date && echo $(date) > /usr/local/apache2/htdocs/dockerfile_volume/date"
         ],
         "essential": false
       }
     ]
   }
   ```

   このタスクが実行されると、2 つのコンテナでボリュームがマウントされ、`busybox` コンテナの `command` がファイルに日付と時刻を書き込みます。このファイルは、各ボリュームフォルダに `date` の名前で保存されています。その後、フォルダは `web` コンテナによって表示されるウェブサイトで見ることができます。
**注記**  
`busybox` コンテナはクイックコマンドを実行して終了するため、コンテナ定義で `"essential": false` として設定する必要があります。そうしなければ、終了時にタスク全体が停止します。