Springboot에서 터널링을 활용하여 데이터 베이스에 접속해야 되는 기능을 만드는 것은 어렵지 않습니다.
터널링을 하여 주는 클래스를 생성한 뒤에 SSH를 통해서 원하는 포트로 연결을 해 준 다음에 데이터베이스를 사용하면 됩니다.
아래와 같은 터널링용 클래스가 있다고 가정하여 봅니다.
데이터베이스는 몽고DB에 접속하는 상황 입니다.
* 터널링용 클래스 예제
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
public class SshTunneling {
private static JSch jsch = new JSch();
private String url = "원격주소";
private String username = "아이디";
private String password = "비밀번호";
private int port = 22; //ssh포트
private int lport = 26016; //원격 접속 후 가상으로 포워딩할 포트
private int rport = 27017; //실제 사용할 데이터베이스 포트
private Session session;
public SshTunneling() {
try {
session = jsch.getSession(username, url, port);
session.setPassword(password);
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
session.setPortForwardingL(lport, "127.0.0.1", rport);
} catch (Exception e) {
}
}
public void shutdown() throws Exception {
if (session != null && session.isConnected()) {
session.disconnect();
}
}
}
이러한 클래스를 @Bean 에노테이션을 활용하거나 @Component 에노테이션등을 활용하여 객체를 빈으로 생성하여 주고 데이터베이스에 연결하면 됩니다.
* 물론! 포트 포워딩이 된 상태 이므로 데이터베이스에 연결 할 때는 가상화 포트를 사용하여야 합니다!
데이터베이스가 몽고DB, Maria, MySql, Ms-sql등 어떠한 데이터베이스던지 간에 상관 없습니다.
그런데 잘 동작중인 프로젝트가 아래와 같은 연결이 되지 않는 오류를 만날 때가 있습니다.
1. 프로젝트를 빌드(build) 할 때 .
2. 서비스의 생성자나 @PostConstruct를 통해 붙여진 메소드에서 데이터 베이스에 바로 접속을 시도하다 할 때.
데이터 베이스 커넥션이 안된다는 단순한 내용입니다.
해당 문제는 스프링 부트의 빈 객체의 생성 순서에 따른 문제 입니다.
@Service나 @Controller로 작성된 클래스는 @Bean과 @Component로 작성된 클래스보다 먼저 생성되게 됩니다.
이러한 현상 때문에 터널링용으로 만든 클래스가 먼저 동작하지 않았는데 데이터베이스에 접속을 시도하다 오류가 발생하게 되는 것 입니다.
이러한 경우를 방지하기 위해서는 터널링용 클래스가 가장 먼저 동작하도록 해 주어야 합니다.
위 SSH 접속용 클래스를 먼저 간단하게 수정 합니다.
* 터널링용 클래스 예제
import java.util.function.Consumer;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
public class SshTunneling {
private static JSch jsch = new JSch();
private String url = "원격주소";
private String username = "아이디";
private String password = "비밀번호";
private int port = 22; //ssh포트
private int lport = 26016; //원격 접속 후 가상으로 포워딩할 포트
private int rport = 27017; //실제 사용할 데이터베이스 포트
private Session session;
public SshTunneling init(Consumer<Boolean> arg) {
try {
session = jsch.getSession(username, url, port);
session.setPassword(password);
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
session.setPortForwardingL(lport, "127.0.0.1", rport);
arg.accept(true);
} catch (Exception e) {
arg.accept(false);
}
return this;
}
public void shutdown() throws Exception {
if (session != null && session.isConnected()) {
session.disconnect();
}
}
}
init 메소드를 호출하면 터널링 기능이 동작하도록 변경 하였습니다.
포워딩이 성공적으로 이루어지면 컨슈머 클래스에 true, 실패하면 false를 반환하게 하였습니다.
나머지 내용은 크게 어렵지가 않습니다.
이를 호출하는 클래스는 스프링부트의 main메소드가 존재하는 곳 입니다.
* main메소드가 존재하는 클래스 예제
import javax.annotation.PreDestroy;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.Banner.Mode;
import 터널링패키지.SshTunneling;
@SpringBootApplication
public class SpringBootApplication {
private static SshTunneling tunnel;
public SpringBootApplication() {
tunnel = new SshTunneling().init( res->{
if(!res) {
System.out.println("포트포워딩 실패, 프로그램을 종료 합니다.");
System.exit(0);
}
});
}
public static void main(String[] args) {
SpringApplication app = new SpringApplication(SpringBootApplication.class);
app.run(args);
}
@PreDestroy
public void end() {
try {
tunnel.shutdown();
} catch (Exception e) {
e.printStackTrace();
}
}
}
main메소드가 존재하는 클래스에서 생성자(constructor)로 터널링 클래스를 동작하게 하였습니다.
데이터베이스가 연결이 되지 않으면 큰 문제이므로 프로그램이 종료 되도록 하였습니다.
그리고 @PreDestroy 에노테이션을 통해서 터널링한 커넥션을 끊어주도록 하였습니다.
초기화 블럭을 사용하여도 상관은 없습니다.
매우 단순한 방법이지만 효과(?)는 아주 확실합니다.
터널링(SSH)을 통해서 프로젝트가 구성 된 다면 이처럼 터널링용 클래스가 가장 먼저 동작 하도록 해 주는 것에 주의하여야 하겠습니다!
궁금한점 또는 틀린점 및 수정이 필요한 부분은 언제든 연락주세요!
'Spring framework > Spring boot' 카테고리의 다른 글
Spring JWT 를 활용한 로그인 (0) | 2021.11.19 |
---|---|
SpringBoot change Java 8 to Java 11(스프링 부트 Java 1.8을 11로 변경) (0) | 2020.12.02 |
SpringBoot InfluxDB(Spring boot 인플럭스DB) (2) | 2020.11.19 |
remove Springboot jsessionid , 스프링부트 jsession 제거 (0) | 2019.12.03 |
Spring boot 마이바티스, Spring boot mybatis, 스프링부트 mybatis 적용 (2) | 2019.12.02 |
댓글