如何在Tomcat Docker中配置环境变量传递给Spring Boot应用
问题根因
- Dockerfile里的
ARG仅在镜像构建流程中生效,不会自动成为容器运行时的环境变量。你写的setenv.sh是Tomcat启动(容器运行阶段)才会调用的脚本,此时脚本里引用的${SPRING_DATASOURCE_*}变量为空值,最终传给JVM的参数自然无效。 - 复制进容器的
setenv.sh默认没有可执行权限,Tomcat启动时不会自动加载执行该脚本,连带你配置的spring.profiles.active=deploy也不会生效。 - 额外注意:通过
-D传JVM参数时,直接传入Spring Boot原生识别的配置项(比如-Dspring.datasource.url=xxx)优先级高于配置文件占位符匹配,稳定性更好。
解决方案(按构建阶段注入要求实现)
你可以选两种实现方式,第二种是完全把值写入配置文件,更贴合“构建阶段传入供应用读取”的需求。
方案1:构建时将参数转为环境变量,启动时传入JVM
- 修改Dockerfile,把构建参数转为镜像内置环境变量,同时给脚本加执行权限:
FROM tomcat:9.0.56 # 声明构建入参 ARG SPRING_DATASOURCE_URL ARG SPRING_DATASOURCE_USERNAME ARG SPRING_DATASOURCE_PASSWORD # 将构建参数固化为镜像内的环境变量,供运行时脚本读取 ENV SPRING_DATASOURCE_URL=${SPRING_DATASOURCE_URL} ENV SPRING_DATASOURCE_USERNAME=${SPRING_DATASOURCE_USERNAME} ENV SPRING_DATASOURCE_PASSWORD=${SPRING_DATASOURCE_PASSWORD} COPY setenv.sh /usr/local/tomcat/bin/setenv.sh # 给脚本加可执行权限 RUN chmod +x /usr/local/tomcat/bin/setenv.sh COPY /app/target/api.war /usr/local/tomcat/webapps/ROOT.war EXPOSE 8080 CMD ["catalina.sh", "run"]
- 修改
setenv.sh,补全脚本解释器,直接传入Spring可识别的配置参数:
#!/bin/bash JAVA_OPTS="$JAVA_OPTS -Dspring.profiles.active=deploy" JAVA_OPTS="$JAVA_OPTS -Dspring.datasource.url=jdbc:mysql://${SPRING_DATASOURCE_URL}" JAVA_OPTS="$JAVA_OPTS -Dspring.datasource.username=${SPRING_DATASOURCE_USERNAME}" JAVA_OPTS="$JAVA_OPTS -Dspring.datasource.password=${SPRING_DATASOURCE_PASSWORD}"
构建镜像时通过--build-arg传入参数即可,例如:
docker build -t api-app \ --build-arg SPRING_DATASOURCE_URL=mysql-host:3306/db_name \ --build-arg SPRING_DATASOURCE_USERNAME=root \ --build-arg SPRING_DATASOURCE_PASSWORD=your_pwd \ .
方案2:构建时直接替换配置文件内的占位符(完全构建阶段注入)
这种方式会在镜像构建时直接把参数值写入war包内的application-deploy.properties文件,不需要依赖运行时环境变量传递,更贴合需求:
- 修改Dockerfile:
FROM tomcat:9.0.56 ARG SPRING_DATASOURCE_URL ARG SPRING_DATASOURCE_USERNAME ARG SPRING_DATASOURCE_PASSWORD # 先复制war包 COPY /app/target/api.war /usr/local/tomcat/webapps/ROOT.war # 安装unzip解压war包,直接替换配置文件里的占位符 RUN apt-get update && apt-get install -y --no-install-recommends unzip && \ cd /usr/local/tomcat/webapps && \ mkdir ROOT && unzip ROOT.war -d ROOT && rm ROOT.war && \ sed -i "s|\${SPRING_DATASOURCE_URL}|${SPRING_DATASOURCE_URL}|g" ROOT/WEB-INF/classes/application-deploy.properties && \ sed -i "s|\${SPRING_DATASOURCE_USERNAME}|${SPRING_DATASOURCE_USERNAME}|g" ROOT/WEB-INF/classes/application-deploy.properties && \ sed -i "s|\${SPRING_DATASOURCE_PASSWORD}|${SPRING_DATASOURCE_PASSWORD}|g" ROOT/WEB-INF/classes/application-deploy.properties && \ # 清理安装的依赖减小镜像体积 apt-get purge -y --auto-remove unzip && rm -rf /var/lib/apt/lists/* COPY setenv.sh /usr/local/tomcat/bin/setenv.sh RUN chmod +x /usr/local/tomcat/bin/setenv.sh EXPOSE 8080 CMD ["catalina.sh", "run"]
- 简化
setenv.sh,只保留profile激活配置即可:
#!/bin/bash JAVA_OPTS="$JAVA_OPTS -Dspring.profiles.active=deploy"
构建命令和方案1一致。
注意:构建阶段注入数据库地址、密码这类敏感信息会直接固化在镜像层中,只要能获取镜像就能提取到明文值,生产环境更建议在容器启动时通过
-e参数传入环境变量,不要把敏感信息打进镜像。
内容的提问来源于stack exchange,提问作者carlonchoboy
相关产品推荐
相关产品推荐

