make_dirs() {
inst="$1"
INST="$ROOT$BASE/tomcat-inst/$inst"
mkdir -p "$INST"/{conf,temp,webapps,work} "$ROOT$BASE/logs/$inst"
run ln -sfn "$BASE/logs/$inst" "$INST/logs"
echo " $inst: conf temp webapps work 생성, logs 는 $BASE/logs/$inst 로 링크"
}
make_dirs app1
make_dirs app2
make_server_xml() {
inst="$1"; http="$2"; shutdown="$3"
XML="$ROOT$BASE/tomcat-inst/$inst/conf/server.xml"
cat > "$XML" <<EOF
<Server port="$shutdown" shutdown="SHUTDOWN">
<Service name="Catalina">
<Connector port="$http" protocol="HTTP/1.1" URIEncoding="UTF-8" />
...
</Service>
</Server>
EOF
validate "$XML"
}
make_server_xml app1 8080 8005
make_server_xml app2 8180 8105== 1. 인스턴스 폴더 생성 (CATALINA_BASE 분리) ==
[dry] ln -sfn /app/logs/app1 WORK/app/tomcat-inst/app1/logs
app1: conf temp webapps work 생성, logs 는 /app/logs/app1 로 링크
[dry] ln -sfn /app/logs/app2 WORK/app/tomcat-inst/app2/logs
app2: conf temp webapps work 생성, logs 는 /app/logs/app2 로 링크
== 2. server.xml 포트 분리 ==
XML 유효성 검사 통과: server.xml
XML 유효성 검사 통과: server.xml인스턴스 이름과 포트만 바꿔 함수를 두 번 호출해 app1·app2 를 만들었습니다. 두 server.xml 모두 XML 문법 검증을 통과했습니다.
make_setenv() {
inst="$1"; xmx="$2"
SETENV="$ROOT$BASE/tomcat-inst/$inst/bin/setenv.sh"
mkdir -p "$(dirname "$SETENV")"
cat > "$SETENV" <<EOF
export JAVA_HOME="$BASE/jdk"
export CATALINA_PID="$BASE/tomcat-inst/$inst/temp/catalina.pid"
JAVA_OPTS="-Xms$xmx -Xmx$xmx -XX:+UseG1GC"
JAVA_OPTS="\$JAVA_OPTS -Duser.timezone=Asia/Seoul -Dfile.encoding=UTF-8"
JAVA_OPTS="\$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$BASE/logs/$inst"
export JAVA_OPTS
EOF
bash -n "$SETENV" && echo " $inst/setenv.sh 문법 확인: 이상 없음, Xmx=$xmx"
}
make_setenv app1 512m
make_setenv app2 256m== 3. setenv.sh JVM 옵션 ==
app1/setenv.sh 문법 확인: 이상 없음, Xmx=512m
app2/setenv.sh 문법 확인: 이상 없음, Xmx=256m같은 함수로 인스턴스마다 힙 크기(Xmx)만 다르게 줬습니다. bash -n 으로 문법만 검사하고 실제 실행은 하지 않습니다.
CTX="$ROOT$BASE/tomcat-inst/app1/conf/context.xml"
cat > "$CTX" <<EOF
<Context>
<Resource name="jdbc/AppDB" auth="Container" type="javax.sql.DataSource"
driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://db.internal:5432/app"
username="app" password="\${db.password}"
initialSize="5" maxTotal="20" maxIdle="10" />
</Context>
EOF
validate "$CTX"
echo " 드라이버 jar 위치: $BASE/tomcat-inst/app1/lib (인스턴스 전용)"== 4. context.xml JNDI DataSource ==
XML 유효성 검사 통과: context.xml
드라이버 jar 위치: /app/tomcat-inst/app1/lib (인스턴스 전용, CATALINA_HOME/lib 과 별도)password 값은 개념을 보여주는 자리 표시(${db.password})이고, 실제 운영에서는 평문으로 커밋하지 않습니다. 드라이버 jar 는 이 인스턴스의 lib 폴더에만 둡니다.
UNIT="$UNITDIR/[email protected]"
cat > "$UNIT" <<EOF
[Service]
Type=forking
Environment=CATALINA_BASE=$BASE/tomcat-inst/%i
Environment=CATALINA_PID=$BASE/tomcat-inst/%i/temp/catalina.pid
PIDFile=$BASE/tomcat-inst/%i/temp/catalina.pid
ExecStart=$BASE/tomcat/current/bin/startup.sh
ExecStop=$BASE/tomcat/current/bin/shutdown.sh
EOF
run systemctl daemon-reload
run systemctl enable --now tomcat@app1
run systemctl enable --now tomcat@app2
run curl -s -o /dev/null -w '%{http_code}\n' "http://localhost:8080/"
run curl -s -o /dev/null -w '%{http_code}\n' "http://localhost:8180/"== 5. systemd 템플릿 유닛 [email protected] ==
[email protected] 필수 키 확인: 이상 없음 (%i 는 인스턴스 이름으로 치환)
[dry] systemctl daemon-reload
== 6. 인스턴스 기동과 확인 ==
[dry] systemctl enable --now tomcat@app1
[dry] systemctl enable --now tomcat@app2
app1 확인:
[dry] curl -s -o /dev/null -w %{http_code}\n http://localhost:8080/
app2 확인:
[dry] curl -s -o /dev/null -w %{http_code}\n http://localhost:8180/
로그 위치: /app/logs/app1/catalina.out, /app/logs/app2/catalina.out%i 하나로 app1·app2 를 같은 유닛 정의로 기동합니다. 실제 서버에서는 curl 이 진짜 상태 코드를 돌려줍니다.