(5) How was your day? - 프로젝트 Dockerize

HEYDAY7·2022년 11월 25일
0

시작하며

전 글에서 언급했듯이 프로젝트를 Docker container 화 시키는 과정과 그 과정에서 겪었던 여러 이슈들을 기록해둔다.

Dockerize 하기

Docker

docker는 간단히 말하면 컨테이너 방식을 통해서 프로젝트(애플리케이션)을 구축하고, 배포할 수 있게 해주는 플랫폼이라고 할 수 있다. Docker의 경우 여러 공식 문제나 잘 설명되어 있는 글들이 많다.
https://www.docker.com/resources/what-container/
https://aws.amazon.com/ko/docker/

그 중에서도 하나 가장 강력한 무기라고 생각되는 점은 docker container가 라이브러리, 코드 등 애플리케이션에 포함된 모든 것들을 포함하여 환경에 구애받지 않고 항상 동일한 애플리케이션을 돌릴 수 있다는 것이다.

Docker 설치

이 작업을 하기전에 먼저 컴퓨터(노트북)에 Docker를 깔아주자.
https://www.docker.com/products/docker-desktop/
desktop용으로 무료로 받을 수 있기 때문에 이를 먼저 설치해주자.

application.yml으로 변경 및 Dockerfile 작성

application.yml

우선 기존의 application.properties를 application.yml 파일로 수정해주면서 여러 설정 값들도 추가해준다.

spring:
  datasource:
    url: jdbc:mysql://db-mysql:3306/mydb?useUnicode=true&characterEncoding=UTF-8
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: spring
    password: spring
  jpa:
    database-platform: org.hibernate.dialect.MySQL8Dialect
    hibernate:
      ddl-auto: update
    show-sql: true
    properties:
      hibernate:
        format_sql: true
  profiles:
    include: oauth
server:
  servlet:
    encoding:
      charset: UTF-8
      force-response: 'true'

간단히 설명을 넣는다.

  • spring:datasource: -> DB에 대한 설정이 나온다. url에서 "db-mysql"은 db conatiner 이름이며, mydb가 database 이름이다. 한글 사용을 위해 unicode, encoding 관련 값을 넣어주었다.

  • jpa:database-platform: -> 후에 작업을 하다 hibernate.dialect 설정이 되어있지 않다는 error를 보고 추가해주었다. 나는 mysql8.0을 쓰기에 해당 버전에 맞는 dialect를 설정해주었다.

  • jpa:hibernate:ddl-auto: -> 나는 우선 프로젝트 개발 진행중이기 때문에 update로 둔다(이 옵션은 DB schema 변환이 있을 때 어떻게 처리하는가이다.)

  • jpa:show-sql -> sql log가 보이도록 해준다

  • jpa:properties:hiberante:format_sql -> sql이 이쁘게 보이게 해준다.

  • profiles:include: oauth -> 이는 oauth용으로 만들어둔 properties 파일을 읽는 용도임으로 그렇게 중요하지는 않다.

Dockerfile

사실 docker file 자체는 아직 별게 없다.

FROM openjdk:17-alpine

ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
  • FROM : base 이미지를 설정하는 명령이며 꼭 있어야 하는 명령이다. 나는 17버전의 openjdk:17-alpine을 사용했다.
  • ARG : 인자를 정해두는 것이며 = 을 통해 default 값을 설정해준다. 여기서는 gradle을 사용하므로 build 시 .jar이 생기는 build/libs 경로를 넣어준다.
  • COPY : 파일이나 디렉토리를 이미지 내부 경로로 복사한다. 여기서는 .jar 실행파일을 app.jar로 복사한다~ 이런 의미이다.
  • ENTRYPOINT : 빌드한 이미지를 컨테이너로 생성할때 실행되는 명령어. 여기서는 java jar을 실행하기 위한 명령어가 들어가있다.

이렇게까지막 적어도 별 어려움 없이 dockerfile 작성이 끝이난 것이다.

Docker container 화

우선 본 프로젝트에서는 mysql과 spring 코드 두 개를 container로 올려야 한다. 먼저 mysql을 해보자

무엇인가가 안된다면 Docker가 켜져있는지 우선 확인해보자 ㅎㅎ

network 만들기

docker 에서 container들 끼리 서로 통신을 할 때는 Docker network를 통해 수행한다. 아직 자세히는 알지 못하지만, 나는 DB와 프로젝트가 통신을 해야 하므로 이를 추가해주자

docker network create how-was-your-day-net

mysql container로 올리기

우선 mysql 이미지를 받아오자.

docker pull mysql:8.0

그 후 셋팅을 하며 container를 생성하고 실행해보자

docker run -p 3306:3306 --name db-mysql --network how-was-your-day-net -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=mydb -e MYSQL_USER=spring -e MYSQL_PASSWORD=spring -d mysql:8.0

관련 설명은 아래와 같다.

  • --name: 컨테이너 이름 설정
  • --network: 네트워크 연결 설정
  • -p: 포트 설정
  • -e: 환경변수 설정
  • -d: 백그라운드로 컨테이너 실행

spring app container로 올리기

실행 파일을 먼저 만들어줘야 한다. 그 이전에 build 했던 결과물들이 있을 수 있기에 우선 이를 지우고 새로 만들어주자

## 여기서 그냥 gradle을 사용해도 되긴 한다.
./gradlew clean 
## assemble은 실행 없이 build 파일 작성
./gradlew asseble

그리고서 docker image를 만들어주자

docker build -t how-was-your-day:1.0 .
  • -t: name:tag 식으로 설정.
  • 맨 뒤에 온점을 잊지 말자

이미지를 만들었으면 이를 이용해서 이제 container로 올려주면 된다.

docker run -p 8080:8080 --name how-was-your-day --network how-was-your-day-net -d how-was-your-day:1.0

결과 확인

우선 terminal에서 별다른 문제 없이 돌아갔다면 docker desktop 앱을 들어가보자. 아래와 같이 images와 containers 탭에서 정상적으로 돌아가고 있다면 성공이다.

에러 처리

하지만 나도 이 과정을 처음부터 성공해내지는 못했다. 여러 힘든 점을 겪었기에 이를 처리했던 방식들을 짧게나마 남겨둔다.

3306 포트 점유 이슈

처음에 mysql container를 올리려고 할 때 마주할 수 있는 에러이다. 나는 서버를 킨 적이 없는데 3306 포트를 누가 점유하고 있다~ 라고 나온다. 이럴 땐 한번 포트 점유 체크를 해주자.
cmd를 켜서 netstat -ano를 쳐주면 현재 사용중인 포트들이 나온다. 그 중에서 3306 포트가 사용중인지를 확인하고 그 pid를 체크하자. 그리고는 taskkill /f /pid [확인한pid]를 해주면 된다. 이 명령이 오류가 난다면 작업관리자를 들어가서 이름에서 우클릭을 해서 pid를 체크해 pid가 보이게 하고, 해당 pid를 직접 찾아서 종료해주면 된다.

mysql 한글 이슈...(윈도우 기준)

container 두 개가 다 켜졌고, localhost:8080에도 잘 접속이 되었다고 치자. 근데 왠걸 db와 통신하는 작업을 하자마자 에러 로그가 파파박 찍힌다. 근데 로그를 확인하니 아래와 같이
java.sql.SQLException: Incorrect string value: '\xEA\xB3\xA0\xED\x83\x9C...' for column 'name' at row 1 한글이 깨진 것과 같은 표현이 뜰 때가 있다. 이때는 mysql에 설정을 바꿔주어야 한다.

  1. application.yml에서 db url 뒤에 useUnicode=true&characterEncoding=UTF-8를 추가해보기

이럼에도 안되는 경우가 있을 것이다. 나도 그러했다.
그렇다면 다음으로 넘어간다.

  1. 우선 mysql을 접속해서 show variables like 'c%' 명령을 친다. 그러면 아래로 변수들이 촤라라 펼쳐질텐데, character_set 관련 값들을 보면 아마 utf8, utf8mb3 등이 아닌 latin1과 같은 값들로 설정되어 있을 것이다.

  2. 실행창에서 서비스를 검색하고 들어가 mysql 을 찾아 중지해준다.

  3. utf8 설정을 위해서 /ProgramData/MySQL/MySQL Server 8.0에 있는 my.ini 파일을 수정해야 한다.
    만약 수정권한이 없다면 파일의 속성/보안/편집을 가서 user에게 권한을 부여하기를 바란다.
    my.ini를 키고 아래와 같은 값들을 넣는다. (여기서 []로 되어 있는 것들은 아마 미리 입력되어 있을 것이기에 그 아래 적힌 코드를 해당 위치에 추가해주면된다.)

[client]
default-character-set=utf8

[mysql]
default-character-set=utf8

[mysqld]
character-set-client-handshake = FALSE
init_connect="SET collation_connection = utf8_general_ci"
init_connect="SET NAMES utf8"
character-set-server = utf8
  1. my.ini 설정을 마쳤다면 다시 서비스로 돌아가 mysql을 실행해주자. 이때 뭔가 오류가 뜬다면 아마 my.ini 파일에 오타가 있을 가능성이 크니 다시 확인해보자.

  2. mysql이 성공적으로 켜졌다면 다시 mysql을 접속해서 다시 show variables like 'c%' 명령을 친다. 아래와 같이 utf8이 잘 설정되었다면 성공이다.

mysql root 계정 로그인 이슈

이는 가장 귀찮게 했던 문제인데 해결법은 단순무식했다. ini 파일을 건들다 뭔가를 잘못건드렸는지 정확한 이유는 모르겠지만 mysql root 계정으로 로그인이 안되기 시작했다. 에러 로그는 아래와 같다.
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)

이는 여러 시도를 많이 해봤는데... 결국 선택한 선택지는 mysql server만 지웠다가 다시 까는거였다. 내가 버린 한시간이 아까우니 안된다 싶으면 지웠다 까는걸 추천한다.

마무리

trouble shooting 때문에 글이 길어진 감이 없지 않지만 이렇게 dockerize를 성공적으로 끝마쳤다. 이제는 docker container를 켜고 끄는 식으로 쉽게 서버를 킬 수 있다. 다음으로는 docker를 좀 더 쉽게 사용하는 docker-compose를 적용해보겠다.

profile
(전) Junior Android Developer (현) Backend 이직 준비생

0개의 댓글