请注意:尽管我在这里提到 Java 和 Spring Boot,但这 100% 是一个 Docker/Docker Compose 网络问题,因此,可以任何熟悉 Docker 生态系统的人都可以回答,无论他们是否熟悉 Java 和 Spring。
我有一个 Spring Boot (Java) Web 服务,它使用 MySQL 数据库作为其数据层。我已使用以下 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 数据库,我编写了以下 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
,但没有任何区别。
所以我目前唯一的两个猜测是:
0.0.0.0:3306
连接到 MySQL 容器,但在主机上运行的 MySQL 客户端可以不幸的是,我不确定如何解决这两种可能性中的任何一种,而且我确定还有其他我什至不知道要考虑的可能性!有什么想法我可能会在这里出错吗?提前致谢!
答案 0 :(得分:0)
你可以configure Spring properties with environment variables。在 Docker 上下文中,这通常比尝试通过命令行注入它们要容易得多。根据它们是什么,您可以通过 Dockerfile 中的 ENV
指令或 Compose environment:
设置提供它们。
您显示的命令行还有一个语法问题。如果您使用 JSON-array form of ENTRYPOINT
(或 CMD
或 RUN
),这里绝对不会发生任何类型的替换。您将 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,因此这会将值传递到容器中的适当属性中。