이젠 application.properties에 있는 DB 접근과 관련된 환경변수들을 Docker Secret 적용을 위해 변경합니다.
→ application.properties 에서 application.yml 로 변경
→ 주요 변수들을 ${docer-secret-.. } 로 변경
spring:
datasource:
url: ${docker-secret-mysql-url}
username: ${docker-secret-mysql-user}
password: ${docker-secret-mysql-user-pw}
docker-secret:
bind-path: /run/secrets
mybatis:
configuration:
map-underscore-to-camel-case: true
mapper-locations: classpath:mybatis/mapper/*.xml
management:
endpoints:
web:
exposure:
include: "*"
그리고 EC2에 제가 방금 올린 Repository을 clone 합니다.
git clone https://github.com/gudtjr2949/docker-secret-with-springboot.git
밑에 보이는 캡쳐에 있는 gradle/ 와 같은 디렉토리 레벨에서
./gradlew clean build
명령어를 입력해 jar 파일을 생성합니다.
그리고 jar 파일을 실행하는 명령어를 Dockerfile에 넣으면 됩니다.
FROM openjdk:17-alpine
# 작업 디렉토리 설정
WORKDIR /app
# 호스트의 target 디렉토리에서 JAR 파일을 컨테이너의 /app 디렉토리로 복사
COPY /docker-secret-with-springboot/refactoring/build/libs/refactoring-0.0.1-SNAPSHOT.jar refactoring-0.0.1-SNAPSHOT.jar
CMD ["java", "-jar", "refactoring-0.0.1-SNAPSHOT.jar"]
spring:
datasource:
url: ${docker-secret-mysql-url}
username: ${docker-secret-mysql-user}
password: ${docker-secret-mysql-user-pw}
docker-secret:
bind-path: /run/secrets
mybatis:
configuration:
map-underscore-to-camel-case: true
mapper-locations: classpath:mybatis/mapper/*.xml
management:
endpoints:
web:
exposure:
include: "*"
참고로 전
docker-secret-with-springboot/refactoring/src..
가 Spring Boot 프로젝트 디렉토리,
docker-secret-with-springboot와 같은 레벨에 Dockerfile과 docker-compose.yml 파일을 뒀습니다.
다음 Docker Secret에 사용할 환경변수를 등록해줍니다.
echo -n "jdbc:mysql://54.89.210.153:3306/common?useSSL=false&allowPublicKeyRetrieval=true"| sudo docker secret create mysql-url -
echo -n "testUser"| sudo docker secret create mysql-user -
echo -n "1234"| sudo docker secret create mysql-user-pw -
아래 명령어를 통해 Docker Secret 이 잘 생성되었는지 확인합니다.
sudo docker secret ls
그리고 아래 명령어를 통해 Service를 시작할려고 했는데!
sudo docker stack deploy -c docker-compose.yml refacotring
Caused by: java.lang.IllegalArgumentException: URL must start with 'jdbc'…
에러가 뜹니다..
딱 봐도 Docker Secret 적용이 안된 것 같은데;;
며칠동안 여러 블로그와 ChatGPT에서 찾아본 결과..!
Spring Boot에서 application.yml이나 application.properties에서 Docker Secret 의 변수들을 사용하기 위해선 Java 코드로 후처리를 거쳐야 하더군요..
그래서 걍 Docker Secret 후처리기 클래스 하나 추가했슴다..
이 분 코드 참고하세요!! 만약 Kwong-Hung YIP 이 분이 없었더라면 전 완성하지 못했을 꺼에요..
코드를 설명해드리자면,
public class DockerSecretProcessor implements EnvironmentPostProcessor {
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
String bindPathPpty = environment.getProperty("docker-secret.bind-path");
if (bindPathPpty!=null) {
Path bindPath = Paths.get(bindPathPpty);
if (Files.isDirectory(bindPath)) {
Map<String,Object> dockerSecrets;
try {
dockerSecrets =
Files.list(bindPath)
.collect(
Collectors.toMap(
path -> {
File secretFile = path.toFile();
return "docker-secret-" + secretFile.getName();
},
path -> {
File secretFile = path.toFile();
try {
byte[] content = FileCopyUtils.copyToByteArray(secretFile);
return new String(content);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
));
} catch (IOException e) {
throw new RuntimeException(e);
}
MapPropertySource pptySource = new MapPropertySource("docker-secrets", dockerSecrets);
environment.getPropertySources().addLast(pptySource);
}
}
}
}
docker-secret.bind-path
프로퍼티에서 Docker 시크릿이 저장된 경로를 가져옵니다.docker-secret-<filename>
의 형식으로 맵에 저장됩니다.MapPropertySource
를 사용하여 환경 속성에 추가됩니다.그리고 이 후처리기를 사용하기 위해 resource/META-INF/spring-factoris 에
org.springframework.boot.env.EnvironmentPostProcessor=common.refactoring.DockerSecretProcessor
이 코드 한 출 추가해줘야 합니다.
전 후처리기가
여기 있어서
common.refactoring.DockerSecretProcessor
이렇게 입력했습니다.
이후 다시 Spring Boot 빌드하고, Docker 이미지 생성하고, service 실행 명령어 날리면?
sudo docker stack deploy -c docker-compose.yml refacotring
잘 실행됩니다!!
접속도 잘 됩니다.
Postman으로 요청 날려보면
DB 와 연결이 되서 정상적으로 잘 날아갑니다!
이렇게 Docker Secret으로 주요 비밀번호와 같은 환경변수를 설정하고 느낀점은
또한 다음에 알아봐야 하는건 저 DockerSecretProcessor 가 안전한 방법인지 알아봐야겠습니다.