

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 搭配 Amazon ECS 使用綁定掛載
<a name="bind-mounts"></a>

透過綁定掛載，主機上的檔案或目錄 (例如 Amazon EC2 執行個體) 會掛載至容器中。在 Fargate 和 Amazon EC2 執行個體上託管的任務支援綁定掛載。綁定掛載與使用它們的容器的生命週期相關聯。使用綁定掛載的所有容器停止之後，例如當任務停止時，資料就會被移除。對於 Amazon EC2 執行個體上託管的任務，可以將資料連接至主機 Amazon EC2 執行個體的生命週期，方法是在任務定義中指定 `host` 與選用的 `sourcePath` 值。如需詳細資訊，請參閱 Docker 文件中的 [Bind mounts](https://docs.docker.com/engine/storage/bind-mounts/)。

以下是綁定掛載的常用案例。
+ 若要提供空白的資料磁碟區以便在一個或多個容器中掛載。
+ 若要在一個或多個容器中掛載主機資料磁碟區。
+ 若要與相同任務中的其他容器共用來源容器的資料磁碟區。
+ 若要將 Dockerfile 中的路徑及其內容公開給一個或多個容器。

## 使用綁定掛載時的考量
<a name="bind-mount-considerations"></a>

使用綁定掛載時，請考量下列事項。
+ 在預設情況下， AWS Fargate 使用平台版本 `1.4.0`或更新版本 (Linux) `1.0.0`或更新版本 (Windows) 在 上託管的任務，會接收至少 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 受管執行個體上的任務，根檔案系統的部分是唯讀的。讀取/寫入繫結掛載必須使用可寫入目錄，例如`/var`持久性資料或`/tmp`暫存資料。嘗試建立其他目錄的讀取/寫入繫結掛載會導致任務無法啟動，並出現類似以下的錯誤：

  ```
  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` 所在的相同磁碟上掛載整個目錄。  
只有在使用託管在 Amazon EC2 執行個體或 Amazon ECS 受管執行個體上的任務時，才支援 `sourcePath` 參數。  
`sourcePath`  
類型：字串  
必要：否  
使用 `host` 參數時，指定 `sourcePath` 以宣告在主機 Amazon EC2 執行個體上提供給容器的路徑。如果此參數是空的，則 Docker 常駐程式會為您指派主機路徑。如果 `host` 參數包含 `sourcePath` 檔案位置，資料磁碟區將保留在主機 Amazon EC2 執行個體上的指定位置，直到您手動將其刪除為止。如果 `sourcePath` 值不存在於主機 Amazon EC2 執行個體，Docker 常駐程式將建立該值。如果位置存在，將匯出來源路徑資料夾的內容。

`mountPoints`  
類型：物件陣列  
必要：否  
容器中資料磁碟區的掛載點。此參數會映射至 Docker API 中 create-container 的 `Volumes`，以及 docker run 的 `--volume` 選項。  
Windows 容器可在 `$env:ProgramData` 所在的相同磁碟上掛載整個目錄。Windows 容器無法在不同的磁碟機上掛載目錄，且掛載點不能跨磁碟機使用。您必須指定掛載點，將 Amazon EBS 磁碟區直接連接至 Amazon ECS 任務。    
`sourceVolume`  
類型：字串  
必要：是 (當使用 `mountPoints` 時)  
要掛載的磁碟區名稱。  
`containerPath`  
類型：字串  
必要：是 (當使用 `mountPoints` 時)  
掛載磁碟區之容器中的路徑。  
`readOnly`  
類型：布林值  
必要：否  
如果此數值為 `true`，容器擁有磁碟區的唯讀存取權。如果此值為 `false`，則容器可寫入磁碟區。預設值為 `false`。  
對於在執行 Windows 作業系統之 EC2 執行個體上執行的任務，將該值保留為預設值 `false`。

`ephemeralStorage`  
類型：物件  
必要：否  
為任務配置的暫時性儲存量。對於 AWS Fargate 使用平台版本 `1.4.0`或更新版本 (Linux) 或更新版本 (`1.0.0`Windows) 在 上託管的任務，此參數用於擴展可用的暫時性儲存總量，超過預設數量。  
您可以使用 Copilot CLI、CloudFormation、 AWS SDK 或 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. 在任務定義 `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"
           }
         ]
       }
     ]
   ```

**若要將 Docker 文件中的路徑及其內容公開給容器**

在此範例中，您有一個 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`。可以在 Docker 檔案中變更這些許可。在下列範例中，`/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 EFS 磁碟區與 Amazon ECS 搭配使用](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` 的網站資料夾。建議您以唯讀方式將該資料磁碟區掛載到有不同文件根目錄的兩個不同 Web 伺服器上。

1. 在任務定義 `volumes` 區段中，以名稱 `webroot` 和來源路徑 `/data/webroot` 定義資料磁碟區。

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

1. 在 `containerDefinitions` 區段中，使用 `mountPoints` 值為每個 Web 伺服器定義容器，這些值會建立 `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 執行個體上託管的任務，您可以在容器上定義一或多個磁碟區，然後在相同的任務中的不同的容器定義中使用 `volumesFrom` 參數，將所有來自 `sourceContainer` 的磁碟區掛載在其原始定義的掛載點。`volumesFrom` 參數適用於在任務定義中定義的磁碟區，以及使用 Dockerfile 內建在映像中的磁碟區。

1. (選用) 若要共用內建在映像的磁碟區，請使用 Dockerfile 中的 `VOLUME` 指令。以下範例 Dockerfile 使用 `httpd` 映像，然後新增磁碟區，再將之掛載到 Apache 文件根中的 `dockerfile_volume`。該資料夾由 `httpd` Web 伺服器使用。

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

   您可以使用此 Dockerfile 建立映像，並將之推送到儲存庫，例如 Docker Hub，然後在您的任務定義中使用。在以下步驟中使用的範例 `my-repo/httpd_dockerfile_volume` 映像是使用前述的 Dockerfile 所建立。

1. 建立任務定義，定義您容器的其他磁碟區及掛載點。在這個範例 `volumes` 區段中，您要建立一個名為 `empty` 的空磁碟區，它是由 Docker 常駐程式管理。您還要定義一個稱為 `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` 容器上。這包括在 Dockerfile 中指定的磁碟區，該磁碟區用於建置 `my-repo/httpd_dockerfile_volume` 映像。

   ```
       {
         "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
       }
     ]
   }
   ```

   執行此任務時，兩個容器會掛載磁碟區，而 `busybox` 容器中的 `command` 會將日期和時間寫入檔案。這個檔案在每個磁碟區資料夾中稱為 `date`。然後，在 `web` 容器所顯示的網站上，就能看到這些資料夾。
**注意**  
由於 `busybox` 容器執行快速命令，然後結束，所以在容器定義中必須設為 `"essential": false`。否則，它結束時會停止整個任務。