Невозможно обмениваться данными между контейнерами докеров на локальном хосте

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

  • Один контейнер докеров для .NET Core API (файл Docker, автоматически созданный VS-2019)
  • Один докер-контейнер для приложения Angular 9

Доступ к API осуществляется по адресу https://localhost:44384/api/weatherforecast Доступно контейнерное приложение angular на https://localhost:4200

Если я запускаю приложение angular без докера, после устранения проблем CORS с прокси-сервером я могу подключиться к https://localhost:44384/api/weatherforecast. Однако, когда я запускаю докеризованную версию, я получаю следующую ошибку:

Failed to load resource: the server responded with a status of 504 (Gateway Timeout)

В консоли VS я вижу эту ошибку:

clearance_1  | [HPM] Error occurred while trying to proxy request /api/weatherforecast from loccoalhost:4200 to https://localhost:44384 (ECONNREFUSED) (https://nodejs.org/api/errors.html#errors_common_system_errors)

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

Вот шаги: 1. Создайте мостовую «тестовую» сеть.

docker network create test
  1. Подключите оба контейнера к вновь созданной сети:

тест подключения к сети докеров [идентификатор контейнера 1]

тест подключения к сети докеров [идентификатор контейнера 2]

  1. Если я проверю сеть, все будет в порядке, но api по-прежнему не вызывается на localhost

Другие потенциально полезные вещи:

docker-compose.yml:

version: "3.7"
services:
  clearance:
     build:
     # network: host
      context: .
      dockerfile: DockerFileLocal
     ports:
       - 4200:4200
     volumes:
       - /app/node_modules
       - .:/app

proxy.conf.json

{
   "/api/*": {
      "target": "https://localhost:44384",
      "secure": false,
      "logLevel": "debug",
      "changeOrigin": true
   }
}

Что мне не хватает?


person Dragos Stoica    schedule 12.03.2020    source источник
comment
Как вы запустили api контейнер докеров?   -  person Thanh Nguyen Van    schedule 12.03.2020
comment
Не знаю, как Visual Studio запускает контейнер. Это конфигурации запуска: Docker: {commandName: Docker, launchBrowser: true, launchUrl: {Scheme}: // {ServiceHost}: {ServicePort} / api / weatherforecast, environmentVariables: {ASPNETCORE_URLS: https: // +: 443; http: // +: 80, ASPNETCORE_HTTPS_PORT: 44384}, httpPort: 52012, useSSL: true, sslPort: 44384}   -  person Dragos Stoica    schedule 12.03.2020
comment
Давайте сосредоточимся на прокси и контейнере api. В конфигурации прокси вы указываете, что запросы к /api/* будут перенаправлены на localhost:44384. Однако в прокси-контейнере localhost ссылается на сам контейнер, а в прокси-контейнере на 44384 ничего не работает. Вы можете найти решение. Прочтите больше и больше .   -  person leopal    schedule 12.03.2020


Ответы (2)


У меня была аналогичная проблема с приложением angular и API, работающими в отдельных контейнерах Docker.
Оба приложения по отдельности работали нормально при следующих настройках:

Angular работает на http://localhost:4200
API работает на http://localhost:8080

Проблема

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

this.http.get('http://localhost:8080').subscribe(console.log);

Решение

Ссылки
Ссылка на контейнеры в другом сервисе. Укажите имя службы и псевдоним ссылки (SERVICE: ALIAS) или просто имя службы. Контейнеры для связанной службы доступны по имени хоста, совпадающему с псевдонимом, или по имени службы, если псевдоним не был указан.

Когда одному контейнеру необходимо достичь другого контейнера по сети, нам нужно создать ссылку.
В итоге я создал ссылку на службу api в определении службы angular в docker-compose.yml

version: "2"
services:
  api:
    build:
      context: .
      dockerfile: ./api/Dockerfile
    volumes:
      - ./api:/usr/src/app
    ports:
      - "8080:8080"

  angular:
    build:
      context: .
      dockerfile: ./angular/Dockerfile
    volumes:
      - ./angular:/usr/src/app
    ports:
      - "4200:4200"
    links:
      - api

Затем я исправил сетевую ошибку, заменив localhost на api в приложении Angular.

this.http.get('http://api:8080').subscribe(console.log);

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

person Reqven    schedule 12.03.2020
comment
ссылки устарела и не должна использоваться. - person leopal; 12.03.2020
comment
Флаг командной строки --link устарел, а не свойство links в файле компоновки докеров. - person Reqven; 12.03.2020
comment
Собственно, @leopal прав: ссылки считаются устаревшими в целом, в том числе в файлах компоновки (docs.docker.com/compose/compose-file/compose-file-v2/#links) - person Z4-tier; 18.03.2020

Добавьте раздел в свой файл композиции под каждой службой, который объявляет статические IP-адреса для каждого контейнера:

services:
  webserver:
    build:
      dockerfile: Dockerfile
      context: .
    depends_on:
      - some_other_container
    ports:
      - "443:443"
    environment:
      - MY_VAR='my_val'
########### ADD THIS PART ##############
    networks:
        dev_net:
          ipv4_address: "192.168.0.50"

и добавьте раздел на том же уровне, что и services для сети:

networks:
  dev_net:
    name: my_dev_net
    driver: overlay
    ipam:
      config:
          - subnet: "192.168.0.0/24"

Затем убедитесь, что размещенные приложения настроены на использование этих IP-адресов для связи. Если IP-адреса не назначаются вручную, докер будет в значительной степени действовать как DHCP-сервер и давать любые IP-адреса, которые он решит назначить.


Чтобы уточнить: я думаю, что часть проблемы, с которой вы столкнулись, связана с самой сетью Docker: на Mac и Windows Docker действительно не может предоставить полностью маршрутизируемую виртуальную сеть, в которой IP-адреса, назначенные контейнерам, доступны. прямо снаружи. Независимо от того, какое решение вы выберете, это ограничение придется обойти. Единственный способ сделать контейнер доступным извне - напрямую привязать его к портам на хосте (используя docker run -p [source_port]:[host_port]).

Вот демонстрация, которая должна прояснить мое предложение. Это будет:

  • Создайте два контейнера, используя один docker-compose.yml файл
  • Контейнер №1 будет использовать openssl для обслуживания простого текстового файла через порт 8080.
  • Порт 8080 в контейнере №1 будет привязан к тому же порту на хосте.
  • Контейнер № 2 будет использовать curl для извлечения файла из Контейнера № 1 с использованием IP-адреса частной сети.
  • Та же команда curl запускается с хоста, но с использованием localhost вместо частного IP (поскольку он недоступен из внешнего докера)
  • Обоим контейнерам назначаются статические IP-адреса в частной сети Docker (которая определена в файле создания).

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


docker-compose.yml:

version: "3.7"
services:
  c1:
    build:
      dockerfile: Dockerfile
      context: ./c1
    ports:
      - "8080:8080"
    networks:
        dev_net:
          ipv4_address: "192.168.0.50"
  c2:
    build:
      dockerfile: Dockerfile
      context: ./c2
    depends_on:
      - c1
    networks:
      dev_net:
        ipv4_address: "192.168.0.51"
networks:
  dev_net:
    name: test_dev_net
    driver: overlay
    external: false
    ipam:
      config:
          - subnet: "192.168.0.0/24"


Контейнер №1 Dockerfile:

FROM alpine:3.7
RUN apk update && apk upgrade && apk add openssl
COPY  run.sh /run.sh
CMD ["/run.sh"]


Контейнер №1 run.sh:

#!/bin/sh

echo "HELLO, WORLD!" >> test_file.txt

openssl req -x509 -newkey rsa:2048 -keyout key.pem \
    -out cert.pem -days 365 -nodes -subj /C=\/ST=\/L=\/O=\/OU=\/CN=\/

openssl s_server -key key.pem -cert cert.pem -accept 8080 -HTTP &

sleep 25


Контейнер №2 Dockerfile:

FROM alpine:3.7
RUN apk update && apk upgrade && apk add curl;
COPY  run.sh /run.sh
CMD ["/run.sh"]


Контейнер №2 run.sh:

#!/bin/sh

c1_url="https://192.168.0.50:8080/test_file.txt"

for _ in $(seq 0 2); do
  curl -k -g  ${c1_url}
  sleep 5
done


сборка / запуск / тест:

$ docker-compose up & \
  sleep 10 && \
  curl -k -g "https://localhost:8080/test_file.txt"
[3] 63380

Starting docker_c1_1 ... done
Starting docker_c2_1 ... done
Attaching to docker_c1_1, docker_c2_1
c1_1  | Generating a RSA private key
c1_1  | .....................................+++++
c1_1  | writing new private key to 'keys/key.pem'
c1_1  | No value provided for Subject Attribute C, skipped
c1_1  | No value provided for Subject Attribute ST, skipped
c1_1  | No value provided for Subject Attribute L, skipped
c1_1  | No value provided for Subject Attribute O, skipped
c1_1  | No value provided for Subject Attribute OU, skipped
c1_1  | No value provided for Subject Attribute CN, skipped
c2_1  |   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
c2_1  |                                  Dload  Upload   Total   Spent    Left  Speed
100    42    0    42    0     0   3230      0 --:--:-- --:--:-- --:--:--  3230
c2_1  | HELLO, WORLD!   <<<<------ Container #2 curl output
c2_1  | HELLO, WORLD!
c2_1  | HELLO, WORLD!
HELLO, WORLD!           <<<<------ Host curl output
docker_c2_1 exited with code 0
c1_1  | DONE. Exiting...
docker_c1_1 exited with code 0
[3]   Done                    docker-compose up
$

Таким образом, это решение будет работать, чтобы позволить docker-compose создавать контейнеры, которые используют статическую IP-адресацию в частной сети докеров и которые также доступны через привязку порта на хосте.

person Z4-tier    schedule 12.03.2020
comment
Частные IP-адреса контейнера работают только в нескольких очень специфических средах; например, если приложение Angular запущено в браузере на хосте MacOS или Windows, оно вообще не сможет получить доступ к этому адресу. - person David Maze; 12.03.2020
comment
@DavidMaze Тебе стоит перечитать вопрос. У OP нет проблем с подключением к контейнерам с использованием опубликованных портов. Установка статического IP-адреса в сети докеров не изменит этого (как показывает пример, который я опубликовал). Это проблема, связанная с обменом между контейнерами в сети докеров. - person Z4-tier; 16.03.2020