본문 바로가기
블로그 이미지

방문해 주셔서 감사합니다! 항상 행복하세요!

  
   - 문의사항은 메일 또는 댓글로 언제든 연락주세요.
   - "해줘","답 내놔" 같은 질문은 답변드리지 않습니다.
   - 메일주소 : lts06069@naver.com


Spring framework/Spring boot

Springboot 터널링(스프링 부트 터널링, Spring boot ssh, 스프링 부트 ssh)

야근없는 행복한 삶을 위해 ~
by 마샤와 곰 2020. 11. 25.

 

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)을 통해서 프로젝트가 구성 된 다면 이처럼 터널링용 클래스가 가장 먼저 동작 하도록 해 주는 것에 주의하여야 하겠습니다!

궁금한점 또는 틀린점 및 수정이 필요한 부분은 언제든 연락주세요!

반응형
* 위 에니메이션은 Html의 캔버스(canvas)기반으로 동작하는 기능 입니다. Html 캔버스 튜토리얼 도 한번 살펴보세요~ :)
* 직접 만든 Html 캔버스 애니메이션 도 한번 살펴보세요~ :)

댓글