Backend/프로젝트

ec2 Springboot와 MySQL 컨테이너 연결, 3일 간의 삽질기

동구름이 2024. 6. 5. 21:07

 ec2 서버 상에 SpringBoot 백엔드 프로젝트와 mysql를 컨테이너로 올렸는데, 자꾸만 SpringBoot 컨테이너에서 MySQL 컨테이너를 연결하지 못하는 오류가 나타났습니다.

 

 결론적으로 백엔드 파이프라인 구성을 잘못한 것을 파악하지 못하고, 애먼 MySQL과 SpringBoot 설정을 이리저리 삽질했습니다

 

 

혹시나 도움이 될까 기록을 정리해두고자 합니다. SpringBoot와 MySQL과의 연결은 대부분 아래 방법으로 해결이 될 것이라 생각합니다.

 

문제 상황

 

도커 백엔드 컨테이너를 실행시키면 얼마지나지 않아 자꾸 내려가는 현상이 발생했다. 분명 젠킨스에서는 빌드가 잘 되는데..

 

빌드 여부와 관계 없이 백엔드 컨테이너 내부의 문제일 것 같아 로그를 출력해보았다.

sudo docker logs {이미지 이름}

 

 

출력해보니 SpringBoot가 실행되다가 아래의 오류를 만나 종료되는 것을 볼 수 있었다.

com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
        at com.mysql.cj.jdbc.exceptions.SQLError.createCommunicationsException(SQLError.java:175) ~[mysql-connector-j-8.0.33.jar!/:8.0.33]
        at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:64) ~[mysql-connector-j-8.0.33.jar!/:8.0.33]

 

MySQL과의 연결이 실패한 것을 확인할 수 있다.

 

 

 

1. MySQL 관련 설정 확인

(1) MySQL 설정 확인

1. container 동작 제대로 하는지 확인

sudo docker ps -a

 

우선 위 명령어를 통해 MySQL 컨테이너가 잘 실행되고 있는지 확인한다.

 

2. 사용자 권한 재확인

MySQL 컨테이너 내부로 접속해 사용자 권한이 올바르게 설정되었는지 확인한다.

sudo docker exec -it mysql-container bash
mysql> SELECT user, host FROM mysql.user;

 

아래처럼 host 부분에 %가 표시되어있어야한다.

 

 

3. MySQL my.cnf 파일에 외부 접속 허용 확인

sudo docker exec -it mysql-container bash

 

# vim /etc/mysql/my.cnf
또는 /etc/my.cnf

 

my.cnf 파일을 열어 [mysqld] 섹션에 다음 줄을 추가한다.

bind-address = 0.0.0.0

 

bind-address = 127.0.0.0 가 있다면 주석처리해준다.

 

 

4. UTF 설정

이것까지는 하지 않아도 해결되는 경우가 다수였지만 이런 경우도 있다고 해서 올린다.

show variables like ‘c%’;

utf 설정이 latin1으로 되어있는 것을 볼 수 있다. 이것도 마찬가지로 

 

my.cnf에 접근하여 아래처럼 추가한다.

# vim /etc/mysql/my.cnf
또는 /etc/my.cnf

 

그럼 아래처럼 변경된 것을 볼 수 있다.

 

 

(2) MySQL 서버 연결 테스트

(1) 백엔드 컨테이너 내부 접속해 mysql로 들어가보기

docker exec -it backend-container bash
apt-get update
apt-get install -y mysql-client

mysql -h {도메인 주소} -P {포트 번호} -u {사용자명} -p

 

접속이 되는지 확인한다.

 

 

 

2. 방화벽 확인

나는 MySQL-container를 호스트 서버에서 2231 포트로 컨테이너 내부로 접근한다.

sudo docker run -d --name mysql-container -p 2231:3306 -v mysql-volume:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=1234 mysql:8.0.22

 

위와 같은 명령어로 컨테이너 접근 포트를 변경했기 때문이다.

 

그래서 해당하는 2231 포트와 SpringBoot 프로젝트의 포트인 8080포트 방화벽을 열어주어야한다.

sudo ufw allow 2231
sudo ufw allow 8080

 

그리고 ec2 인스턴스에 접속하며 ec2 인바운드 보안 규칙도 2231포트와 8080포트를 추가해준다.

 

 

 

 

3. EC2 서버 용량 확인

갑자기 빌드가 먹통이 되는 상황이 생겼다. 이전에도 이런 경험이 있어 용량 문제인가 했다. 

jenkins에 접속하니 이런 경고메시지가 반겨준다.

 

 

디스크 용량은 아래 명령으로 확인할 수 있다.

df -h

 

/var/jenkins_home이 95프로의 용량을 차지하는 것을 볼 수 있다.

 

 

version: '3'
services:
  jenkins:
    image: jenkins/jenkins:lts
    container_name: jenkins
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /jenkins:/var/jenkins_home
    ports:
      - "9090:8080"
    user: root

 

 참고로 jenkins/home이 ec2 프리티어 인스턴스 대부분 용량으로 나타나는 이유는 젠킨스 컨테이너를 빌드할 때 이처럼 도커 공간을 할당해 젠킨스 용량이 호스트 서버와 연결되어있기 때문이다.

 

 

 

 

도커 용량은 아래 명령으로 자세히 확인할 수 있다.

sudo docker system df --verbose

 

 

docker builder prune

 

이런 빌드 캐시들이 많이 남아있는데  명령을 통해 빌드 캐시를 제거했다.

 

 

 용량을 확보하고서는 빌드가 재시작되는 것을 볼 수 있다. 이렇게 불필요한 캐시 삭제외에도 ec2 서버 인스턴스 용량을 늘리는 법이 있다. 이 방법은 구글링하면 자세히 나오니 여기서는 생략하도록 하겠다.

 

 

 

 

4. 환경 변수 전달, 설정 확인

 application.properties는 아래처럼 구성되어있다.

##MySQL
spring.datasource.url=jdbc:mysql://{HOST_NAME}:{HOST_PORT}/deryeogage
spring.datasource.username=${MYSQL_USERNAME}
spring.datasource.password=${MYSQL_PASSWORD}

 

그래서 컨테이너에 환경 변수가 잘 들어가 있는지 확인이 필요했다.

 

 

sudo docker inspect {컨테이너 이름}

 

위 명령어를 통해 해당 컨테이너에 전달되는 환경변수들을 확인할 수 있다.

 

 

 

 

 

 

 여기까지는 MySQL에서의 설정 문제다. 나는 위 부분들을 모두 확인했지만 전혀 문제가 없었고, MySQL이 정상적으로 동작하는 것이라면, 문제는 오직 Backend 빌드 과정에서겠구나라는 생각이 들었다.

 

 

5. 빌드된 백엔드 프로젝트 확인

 그래서 빌드된 파일을 확인했다. 젠킨스를 통해 배포했는데, 젠킨스도 컨테이너로 띄웠기 때문에 아래 과정을 통해 빌드된 프로젝트에 접근할 수 있다.

 

sudo docker exec -it jenkins /bin/bash

 

cd /var/jenkins_home/workspace/{프로젝트 이름}/{하위 폴더}

 

 

나는 여기서 프로젝트의 resources/application.properties에 접근해보았다.

cd /var/jenkins_home/workspace/{프로젝트 이름}/{백엔드폴더}/src/main/resources
vim application.properties

 

 

#spring.datasource.url=jdbc:mysql://{호스트주소}:3306/{데이터베이스 명}

 

그런데.. application.properties의 설정이 3306으로 되어있었다.... 울었다.. 남자는 살면서 4번 운다. 태어날 때.. 부모님이 돌아가셨을 때.. 나라를 빼앗겼을때.. 그리고 3일동안 삽질했을 때...

 

 임시방편으로 vim 파일로 올바르게 2231 포트를 지정했더니 바로 해결이 되었다.....

 

알고보니 깃허브의 웹 훅이 제대로 동작을 하고 있지 않았다... 파이프 라인을 잘 못 설정해둔 것이었다...

 

 

 

 stages {
        stage('Build') {
            steps {
                dir('Back') {
                    sh 'chmod +x gradlew'
                    sh './gradlew clean build'
                }
            }
            post {
                success {
                    echo 'gradle build success'
                }
                failure {
                    echo 'gradle build failed'
                }
            }
        }
        ....

 

이처럼 pipeline을 구성했던 것은 젠킨스에서 git 프로젝트의 JenkinsFile을 통해 가져오는 경우로 생각해 파이프라인 밖에서 git 연동 설정 정보가 포함되어 문제가 없었다. 즉 Jenkinsfile이라는 파이프라인이 github 프로젝트 내부 경로에 있었다

 

 

 하지만 추후 수정을 하면서, pipeline을 젠킨스에서 구성을 했다. 그래서 아래와 같은 stage를 구성해 webhook을 연결해주어야한다.

 

    stages {
         stage('Checkout') {
            steps {
                git branch: '{배포할 브랜치명}',
                    credentialsId: '{ssh 키}', //private repo임
                    url: 'git@github.com:{깃 레포 주소}' //private repo임
            }
        }
        
        
        stage('Build') {
            steps {
                dir('Back') {
                    sh 'chmod +x gradlew'
                    sh './gradlew clean build'
		....

 

 

 

젠킨스(Jenkins) GitHub Webhooks 연동

<br /><br />

junhyunny.github.io

 

해당 내용은 위 블로그에서 참고했다.

 

 

 

좋은 경험이었다!