Разное

Настройка сети docker: как Docker использует iptables и интерфейсы Linux / Хабр

Содержание

как Docker использует iptables и интерфейсы Linux / Хабр

Я познакомился с Docker довольно давно и, как и большинство его пользователей, был мгновенно очарован его мощью и простотой использования. Простота является основным столпом, на котором основывается Docker, чья сила кроется в легких CLI-командах. Когда я изучал Docker, я захотел выяснить, что происходит у него в бэкграунде, как вообще все происходит, особенно что касается работы с сетью (для меня это одна из самых интересных областей).

Я нашел много разной документации о том, как создавать контейнерные сети и управлять ими, но в отношении того, как именно они работают, материалов намного меньше. Docker широко использует Linux iptables и bridge-интерфейсы для создания контейнерных сетей, и в этой статье я хочу подробно рассмотреть именно этот аспект. Информацию я почерпнул, в основном, из комментариев на github-е, разных презентаций, ну и из моего собственного опыта. В конце статьи можно найти список полезных ресурсов.

Я использовал Docker версии 1.12.3 для примеров в этой статье. Я не ставил своей целью дать исчерпывающее описание Docker-сетей или написать полное введение в эту тему. Я надеюсь, что этот материал будет полезен для пользователей, и я буду рад, если вы в комментариях оставите обратную связь, укажете на ошибки или скажете, чего недостает.

Оглавление

Обзор сетей Docker

Сеть Docker построена на Container Network Model (CNM), которая позволяет кому угодно создать свой собственный сетевой драйвер. Таким образом, у контейнеров есть доступ к разным типам сетей и они могут подключаться к нескольким сетям одновременно. Помимо различных сторонних сетевых драйверов, у самого Docker-а есть 4 встроенных:

  • Bridge: в этой сети контейнеры запускаются по умолчанию. Связь устанавливается через bridge-интерфейс на хосте. У контейнеров, которые используют одинаковую сеть, есть своя собственная подсеть, и они могут передавать данные друг другу по умолчанию.
  • Host: этот драйвер дает контейнеру доступ к собственному пространству хоста (контейнер будет видеть и использовать тот же интерфейс, что и хост).
  • Macvlan: этот драйвер дает контейнерам прямой доступ к интерфейсу и суб-интерфейсу (vlan) хоста. Также он разрешает транкинг.
  • Overlay: этот драйвер позволяет строить сети на нескольких хостах с Docker (обычно на Docker Swarm кластере). У контейнеров также есть свои адреса сети и подсети, и они могут напрямую обмениваться данными, даже если они располагаются физически на разных хостах.

Сетевые драйвера Bridge и Overlay, возможно, используются чаще всего, поэтому в этой статье я буду больше уделять им внимание.

Сети типа мост (bridge)

По умолчанию для контейнеров используется bridge. При первом запуске контейнера Docker создает дефолтную bridge-сеть с одноименным названием. Эту сеть можно увидеть в общем списке по команде docker network ls:

Чтобы проинспектировать ее свойства, запустим команду docker network inspect bridge:

Вы также можете создать свои собственные bridge-сети при помощи команды docker network create, указав опцию --driver bridge.

Например, команда docker network create --driver bridge --subnet 192.168.100.0/24 --ip-range 192.168.100.0/24 my-bridge-network создает еще одну bridge-сеть с именем “my-bridge-network” и подсетью 192.168.100.0/24.

Bridge-интерфейсы в Linux

Каждая bridge-сеть имеет свое представление в виде интерфейса на хосте. С сетью “bridge”, которая стоит по умолчанию, обычно ассоциируется интерфейс docker0, и с каждой новой сетью, которая создается при помощи команды docker network create, будет ассоциироваться свой собственный новый интерфейс.

Чтобы найти интерфейс, который ассоциируется с сетью, которую вы создали, введите команду ifconfig, чтобы вывести все интерфейсы, а затем найти тот интерфейс, который относится к созданной вами подсети. Например, если нам надо найти интерфейс для сети my-bridge-network, которую мы только что создали, то можно запустить такую команду:

Bridge-интерфейсы Linux похожи на свичи тем, что они присоединяют несколько интерфесов к одной подсети и перенаправляют трафик на основе MAC-адресов. Как будет видно ниже, у каждого контейнера, привязанного к bridge-сети, будет свой собственный виртуальный интерфейс на хосте, и все контейнеры в одной сети будут привязаны к одному интерфейсу, что позволит им передавать друг другу данные. Можно получить больше данных о статусе моста при помощи утилиты brctl:

Как только мы запустим контейнеры и привяжем их к этой сети, интерфейс каждого из этих контейнеров будет выведен в списке в отдельной колонке. А если включить захват трафика в bridge-интерфейсе, то можно увидеть, как передаются данные между контейнерами в одной подсети.

Виртуальные интерфейсы Linux

Container Networking Model дает каждому контейнеру свое собственное сетевое пространство. Если запустить команду ifconfig внутри контейнера, то можно увидеть его интерфейсы такими, какими их видит сам контейнер:

Впрочем, eth0, который представлен в этом примере, можно увидеть только изнутри контейнера, а снаружи, на хосте, Docker создает соответствующую копию виртуального интерфейса, которая служит связью с внешним миром. Затем эти виртуальные интерфейсы соединяются с bridge-интерфейсами, о которых мы говорили выше, чтобы легче установить связь между разными контейнерами в одной подсети.

Чтобы рассмотреть этот процесс, для начала запустим два контейнера, связанных с дефолтной bridge-сетью, а затем посмотрим на конфигурацию интерфейса хоста.

До запуска каких-либо контейнеров у bridge-интерфейса docker0 нет никаких других присоединенных интерфейсов:

Затем я запустил два контейнера на образе ubuntu:14.04:

Сразу стало видно, что два интерфейса присоединены к bridge-интерфейсу docker0 (по одному на каждый контейнер):

Если начать пинговать Google с одного из контейнеров, то захват трафика с хоста на виртуальном интерфейсе контейнера покажет нам трафик контейнеров:

Аналогично можно выполнить пинг от одного контейнера к другому.

Во-первых, надо получить IP-адрес контейнера. Это можно сделать либо при помощи команды ifconfig, либо при помощи docker inspect, что позволяет проинспектировать контейнер:

Затем начинаем пинг от одного контейнера к другому:

Чтобы увидеть трафик с хоста, мы можем сделать захват на любом из виртуальных интерфейсов, которые соотносятся с контейнерами, либо на bridge-интерфейсе (в данном случае docker0), что покажет нам все коммуникации внутри контейнеров данной подсети:

Находим Veth-интерфейс в контейнере

Если вы хотите узнать, какой veth-интерфейс хоста привязан к интерфейсу внутри контейнера, то простого способа вы не найдете. Однако, есть несколько методов, которые можно найти на разных форумах и в обсуждениях на github. Самый простой, на мой взгляд, способ я почерпнул из этого обсуждения на github, немного его изменив. Он зависит от того, присутствует ли ethtool в контейнере.

Например, у меня в системе запущены 3 контейнера:

Для начала, я выполняю следующую команду в контейнере и получаю номер peer_ifindex:

Затем на хосте я использую peer_ifindex, чтобы узнать имя интерфейса:

В данном случае интерфейс называется veth7bd3604.

iptables

Docker использует linux iptables, чтобы контролировать коммуникации между интерфейсами и сетями, которые он создает. Linux iptables состоят из разных таблиц, но нам в первую очередь интересны только две из них: filter и nat. Таблица filter содержит правила безопасности, которые решают, допускать ли трафик к IP-адресам или портам. С помощью таблицы nat Docker дает контейнерам в bridge-сетях связываться с адресатами, которые находятся снаружи хоста (иначе пришлось бы добавлять маршруты к контейнерным сетям в сети хоста).

iptables:filter

Таблицы в iptables состоят из различных цепочек, которые соответствуют разным состояниям или стадиям обработки пакета на хосте. По умолчанию, у таблицы filter есть 3 цепочки:
Input для обработки входящих пакетов, предназначенных для того же хоста, на который они приходят;
Output для пакетов, возникающих на хосте, предназначенных для внешнего адресата;
Forward для обработки входящих пакетов, предназначенных для внешнего адресата.

Каждая цепочка включает в себя правила, которые определяют, какие действия и при каких условиях надо применить к пакету (например, отклонить или принять его). Правила обрабатываются последовательно, пока не будет найдено соответствие, иначе применяются дефолтные правила цепочки. Также в таблице можно задать кастомные цепочки.

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

Жирным выделены разные цепочки и дефолтные установки для каждой из них (у кастомных цепочек дефолтных установок нет). Также видно, что Docker добавил две кастомные цепочки: Docker и Docker-Isolation, также добавил правила в цепочку Forward, целью которых являются эти две новые цепочки.

Цепочка Docker-isolation

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

Можно увидеть несколько правил DROP, которые блокируют трафик между всеми bridge-интерфейсами, которые создал Docker, и таким образом не дают сетям обмениваться данными.

icc=false

Одна из опций, которую можно передать команде docker network create, — это опция, которая отвечает за передачу данных внутри контейнера: com.docker.network.bridge.enable_icc. Если задать ей значение false, то передача данных между контейнерами внутри одной сети будет заблокирована. Для этого нужно добавить DROP-правило в цепочку forward, которое соответствует пакетам, приходящим от bridge-интерфейса, связанного с сетью для данного интерфейса.

Например, если создать новую сеть при помощи команды docker network create --driver bridge --subnet 192.168.200.0/24 --ip-range 192.168.200.0/24 -o "com.docker.network.bridge.enable_icc"="false" no-icc-network, то мы получим следующее:

iptables:nat

С помощью nat можно поменять IP-адрес или порт пакета. В данном случае он используется, чтобы за IP-адресом хоста спрятать адреса источников пакетов, которые приходят от bridge-сетей (например, хосты в подсети 172.18.0.0/24) и направлены во внешний мир. Эта фича контролируется опцией com.docker.network.bridge.enable_ip_masquerade, которую можно передать docker network create (если не задать ничего специфического, то по умолчанию будет значение true).

Результат этой команды можно увидеть в таблице nat:

В этой цепочке postrouting можно увидеть все сети, которые созданы под действием masquerade, которое применяется, когда они передают данные любому хосту вне своей собственной сети.

Итог

  • У bridge-сети есть соответствующий bridge-интерфейс в Linux на хосте, который действует как layer2 свич и который соединяет разные контейнеры одной подсети.
  • У каждого интерфейса сети есть соответствующий виртуальный интерфейс на хосте, который создается во время работы контейнера.
  • Захват трафика с хоста на bridge-интерфейсе равноценен созданию SPAN-порта в свиче, в котором можно увидеть все внутренние коммуникации между контейнерами данной сети.
  • Захват трафика с хоста на виртуальном интерфейсе (veth-*) покажет весь трафик, исходящий из контейнера по конкретной подсети.
  • Правила iptables в цепочке filter используются, чтобы не давать разным сетям (и иногда еще хостам внутри сети) обмениваться данными. Эти правила обычно добавляют в цепочку Docker-isolation.
  • Контейнеры, которые обмениваются данными с внешним миром через bridge-интерфейс, прячут свой IP за адресом хоста. Для этого добавляются необходимые правила nat-таблицу в iptables.

Ссылки/ресурсы

Настройка сети Docker Bridge — docker

Я хочу, чтобы мой docker0 и все контейнеры имели тот же адрес шлюза или тот же IP-адрес, что и мой локальный компьютер. Я начал с определения фиксированного cidr в файле daemon.json /etc/docker/daemon.json

{
  "bip": "10.80.44.248/24",
  "fixed-cidr": "10.80.44.250/25",
  "mtu": 1500,
  "default-gateway": "10.80.44.254",
  "dns": ["10.80.41.14"]
}

Похоже, что работает, глядя на вывод ip -aКажется, с тех пор docker0 никогда не получал никаких данных.

docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet *10.80.44.248*  netmask 255.255.255.0  broadcast *10.80.44.255*
        ether 02:42:9c:b9:e1:63  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

ens192: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet *10. 80.44.39*  netmask 255.255.255.0  broadcast *10.80.44.255*
        inet6 fe80::250:56ff:feb1:79e4  prefixlen 64  scopeid 0x20<link>
        ether 00:50:56:b1:79:e4  txqueuelen 1000  (Ethernet)
        RX packets 211061  bytes 30426474 (29.0 MiB)
        RX errors 0  dropped 33861  overruns 0  frame 0
        TX packets 3032  bytes 260143 (254.0 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Локальный компьютер и docker0 находятся в одном диапазоне IP-адресов с одним и тем же шлюзом. Хорошо. Но когда я запускал докеры контейнеров и проверял настройки моста, все было иначе. Это вывод

docker network inspect bridge


[
    {
        "Name": "bridge",
        "Id": "b326a37a589245449e1268bbb9ee65262eb7986574c0e972c56d350aa82d7238",
        "Created": "2018-04-04T03:25:52.00544539+02:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "10. 80.44.248/24",
                    "IPRange": "10.80.44.128/25",
                    "Gateway": "10.80.44.248",
                    "AuxiliaryAddresses": {
                        "DefaultGatewayIPv4": "10.80.44.254"
                    }
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {
            "com.docker.n

Развертывание контейнеров с помощью Docker Swarm и Docker Networking

Цель этой статьи — изучить новые сетевые функции Docker, представленные в версии 1.9. Мы применим их к кластеру Docker Swarm. В практических целях мы будем развертывать контейнеры в кластере Swarm, созданном локально с помощью Vagrant и использующим Consul в качестве реестра служб и Registrator в качестве инструмента, который будет отслеживать демоны Docker и регистрировать / отменять регистрацию контейнеров, которые мы запускаем / останавливаем. В совокупности Консул и Регистратор будут действовать как обнаружение службы в нашем кластере. Я не буду вдаваться в подробности того, как работает Docker Swarm или служба обнаружения. Вы можете найти больше информации об этом предмете в следующих статьях.

Мы сразу перейдем к сетевым функциям Docker, используемым в кластере Swarm.

Настройка кластера

Обо всем по порядку. Давайте создадим три виртуальные машины, которые мы будем использовать в качестве тренировочного поля. Главный узел swarm будет действовать как главный, а две другие виртуальные машины будут представлять наш кластер, состоящий из двух узлов. Все три виртуальные машины будут работать под управлением Ubuntu и будут созданы с использованием VirtualBox и Vagrant . Пожалуйста, убедитесь, что оба установлены. Вам также понадобится Git для клонирования кода, который будет использоваться в этой статье. Если вы пользователь Windows, пожалуйста, следуйте инструкциям, описанным в разделе Запуск виртуальных машин Linux в Windows, прежде чем углубляться в описанные ниже.

Давайте начнем с создания виртуальных машин, которые будут моделировать наш кластер Swarm.

1

2

3

4

5

6

7

git clone https://github.com/vfarcic/docker-swarm-networking.git

 

cd docker-swarm-networking

 

vagrant up swarm-master swarm-node-1 swarm-node-2

 

vagrant ssh swarm-master

Теперь, когда виртуальные машины созданы, и мы находимся внутри Swarm-Master , давайте предоставим виртуальным машинам Docker, Docker Compose, Consul, Registrator и Swarm. Мы сделаем это через Ansible . Если вы новичок в Ansible, вы найдете множество примеров в этом блоге.

1

2

ansible-playbook /vagrant/ansible/swarm. yml \

    -i /vagrant/ansible/hosts/prod

Playbook swarm.yml убедился, что Docker запущен и настроен для поддержки Swarm. Он также предоставил серверам Docker Compose, Consul, Swarm и Registrator.

Давайте дважды проверим, что все работает как положено.

1

2

3

4

5

export DOCKER_HOST=tcp://localhost:2375

 

docker info

 

curl localhost:8500/v1/catalog/nodes | jq '.'

Переменная DOCKER_HOST указывает Docker отправлять команды ведущему Swarm, работающему через порт 2375 . За этим последовала docker info о docker info которая показала, что в кластере Swarm есть два узла. Наконец, последняя команда запросила список всех узлов, зарегистрированных в Консуле, и получила все три виртуальные машины (один Swarm-мастер и два Swarm-узла) в качестве ответа.

На данный момент у нас запущен и работает кластер Swarm, и мы можем начать играть с сетью Docker. Однако прежде чем мы продолжим с практическими примерами, давайте быстро рассмотрим идею, лежащую в основе.

Развертывание с помощью Docker Swarm и Docker Networking

Недавно Docker представил новую версию 1.9. Это, без сомнения, самый важный выпуск с версии 1.0. Это дало нам две долгожданные функции; многоузловая сеть и постоянные тома. Сеть делает связывание устаревшим и является функцией, которая нам нужна для соединения контейнеров между несколькими хостами. Больше не нужно, чтобы прокси связывал несколько контейнеров, которые составляют сервис. Это не означает, что прокси-сервер бесполезен, но мы должны использовать его в качестве открытого интерфейса для наших служб и сетей для соединения контейнеров, которые образуют логическую группу. Новые сетевые и прокси-сервисы Docker имеют разные преимущества и должны использоваться для разных случаев использования. Среди прочего, прокси-сервисы обеспечивают балансировку нагрузки и могут контролировать доступ к нашим сервисам. Сеть Docker — это удобный способ подключения отдельных контейнеров, которые образуют единый сервис и находятся в одной сети. Распространенным вариантом использования Docker-сетей может быть служба, требующая подключения к базе данных. Мы можем соединить эти два через сеть. Более того, может потребоваться масштабирование самой службы и запуск нескольких экземпляров. Прокси-сервис с балансировщиком нагрузки должен соответствовать этому требованию. Наконец, другие службы могут нуждаться в доступе к этой услуге. Поскольку мы хотим использовать преимущества балансировки нагрузки, этот доступ также должен осуществляться через прокси-сервер.

Эта цифра представляет один общий случай использования. У нас есть масштабированная служба с двумя экземплярами, работающими на узлах 1 и 3. Вся связь с этими службами осуществляется через прокси-службу, которая заботится о балансировке нагрузки и безопасности. Любой другой сервис (будь то внешний или внутренний), который хочет получить доступ к нашему сервису, должен пройти через прокси. Внутренне служба использует базу данных. Связь между службой и базой данных является внутренней и осуществляется через сеть с несколькими узлами. Этот параметр позволяет нам легко масштабировать внутри кластера, сохраняя при этом всю связь между контейнерами, которые составляют один внутренний сервис. Другими словами, вся связь между контейнерами, составляющими сервис, осуществляется через сеть, тогда как связь между различными сервисами осуществляется через прокси.

Существуют разные способы создания многоузловой сети. Мы можем настроить сеть вручную.

1

2

3

docker network create my-network

 

docker network ls

Вывод команды network ls выглядит следующим образом.

01

02

03

04

05

06

07

08

09

10

NETWORK ID          NAME                           DRIVER

f8a50a3c9c13        swarm-node-1/host              host

8ae6cefc3957        swarm-node-2/host              host

5f68a88668f6        swarm-node-2/bridge            bridge

397107ba0daf        swarm-node-2/none              null

b655577f0030        swarm-node-1/bridge            bridge

efb02b0fa9b9        swarm-node-1/docker_gwbridge   bridge

eb5ff0f0136a        swarm-node-1/none              null

71b80ae02620        my-network                     overlay

ac4261d5e27a        swarm-node-2/docker_gwbridge   bridge

Вы можете видеть, что одной из сетей является my-network, которую мы создали ранее. Он охватывает весь Рой кластер. Мы можем использовать эту сеть с аргументом –net .

1

2

3

4

5

6

7

8

9

docker run -d --name books-ms-db \

    --net my-network \

    mongo

 

docker run -d --name books-ms \

    --net my-network \

    -e DB_HOST=books-ms-db \

    -p 8080 \

    vfarcic/books-ms

Прежде чем мы продолжим, давайте подтвердим, что Swarm распределил контейнеры внутри кластера.

1

docker ps --filter name=books --format "table {{. Names}}"

Вывод в моем случае следующий.

1

2

3

NAMES

swarm-node-2/books-ms

swarm-node-1/books-ms-db

Вы можете видеть, что каждый контейнер был развернут на другом узле. Это главная цель Docker Swarm; распределить контейнеры по кластеру. Вопрос в том, как эти контейнеры могут взаимодействовать друг с другом, если они находятся на отдельных узлах?

Мы запустили два контейнера, которые составляют один сервис; books-ms — это API, который связывается с books-ms-db, который действует как база данных. Поскольку оба контейнера имеют аргумент -net my-network , они оба принадлежат сети my- network. В результате Docker обновил файл hosts, предоставив каждому контейнеру псевдоним, который можно использовать для внутренней связи.

Давайте войдем в контейнер books-ms и посмотрим на файл hosts.

1

docker exec -it books-ms cat /etc/hosts

Вывод команды exec выглядит следующим образом.

1

2

3

4

5

6

7

8

9

10.0.0.2    3166318f0f9c

127.0.0.1   localhost

::1 localhost ip6-localhost ip6-loopback

fe00::0 ip6-localnet

ff00::0 ip6-mcastprefix

ff02::1 ip6-allnodes

ff02::2 ip6-allrouters

10.0.0.2    books-ms-db

10.0.0.2    books-ms-db.my-network

Интересной частью файла hosts являются последние две записи. Докер обнаружил, что контейнер books-ms-db использует ту же сеть, и обновил файл hosts , добавив books-ms-db (имя контейнера DB) и books-ms-db.my-network (имя контейнера DB плюс название сети) псевдонимы. Если используется какое-то соглашение, тривиально кодировать наши сервисы так, чтобы они использовали псевдонимы, подобные этому, для связи с ресурсами, расположенными в отдельном контейнере (в данном случае с базой данных).

Мы также передали переменную окружения DB_HOST в книгу-мс . Это указывает нашему сервису, какой хост использовать для подключения к базе данных. Мы можем видеть это, выводя среды контейнера.

1

docker exec -it books-ms env

Вывод команды следующий.

1

2

3

4

5

6

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

HOSTNAME=eb3443a66355

DB_HOST=books-ms-db

DB_DBNAME=books

DB_COLLECTION=books

HOME=/root

Как видите, одной из переменных среды является DB_HOST со значением books-ms-db .

Сейчас у нас есть сеть Docker, которая создала псевдоним hosts -ms-db, указывающий на IP сети, созданной Docker. У нас также есть переменная окружения DB_HOST со значением books-ms-db . Код службы использует эту переменную для подключения к базе данных. Вы можете использовать другую логику. Важной частью является то, что Docker обновил файл hosts с помощью псевдонимов, которые можно использовать для доступа к любому другому контейнеру, который принадлежит той же сети наложения .

Существует даже лучший способ создать сеть, чем запуск команды create network . Прежде чем мы попробуем это, давайте остановим эти два контейнера и удалим сеть.

1

2

3

docker rm -f books-ms books-ms-db

 

docker network rm my-network

На этот раз мы будем запускать контейнеры через Docker Compose. Хотя мы могли бы использовать аргумент net внутри docker-compose.yml и, таким образом, выполнять точно такой же процесс, как мы делали ранее, лучше использовать новый аргумент Docker Compose — x-network .

1

2

3

cd /vagrant/booksms

 

docker-compose --x-networking up -d db app

Вывод команды, которую мы только что выполнили, следующий.

1

2

3

Creating network "booksms" with driver "None"

Creating booksms_app_1

Creating books-ms-db

Перед созданием приложения служб и базы данных Docker создал новую сеть под названием booksms . Имя сети совпадает с именем проекта (по умолчанию используется имя каталога).

Мы можем подтвердить, что сеть была создана с помощью команды docker network ls .

Вывод следующий.

01

02

03

04

05

06

07

08

09

10

NETWORK ID          NAME                           DRIVER

6e5f816d4800        swarm-node-1/host              host

aa1ccdaefd70        swarm-node-2/docker_gwbridge   bridge

cd8b1c3d9be5        swarm-node-2/none              null

ebcc040e5c0c        swarm-node-1/bridge            bridge

6768bad8b390        swarm-node-1/docker_gwbridge   bridge

8ebdbd3de5a6        swarm-node-1/none              null

58a585d09bbc        booksms                        overlay

de4925ea50d1        swarm-node-2/bridge            bridge

2b003ff6e5da        swarm-node-2/host              host

Как видите, наложенные сетевые книги были созданы.

Мы также можем проверить, что файл hosts внутри контейнеров был обновлен.

1

docker exec -it booksms_app_1 cat /etc/hosts

Вывод следующий.

1

2

3

4

5

6

7

8

9

10.0.0.2    3166318f0f9c

127.0.0.1   localhost

::1 localhost ip6-localhost ip6-loopback

fe00::0 ip6-localnet

ff00::0 ip6-mcastprefix

ff02::1 ip6-allnodes

ff02::2 ip6-allrouters

10.0.0.3    books-ms-db

10.0.0.3    books-ms-db.my-network

Наконец, давайте посмотрим, как Swarm распространял наши контейнеры.

1

docker ps --filter name=books --format "table {{.Names}}"

Вывод следующий.

1

2

3

NAMES

swarm-node-2/books-ms-db

swarm-node-1/booksms_app_1

Swarm развернул контейнер приложения в swarm-node-1, а контейнер db — в swarm-node-2 .

Наконец, давайте проверим, правильно ли работает сервис book-ms . Мы не знаем, на каком сервере Swarm развернут контейнер или какой порт открыт. Поскольку у нас нет (пока) прокси-сервера, мы получим IP-адрес и порт службы от Consul, отправим запрос PUT для сохранения некоторых данных в базе данных, находящейся в другом контейнере, и, наконец, отправим запрос GET чтобы проверить, можем ли мы получить запись. Поскольку у нас нет прокси-службы, которая бы обеспечивала перенаправление запросов на правильный сервер и порт, нам придется получить адрес и порт от Consul. Для получения дополнительной информации о том, как настроить прокси-сервис, пожалуйста, обратитесь к статьям Scaling To Infinity с Docker Swarm, Docker Compose и Consul .

01

02

03

04

05

06

07

08

09

10

11

12

ADDRESS=`curl \

    localhost:8500/v1/catalog/service/books-ms \

    | jq -r '.[0].ServiceAddress + ":" + (.[0].ServicePort | tostring)'`

 

curl -H 'Content-Type: application/json' -X PUT -d \

  '{"_id": 2,

  "title": "My Second Book",

  "author": "John Doe",

  "description": "A bit better book"}' \

  $ADDRESS/api/v1/books | jq '. '

 

curl $ADDRESS/api/v1/books | jq '.'

Последний вывод команды выглядит следующим образом.

1

2

3

4

5

6

7

[

  {

    "author": "John Doe",

    "title": "My Second Book",

    "_id": 2

  }

]

Если бы служба не могла обмениваться данными с базой данных, расположенной в другом узле, мы не смогли бы ни поместить, ни получить данные. Сеть между контейнерами, развернутыми на отдельных серверах, работала! Все, что нам нужно сделать, это использовать дополнительный аргумент с Docker Compose ( –x-network ) и убедиться, что код службы использует информацию из файла hosts.

Другое преимущество работы с сетями Docker заключается в том, что если один контейнер перестает работать, мы можем повторно развернуть его (возможно, на отдельном сервере) и, предполагая, что сервисы, использующие его, могут обрабатывать временную потерю соединения, продолжать использовать его, как будто ничего не произошло.

Сеть Docker была долгожданной функцией, которая позволяет нам распределять контейнеры, не опасаясь, смогут ли они общаться друг с другом. Наконец, мы можем распространять контейнеры без ограничений, введенных ссылками (связанный контейнер должен был работать на том же сервере). Больше нет необходимости в обходных решениях, которые некоторым из нас приходилось использовать в прошлом. Это захватывающая функция, которая, несомненно, позволит Docker Swarm перейти на следующий уровень.

Попробуй сам. Изучите другие варианты представленных сетей Docker. Когда вы закончите, вы, вероятно, захотите остановить виртуальные машины, которые мы создали, чтобы освободить ресурсы для других задач.

Сеть с автономными контейнерами | Документация Docker

Расчетное время чтения: 18 минут

Эта серия руководств посвящена работе в сети для автономных контейнеров Docker.
Для работы в сети с сервисами Swarm см.
Работа в сети с услугами роя. Если вам нужно
узнать больше о сети Docker в целом, см. обзор.

В этот раздел включены три разных руководства. Вы можете запустить каждый из них на
Linux, Windows или Mac, но для последних двух вам понадобится второй Docker
хост работает в другом месте.

  • Использовать мостовую сеть по умолчанию демонстрирует
    как использовать сеть по умолчанию bridge , которую Docker настраивает для вас
    автоматически. Эта сеть — не лучший выбор для производственных систем.

  • Использование пользовательских мостовых сетей показывает
    как создавать и использовать свои собственные сети мостов, чтобы соединять контейнеры
    работает на том же хосте Docker. Это рекомендуется для автономных контейнеров.
    запущено в производство.

Хотя оверлейные сети обычно используются для служб роя,
вы также можете использовать оверлейную сеть для автономных контейнеров.Это покрыто как
часть учебника по использованию оверлейных сетей.

Использовать мостовую сеть по умолчанию

В этом примере вы запускаете два разных контейнера alpine на одном Docker.
хост и проведите несколько тестов, чтобы понять, как они общаются друг с другом. Вы
должен быть установлен и запущен Docker.

  1. Откройте окно терминала. Составьте список текущих сетей, прежде чем делать что-либо еще.
    Вот что вы должны увидеть, если никогда не добавляли сеть или не инициализировали
    на этот демон Docker.Вы можете видеть разные сети, но вы должны
    хотя бы посмотрите эти (идентификаторы сети будут другими):

      $ докер сеть ls
    
    ИМЯ СЕТЕВОГО ИДЕНТИФИКАЦИИ ДРАЙВЕРА ОБЪЕМ
    17e324f45964 мост мост местный
    6ed54d316334 хост хост локальный
    7092879f2cc8 нет null локальный
      

    В списке отображается сеть моста по умолчанию , а также хост и нет . В
    последние два не являются полноценными сетями, но используются для запуска контейнера
    подключен напрямую к сетевому стеку хоста демона Docker, или для запуска
    контейнер без сетевых устройств. Этот учебник соединит два
    контейнеров к сети bridge .

  2. Запустите два контейнера alpine , в которых работает ash , оболочка Alpine по умолчанию.
    а не bash . Флаги -dit означают запуск отсоединенного контейнера
    (в фоновом режиме), интерактивный (с возможностью ввода текста) и
    с TTY (чтобы вы могли видеть ввод и вывод).Поскольку вы начинаете это
    detached, вы не будете подключены к контейнеру сразу. Вместо этого
    будет напечатан идентификатор контейнера. Поскольку вы не указали ни одного
    - флаги сети , контейнеры подключаются к сети моста
    по умолчанию .

      $ docker run -dit --name alpine1 альпийский ясень
    
    $ docker run -dit --name alpine2 альпийский ясень
      

    Убедитесь, что оба контейнера действительно запущены:

      $ док-контейнер ls
    
    КОНТЕЙНЕР ИДЕНТИФИКАЦИЯ ИЗОБРАЖЕНИЕ КОМАНДА СОЗДАНО СОСТОЯНИЕ ИМЕНА ПОРТОВ
    602dbf1edc81 alpine "ясень" 4 секунды назад Вверх на 3 секунды alpine2
    da33b7aa74b0 альпийский "ясень" 17 секунд назад Вверх на 16 секунд альпийский1
      
  3. Проверьте сеть bridge , чтобы узнать, какие контейнеры к ней подключены.

      $ docker network осмотреть мост
    
    [
        {
            «Название»: «мост»,
            «Id»: «17e324f459648a9baaea32b248d3884da102dde19396c25b30ec800068ce6b10»,
            «Создано»: «2017-06-22T20: 27: 43.826654485Z»,
            "Область": "местный",
            «Водитель»: «мост»,
            «EnableIPv6»: ложь,
            "IPAM": {
                "Драйвер": "по умолчанию",
                «Параметры»: ноль,
                "Конфиг": [
                    {
                        «Подсеть»: «172.17.0.0/16»,
                        «Шлюз»: «172.17.0.1 "
                    }
                ]
            },
            «Внутренний»: ложь,
            "Присоединяемый": ложь,
            "Контейнеры": {
                "602dbf1edc81813304b6cf0a647e65333dc6fe6ee6ed572dc0f686a3307c6a2c": {
                    «Имя»: «alpine2»,
                    "EndpointID": "03b6aafb7ca4d7e531e292901b43719c0e34cc7eef565b38a6bf84acf50f38cd",
                    "MacAddress": "02: 42: ac: 11: 00: 03",
                    «IPv4Address»: «172.17.0.3/16»,
                    "IPv6Address": ""
                },
                "da33b7aa74b0bf3bda3ebd502d404320ca112a268aafe05b4851d1e3312ed168": {
                    «Имя»: «alpine1»,
                    "EndpointID": "46c044a645d6afc42ddd7857d19e9dcfb89ad790afb5c239a35ac0af5e8a5bc5",
                    "MacAddress": "02: 42: ac: 11: 00: 02",
                    «IPv4Address»: «172. 17.0.2 / 16 ",
                    "IPv6Address": ""
                }
            },
            "Параметры": {
                "com.docker.network.bridge.default_bridge": "истина",
                "com.docker.network.bridge.enable_icc": "правда",
                "com.docker.network.bridge.enable_ip_masquerade": "правда",
                "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
                "com.docker.network.bridge.name": "docker0",
                "com.docker.network.driver.mtu": "1500"
            },
            "Ярлыки": {}
        }
    ]
      

    Вверху приведена информация о сети моста , включая
    IP-адрес шлюза между хостом Docker и мостом
    сеть ( 172.17.0.1 ). Под ключом Контейнеры каждый подключенный контейнер
    указан вместе с информацией о его IP-адресе ( 172.17.0.2 для
    alpine1 и 172.17.0.3 для alpine2 ).

  4. Контейнеры работают в фоновом режиме. Используйте присоединение докера
    команда для подключения к alpine1 .

      $ докер прикрепить alpine1
    
    / #
      

    Приглашение изменится на # , чтобы указать, что вы являетесь пользователем root в пределах
    контейнер.Используйте команду ip addr show , чтобы показать сетевые интерфейсы.
    для alpine1 как выглядят изнутри контейнера:

      # ip адрес показать
    
    1: lo:  mtu 65536 qdisc noqueue state UNKNOWN qlen 1
        ссылка / петля 00: 00: 00: 00: 00: 00 brd 00: 00: 00: 00: 00: 00
        inet 127.0.0.1/8 область видимости хоста lo
           valid_lft навсегда предпочтительный_lft навсегда
        inet6 :: 1/128 хост области
           valid_lft навсегда предпочтительный_lft навсегда
    27: eth0 @ if28:  mtu 1500 qdisc noqueue state UP
        ссылка / эфир 02: 42: ac: 11: 00: 02 brd ff: ff: ff: ff: ff: ff
        Инет 172.17.0.2 / 16 область действия global eth0
           valid_lft навсегда предпочтительный_lft навсегда
        inet6 fe80 :: 42: acff: fe11: 2/64 ссылка на область видимости
           valid_lft навсегда предпочтительный_lft навсегда
      

    Первый интерфейс — это устройство обратной связи. Пока не обращай на это внимания. Заметить, что
    второй интерфейс имеет IP-адрес 172.17.0.2 , который совпадает
    адрес, указанный для alpine1 на предыдущем шаге.

  5. Изнутри alpine1 убедитесь, что вы можете подключиться к Интернету через
    пингует гугл.com . Флаг -c 2 ограничивает команду двумя ping
    попытки.

      # ping -c 2 google.com
    
    PING google.com (172.217.3.174): 56 байтов данных
    64 байта из 172.217.3.174: seq = 0 ttl = 41 time = 9,841 мс
    64 байта из 172.217.3.174: seq = 1 ttl = 41 time = 9,897 мс
    
    --- статистика пинга google.com ---
    2 пакета передано, 2 пакета получено, потеря пакетов 0%
    туда и обратно мин. / сред. / макс. = 9,841 / 9,869 / 9,897 мс
      
  6. Теперь попробуйте пропинговать второй контейнер.Сначала проверьте его IP-адрес,
    172.17.0.3 :

      # пинг -c 2 172.17.0.3
    
    PING 172. 17.0.3 (172.17.0.3): 56 байтов данных
    64 байта из 172.17.0.3: seq = 0 ttl = 64 time = 0,086 мс
    64 байта из 172.17.0.3: seq = 1 ttl = 64 time = 0,094 мс
    
    --- 172.17.0.3 статистика пинга ---
    2 пакета передано, 2 пакета получено, потеря пакетов 0%
    двусторонний мин. / средн. / макс. = 0,086 / 0,090 / 0,094 мс
      

    Успешно. Затем попробуйте пропинговать контейнер alpine2 за контейнером.
    название.Это не удастся.

      # пинг -c 2 alpine2
    
    пинг: неверный адрес 'alpine2'
      
  7. Отсоединить от alpine1 , не останавливая его, используя последовательность отсоединения,
    CTRL + p CTRL + q (удерживая нажатой CTRL и введите p , а затем q ).
    Если хотите, подключитесь к alpine2 и повторите шаги 4, 5 и 6 там,
    заменив alpine1 на alpine2 .

  8. Остановите и снимите оба контейнера.

      $ docker контейнер остановка alpine1 alpine2
    $ docker контейнер rm alpine1 alpine2
      

Помните, что сеть по умолчанию bridge не рекомендуется для производства. Чтобы
узнайте об определяемых пользователем мостовых сетях, перейдите к
следующий урок.

Использовать определяемые пользователем мостовые сети

В этом примере мы снова запускаем два контейнера alpine , но прикрепляем их к
пользовательская сеть под названием alpine-net , которую мы уже создали.Эти
контейнеры вообще не подключены к сети моста по умолчанию. Мы тогда
запустить третий контейнер alpine , который подключен к сети bridge , но
не подключен к alpine-net и четвертому контейнеру alpine , который
подключен к обеим сетям.

  1. Создайте сеть alpine-net . Вам не нужен флаг --driver bridge
    поскольку это значение по умолчанию, но в этом примере показано, как его указать.

      $ docker network create --driver bridge alpine-net
      
  2. Список сетей Docker:

      $ докер сеть ls
    
    ИМЯ СЕТЕВОГО ИДЕНТИФИКАЦИИ ДРАЙВЕРА ОБЪЕМ
    e9261a8c9a19 альпийский мост местный
    17e324f45964 мост мост местный
    6ed54d316334 хост хост локальный
    7092879f2cc8 нет null локальный
      

    Проверьте сеть alpine-net .Это показывает вам его IP-адрес и факт
    что к нему не подключены никакие контейнеры:

      $ проверка сети докеров alpine-net
    
    [
        {
            «Название»: «альпийская сеть»,
            «Id»: «e9261a8c9a19eabf2bf1488bf5f208b99b1608f330cff585c273d39481c9b0ec»,
            «Создано»: «2017-09-25T21: 38: 12.620046142Z»,
            "Область": "местный",
            «Водитель»: «мост»,
            «EnableIPv6»: ложь,
            "IPAM": {
                "Драйвер": "по умолчанию",
                "Параметры": {},
                "Конфиг": [
                    {
                        «Подсеть»: «172.18. 0.0 / 16 ",
                        «Шлюз»: «172.18.0.1»
                    }
                ]
            },
            «Внутренний»: ложь,
            "Присоединяемый": ложь,
            "Контейнеры": {},
            "Параметры": {},
            "Ярлыки": {}
        }
    ]
      

    Обратите внимание, что шлюз этой сети — 172.18.0.1 , в отличие от
    сеть моста по умолчанию, шлюз которой 172.17.0.1 . Точный IP-адрес
    может отличаться в вашей системе.

  3. Создайте свои четыре контейнера.Обратите внимание на флаги --network . Ты можешь только
    подключитесь к одной сети во время команды docker run , поэтому вам нужно использовать
    сеть докеров подключите затем, чтобы подключить alpine4 к мосту
    сеть.

      $ docker run -dit --name alpine1 --network alpine-net alpine ash
    
    $ docker run -dit --name alpine2 --network alpine-net альпийский ясень
    
    $ docker run -dit --name alpine3 альпийский ясень
    
    $ docker run -dit --name alpine4 --network alpine-net альпийский ясень
    
    $ docker network connect мост alpine4
      

    Убедитесь, что все контейнеры работают:

      $ док-контейнер ls
    
    КОНТЕЙНЕР ИДЕНТИФИКАЦИЯ ИЗОБРАЖЕНИЕ КОМАНДА СОЗДАНО СОСТОЯНИЕ ИМЕНА ПОРТОВ
    156849ccd902 альпийский "ясень" 41 секунду назад Вверх на 41 секунду альпийский4
    fa1340b8d83e альпийский "ясень" 51 секунду назад Вверх на 51 секунду альпийский3
    a535d969081e альпийский "ясень" Минуту назад Вверх Около минуты alpine2
    0a02c449a6e9 альпийский "ясень" Около минуты назад Вверх Около минуты alpine1
      
  4. Еще раз проверьте сеть bridge и сеть alpine-net :

      $ docker network осмотреть мост
    
    [
        {
            «Название»: «мост»,
            «Id»: «17e324f459648a9baaea32b248d3884da102dde19396c25b30ec800068ce6b10»,
            «Создано»: «2017-06-22T20: 27: 43. 826654485Z ",
            "Область": "местный",
            «Водитель»: «мост»,
            «EnableIPv6»: ложь,
            "IPAM": {
                "Драйвер": "по умолчанию",
                «Параметры»: ноль,
                "Конфиг": [
                    {
                        «Подсеть»: «172.17.0.0/16»,
                        «Шлюз»: «172.17.0.1»
                    }
                ]
            },
            «Внутренний»: ложь,
            "Присоединяемый": ложь,
            "Контейнеры": {
                "156849ccd902b812b7d17f05d2d81532ccebe5bf788c9a79de63e12bb92fc621": {
                    «Имя»: «alpine4»,
                    "EndpointID": "7277c5183f0da5148b33d05f329371fce7befc5282d2619cfb23690b2adf467d",
                    "MacAddress": "02: 42: ac: 11: 00: 03",
                    «IPv4Address»: «172.17.0.3 / 16 ",
                    "IPv6Address": ""
                },
                "fa1340b8d83eef5497166951184ad3691eb48678a3664608ec448a687b047c53": {
                    «Имя»: «alpine3»,
                    "EndpointID": "5ae767367dcbebc712c02d49556285e888819d4da6b69d88cd1b0d52a83af95f",
                    "MacAddress": "02: 42: ac: 11: 00: 02",
                    «IPv4Address»: «172. 17.0.2/16»,
                    "IPv6Address": ""
                }
            },
            "Параметры": {
                "com.docker.network.bridge.default_bridge": "истина",
                "com.docker.network.bridge.enable_icc ":" правда ",
                "com.docker.network.bridge.enable_ip_masquerade": "правда",
                "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
                "com.docker.network.bridge.name": "docker0",
                "com.docker.network.driver.mtu": "1500"
            },
            "Ярлыки": {}
        }
    ]
      

    Контейнеры alpine3 и alpine4 подключены к сети bridge .

      $ проверка сети докеров alpine-net
    
    [
        {
            «Название»: «альпийская сеть»,
            «Id»: «e9261a8c9a19eabf2bf1488bf5f208b99b1608f330cff585c273d39481c9b0ec»,
            «Создано»: «2017-09-25T21: 38: 12.620046142Z ",
            "Область": "местный",
            «Водитель»: «мост»,
            «EnableIPv6»: ложь,
            "IPAM": {
                "Драйвер": "по умолчанию",
                "Параметры": {},
                "Конфиг": [
                    {
                        «Подсеть»: «172. 18.0.0/16»,
                        «Шлюз»: «172.18.0.1»
                    }
                ]
            },
            «Внутренний»: ложь,
            "Присоединяемый": ложь,
            "Контейнеры": {
                "0a02c449a6e9a15113c51ab2681d72749548fb9f78fae4493e3b2e4e74199c4a": {
                    «Имя»: «alpine1»,
                    "EndpointID": "c83621678eff9628f4e2d52baf82c49f974c36c05cba152db4c131e8e7a64673",
                    "MacAddress": "02: 42: ac: 12: 00: 02",
                    «IPv4Address»: «172.18.0.2 / 16 ",
                    "IPv6Address": ""
                },
                "156849ccd902b812b7d17f05d2d81532ccebe5bf788c9a79de63e12bb92fc621": {
                    «Имя»: «alpine4»,
                    "EndpointID": "058bc6a5e9272b532ef9a6ea6d7f3db4c37527ae2625d1cd1421580fd0731954",
                    "MacAddress": "02: 42: ac: 12: 00: 04",
                    «IPv4Address»: «172.18.0.4/16»,
                    "IPv6Address": ""
                },
                "a535d969081e003a149be8917631215616d9401edcb4d35d53f00e75ea1db653": {
                    «Имя»: «alpine2»,
                    "EndpointID": "198f3141ccf2e7dba67bce358d7b71a07c5488e3867d8b7ad55a4c695ebb8740",
                    "MacAddress": "02: 42: ac: 12: 00: 03",
                    «IPv4Address»: «172. 18.0.3 / 16 ",
                    "IPv6Address": ""
                }
            },
            "Параметры": {},
            "Ярлыки": {}
        }
    ]
      

    Контейнеры alpine1 , alpine2 и alpine4 подключены к
    сеть alpine-net .

  5. В пользовательских сетях, таких как alpine-net , контейнеры могут не только
    общаться по IP-адресу, но также может преобразовывать имя контейнера в IP
    адрес. Эта возможность называется автоматическим обнаружением службы .Давайте
    подключитесь к alpine1 и проверьте это. alpine1 должно уметь разрешить
    alpine2 и alpine4 (и сам alpine1 ) на IP-адреса.

      $ докер-контейнер прикрепить alpine1
    
    # пинг -c 2 alpine2
    
    PING alpine2 (172.18.0.3): 56 байтов данных
    64 байта из 172.18.0.3: seq = 0 ttl = 64 time = 0,085 мс
    64 байта из 172.18.0.3: seq = 1 ttl = 64 time = 0,090 мс
    
    --- alpine2 статистика пинга ---
    2 пакета передано, 2 пакета получено, потеря пакетов 0%
    туда и обратно мин.  / сред. / макс. = 0.085 / 0,087 / 0,090 мс
    
    # пинг -c 2 alpine4
    
    PING alpine4 (172.18.0.4): 56 байтов данных
    64 байта из 172.18.0.4: seq = 0 ttl = 64 time = 0,076 мс
    64 байта из 172.18.0.4: seq = 1 ttl = 64 time = 0,091 мс
    
    --- alpine4 статистика пинга ---
    2 пакета передано, 2 пакета получено, потеря пакетов 0%
    двусторонний мин. / сред. / макс. = 0,076 / 0,083 / 0,091 мс
    
    # пинг -c 2 альпийский1
    
    PING alpine1 (172.18.0.2): 56 байтов данных
    64 байта из 172.18.0.2: seq = 0 ttl = 64 time = 0,026 мс
    64 байта из 172.18.0.2: seq = 1 ttl = 64 time = 0,054 мс
    
    --- alpine1 статистика пинга ---
    2 пакета передано, 2 пакета получено, потеря пакетов 0%
    туда и обратно мин. / сред. / макс. = 0.026 / 0,040 / 0,054 мс
      
  6. С alpine1 у вас вообще не должно быть возможности подключиться к alpine3 , т.к.
    его нет в сети alpine-net .

      # пинг -c 2 alpine3
    
    пинг: неверный адрес 'alpine3'
      

    Не только это, но вы не можете подключиться к alpine3 из alpine1 по его IP
    адрес тоже. Вернитесь к сети докеров и проверьте вывод на наличие
    соедините сеть и найдите IP-адрес alpine3 : 172.17.0.2 Попробуйте пинговать
    Это.

      # пинг -c 2172.17.0.2
    
    PING 172.17.0.2 (172.17.0.2): 56 байтов данных
    
    --- 172.17.0.2 статистика пинга ---
    2 пакета передано, 0 пакетов получено, 100% потеря пакетов
      

    Отсоедините от alpine1 , используя последовательность отсоединения,
    CTRL + p CTRL + q (удерживая нажатой CTRL и введите p , а затем q ).

  7. Помните, что alpine4 подключен к обоим мостам по умолчанию и сети
    и alpine-net .Он должен иметь доступ ко всем другим контейнерам.
    Однако вам нужно будет адресовать alpine3 по его IP-адресу. Прикрепить к нему
    и запускаем тесты.

      $ док-контейнер прикрепить alpine4
    
    # пинг -c 2 альпийский1
    
    PING alpine1 (172. 18.0.2): 56 байтов данных
    64 байта из 172.18.0.2: seq = 0 ttl = 64 time = 0,074 мс
    64 байта из 172.18.0.2: seq = 1 ttl = 64 time = 0,082 мс
    
    --- alpine1 статистика пинга ---
    2 пакета передано, 2 пакета получено, потеря пакетов 0%
    туда и обратно мин. / сред. / макс. = 0.074 / 0,078 / 0,082 мс
    
    # пинг -c 2 alpine2
    
    PING alpine2 (172.18.0.3): 56 байтов данных
    64 байта из 172.18.0.3: seq = 0 ttl = 64 time = 0,075 мс
    64 байта из 172.18.0.3: seq = 1 ttl = 64 time = 0,080 мс
    
    --- alpine2 статистика пинга ---
    2 пакета передано, 2 пакета получено, потеря пакетов 0%
    двусторонний мин. / сред. / макс. = 0,075 / 0,077 / 0,080 мс
    
    # пинг -c 2 альпийский3
    пинг: неверный адрес 'alpine3'
    
    # пинг -c 2 172.17.0.2
    
    PING 172.17.0.2 (172.17.0.2): 56 байтов данных
    64 байта из 172.17.0.2: seq = 0 ttl = 64 time = 0,089 мс
    64 байта из 172.17.0.2: seq = 1 ttl = 64 time = 0,075 мс
    
    --- 172.17.0.2 статистика пинга ---
    2 пакета передано, 2 пакета получено, потеря пакетов 0%
    двусторонний мин. / сред. / макс. = 0,075 / 0,082 / 0,089 мс
    
    # пинг -c 2 alpine4
    
    PING alpine4 (172. 18.0.4): 56 байтов данных
    64 байта из 172.18.0.4: seq = 0 ttl = 64 time = 0,033 мс
    64 байта из 172.18.0.4: seq = 1 ttl = 64 time = 0,064 мс
    
    --- alpine4 статистика пинга ---
    2 пакета передано, 2 пакета получено, потеря пакетов 0%
    туда и обратно мин. / сред. / макс. = 0,033 / 0,048 / 0,064 мс
      
  8. В качестве финального теста убедитесь, что все ваши контейнеры могут подключаться к Интернету.
    пингуя google.com . Вы уже подключены к alpine4 , поэтому начните с
    пытаюсь оттуда. Затем отсоедините от alpine4 и подключите к alpine3
    (который подключен только к сети bridge ) и повторите попытку. В заключение,
    подключиться к alpine1 (который подключен только к сети alpine-net )
    и попробуй еще раз.

      # ping -c 2 google.com
    
    PING google.com (172.217.3.174): 56 байтов данных
    64 байта из 172.217.3.174: seq = 0 ttl = 41 time = 9.778 мс
    64 байта из 172. 217.3.174: seq = 1 ttl = 41 time = 9,634 мс
    
    --- статистика пинга google.com ---
    2 пакета передано, 2 пакета получено, потеря пакетов 0%
    туда и обратно мин. / сред. / макс. = 9,634 / 9,706 / 9,778 мс
    
    CTRL + p CTRL + q
    
    $ docker container attach alpine3
    
    # ping -c 2 google.com
    
    PING google.com (172.217.3.174): 56 байтов данных
    64 байта из 172.217.3.174: seq = 0 ttl = 41 time = 9,706 мс
    64 байта из 172.217.3.174: seq = 1 ttl = 41 time = 9,851 мс
    
    --- статистика пинга google.com ---
    2 пакета передано, 2 пакета получено, потеря пакетов 0%
    туда и обратно мин. / сред. / макс. = 9.706 / 9,778 / 9,851 мс
    
    CTRL + p CTRL + q
    
    $ docker container attach alpine1
    
    # ping -c 2 google.com
    
    PING google.com (172.217.3.174): 56 байтов данных
    64 байта из 172.217.3.174: seq = 0 ttl = 41 time = 9.606 мс
    64 байта из 172.217.3.174: seq = 1 ttl = 41 time = 9.603 мс
    
    --- статистика пинга google.com ---
    2 пакета передано, 2 пакета получено, потеря пакетов 0%
    туда и обратно мин. / сред. / макс. = 9,603 / 9,604 / 9,606 мс
    
    CTRL + p CTRL + q
      
  9. Остановите и удалите все контейнеры и сеть alpine-net .

      $ docker контейнер остановка alpine1 alpine2 alpine3 alpine4
    
    $ docker контейнер rm alpine1 alpine2 alpine3 alpine4
    
    $ docker сеть rm alpine-net
      

Другие руководства по работе с сетями

Теперь, когда вы завершили учебные пособия по сети для автономных контейнеров,
вы можете захотеть пройти через эти другие сетевые учебники:

сеть, мост, маршрутизация, порты, оверлей

Настроить Docker в Windows | Документы Microsoft

  • 5 минут на чтение

В этой статье

Docker Engine и клиент не входят в состав Windows и должны устанавливаться и настраиваться отдельно.Кроме того, Docker Engine может принимать множество пользовательских конфигураций. Некоторые примеры включают настройку того, как демон принимает входящие запросы, параметры сети по умолчанию и параметры отладки / журнала. В Windows эти конфигурации можно указать в файле конфигурации или с помощью диспетчера управления службами Windows. В этом документе подробно описано, как установить и настроить Docker Engine, а также приведены некоторые примеры часто используемых конфигураций.

Установить Docker

Docker необходим для работы с контейнерами Windows.Docker состоит из Docker Engine (dockerd.exe) и клиента Docker (docker.exe). Самый простой способ установить все — воспользоваться кратким руководством, которое поможет вам все настроить и запустить первый контейнер.

Для установки по сценарию см. Использование сценария для установки Docker EE.

Прежде чем вы сможете использовать Docker, вам необходимо установить образы контейнеров. Для получения дополнительной информации см. Документацию для наших базовых образов контейнеров.

Настроить Docker с помощью файла конфигурации

Предпочтительным методом настройки Docker Engine в Windows является использование файла конфигурации. Файл конфигурации можно найти в ‘C: \ ProgramData \ Docker \ config \ daemon.json’. Вы можете создать этот файл, если он еще не существует.

Примечание

Не все доступные параметры конфигурации Docker применимы к Docker в Windows. В следующем примере показаны применимые параметры конфигурации. Дополнительные сведения о конфигурации Docker Engine см. В разделе Файл конфигурации демона Docker.

  {
    "плагины авторизации": [],
    "dns": [],
    "dns-opts": [],
    "dns-search": [],
    "exec-opts": [],
    "накопитель-драйвер": "",
    "storage-opts": [],
    "ярлыки": [],
    "лог-драйвер": "",
    «mtu»: 0,
    "pidfile": "",
    "корень данных": "",
    "кластер-магазин": "",
    "кластер-реклама": "",
    "отладка": правда,
    "хосты": [],
    "уровень журнала": "",
    "tlsverify": правда,
    "tlscacert": "",
    "tlscert": "",
    "tlskey": "",
    "группа": "",
    "default-ulimits": {},
    "мост": "",
    "фиксированный сидр": "",
    "raw-logs": ложь,
    "зеркала реестра": [],
    "небезопасные реестры": [],
    "disable-legacy-registry": ложь
}
  

Вам нужно только добавить желаемые изменения конфигурации в файл конфигурации. Например, следующий пример настраивает Docker Engine для приема входящих подключений через порт 2375. Все остальные параметры конфигурации будут использовать значения по умолчанию.

  {
    "hosts": ["tcp: //0.0.0.0: 2375"]
}
  

Аналогичным образом, следующий пример настраивает демон Docker для хранения образов и контейнеров по альтернативному пути. Если не указано иное,
по умолчанию — c: \ programdata \ docker .

  {
    "корень данных": "d: \\ docker"
}
  

В следующем примере демон Docker настраивается на прием только защищенных подключений через порт 2376.

  {
    «хосты»: [«tcp: //0.0.0.0: 2376», «npipe: //»],
    "tlsverify": правда,
    "tlscacert": "C: \\ ProgramData \\ docker \\ certs.d \\ ca.pem",
    "tlscert": "C: \\ ProgramData \\ docker \\ certs.d \\ server-cert.pem",
    "tlskey": "C: \\ ProgramData \\ docker \\ certs.d \\ server-key.pem",
}
  

Настроить Docker в службе Docker

Docker Engine также можно настроить, изменив службу Docker с помощью sc config . Используя этот метод, флаги Docker Engine устанавливаются непосредственно в службе Docker.Выполните следующую команду в командной строке (cmd.exe, а не PowerShell):

  sc config docker binpath = "\" C: \ Program Files \ docker \ dockerd.exe \ "--run-service -H tcp: //0.0.0.0: 2375"
  

Примечание

Вам не нужно запускать эту команду, если ваш файл daemon.json уже содержит запись "hosts": ["tcp: //0.0.0.0: 2375"] .

Общая конфигурация

В следующих примерах файлов конфигурации показаны общие конфигурации Docker. Их можно объединить в один файл конфигурации.

Создание сети по умолчанию

Чтобы настроить Docker Engine так, чтобы он не создавал сеть NAT по умолчанию, используйте следующую конфигурацию.

  {
    "мост": "нет"
}
  

Для получения дополнительной информации см. Управление сетями Docker.

Установить группу безопасности Docker

Когда вы вошли в систему на хосте Docker и локально выполняете команды Docker, эти команды выполняются через именованный канал. По умолчанию только члены группы администраторов могут получить доступ к Docker Engine через именованный канал.Чтобы указать группу безопасности, которая имеет этот доступ, используйте флаг group .

  {
    "группа": "докер"
}
  

Конфигурация прокси

Чтобы задать информацию прокси для поиска докеров и вытягивания докеров , создайте переменную среды Windows с именем HTTP_PROXY или HTTPS_PROXY и значением информации прокси. Это можно сделать с помощью PowerShell с помощью команды, подобной этой:

  [Environment] :: SetEnvironmentVariable ("HTTP_PROXY", "http: // имя пользователя: пароль @ прокси: порт /", [EnvironmentVariableTarget] :: Machine)
  

После установки переменной перезапустите службу Docker.

  Докер Restart-Service
  

Дополнительные сведения см. В файле конфигурации Windows на сайте Docker.com.

Как удалить Docker

В этом разделе рассказывается, как удалить Docker и выполнить полную очистку компонентов системы Docker из вашей системы Windows 10 или Windows Server 2016.

Примечание

Все команды в этих инструкциях необходимо запускать из сеанса PowerShell с повышенными привилегиями.

Подготовьте вашу систему к удалению Docker

Перед удалением Docker убедитесь, что в вашей системе не запущены контейнеры.

Выполните следующие командлеты, чтобы проверить наличие запущенных контейнеров:

  # Выйти из режима роя (это автоматически остановит и удалит службы и оверлейные сети)
docker swarm leave --force

# Остановить все запущенные контейнеры
docker ps --quiet | ForEach-Object {docker stop $ _}
  

Также рекомендуется удалить все контейнеры, образы контейнеров, сети и тома из вашей системы перед удалением Docker. Вы можете сделать это, запустив следующий командлет:

  docker system prune --volumes --all
  

Удалить Docker

Затем вам нужно будет удалить Docker.

Для удаления Docker в Windows 10

  • Перейдите к настройкам > Приложения на вашем компьютере с Windows 10
  • В разделе Приложения и функции найдите Docker для Windows
  • Перейти к Docker для Windows > Удалить

Для удаления Docker в Windows Server 2016:

В сеансе PowerShell с повышенными привилегиями используйте командлеты Uninstall-Package и Uninstall-Module для удаления модуля Docker и соответствующего ему поставщика управления пакетами из вашей системы, как показано в следующем примере:

  Удалить-пакет -Name docker -ProviderName DockerMsftProvider
Uninstall-Module -Name DockerMsftProvider
  

Подсказка

Вы можете найти поставщика пакетов, который вы использовали для установки Docker с PS C: \> Get-PackageProvider -Name * Docker *

Очистить данные Docker и системные компоненты

После удаления Docker вам необходимо удалить сети Docker по умолчанию, чтобы их конфигурация не оставалась в вашей системе после того, как Docker исчезнет.Вы можете сделать это, запустив следующий командлет:

  Get-HNSNetwork | Remove-HNSNetwork
  

Для удаления сетей Docker по умолчанию в Windows Server 2016.

  Get-ContainerNetwork | Remove-ContainerNetwork
  

Запустите следующий командлет, чтобы удалить данные программы Docker из вашей системы:

  Remove-Item "C: \ ProgramData \ Docker" -Recurse
  

Вы также можете удалить дополнительные функции Windows, связанные с Docker / контейнерами в Windows.

Сюда входит функция «Контейнеры», которая автоматически включается в любой Windows 10 или Windows Server 2016 при установке Docker. Он также может включать в себя функцию «Hyper-V», которая автоматически включается в Windows 10 при установке Docker, но должна быть явно включена в Windows Server 2016.

Важно

Функция Hyper-V — это общая функция виртуализации, которая позволяет гораздо больше, чем просто контейнеры. Перед отключением функции Hyper-V убедитесь, что в вашей системе нет других виртуализированных компонентов, которым требуется Hyper-V.

Для удаления компонентов Windows в Windows 10:

  • Перейдите в панель управления > Программы > Программы и компоненты > Включите или выключите функции Windows .
  • Найдите имя функции или функций, которые вы хотите отключить — в данном случае Containers и (необязательно) Hyper-V .
  • Снимите флажок рядом с названием функции, которую вы хотите отключить.
  • Выбрать «ОК»

Для удаления компонентов Windows в Windows Server 2016:

В сеансе PowerShell с повышенными привилегиями запустите следующие командлеты, чтобы отключить функции Containers и (необязательно) Hyper-V в вашей системе:

  Remove-WindowsFeature Контейнеры
Удалить-WindowsFeature Hyper-V
  

Перезагрузите систему

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

  Перезагрузить компьютер-принудительно
  

В соединении отказано? Сеть Docker и ее влияние на ваш образ

Не удается подключиться к серверу, работающему в вашем контейнере? Давайте посмотрим, почему и как это исправить, начав с примера.

Если на вашем компьютере запущен сервер, прослушивающий 127.0.0.1 , адрес «loopback» или «localhost»:

  $ python3 -m http.server --bind 127.0.0.1
Обслуживание HTTP на 127.0.0.1 порту 8000 (http://127.0.0.1:8000/) ...
  

Затем вы можете загрузить его в свой браузер по адресу http://127.0.0.1:8000.

Но если вы убьете его и запустите в контейнере:

  $ docker run -p 8000: 8000 -it --entrypoint = bash python: 3.7-тонкий
root @ 85bdb39291b3: / # python3 -m http.сервер --bind 127.0.0.1
Обслуживание HTTP на 127.0.0.1 порту 8000 (http://127.0.0.1:8000/) ...
  

Если вы затем попытаетесь подключиться с помощью браузера к http://127.0.0.1:8000, вы получите отказ в соединении или сброс соединения.

Что происходит?
Чтобы понять, как решить эту проблему, вам нужно знать минимум о том, как работает сеть Docker.
В частности, эта статья будет охватывать:

  • Сетевые пространства имен и то, как Docker их использует.
  • Что делает docker run -p 5000: 5000 и почему наш пример выше не работает.
  • Как исправить ваше изображение, чтобы сервер был доступен.

Сеть без Docker

Давайте начнем с нашего первого сценария: вы запускаете сервер непосредственно внутри своей операционной системы, а затем подключаетесь к нему.
Я предполагаю, что основной ОС является Linux для простоты объяснения. Docker работает в операционных системах, отличных от Linux, таких как macOS, при запуске виртуальной машины Linux, но практические последствия такие же.

Ваша операционная система имеет несколько сетевых «интерфейсов».Например, на моем компьютере (вывод сокращен для ясности):

  $ ifconfig
docker0: flags = 4099  mtu 1500
  инет 172.17.0.1

lo: flags = 73  mtu 65536
  инет 127.0.0.1

wlp0s20u8: flags = 4163  mtu 1500
  инет 192.168.7.202
  

В этом выводе мы видим три сетевых интерфейса:

  • На данный момент мы игнорируем docker0 .
  • lo — это интерфейс обратной связи с IPv4-адресом 127.0.0.1: это ваш собственный компьютер, адресный в памяти без какого-либо сетевого оборудования.
  • wlp0s20u8 — это моя WiFi-карта с IPv4-адресом 192.168.7.202 , и когда я разговариваю с компьютерами в Интернете, пакеты отправляются через этот интерфейс.

Давайте вернемся к нашему начальному рабочему примеру — вы запускаете сервер, прослушивающий 127.0.0.1 , а затем подключаетесь к нему.
Мы можем представить это так:

Сетевые пространства имен

Вы заметите, что изображение выше говорит о «пространстве имен сети по умолчанию».Так что это?

Docker — это система для запуска контейнеров : способ изолировать процессы друг от друга.
Он основан на ряде функций ядра Linux, одна из которых — сетевые пространства имен — способ, которым разные процессы могут иметь разные сетевые устройства, IP-адреса, правила брандмауэра и так далее.

По умолчанию каждый контейнер, запускаемый Docker, имеет собственное сетевое пространство имен со своими IP-адресами:

  $ docker run --rm -it busybox
/ # ifconfig
eth0 Link encap: Ethernet HWaddr 02: 42: AC: 11: 00: 02
          inet адрес: 172.17.0.2 Bcast: 172.17.255.255 Маска: 255.255.0.0

lo Link encap: Локальный шлейф
          inet адрес: 127.0.0.1 Маска: 255.0.0.0
  

Итак, этот контейнер имеет два интерфейса: eth0 и lo , каждый со своими собственными IP-адресами.
Но поскольку это другое сетевое пространство имен, это различных интерфейса , чем пространство имен по умолчанию, которое мы видели выше.

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

  $ docker run --rm пример
 * Работает на http: // 127.0.0.1: 5000 / (Для выхода нажмите CTRL + C)
  

Итоговая настройка сети выглядит так:

Теперь понятно, почему в соединении отказано: сервер прослушивает 127.0.0.1 внутри сетевого пространства имен контейнера.
Браузер подключается к 127.0.0.1 в основном сетевом пространстве имен по умолчанию.
Но это разные интерфейсы, поэтому соединение не выполняется.

Как нам соединить два сетевых пространства имен? С перенаправлением портов Docker.

Docker запускает перенаправление портов (недостаточно)

Если мы запустим docker run с -p 5000: 5000 , он перенаправит с все интерфейсы , на которых работает демон Docker (для наших целей, основное сетевое пространство имен), на внешний IP-адрес контейнера.

Чтобы разбить его явно: -p 5000: 5000 означает перенаправление трафика с порта 5000 на всех интерфейсах в основном сетевом пространстве имен на порт 5000 на внешнем интерфейсе контейнера. -p 8080: 80 перенаправит трафик с порта 8080 на всех интерфейсах в основном сетевом пространстве имен на порт 80 внешнего интерфейса контейнера. И так далее.

(Мы делаем порт 5000 специально, потому что именно там наш образ Docker прослушивает, порт по умолчанию для Flask.)

Итак, запустим контейнер, а затем посмотрим на диаграмму, чтобы визуально увидеть, что это означает:

  $ docker run --rm -p 5000: 5000 пример
 * Запуск на http://127.0.0.1:5000/ (для выхода нажмите CTRL + C)
  

И теперь мы видим вторую проблему: сервер прослушивает 127.0.0.1 внутри пространства имен контейнерной сети, но перенаправление портов идет на внешний IP-адрес 172.17.0.2 .

Таким образом, соединение сброшено или отказано.

Решение: слушать на всех интерфейсах

Переадресация портов может подключаться только к одному месту назначения, но вы можете изменить место прослушивания серверным процессом.
Вы делаете это, прослушивая 0.0.0.0 , что означает «прослушивать все интерфейсы».

Например, вы можете:

  $ docker run -p 8000: 8000 -it python: 3.7-тонкий python3 -m http.server --bind 0.0.0.0
  

Примечание: --bind 0.0.0.0 — это опция для http.server ; это не вариант для Docker.
У других серверов будут другие способы указать это.
Например, для приложения Flask, упакованного с Dockerfile , вы можете сделать:

Примечание: Помимо конкретной обсуждаемой темы, файлы Dockerfiles в этой статье не являются примерами передового опыта, поскольку из-за дополнительной сложности основная мысль статьи будет затемнена.

Чтобы убедиться, что вы пишете безопасные, правильные и быстрые файлы Docker, ознакомьтесь с моим руководством по быстрому запуску, которое включает в себя процесс упаковки и более 60 лучших практик.

  ИЗ питона: 3,7-тонкий-стрейч
RUN pip install колба
КОПИРОВАТЬ. .
ENV FLASK_APP = exampleapp: app
CMD [«колба», «запустить», «--host», «0.0.0.0»]
  

Теперь схема сети выглядит так:

Хотите быстро освоить упаковку Docker? Эта статья — отрывок из моей книги Just Enough Docker
Упаковка
.

Еда на вынос

  1. По умолчанию контейнеры работают в собственных сетевых пространствах имен со своими собственными IP-адресами.
  2. docker run -p 5000: 5000 перенаправит с все интерфейсы в основном сетевом пространстве имен (или, точнее, тот, где работает демон Docker) на внешний IP-адрес в контейнере.
  3. Следовательно, вам необходимо прослушивать внешний IP-адрес внутри контейнера, и самый простой способ сделать это — прослушать все интерфейсы: 0.0.0.0 .

Многопользовательская сеть Docker без Swarm

Docker имеет несколько типов сетей, но одна из них особенно интересна. Оверлейная сеть может охватывать границы хостов, поэтому контейнер вашего веб-приложения на HostA может легко взаимодействовать с контейнером базы данных на HostB по его имени. Ему даже не нужно знать, где находится этот контейнер.

К сожалению, вы не можете просто создать оверлейную сеть и надеяться, что она волшебным образом узнает обо всех участвующих хостах.Для этого должен быть еще один компонент.

Конечно, мы могли использовать Docker в режиме Swarm, и проблема была решена. Но нам не обязательно. Настроить сеть Docker с несколькими хостами без Swarm на самом деле довольно просто.

Предварительные требования

Поскольку нам придется иметь дело с несколькими хостами, мы будем использовать следующие дополнительные инструменты:

  1. VirtualBox — для запуска виртуальных хостов.
  2. Докер-машина

  3. — для создания и настройки этих хостов. Если вы используете Docker на Mac или Windows, скорее всего, он уже установлен.Но если этого не произойдет, инструкции по установке будут короткими и простыми.

План

Поскольку отдельные хосты Docker не знают друг о друге, им будет сложно поделиться чем-либо, особенно чем-то таким сложным, как сеть. Но если бы мы представили специальную службу, единственной задачей которой было бы вести список участвующих хостов, а также конфигурацию сети в целом, а затем сказали бы механизмам Docker использовать ее, это, вероятно, помогло бы.

Docker из коробки может работать с несколькими службами обнаружения.Я буду использовать Consul, но ZooKeeper и Etcd тоже подойдут. После того, как он будет запущен, мы создадим несколько хостов Docker и настроим их для использования одного с Consul в качестве хранилища конфигурации кластера. Тогда было бы тривиально создать оверлейную сеть, охватывающую эти хосты.

Установка службы обнаружения

Итак, нам нужно создать хост с установленным на нем Consul. Очень просто. Во-первых, давайте создадим для этого хост:

docker-machine создать -d virtualbox keyvalue

docker-machine create -d virtualbox keyvalue

Он в основном сообщает docker-machine создать хост с именем keyvalue , используя virtualbox в качестве драйвера.Созданный им хост будет иметь полностью настроенный движок Docker, поэтому мы можем использовать его для извлечения и запуска образа Consul.

Еще одно волшебство: поскольку сам исполняемый файл docker является просто клиентом движка Docker, мы можем сказать ему подключиться к движку на другой машине и отправить туда наши локальные команды! Конечно, мы могли бы просто docker-machine ssh keyvalue и делать все прямо там, но да ладно, это не так круто.

docker-machine config keyvalue может предоставлять настройки для подключения к движку Docker внутри вновь созданного хоста, поэтому все, что нам нужно сделать, это передать их клиенту докера:

docker $ (значение ключа конфигурации докер-машины) \
запустить -d -p 8500: 8500 прогриум / консул -сервер -bootstrap

docker $ (значение ключа конфигурации docker-machine) \

run -d -p 8500: 8500 progrium / consul -server -bootstrap

Имея IP-адрес keyvalue , мы действительно можем перейти в браузере к порту 8500 и посмотреть, отвечает ли что-нибудь:

докер-машина IP keyvalue
№192.168.99.104

IP-адрес докер-машины keyvalue

# 192.168.99.104

Настройка хостов с движками Docker

Теперь нам нужно создать два хоста с обычными механизмами Docker, которые знают о только что созданной нами службе обнаружения. Движок Docker имеет два свойства для кластерного режима:

  1. кластер-хранилище для указания на службу обнаружения и
  2. cluster-Advertise , чтобы указать дверь к текущему движку Docker для других.Для хостов, созданных докер-машиной, это обычно eth2: 2376 .

Обычно мы идем в файл конфигурации Docker, чтобы установить их, но, поскольку мы используем docker-machine, мы фактически можем указать эти параметры во время создания хоста:

докер-машина создать -d virtualbox \
—engine-opt = «cluster-store = consul: // $ (IP-ключ докер-машины): 8500» \
—engine-opt = «cluster-Advertise = eth2: 2376» \
узел-0

docker-machine create -d virtualbox \

—engine-opt = «cluster-store = consul: // $ (docker-machine ip keyvalue): 8500» \

—engine-opt = «cluster- Advertise = eth2: 2376 «\

узел-0

А для второго узла:

докер-машина создать -d virtualbox \
—engine-opt = «cluster-store = consul: // $ (IP-ключ докер-машины): 8500» \
—engine-opt = «cluster-Advertise = eth2: 2376» \
узел-1

docker-machine create -d virtualbox \

—engine-opt = «cluster-store = consul: // $ (docker-machine ip keyvalue): 8500» \

—engine-opt = «cluster- Advertise = eth2: 2376 «\

узел-1

Магия: часть 1

Теперь давайте подключимся к первому хосту по SSH и создадим на нем оверлейную сеть.Тот, который должен был пересекать границы хоста, помните?

Сеть Docker

— Часть 2 | Блог Шриниваса Макама

Этот блог — часть моей серии статей о Docker. Это продолжение моего предыдущего блога о Docker Networking. В этом блоге я расскажу о текущих сетевых ограничениях Docker, обзоре Pipework и примере приложения Docker, в котором я связал контейнеры на 2 разных хостах.

При создании контейнеров Docker предоставляет 4 сетевых параметра:

  1. –net = мост.Это вариант по умолчанию, который Docker предоставляет, когда контейнеры подключаются к мосту Linux «docker».
  2. –net = хост. В этом варианте для контейнера не создается новое сетевое пространство имен, и контейнер использует то же сетевое пространство имен, что и хост-компьютер.
  3. –net = (имя или идентификатор контейнера). В этом варианте новый контейнер использует то же сетевое пространство имен, что и указанный контейнер в параметре «net». (Пример: «sudo docker run -ti –name = ubuntu2 –net = container: ubuntu1 ubuntu: 14.04 / bin / bash ». Здесь контейнер ubuntu2 использует то же сетевое пространство имен, что и контейнер ubuntu1)
  4. –net = нет. В этом варианте контейнеру не выделяется новое сетевое пространство имен. В этом случае создается только интерфейс обратной связи. Этот параметр полезен в сценариях, где мы хотим создать собственные сетевые параметры для контейнера.

В настоящее время встроенная сеть Docker имеет следующие ограничения.

  • Невозможно создать более 1 интерфейса в контейнере.
  • Контейнеры с несколькими хостами сложно создать.
  • Схема IP-адресации

  • для контейнеров не является гибкой.

В Docker Networking ведется большая работа. Некоторые из них — Weave, Flannel, Docknet, Pipework. Также обсуждается предложение по созданию сети Docker с несколькими хостами. В этом блоге я расскажу о Pipework.

Обзор трубопроводов:

Pipework — это сценарий, разработанный Джеромом Петазонни для объединения контейнеров Docker в сеть в сложных средах.Как упоминал сам Джереми, сценарий является временным решением до тех пор, пока более постоянное решение не будет разработано изначально в Docker. Для контейнеров трубопровод имеет следующие особенности.

  • Создавайте любое количество интерфейсов с произвольными IP-адресами.
  • Позволяет использовать мост ovs вместо моста Linux.
  • Позволяет изолировать контейнеры с помощью vlan.
  • Позволяет настроить IP, mac, маску сети, шлюз.

Отсюда можно установить трубопровод.

Пример приложения с контейнерами между 2 хостами:

Мы создадим приложение, как показано ниже. Здесь цель состоит в том, чтобы веб-контейнеры взаимодействовали с контейнерами БД через другой хост и обеспечивали изоляцию между контейнерами. Это устанавливается в первую очередь через сценарий конвейера.

  • Узел 1 имеет 2 экземпляра веб-контейнера. В веб-контейнере уже установлено клиентское приложение postgres.
  • Хост 2 имеет 2 экземпляра контейнера db.
  • Веб-контейнер 1 находится в vlan 10, а веб-контейнер 2 находится в vlan 20. Клиент db 1 находится в vlan 10, а клиент 2 db находится в vlan 20. Это позволяет веб-контейнеру 1 взаимодействовать с контейнером 1 db, а веб-контейнер 2 — для разговора в контейнер 2.
  • Между двумя хостами есть туннель GRE для соединения хоста с хостом.

Предварительные требования:

  • У меня есть 2 виртуальных машины с Ubuntu 14.04 в качестве 2 хостов на Virtualbox. У меня на обоих хостах установлен Docker 1.4.1.
  • Два хоста имеют сетевой интерфейс только для хоста, который обеспечивает соединение между двумя хостами.
  • На обоих хостах установлены следующие образы контейнеров — smakam / apachedocker и training / postgres. Оба они доступны в Docker Hub, первый — это веб-контейнер, а второй — контейнер postgres.
  • Установите трубопроводы в оба хоста.
  • Openvswitch необходимо установить на обоих хостах. В моем случае у меня установлен openvswitch 2.3.0.

Выполнить следующее на хосте 1. Это создаст 2 контейнера и туннель GRE. Контейнеры будут созданы без возможности подключения к сети. Конечная точка туннеля GRE должна быть другим концом интерфейса Ethernet только для хоста на хост-машине.

 sudo docker run -d --net = нет smakam / apachedocker
sudo docker run -d --net = none smakam / apachedocker
sudo ovs-vsctl add-port ovsbr0 gre0 - установить параметры интерфейса gre0 type = gre: remote_ip = 192.168.56.105
 

Запишите идентификаторы контейнеров и выполните следующее.Это будет использовать сценарий конвейерной обработки и создать интерфейс от контейнера к мосту ovs с указанным IP-адресом и vlan.

 sudo ~ / pipework / pipework ovsbr0  11.1.1.1/24 @ 10
sudo ~ / pipework / pipework ovsbr0  11.1.1.2/24 @ 20
 

Выполните следующее на хосте 2. Это создаст 2 контейнера и туннель GRE.

 sudo docker run -d --net = нет обучения / postgres
sudo docker run -d --net = нет обучения / postgres
sudo ovs-vsctl add-port ovsbr0 gre0 - установить параметры интерфейса gre0 type = gre: remote_ip = 192.168.56.102
 

Запишите идентификаторы контейнеров и выполните следующее.

 sudo ~ / pipework / pipework ovsbr0  11.1.1.3/24 @ 10
sudo ~ / pipework / pipework ovsbr0  11.1.1.4/24 @ 20
 

Ниже приведены выходные данные моста ovs на хосте 1. Здесь показаны 2 интерфейса veth, соответствующие 2 контейнерам, а также интерфейс туннеля.

 $ sudo ovs-vsctl показать
91dc682f-5496-45ec-9113-7be0f5ecce56
    Мост "овсбр0"
        Порт "gre0"
            Интерфейс "gre0"
                тип: gre
                варианты: {remote_ip = "192.168.56.105 "}
        Порт "veth2pl2852"
            тег: 10
            Интерфейс "veth2pl2852"
        Порт "veth2pl2747"
            тег: 20
            Интерфейс "veth2pl2747"
    ovs_version: "2.3.0"
 

Ниже приведен вывод ifconfig в контейнере 1 хоста 1:

.

 # ifconfig
eth2 Link encap: Ethernet HWaddr a6: 8d: d9: 3d: b2: e2
          inet адрес: 11.1.1.1 Bcast: 0.0.0.0 Маска: 255.255.255.0
          inet6 адрес: fe80 :: a48d: d9ff: fe3d: b2e2 / 64 Область действия: Ссылка
          ВВЕРХ ТРАНСЛЯЦИИ МУЛЬТИКАЛТА MTU: 1500 Метрическая система: 1
          Пакеты RX: 67 ошибок: 0 отброшено: 0 переполнений: 0 кадров: 0
          Пакеты TX: 51 ошибка: 0 сброшено: 0 переполнено: 0 несущая: 0
          коллизии: 0 txqueuelen: 1000
          Байт RX: 13666 (13.6 КБ) Байт передачи: 5796 (5,7 КБ)

lo Link encap: Локальный шлейф
          inet адрес: 127.0.0.1 Маска: 255.0.0.0
          inet6 адрес: :: 1/128 Область: Хост
          ЗАПИСЬ ВВЕРХ MTU: 65536 Метрическая система: 1
          Пакеты RX: 1 ошибок: 0 отброшено: 0 переполнений: 0 кадров: 0
          Пакеты TX: 1 ошибок: 0 сброшено: 0 переполнений: 0 несущая: 0
          коллизии: 0 txqueuelen: 0
          Байты приема: 112 (112,0 Б) байты передачи: 112 (112,0 Б)
 

Ниже приведен вывод ifconfig в контейнере 2 хоста 1:

.

 # ifconfig
eth2 Link encap: Ethernet HWaddr 8a: 86: c5: c0: 7b: a3
          inet адрес: 11.1.1.2 Bcast: 0.0.0.0 Маска: 255.255.255.0
          inet6 адрес: fe80 :: 8886: c5ff: fec0: 7ba3 / 64 Область действия: Ссылка
          ВВЕРХ ТРАНСЛЯЦИИ МУЛЬТИКАЛТА MTU: 1500 Метрическая система: 1
          Пакеты RX: 69 ошибок: 0 отброшено: 0 переполнений: 0 кадров: 0
          Пакеты TX: 50 ошибок: 0 сброшено: 0 переполнено: 0 несущая: 0
          коллизии: 0 txqueuelen: 1000
          Байт приема: 13798 (13,7 КБ) байтов передачи: 5778 (5,7 КБ)

lo Link encap: Локальный шлейф
          inet адрес: 127.0.0.1 маска: 255.0.0.0
          inet6 адрес: :: 1/128 Область: Хост
          ЗАПИСЬ ВВЕРХ MTU: 65536 Метрическая система: 1
          Пакеты RX: 0 ошибок: 0 отброшено: 0 переполнений: 0 кадров: 0
          Пакеты TX: 0 ошибок: 0 отброшено: 0 переполнений: 0 носитель: 0
          коллизии: 0 txqueuelen: 0
          Байты RX: 0 (0,0 B) Байты TX: 0 (0,0 B)
 

Контейнер 1 на хосте 2 имеет IP-адрес 11.1.1.3, а контейнер 2 на хосте 2 имеет IP-адрес 11.1.1.4.

Тестирование IP-соединения:

Убедитесь, что контейнер 1 на хосте 1 (веб-контейнер) может проверять связь только с контейнером 1 на хосте 2 (контейнер db).Точно так же убедитесь, что контейнер 2 на хосте 1 (веб-контейнер) может пинговать только контейнер 2 на хосте 2 (контейнер db).

Подключение тестового приложения:

Для этого я выполнил следующие команды на хосте 1, контейнере 1. Это создает простую таблицу, вставляет строку и выполняет запрос к базе данных postgres.

 psql -h 11.1.1.3 -p 5432 -U docker -c «СОЗДАТЬ проекты таблиц (заголовок TEXT NOT NULL, описание TEXT NOT NULL)»
psql -h 11.1.1.3 -p 5432 -U docker -c "ВСТАВИТЬ в проекты VALUES ('first', 'sample')"
psql -h 11.1.1.3 -p 5432 -U docker -c «ВЫБРАТЬ * из проектов»
 

Ниже приводится окончательный результат:

 # psql -h 11.1.1.3 -p 5432 -U docker -c "ВЫБРАТЬ * из проектов"
 название | описание
------- + -------------
 первый | образец
(1 ряд)
 

Я провел аналогичный тест на хосте 1, контейнере 2.

Ссылки:

Нравится:

Нравится Загрузка …

Связанные

.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *