[AWS][docker] docker build 時にインターネット接続に失敗


AWS EC2 上で docker イメージをビルドしようとして、ハマったので覚え書き。


### 現象

docker イメージのビルドで以下のエラーになった。
内容は fluentd のイメージにプラグインの gem を追加するというもの。

```
$ docker build . --no-cache
Sending build context to Docker daemon  2.048kB
Step 1/4 : FROM fluent/fluentd:v1.11.4-2.0
v1.11.4-2.0: Pulling from fluent/fluentd
df20fa9351a1: Pull complete
5bbb4150a5a0: Pull complete
0a2f393cb307: Pull complete
b1dea35b5d99: Pull complete
65de893ed157: Pull complete
Digest: sha256:0c6ae6c72902cbc3a4f60bc15069cb89fd72b57391bff150960a6f911361d6c9
Status: Downloaded newer image for fluent/fluentd:v1.11.4-2.0
 ---> 7bcbcb847e0d
Step 2/4 : USER root
 ---> Running in 79fb5c74b17f
Removing intermediate container 79fb5c74b17f
 ---> 03af9cdb324e
Step 3/4 : RUN gem install         fluent-plugin-cloudwatch-logs
 ---> Running in 1bcf43a8efb2
ERROR:  Could not find a valid gem 'fluent-plugin-cloudwatch-logs' (>= 0), here is why:
          Unable to download data from https://rubygems.org/ - no such name (https://rubygems.org/specs.4.8.gz)
ERROR: Service 'fluentd' failed to build : The command '/bin/sh -c gem install         fluent-plugin-cloudwatch-logs' returned a non-zero code: 2
```

rubygems.org に接続できないというもので、調べてみるとプロキシの設定が必要などの情報が出てくる。
が、ホスト上では接続できているので関係はなさそう。

サイトへの直接アクセスもできず、名前解決もできていない。
で、分かったのはネットワークインターフェースの eth0 がないこと。

```
$ docker build . --no-cache
Sending build context to Docker daemon  2.048kB
Step 1/3 : FROM fluent/fluentd:v1.11.4-2.0
 ---> 7bcbcb847e0d
Step 2/3 : USER root
 ---> Running in c80c0a20cd21
Removing intermediate container c80c0a20cd21
 ---> 16f2ba30695a
Step 3/3 : RUN ifconfig
 ---> Running in 1d9cb7d5e2ec
lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

Removing intermediate container 1d9cb7d5e2ec
 ---> de98e34f64e7
Successfully built de98e34f64e7
```

ホスト側で見てみると docker0 がなく、docker network でデフォルトの bridge がいないことが分かった。

```
$ docker network ls
NETWORK ID          NAME                           DRIVER              SCOPE
2d9ce67d06f5        host                           host                local
9a455bcae53c        none                           null                local
```


### 確認

ホストの OS は Amazon Linux 2 (EKS-Optimized) ですが、別のサーバでは問題なくビルドできていたので、比べてみるとバージョンが違っている。

- amazon-eks-node-1.11-v20190220 → ビルドできている環境
- amazon-eks-node-1.17-v20201002 → ビルド失敗する環境

それぞれの docker のバージョンを見てみると、以下の違いがあった。


```
# ビルドできている環境
$ docker version
Client:
 Version:           18.06.1-ce
 API version:       1.38
 Go version:        go1.10.3
 Git commit:        e68fc7a215d7133c34aa18e3b72b4a21fd0c6136
 Built:             Mon Jan 28 21:03:38 2019
 OS/Arch:           linux/amd64
 Experimental:      false
    :

# ビルド失敗する環境
$ docker version
Client:
 Version:           19.03.6-ce
 API version:       1.40
 Go version:        go1.13.4
 Git commit:        369ce74
 Built:             Fri May 29 04:01:26 2020
 OS/Arch:           linux/amd64
 Experimental:      false
    :
```

なお、ビルドできている方ではデフォルトの bridge ネットワークが存在している。

```
$ docker network ls
NETWORK ID          NAME                               DRIVER              SCOPE
2f3fd9d451c6        bridge                             bridge              local
cd2fe4f72dff        host                               host                local
f56d76b46acb        none                               null                local
```

この bridge の有無が docker build のエラー原因かは情報を見つけられなかったのですが、デフォルト bridge の有無の方向で調べてみると **/etc/docker/daemon.json** という設定ファイルが出てきたので上記のサーバで比較してみた。

**ビルドできている環境**

```/etc/docker/daemon.json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "10"
  },
  "live-restore": true,
  "max-concurrent-downloads": 10,
  "default-ulimits": {
    "nofile": {
      "Name": "nofile",
      "Soft": 2048,
      "Hard": 8192
    }
  }
}
```

**ビルド失敗する環境**

```/etc/docker/daemon.json
{
  "bridge": "none",
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "10"
  },
  "live-restore": true,
  "max-concurrent-downloads": 10
}
```

**bridge: none** という設定が関係しそう。


### 対処

/etc/docker/daemon.json ファイルの bridge: none の設定を削除して docker サービスを再起動してみる。

```
$ sudo service docker restart
```

上記のコマンドでサービス再起動をしてもすぐ解決しなかった。
その後、stop、start と別にしたり、systemctl コマンドで操作したりしてるうちにデフォルト bridge ができた。

どうも、稼働中のコンテナがいたり、docker-compose で作られるネットワークがいるとダメなようで、すべてのコンテナを停止して、後から作られたネットワークも削除してから docker サービスを再起動したら設定が反映された。

```
$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
c4433dcfbe9b        bridge              bridge              local
2d9ce67d06f5        host                host                local
9a455bcae53c        none                null                local
```

先ほどの docker build を試してみると、eth0 もできてる。

```
$ docker build . --no-cached
Sending build context to Docker daemon  2.048kB
Step 1/3 : FROM fluent/fluentd:v1.11.4-2.0
 ---> 7bcbcb847e0d
Step 2/3 : USER root
 ---> Using cache
 ---> 15b06f798b72
Step 3/3 : RUN ifconfig
 ---> Running in 713f15663040
eth0      Link encap:Ethernet  HWaddr 02:42:AC:12:00:02
          inet addr:172.18.0.2  Bcast:172.18.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:2 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:180 (180.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

Removing intermediate container 713f15663040
 ---> 6d99f256433b
Successfully built 6d99f256433b
```

元の fluentd のビルドを試してみると、gem のダウンロードもできて、問題なくビルドができるようになった。

```
$ docker build . --no-cached
Sending build context to Docker daemon  2.048kB
Step 1/4 : FROM fluent/fluentd:v1.11.4-2.0
 ---> 7bcbcb847e0d
Step 2/4 : USER root
 ---> Using cache
 ---> a733f7c02648
Step 3/4 : RUN gem install         fluent-plugin-cloudwatch-logs
 ---> Running in 1d43a2226fb4
Successfully installed jmespath-1.4.0
Successfully installed aws-partitions-1.391.0
Successfully installed aws-eventstream-1.1.0
Successfully installed aws-sigv4-1.2.2
Successfully installed aws-sdk-core-3.109.2
Successfully installed aws-sdk-cloudwatchlogs-1.38.0
Successfully installed fluent-plugin-cloudwatch-logs-0.11.1
7 gems installed
Removing intermediate container 1d43a2226fb4
 ---> f7242c21bd02
Step 4/4 : USER fluent
 ---> Running in 7baaad7e3b2d
Removing intermediate container 7baaad7e3b2d
 ---> c39b2ddf48d9
Successfully built c39b2ddf48d9
```


ビルドエラーは解消できたのでひとまずは完了ですが、なぜ新しいバージョンの docker、OS 環境で bridge が無効化されているのかが分からない。

デフォルトの bridge は作るべきではないという情報も見かけたのだけど、なぜダメで、bridge を作らないのであればどうすべきかというはっきりとした情報が見つけられなかった。

あるいは EKS-Optimized なイメージなので、通常はランタイムのみの利用で docker build の実行を想定していないのかもしれない。