Назад | Перейти на главную страницу

Исправьте правила iptables, чтобы разрешить связывание контейнеров докеров

У меня есть два контейнера Docker на узле Debian 8.3. Один - это официальный образ postgres, другой - базовое приложение Phoenix / elixir. Я связываю оба с файлом стека докеров. Но феникс не может подключиться к postgres, если я не опубликую порт. Это позволяет мне думать, что что-то с внутренней сетью докеров не так, и, поскольку узел представляет собой новую установку Debian, это может быть iptables. Это также исключает неправильный пароль или имя хоста.

Что я делаю не так и как правильно настроить правила iptables, чтобы два контейнера могли взаимодействовать?

Сообщение об ошибке в приложении Phoenix:

app-1 | 2016-03-15T16:15:18.019402549Z ** (Mix) The database for App.Repo couldn't be created, reason given: psql: could not connect to server: Connection refused
app-1 | 2016-03-15T16:15:18.019456447Z  Is the server running on host "postgres" (10.7.0.1) and accepting
app-1 | 2016-03-15T16:15:18.019468609Z  TCP/IP connections on port 5432?

Вывод файла журнала в контейнер postgres

postgres-1 | 2016-03-15T16:46:32.457844697Z LOG:  MultiXact member wraparound protections are now enabled
postgres-1 | 2016-03-15T16:46:32.464806051Z LOG:  database system is ready to accept connections
postgres-1 | 2016-03-15T16:46:32.465087076Z LOG:  autovacuum launcher started

Мой файл стека Docker

app:
  image: myrepo/app
  environment:
    POSTGRES_USER: postgres
    POSTGRES_PASSWORD: postgrespassword
    PORT: 4000
  links:
    - postgres
  ports:
    - 80:4000
postgres:
  image: postgres:9.5
  environment:
    POSTGRES_USER: postgres
    POSTGRES_PASSWORD: postgrespassword
  volumes:
    - /var/dbdata:/var/lib/postgresql/data

Конфигурация базы данных в приложении Phoenix (prod.secret.exs)

config :data_bucket, DataBucket.Repo,
  adapter: Ecto.Adapters.Postgres,
  username: System.get_env("POSTGRES_USER"),
  password: System.get_env("POSTGRES_PASSWORD"),
  database: "app_prod",
  hostname: "postgres",
  pool_size: 20

Результат $ sudo iptables -L

Chain INPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     all  --  anywhere             anywhere
REJECT     all  --  anywhere             loopback/8           reject-with icmp-port-unreachable
ACCEPT     all  --  anywhere             anywhere             state RELATED,ESTABLISHED
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:http
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:https
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:2375
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:6783
ACCEPT     udp  --  anywhere             anywhere             udp dpt:6783
ACCEPT     tcp  --  anywhere             anywhere             state NEW tcp dpt:ssh
ACCEPT     icmp --  anywhere             anywhere             icmp echo-request
LOG        all  --  anywhere             anywhere             limit: avg 5/min burst 5 LOG level debug prefix "iptables denied: "
REJECT     all  --  anywhere             anywhere             reject-with icmp-port-unreachable
DROP       tcp  --  anywhere             172.17.0.1           tcp dpt:6783
DROP       udp  --  anywhere             172.17.0.1           udp dpt:6783
DROP       udp  --  anywhere             172.17.0.1           udp dpt:6784
ACCEPT     udp  --  anywhere             anywhere             udp dpt:domain
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:domain

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
DROP       all  --  anywhere             anywhere
DROP       all  --  anywhere             anywhere
DOCKER     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
ACCEPT     all  --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere
REJECT     all  --  anywhere             anywhere             reject-with icmp-port-unreachable
ACCEPT     all  --  anywhere             anywhere

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     all  --  anywhere             anywhere

Chain DOCKER (1 references)
target     prot opt source               destination

Результат $ sudo docker version

Client:
 Version:      1.9.1-cs2
 API version:  1.21
 Go version:   go1.4.3
 Git commit:   4ade326
 Built:        Mon Nov 30 21:56:07 UTC 2015
 OS/Arch:      linux/amd64

Server:
 Version:      1.9.1-cs2
 API version:  1.21
 Go version:   go1.4.3
 Git commit:   4ade326
 Built:        Mon Nov 30 21:56:07 UTC 2015
 OS/Arch:      linux/amd64

Результат sudo docker ps:

CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS              PORTS                  NAMES
f113435b781b        myrepo/app:latest       "elixir --erl '-smp d"   35 seconds ago      Up 34 seconds       0.0.0.0:80->4000/tcp   app-1.App.15ffa2c2
6e2879fd9f2c        postgres:9.5            "/docker-entrypoint.s"   37 minutes ago      Up 5 minutes        5432/tcp               postgres-1.App.cbe400ac

Для последнего вывода: приложение Phoenix, конечно, запускается только в том случае, если я не выполняю миграции. Обычно это в конце моего Dockerfile:

CMD ["elixir", "--erl", "-smp disable", "/usr/local/bin/mix", "do", "compile", ",", "ecto.create", ",", "ecto.migrate", ",", "phoenix.server"]

Что я изменил на следующее, чтобы получить этот вывод

CMD ["elixir", "--erl", "-smp disable", "/usr/local/bin/mix", "do", "compile", ",", "phoenix.server"]

Я нашел решение: проблема заключалась в настройках iptables. У меня было правило отказаться от пересылки, если не указано иное:

-A FORWARD -j REJECT

Решением было избавиться от этого правила.

Редактировать:

Как отметил @Zoredache, просто удаление правила - это, очевидно, плохая идея, и я идиот. Правильный способ - поместить его в самый конец цепочки правил после правил, созданных докером. Итак, если у вас такая же проблема, это работает для меня:

Избавьтесь от правила

$ sudo iptables -D FORWARD -j REJECT

Добавьте его снова, чтобы переместить в конец набора

$ sudo iptables -A FORWARD -j REJECT

Убедитесь, что они расположены в правильном порядке. Так что правило отклонить все остальное должно быть в самом конце.

$ sudo iptables -v -L FORWARD

В Debian вы можете убедиться, что правила по-прежнему применяются при перезапуске сервера.:

Когда вы будете довольны, сохраните новые правила в главном файле iptables:

$ iptables-save > /etc/iptables.up.rules

Чтобы убедиться, что правила iptables запускаются при перезагрузке, мы создадим новый файл:

$ editor /etc/network/if-pre-up.d/iptables

Добавьте к нему эти строки:

#!/bin/sh
/sbin/iptables-restore < /etc/iptables.up.rules

Файл должен быть исполняемым, поэтому измените разрешения:

$ sudo chmod +x /etc/network/if-pre-up.d/iptables