시험 서버가 한 대 늘었다. 같은 .war 를 그대로 올렸는데 Tomcat 이 안 떴다. MySQL 주소가 Java 클래스에 문자열로 박혀 있었다. 그 줄을 고치고 다시 빌드해서 올렸다.
Table of contents
Open Table of contents
여섯 군데에 박혀 있었다
grep 으로 찾아보니 한 군데가 아니었다. MySQL 주소와 계정이 한 클래스에 있었다. 업로드 경로는 다른 클래스에 있었다. 문자 발송 주소와 포트는 또 다른 클래스에 있었다.
private static final String URL = "jdbc:mysql://10.0.0.21:3306/adsvc";
private static final String BASE = "/data/upload/";
private static final String HOST = "10.0.0.35";
주소와 경로와 포트와 계정. 환경이 바뀌면 전부 바뀌는 것들이다. 서버를 하나 늘리면 여섯 군데를 고치고 빌드해야 한다. 하나를 빠뜨리면 그 기능만 다른 서버를 본다.
어떤 결과물이 어느 서버 것인지 몰랐다
더 나빴던 것은 빌드된 .war 끼리 구분이 안 된다는 점이었다. 파일 이름이 같고 안에 든 주소만 다르다. 두 개를 나란히 두면 어느 것이 시험용인지 열어 봐야 안다.
한 번은 시험용을 운영에 올렸다. JSP 는 정상으로 떴는데 데이터가 시험 데이터였다. .war 에 환경이 들어가 있으면 그 파일은 한 곳에서만 쓸 수 있는 것이었다.
값을 밖으로 뺐다
환경마다 다른 값을 .properties 로 분리했다. Java 코드에는 키 이름만 남고 값은 파일에 있다. Spring 의 PropertyPlaceholderConfigurer 가 ${db.url} 자리를 채워 준다.
db.url=jdbc:mysql://10.0.0.21:3306/adsvc
upload.base=/data/upload/
sms.host=10.0.0.35
그런데 그 파일을 소스와 같이 두면 .war 에 들어가니 결국 같은 문제가 된다. 서버 바깥 경로에 두고 그 경로를 Tomcat 이 뜰 때 넘기게 했다.
# CATALINA_OPTS
-Dconfig.path=/etc/adsvc/config.properties
<context:property-placeholder location="file:${config.path}"/>
file: 를 안 붙이면 클래스패스에서 찾는다. 밖에 둔 파일은 file: 로 가리켜야 읽힌다.
이러니 빌드 결과물은 어느 서버에나 같은 것이 올라가고 서버에 있는 파일만 다르다.
없는 키와 예시 파일
파일이 밖에 있으니 키가 빠질 수 있다. 이건 Spring 이 이미 그렇게 한다. 키가 없으면 Could not resolve placeholder 를 내고 Context 가 안 뜬다. ignore-unresolvable 을 켜면 그 실패가 사라진다. 켜지 않았다. 접속 정보가 없으면 아예 안 뜨는 편이 낫다. 빈 값이 흘러가면 접속 시점에 엉뚱한 오류가 난다. 그러면 설정 파일을 의심하기까지 시간이 걸린다.
설정 파일이 소스에 없으니 새 서버를 만들 때 무슨 키가 필요한지 알 방법도 없어졌다. 값이 빈 config.properties.example 을 SVN 에 넣었다. 키 목록이 코드와 같이 관리된다. 새 키를 쓸 때 예시 파일에도 한 줄 넣는다.
비밀번호는 예시 파일에도 빈칸으로 두고 실제 값은 서버 파일에만 뒀다. 그 파일은 chmod 600 으로 좁혔다. 주소나 경로는 비밀이라기보다 환경 차이다. 둘을 같은 파일에 두면 파일 전체가 비밀 취급을 받는다. 그러면 환경 차이 부분도 편하게 못 본다.
정리
- 환경마다 다른 값이 코드에 있으면 서버가 늘 때마다 빌드가 필요하다
- 하나를 빠뜨리면 그 기능만 다른 서버를 본다
- 빌드 결과물에 환경이 들어가면 그 결과물은 한 곳에서만 쓸 수 있다
- 파일 이름이 같고 내용만 다르면 어느 것이 어느 환경 것인지 구분이 안 된다
- 값을
.properties로 빼고 그 파일을.war밖 경로에 둔다.file:로 가리킨다 - 없는 키는 Spring 이
Could not resolve placeholder로 막는다. 그 실패를 끄지 않는다 - 빈 값이 흘러가면 엉뚱한 자리에서 오류가 나서 원인 추적이 늦어진다
- 값이 빈 예시 파일을 소스에 둬야 키 목록이 코드와 같이 관리된다
- 비밀 값과 환경 차이 값을 나눠 둔다