无法在本地主机上的Docker容器之间进行通信

时间:2020-03-12 07:48:23

标签: angular docker docker-compose docker-networking core-api

首先,我是docker容器的新手,我对它们的运行方式了解不多,但是我有以下设置:

  • 一个用于.NET Core API的docker容器(由VS-2019自动生成的Docker文件)
  • 一个用于Angular 9应用程序的docker容器

可以通过https://localhost:44384/api/weatherforecast访问该API 可以通过https://localhost:4200

访问容器化的角度应用程序

如果我在没有docker的情况下运行有角度的应用程序,则在使用代理解决了CORS问题之后,我可以连接到https://localhost:44384/api/weatherforecast。但是,当我运行dockerized版本时,出现以下错误:

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. 将两个容器都连接到新创建的网络:

docker网络连接测试[容器ID 1]

docker网络连接测试[容器ID 2]

  1. 如果我检查网络,一切似乎都很好,但是api仍无法在本地主机上调用

其他可能有用的东西:

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
   }
}

我想念什么?

2 个答案:

答案 0 :(得分:2)

Angular应用程序和API都在单独的Docker容器中运行时遇到类似的问题。
通过以下设置,两个应用都可以正常运行:

Angularhttp://localhost:4200运行
APIhttp://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

然后,我通过在Angular应用中将localhost替换为api来解决了网络错误。

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

您不需要代理。但是,您可能需要调整配置才能使其正常工作。

答案 1 :(得分:0)

在每个服务下的组成文件中添加一个部分,为每个容器声明静态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,则docker几乎会像DHCP服务器一样工作,并提供其决定分配的IP。


要澄清:我认为您遇到的部分问题是由于Docker联网本身:在Mac和Windows上,Docker不能真正提供将IP分配给其的可完全路由的虚拟网络。容器可直接从外部访问。无论采用哪种解决方案,都必须解决该限制。使容器从外部可访问的唯一方法是将其直接绑定到主机上的端口(使用docker run -p [source_port]:[host_port]

以下是一个演示,可以阐明我的建议。这将:

  • 使用单个docker-compose.yml文件构建两个容器
  • 容器#1 将使用openssl在端口8080上提供简单的文本文件
  • 容器#1 上的端口8080将绑定到主机上的相同端口
  • 第2容器将使用curl使用专用网络IP地址从第1容器获取文件
  • 主机运行相同的curl命令,但是使用localhost而不是私有IP(因为无法从外部docker访问)
  • 两个容器在Docker专用网络上均被分配了静态IP地址(在撰写文件中定义)

这样做的目的是提供一个最小的示例,该示例:允许两个Docker容器进行通信;通过码头工人专用网络;使用私有静态IP地址;同时还绑定到主机系统上的端口;允许从docker私有网络外部入站到容器的连接。


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构建使用私有docker网络上的静态IP寻址并且还通过主机上的端口绑定公开的容器。