AWS Fargateでコンテナ間通信させたいとき

この記事は [AWS Fargate Advent Calendar 2017](https://qiita.com/advent-calendar/2017/aws-fargate) の19日目の記事です。

cloudpack大阪の佐々木です。
Fargateでコンテナ間通信させるときの話です。

# 概要

Docker環境で、コンテナ間で通信させるためにLinkという機能があります。[^1]

ECS上でLink機能を使用しているタスク定義を、Fargateで実行しようとしてもエラーになって動きません。


# 実行結果

まず簡単な例として、Wordpress + MySQLという構成があるとします。[^2]
WordpressコンテナとMySQLコンテナがあって、Wordpressの方にLinkを指定することで、mysqlという名前で通信できるようになります。

```yaml:docker-compose.yml
version: '2'
services:
  wordpress:
    image: wordpress
    ports:
      - "80:80"
    links:
      - mysql
  mysql:
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: password
```

ECSであれば、この構成で問題なく動くんですが、Fargateで起動させると下のようなエラーになります。

```bash:
$ ecs-cli compose service up --launch-type FARGATE                                          
WARN[0000] Skipping unsupported YAML option...           option name=networks
WARN[0000] Skipping unsupported YAML option for service...  option name=networks service name=mysql
WARN[0000] Skipping unsupported YAML option for service...  option name=networks service name=wordpress
ERRO[0001] Error registering task definition             error="ClientException: Links are not supported when networkMode=awsvpc.\n\tstatus code: 400, request id:  axxxxx-e39c-11e7-a22a-xxxxxxxxx" family=wordpress
ERRO[0001] Create task definition failed                 error="ClientException: Links are not supported when networkMode=awsvpc.\n\tstatus code: 400, request id:  axxxxx-e39c-11e7-a22a-xxxxxxxxx"
FATA[0001] ClientException: Links are not supported when networkMode=awsvpc.
	status code: 400, request id: axxxxx-e39c-11e7-a22a-xxxxxxxxx
```

つまりFargateではLink機能はサポートされていないということです。

AWSのドキュメントには下記のように記載されてました。

> Only supported if the network mode of a task definition is set to bridge. 

http://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html

Fargateのネットワークモードは `awsvpc` になるので、この機能はサポートされてないと。

# 解決方法

色々見てみたんですが、Link機能の代替となるようなものを見つけられなかったので、@riywo さんに質問してみたところあっさり教えてもらいました。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">同じタスク定義内のコンテナはlocalhostを共有しているので、localhost+ポート番号でアクセスさせると良いです。</p>&mdash; riywo (@riywo) <a href="https://twitter.com/riywo/status/938723080494448640?ref_src=twsrc%5Etfw">2017年12月7日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

https://qiita.com/sawanoboly/items/2766c8b0760ad9f9be99

なるほど・・・

ん？ 別のコンテナの起動しているポートもlocalhostとして見えるのか？

確認してみました。

# 確認

同じタスク定義内に、もう一つ別にssh接続用のコンテナを起動して、そのコンテナからどう見えるのかを確認してみました。
ssh接続用コンテナの作り方はこのへんを参考にしました。

https://qiita.com/sawanoboly/items/2766c8b0760ad9f9be99

```yaml:docker-compose.yml
version: '2'
services:
  sshd:
    image: taishin/amazonlinux-sshd
    ports:
      - "22:22"
  wordpress:
    image: wordpress
    ports:
      - "80:80"
    # links:
    #   - mysql
  mysql:
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: password
```

起動して、sshログインし、確認してみます。

```bash:
-bash-4.2# netstat -nl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State
tcp        0      0 0.0.0.0:80                  0.0.0.0:*                   LISTEN
tcp        0      0 0.0.0.0:3128                0.0.0.0:*                   LISTEN
tcp        0      0 :::3306                     :::*                        LISTEN
tcp        0      0 :::3128                     :::*                        LISTEN
udp        0      0 0.0.0.0:68                  0.0.0.0:*
Active UNIX domain sockets (only servers)
Proto RefCnt Flags       Type       State         I-Node Path
unix  2      [ ACC ]     STREAM     LISTENING     17520  /var/run/mysqld/mysqld.sock
```

おー 確かに別コンテナが使用しているTCP/80、TCP/3306もローカルでLISTENしてます。

ブラウザでアクセスしてみます。


![image.png](https://qiita-image-store.s3.amazonaws.com/0/3246/b96a8f83-7f9a-4a60-3934-12e07e260b16.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/3246/84dba043-d355-2d85-cc97-f05252820826.png)

データベースがないってエラーにはなってますが、MySQLへの接続は問題なくてきているようです。
ちなみに `データベースのホスト名` のところは `localhost` ではなく、 `１２７．０．０．１` と入力しないとエラーになります。
理由はこちら
https://qiita.com/TanukiTam/items/f6a08740d0fcda0db7be

# 完成形

最終的に作成した `docker-compose.yml` は下記のようになります。

```yaml:docker-compose.yml
version: '2'
services:
  wordpress:
    image: wordpress
    ports:
      - "80:80"
    environment:
      WORDPRESS_DB_HOST: 127.0.0.1
      WORDPRESS_DB_PASSWORD: password
  mysql:
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: password
```
Wordpressコンテナの環境変数はこちらを参照
https://hub.docker.com/_/wordpress/

```bash:
ecs-cli compose service up --launch-type FARGATE                                          [15:20:08]
WARN[0000] Skipping unsupported YAML option...           option name=networks
WARN[0000] Skipping unsupported YAML option for service...  option name=networks service name=wordpress
WARN[0000] Skipping unsupported YAML option for service...  option name=networks service name=mysql
WARN[0000] Skipping unsupported YAML option for service...  option name=networks service name=sshd
INFO[0001] Using ECS task definition                     TaskDefinition="wordpress:11"
INFO[0002] Created an ECS service                        service=ecscompose-service-wordpress taskDefinition="wordpress:11"
INFO[0002] Updated ECS service successfully              desiredCount=1 serviceName=ecscompose-service-wordpress
INFO[0018] (service ecscompose-service-wordpress) has started 1 tasks: (task xxxxxxx-46f4-4b29-b09f-5484982bd294).  timestamp=2017-12-18 06:22:45 +0000 UTC
INFO[0124] Service status                                desiredCount=1 runningCount=1 serviceName=ecscompose-service-wordpress
INFO[0124] (service ecscompose-service-wordpress) has reached a steady state.  timestamp=2017-12-18 06:24:31 +0000 UTC
INFO[0124] ECS Service has reached a stable state        desiredCount=1 runningCount=1 serviceName=ecscompose-service-wordpress
```

ブラウザでアクセスすると、

![image.png](https://qiita-image-store.s3.amazonaws.com/0/3246/e962a173-3f9c-cd7a-417e-27370b0764c5.png)

正常に動きました。

# まとめ

Fargateでコンテナ間で通信させたい場合は、Link機能は使えないけど、localhost:ポート番号でアクセスできる！

---
[^1]: Dockerのlink機能は非推奨になってるみたいです。https://docs.docker.com/engine/userguide/networking/default_network/dockerlinks/
[^2]: Fargateではボリュームマウントもできないので、データ永続化させるようなMySQLコンテナを動かすってことはあまりないかと思いますが・・・