无法在本地主机上的 docker 个容器之间进行通信
Unable to communicate between docker containers on localhost
首先,我是 docker 容器的新手,我不太了解它们 运行,但我有这样的设置:
- .NET Core 的一个 docker 容器 API(Docker 由 VS-2019 自动生成的文件)
- 一个 docker 容器用于 Angular 9 应用程序
API 可在 https://localhost:44384/api/weatherforecast 到达
容器化 angular 应用可在 https://localhost:4200
访问
如果我是 运行 没有 docker 的 angular 应用程序,在使用代理修复 CORS 问题后,我可以连接到 https://localhost:44384/api/weatherforecast。但是,当我 运行 docker 化版本时,我收到以下错误:
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.创建网桥"test"网络
docker network create test
- 将两个容器连接到新创建的网络:
docker 网络连接测试 [container id 1]
docker 网络连接测试 [container id 2]
- 如果我检查网络,一切似乎都很好,但 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
}
}
我错过了什么?
在为每个容器声明静态 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 将绑定到主机上的相同端口
- Container #2 将使用 curl 从 Container #1 使用私有网络 IP 地址
获取文件
- 相同的 curl 命令是来自 host 的 运行,但使用
localhost
而不是私有 IP(因为无法从外部访问 [= =99=])
- 两个容器 都在 Docker 私有网络(在撰写文件中定义)
上分配了静态 IP 地址
这样做的目的是提供一个最小的示例:允许两个 Docker 容器进行通信;通过 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 Docker文件:
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 Docker文件:
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 地址,并且还通过主机上的端口绑定公开。
我在 angular 应用程序和 API 两个 运行 在 单独的 Docker 容器 中遇到了类似的问题。
这两个应用程序在以下设置下单独运行良好:
Angular
运行 在 http://localhost:4200
API
运行 在 http://localhost:8080
问题
Angular 应用无法访问 API。
下面的代码一直给我网络相关的错误。
this.http.get('http://localhost:8080').subscribe(console.log);
解决方案
Links
Link to containers in another service. Either specify both the service name and a link alias (SERVICE:ALIAS), or just the service name. Containers for the linked service are reachable at a hostname identical to the alias, or the service name if no alias was specified.
当一个容器需要通过网络到达另一个容器时,我们需要创建一个link.
我最终在 docker-compose.yml
的 angular
服务定义中为 api
服务创建了一个 link
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);
您不需要代理。但是,您可能需要调整配置才能使其正常工作。
首先,我是 docker 容器的新手,我不太了解它们 运行,但我有这样的设置:
- .NET Core 的一个 docker 容器 API(Docker 由 VS-2019 自动生成的文件)
- 一个 docker 容器用于 Angular 9 应用程序
API 可在 https://localhost:44384/api/weatherforecast 到达 容器化 angular 应用可在 https://localhost:4200
访问如果我是 运行 没有 docker 的 angular 应用程序,在使用代理修复 CORS 问题后,我可以连接到 https://localhost:44384/api/weatherforecast。但是,当我 运行 docker 化版本时,我收到以下错误:
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.创建网桥"test"网络
docker network create test
- 将两个容器连接到新创建的网络:
docker 网络连接测试 [container id 1]
docker 网络连接测试 [container id 2]
- 如果我检查网络,一切似乎都很好,但 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
}
}
我错过了什么?
在为每个容器声明静态 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 将绑定到主机上的相同端口
- Container #2 将使用 curl 从 Container #1 使用私有网络 IP 地址 获取文件
- 相同的 curl 命令是来自 host 的 运行,但使用
localhost
而不是私有 IP(因为无法从外部访问 [= =99=]) - 两个容器 都在 Docker 私有网络(在撰写文件中定义) 上分配了静态 IP 地址
这样做的目的是提供一个最小的示例:允许两个 Docker 容器进行通信;通过 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 Docker文件:
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 Docker文件:
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 地址,并且还通过主机上的端口绑定公开。
我在 angular 应用程序和 API 两个 运行 在 单独的 Docker 容器 中遇到了类似的问题。
这两个应用程序在以下设置下单独运行良好:
Angular
运行 在 http://localhost:4200
API
运行 在 http://localhost:8080
问题
Angular 应用无法访问 API。
下面的代码一直给我网络相关的错误。
this.http.get('http://localhost:8080').subscribe(console.log);
解决方案
Links
Link to containers in another service. Either specify both the service name and a link alias (SERVICE:ALIAS), or just the service name. Containers for the linked service are reachable at a hostname identical to the alias, or the service name if no alias was specified.
当一个容器需要通过网络到达另一个容器时,我们需要创建一个link.
我最终在 docker-compose.yml
angular
服务定义中为 api
服务创建了一个 link
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);
您不需要代理。但是,您可能需要调整配置才能使其正常工作。