Docker로 Spring 웹 애플리케이션 배포하기 (3) - MySQL DB 연결과 데이터 옮기기
1. docker-compose.yml 파일 작성

프로젝트 루트에 docker-compose.yml 파일 작성 (target 폴더 내부 아님!!)
docker-compose.yml
services:
test8_shop-web-1:
image: oeun/animalpage
container_name: test8_shop-web-1
ports:
- "8081:8080"
volumes:
- "C:/GovFrameDev-3.10.0-64bit/workspace/Test8_shop/target/Test8_shop-1.0.0.war:/usr/local/tomcat/webapps/ROOT.war"
environment:
- DB_HOST=test8_shop-db-1 # db 컨테이너 이름 사용
- DB_PORT=3307
- DB_NAME=shop
- DB_USER=root
- DB_PASSWORD=1111
- DB_CHARSET=utf8mb4
- DB_COLLATE=utf8mb4_unicode_ci
db:
container_name: test8_shop-db-1
image: mysql:8.0
environment:
MYSQL_DATABASE: "shop"
MYSQL_ROOT_PASSWORD: "1111"
ports:
- "3307:3306" # 호스트 3307 -> 컨테이너 3306 (MySQL 포트)
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
retries: 5
start_period: 30s
timeout: 10s
networks:
my-network:
driver: bridge
2. 쉘에서 도커 컴포즈 실행
> docker-compose up -d

로그 확인 명령어
> docker logs {웹 컨테이너 이름} # web 컨테이너 로그
> docker logs {DB 컨테이너 이름} # db 컨테이너 로그
이건 Docker Desktop에서도 확인 가능
컨테이너 재시작 명령어
> docker restart {컨테이너 이름}
컨테이너 상태 확인
> docker ps

web과 mysql 모두 정상 작동중이지만 여전히 흰 화면만 뜸
웹 로그 확인

확인 결과 DB 오류 (이건 내가 DB연결 오류 시 print문 설정해놓음)
DB 컨테이너로 MySQL 접근해보기
> # docker exec -it {DB 컨테이너 이름} mysql -uroot -p{비밀번호}
> docker exec -it test8_shop-db-1 mysql -uroot -p1111

show databases;를 해보니 shop이라는 이름으로 DB를 생성했지만, 테이블이 존재하지 않는다...
내 DB 데이터 불러오기
1. MySQL Workbencth 열기
아래 쿼리 실행
# use {database명};
use shop;
2. Data Export
MySQL Workbencth의 사이드바 메뉴에서 Data Export 선택


좌측에서 사용할 DB를 고르고, 우측에서 사용할 Table을 선택한다.
Object to Expot에서 Dump Started Procedures and Functions, Dump Events, Dump Triggers 모두 선택
Export Options에서 Exprot to Self-Contained File 선택 후 나머지 체크박스도 모두 선택
선택을 마쳤으면 Start Export
3. sql 파일 연동

그렇게 Export한 sql 파일을 프로젝트의 루트 폴더에 복사해준다.
4. Dockerfile과 docker-compose.yml 파일 수정
Dockerfile 맨 아래에 아래 코드 추가
# COPY {export한 파일명} /docker-entrypoint-initdb.d/
COPY Dump20241212.sql /docker-entrypoint-initdb.d/
docker-compose.yml 수정
db:
container_name: test8_shop-db-1
image: mysql:8.0
environment:
MYSQL_DATABASE: "shop"
MYSQL_ROOT_PASSWORD: "1111"
ports:
- "3307:3306" # 호스트 3307 -> 컨테이너 3306 (MySQL 포트)
volumes:
- db-data:/var/lib/mysql
- ./Dump20241212.sql:/docker-entrypoint-initdb.d/Dump20241212.sql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
retries: 5
start_period: 30s
timeout: 10s
volumes:
db-data:
driver: local
db의 volumes 부분과 하단 volumes가 추가됨
5. 재실행 후 확인
docker-compose 실행
> docker-compose up -d
db 컨테이너 재시작
> # docker restart {DB 컨테이너 이름}
> docker restart test8_shop-db-1
컨테이너에서 MySQL 접속
> # docker exec -it {DB 컨테이너 이름} mysql -uroot -p{비밀번호}
> docker exec -it test8_shop-db-1 mysql -uroot -p1111
쿼리 날리기
use shop;
show tables;

테이블들이 정상적으로 들어갔다!
하지만 여전히 계속되는 DB 연결 오류..
여기서부턴 시도했던 해결 과정
1. 우분투에 명령어 입력하여 포트 매핑 확인해보기
$ # netstat -anl | grep {DB 포트번호}
$ netstat -anl | grep 3306
$ # docker inspect {DB 컨테이너 이름} | grep -i '"hostport"'
$ docker inspect test8_shop-db-1 | grep -i '"hostport"'

웹 컨테이너는 정상 연결되었지만 DB 컨테이너는 연결되지 않음
3306 포트가 죽어있음, 로컬의 MySQL 포트와 DB 호스트 포트 충돌
=> 이건 DB 호스트 포트를 3307:3306으로 하여 해결
2. 같은 네트워크로 연결됐는지 확인해보기
> # 네트워크 목록 확인
> docker network ls
> # 같은 네트워크에 있는지 확인
> # docker inspect {컨테이너 이름 또는 ID}
> docker inspect Test8_shop-web-1
> # 해당 네트워크에 연결된 컨테이너 목록
> # docker network inspect {네트워크 이름}
> docker network inspect my-network

web 컨테이너만 연결돼있음
> # (필요 시) 새 네트워크 생성
> docker network create my-network
> # 컨테이너를 네트워크에 연결
> # docker network connect {네트워크 이름} {연결할 컨테이너 이름}
> docker network connect my-network test8_shop-web-1
> docker network connect my-network test8_shop-db-1
연결 후

=> 같은 네트워크 연결로 해결
3. 방화벽 및 권한 설정
우분투에서 명령어 입력
$ sudo vim /etc/iptables/rules.v4
-A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 3306 -j ACCEPT
-A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 3307 -j ACCEPT
혹시 몰라 3306, 3307 모두 권한을 주고
엔터 > ESC > 아래 코드 입력 후 저장 및 종료
:w !sudo tee % > /dev/null
권한 조회
> select host,user,authentication_string from mysql.user;

맨 위에 외부에서 접근할 수 있도록 host를 %로 설정해둔 데이터가 보이지만,
맨 아래 데이터는 host가 localhost이기 때문에 로컬에서만 접속할 수 있게 하고있다..
> DELETE FROM mysql.user WHERE user = 'root' AND host = 'localhost';
> FLUSH PRIVILEGES; # 즉시 반영
삭제 후 재조회

=> 사실 이 3번 과정들은 DB 연결에 기여한 것인지 잘 모르겠음..
4. 프로젝트 내부의 JDBC 연동 부분의 URL 변경

기존 localhost에서
private static final String URL = "jdbc:mysql://localhost:3306/shop";
변경 후
private static final String URL = "jdbc:mysql://{hostIP}:3307/shop?useSSL=false&serverTimezone=UTC$allowPublicKeyRetrieval=true";
hostIP는 쉘에 hostname -I 했을 때 나오는 IP
=> 근본적인 해결 방법이라 생각함. 여태 이걸 고치지 않아서 삽질한듯
java.sql.SQLSyntaxErrorException: Table 'shop.POST' doesn't exist
그런데 또 에러 발생

DB 컨테이너에 들어가서 show tables;를 해보니 테이블들이 정상적으로 들어있음
알고보니 내가 작성한 DAO 코드에서 쿼리를 대문자로 적어서
테이블명 POST와 post를 다르게 인식했던 것..
소문자로 바꿔주고 해결!
연결 테스트를 위해 접속
http://X.X.X.X:8081

DB 연결 성공!
이제 톰캣과 이클립스를 종료해도, 저 주소로 들어가면 웹 페이지가 열림!
그런데 내 컴퓨터에 저장된 이미지를 못불러온다..
이미지 문제 해결은 다음 편에 계속