Docker Compose容器间通信

5

我目前正在尝试使用基于Spring Boot的微服务,并且正在研究docker,但遇到了一些问题。

基本上我正在尝试将2个小型服务放到容器中:一个Spring Cloud Config服务和一个Spring Cloud Eureka服务(发现服务)。Eureka服务从配置服务中获取其配置。

这两个服务都是具有自己的Dockerfile的单独项目:

Dockerfile-cloud-config-service:

FROM openjdk:10.0.2-13-jre-sid
ENV APP_FILE cloud-config-service.jar
ENV APP_HOME /usr/apps
EXPOSE 8888
COPY target/$APP_FILE $APP_HOME/
WORKDIR $APP_HOME
ENTRYPOINT ["sh", "-c"]
CMD ["exec java -jar $APP_FILE"]

Dockerfile-discovery-service:

FROM openjdk:10.0.2-13-jre-sid
ENV APP_FILE discovery-service.jar
ENV APP_HOME /usr/apps
EXPOSE 8761
COPY target/$APP_FILE $APP_HOME/
WORKDIR $APP_HOME
ENTRYPOINT ["sh", "-c"]
CMD ["exec java -jar $APP_FILE"]

我正在使用docker-compose,尝试使用以下docker-compose.yml将它们绑定在一起:

version: '3.7'
services:
  cloud-config-service:
    container_name: cloud-config-service
    build:
      context: cloud-config-service
      dockerfile: Dockerfile-cloud-config-service
    image: cloud-config-service:latest
    ports:
      - 8888:8888
    networks:
      - emp-network

  discovery-service:
    container_name: discovery-service
    build:
      context: discovery-service
      dockerfile: Dockerfile-discovery-service
    image: discovery-service:latest
    ports:
      - 8761:8761
    networks:
      - emp-network
    links:
      - cloud-config-service

networks:
  emp-network:
    driver: bridge

起初我将discovery-service配置为从 http://localhost:8888 获取其配置,但经过一番探索,我发现容器中的 localhost 指的是容器本身,并在Docker文档中发现服务可以使用它们的名称相互引用。因此,我将discovery-service的属性更改为从 http://cloud-config-service:8888 获取其配置。这样做并不起作用,因此我写了这篇文章。
两个 Dockerfile 都能够很好地构建和运行,只是 discovery-service 无法获取位于 http://cloud-config-service:8888 上的 config-service。
如果使用 host 网络驱动程序和 http://localhost:8888 终端点,它确实可行,但这种方法感觉上有些投机取巧,不是应该这样做的方式。
我可能错过了一些微不足道的东西,但恐怕我找不到它。 编辑: discovery-service 控制台日志的小片段:
discovery-service       | 2018-10-02 13:14:26.798  INFO 1 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at : http://cloud-config-service:8888
cloud-config-service    | 2018-10-02 13:14:26.836  INFO 1 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration' of type [org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration$$EnhancerBySpringCGLIB$$8a18e3b3] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
discovery-service       | 2018-10-02 13:14:27.129  INFO 1 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Connect Timeout Exception on Url - http://cloud-config-service:8888. Will be trying the next url if available
discovery-service       | 2018-10-02 13:14:27.129  WARN 1 --- [           main] c.c.c.ConfigServicePropertySourceLocator : Could not locate PropertySource: I/O error on GET request for "http://cloud-config-service:8888/discovery-service/default": Connection refused (Connection refused); nested exception is java.net.ConnectException: Connection refused (Connection refused)
3个回答

2
首先,Docker 容器之间的通信是分布式服务中更大问题的一个子集 - 你不知道哪个服务(因此也不知道 它们的依赖)会在任何时刻停止工作,因此在构建应用程序时应考虑这种故障。
你所面临的问题很常见,特别是在 Docker 容器中,我认为容器之间的通信是 Docker 中一个经常处于开发变化中的主要部分。
为了解决您的问题,首先我想提出一些观点 -
  1. 从容器内部访问 localhost 将引用该容器本身。
  2. 在您的计算机上,localhost 实际上指的是您的本地主机,并将与您在 docker-compose 文件中为每个服务映射的服务一起映射。
  3. depends_on 仅等待容器启动,而不是等待实际进程开始运行 - 这可能意味着您正在等待的服务尚未完全启动,从而导致依赖服务超时。
你需要等待服务开始运行,而不仅仅是容器启动。你可以有两种可能的方法来实现这一点 -
1. 为你的`discovery-service`指定一个基于故障的重启策略。在你的情况下,故障是指它在连接到`cloud-config-service`时超时。类似于`restart: on-failure:10`,这意味着当`discover-service`失败并达到最大重试次数为10次时,你要求docker重新启动`discover-service`。这样,你将给其他容器(服务)足够的时间来启动和运行并确保具有重启策略的容器最终连接到该服务。
2. 使用另一个工具,如dockerize,在启动容器之前允许你等待其他服务。
此外,为确保您正确调试问题,请务必检查容器的日志以了解实际问题 - docker logs -f --tail=100 <container_name/container_id>
希望这能帮到您。

感谢您的评论。我将更深入地了解启动顺序和依赖关系。奇怪的是:按照@Niradnik的建议执行 docker exec curl 实际上返回了正确的配置。我开始认为问题可能出在Spring Cloud查询属性文件中指定的地址的方式上。 - Ash
我一直在努力解决类似的问题。通过docker-compose实现MySQL和Spring Boot容器之间的通信。解决方案#1(restart:on-failure:10)对我有用。感谢@graveti。 - Naresh Ravuru

1
我无法评论,所以我写了一个新答案。 你是否尝试运行像 docker exec -it myconatiner1 curl myconatiner2:port 这样的命令,来查看它是否能够识别或者 ping,如果不行,那么错误是什么?

感谢您的评论。事实证明,对配置服务进行卷曲确实有效!我现在开始认为问题可能出在Spring Cloud查询属性文件中指定的地址的方式上。 - Ash

0
听起来你走在正确的轨道上了... 我会介绍一个叫做 depends_on 的概念,告诉容器 discovery-service 在启动之前等待容器 cloud-config-service 启动完成。
  discovery-service:
    container_name: discovery-service
    build:
      context: discovery-service
      dockerfile: Dockerfile-discovery-service
    image: discovery-service:latest
    depends_on:
      - cloud-config-service
    ports:
      - 8761:8761
    networks:
      - emp-network
    links:
      - cloud-config-service

在容器启动之前,需要有一个有限的时间来启动它,以便能够积极地处理流量,因此最好关注这个启动序列,特别是当处理数据库容器时,其他容器应该使用depends_on


感谢您的回复@scott-stensland。不幸的是,那不是答案。最初我在docker-compose.yml中确实有一个depends-on,直到我遇到了Docker Compose文档中关于“链接”的以下段落:“链接还以与depends_on相同的方式表达服务之间的依赖关系,因此它们确定服务启动的顺序。” - Ash
接下来,我将消除对网络的提及...默认情况下,它会启动一个桥接网络。 - Scott Stensland
我已经从.yml文件中删除了所有与网络相关的内容,但不幸的是没有起到作用。 - Ash

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接