【问题标题】:Docker Compose build order and/or firewall/networking errorDocker Compose 构建顺序和/或防火墙/网络错误
【发布时间】:2021-02-04 21:02:38
【问题描述】:

请注意:尽管我在此处提到 Java 和 Spring Boot,但本质上这 100% 是 Docker/Docker Compose 网络问题,因此,可以任何有 Docker 生态系统经验的人都会回答,无论他们是否熟悉 Java 和 Spring。


我有一个使用 MySQL 数据库作为其数据层的 Spring Boot (Java) Web 服务。我已使用以下Dockerfile 将其容器化:

FROM openjdk:8-jdk-alpine as cce

COPY application.yml application.yml
COPY my-service-local-keystore.p12 my-service-local-keystore.p12
COPY build/libs/my-service.jar my-service.jar

EXPOSE 9200

ENTRYPOINT [ \
    "java", \
    "-Dspring.config=.", \
    "-Dspring.profiles.active=${MY_ENV}", \
    "-Ddb.hostAndPort=${MY_SERVICE_DB_HOST}:${MY_SERVICE_DB_PORT}", \
    "-Ddb.name=MY_service_db_${MY_ENV}", \
    "-Ddb.username=${MY_SERVICE_DB_APP_USER}", \
    "-Ddb.password=${MY_SERVICE_DB_APP_PASSWORD}", \
    "-Dkeystore.file=my-service-local-keystore.p12", \
    "-Dkeystore.password=${MY_SERVICE_KEYSTORE_PASSWORD}", \
    "-jar", \
    "my-service.jar" \
]

为了同时管理这个镜像的容器以及它的支持 MySQL DB,我编写了下面的docker-compose.yml 文件,它与上面的Dockerfile 位于同一目录中(这是我的根目录网络服务项目):

version: "3.7"
services:
  my-service-db:
    env_file:
      - .env
    image: mysql:8
    container_name: $MY_SERVICE_DB_HOST
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    ports:
      - $MY_SERVICE_DB_PORT:$MY_SERVICE_DB_PORT
    environment:
      MYSQL_ROOT_PASSWORD: $MY_SERVICE_DB_ROOT_PASSWORD
      MYSQL_DATABASE: my_service_db_$MY_ENV
      MYSQL_USER: $MY_SERVICE_DB_APP_USER
      MYSQL_PASSWORD: $MY_SERVICE_DB_APP_PASSWORD
    volumes:
      - ./my-service-db-data:/var/lib/mysql
  my-service:
    env_file:
      - .env
    build: .
    depends_on:
      - my-service-db

在同一个项目根目录下我也有以下.env文件:

MY_ENV=local
MY_SERVICE_DB_HOST=my-service-db
MY_SERVICE_DB_PORT=3306
MY_SERVICE_DB_ROOT_PASSWORD=abc123
MY_SERVICE_DB_APP_USER=my-service-user
MY_SERVICE_DB_APP_PASSWORD=def456
MY_SERVICE_KEYSTORE_PASSWORD=abcdef123456

当我运行docker-compose up -d 时,我看到 Web 服务和 MySQL 容器都在启动,但不久之后 Web 服务容器就会死机/停止。当我关注日志时(在它死之前),它抱怨无法连接到 MySQL(服务需要在启动时能够做到这一点)。

有趣的是,我可以从在我的主机上运行的 MySQL 客户端连接到 MySQL 数据库,并通过0.0.0.0:3306 建立连接。所以我相信 MySQL 容器已正确配置并运行。

FWIW 我尝试将 MY_SERVICE_DB_HOST env var(在 .env 中)从 my-service-db 更改为 0.0.0.0,但这没有区别。

所以我目前仅有的两个猜测是:

  1. 不知何故,Web 服务容器首先被运行/启动,由于 MySQL 容器还不存在,它无法连接并死掉;或
  2. 这里存在 Docker 网络问题,导致另一个 Docker 容器无法通过 0.0.0.0:3306 连接到 MySQL 容器,但在主机上运行的 MySQL 客户端可以

不幸的是,我不确定如何排除这两种可能性中的任何一种,而且我敢肯定还有其他一些我什至不知道要考虑的问题!有什么想法我可能会在这里出错吗?提前致谢!

【问题讨论】:

    标签: docker docker-compose docker-networking


    【解决方案1】:

    您可以configure Spring properties with environment variables。在 Docker 上下文中,这通常比尝试通过命令行注入它们要容易得多。根据它们是什么,您可以通过 Dockerfile 中的 ENV 指令或 Compose environment: 设置来提供它们。

    您显示的命令行还有一个语法问题。如果您使用JSON-array form of ENTRYPOINT(或CMDRUN)绝对不会发生任何类型的替换。您将 Java 属性 spring.profiles.active 设置为文字字符串 ${MY_ENV},而不是环境变量的值。 (出于几个原因,我不会在这里讨论,如果你不需要两者,我更喜欢CMD 而不是ENTRYPOINT。)

    因此您可以将Dockerfile 更新为如下所示:

    # As in the original, mostly
    FROM openjdk:8-jdk-alpine as cce
    WORKDIR /app
    COPY application.yml application.yml
    COPY build/libs/my-service.jar my-service.jar
    EXPOSE 9200
    
    # Set fixed environment variables for Spring properties (or defaults)
    ENV SPRING_CONFIG=.
    ENV SPRING_PROFILES_ACTIVE=development
    
    # Then set the main command to be run, without setting properties
    CMD ["java", "-jar", "my-service.jar"]
    

    以及对应的docker-compose.yml

    version: "3.8"
    services:
      my-service-db: { ... unchanged ... }
      my-service:
        env_file:
          - .env
        build: .
        depends_on:
          - my-service-db
        # Inject the keystore file
        volumes:
          - ./my-service-local-keystore.p12:/app/my-service-local-keystore.p12
        # Set Spring properties through environment variables
        environment:
          SPRING_PROFILES_ACTIVE: "${MY_ENV}"
          DB_HOSTANDPORT: "${MY_SERVICE_DB_HOST}:${MY_SERVICE_DB_PORT}"
          DB_NAME: "MY_service_db_${MY_ENV}"
          DB_USERNAME: "${MY_SERVICE_DB_APP_USER}"
          DB_PASSWORD: "${MY_SERVICE_DB_APP_PASSWORD}"
          KEYSTORE_FILE: /app/my-service-local-keystore.p12
          KEYSTORE_PASSWORD: "${MY_SERVICE_KEYSTORE_PASSWORD}"
    

    Compose 将substitute values from the host environment,因此这会将值传递到容器的相应属性中。

    【讨论】:

      猜你喜欢
      • 2020-07-22
      • 1970-01-01
      • 1970-01-01
      • 2021-09-14
      • 2018-11-08
      • 2021-09-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多