im developing an application in spring boot, and i have been using the secrets from Docker Compose with no problems.
I can do docker compose build my_service
and docker compose run my_service
with no issues.
My problem is the following:
When i build the image (either with docker build
or docker compose build
), and I try to run it using docker run
(without using compose) , I find out the secrets are no longer being mounted in /run/secrets, so spring boot can’t load them in the application.properties.
How can I tell my Dockerfile to mount the secrets when I do docker compose build
, so i can use them with a normal docker run
?
My code
I have the following (simplified) Docker Compose
services:
my_service:
build:
target: ${BACKEND_BUILD_TARGET:-final} # Use environment variable BUILD_TARGET if set, otherwise default to final. The other option is development
context: .
secrets:
- db_username
- db_password
- azure_devops_pat
- ldap_password
- ldap_user
- smtp_user
args:
TARGET_ENVIRONMENT: ${TARGET_ENVIRONMENT} #Set the ARG `TARGET_ENVIRONMENT` in the Dockerfile to have the value of `TARGET_ENVIRONMENT` in the .env file
secrets:
- db_username
- db_password
- azure_devops_pat
- ldap_password
- ldap_user
- smtp_user
# See https://docs.docker.com/compose/use-secrets/
secrets:
db_username:
file: secrets/${TARGET_ENVIRONMENT}/db-username.txt
db_password:
file: secrets/${TARGET_ENVIRONMENT}/db-password.txt
azure_devops_pat:
file: secrets/shared/azure-devops-pat.txt
ldap_password:
file: secrets/shared/ldap-password.txt
ldap_user:
file: secrets/shared/ldap-user.txt
smtp_user:
file: secrets/shared/smtp-user.txt
with this .env
file, that helps me choose the target environment for Spring and to select the secrets to use.
TARGET_ENVIRONMENT=testing
It uses the secrets defined in this folder
secrets/
├── README.md
├── shared
│ ├── azure-devops-pat.txt
│ ├── ldap-password.txt
│ ├── ldap-user.txt
│ └── smtp-user.txt
└── testing
├── db-password.txt
└── db-username.txt
Which i use in this application.properties
#See /questions/70007677/how-to-handle-docker-secrets-in-application-properties-files and https://docs.spring.io/spring-boot/reference/features/external-config.html#features.external-config.files.configtree
spring.config.import=optional:configtree:/run/secrets/
ldap.user = ${ldap_user}
ldap.pass = ${ldap_password}
email.smtp.user=${smtp_user}
spring.datasource.username=${db_username}
spring.datasource.password=${db_password}
And i have this (extremely simplified version of the) Dockerfile
#* ------------- FINAL ------------------- #
# Define final stage for the production image
# This stage defines the final image for deploying the Java Spring Boot application.
# It starts with a minimal runtime image and adds necessary files from the development stage.
# It sets up a non-root user for security reasons and exposes port 8080 for external access.
# The entry point is configured to run the Spring Boot application.
FROM eclipse-temurin:11-jre-alpine AS final
# Set user ID for non-root user
ARG UID=10001
ARG TARGET_ENVIRONMENT
ENV PROFILE=$TARGET_ENVIRONMENT
RUN adduser
--disabled-password
--gecos ""
--home "/nonexistent"
--shell "/sbin/nologin"
--no-create-home
--uid "${UID}"
appuser
# Switch to the non-root user
USER appuser
# Copy extracted dependencies, Spring Boot loader, snapshot dependencies, and application files
COPY --from=extract build/target/extracted/dependencies/ ./
COPY --from=extract build/target/extracted/spring-boot-loader/ ./
COPY --from=extract build/target/extracted/snapshot-dependencies/ ./
COPY --from=extract build/target/extracted/application/ ./
# Expose port 8080 to the outside world
EXPOSE 8080
# Define entry point to run the Spring Boot application
ENTRYPOINT ["sh", "-c", "java org.springframework.boot.loader.JarLauncher --spring.profiles.active=$PROFILE"]
#* -------------------------------------- #