6 분 소요

나중에 mysql과 redis에 볼륨 설정을 추가로 해야한다!
일단 배포부터 진행해보자.

(원래 aws ec2 ubuntu를 사용하려고 했는데, 자꾸 중단되는 문제가 발생해 gcp centos7를 사용했다.
따라서 0번은 필요 없지만, 나중에 참고하기 위해 남겨두었다.)

0. Ubuntu에 Docker Engine 설치

공식 사이트를 참고했다.

Repository 설정

# apt-get 업데이트
$ sudo apt-get update

$ sudo apt-get install \
ca-certificates \
curl \
gnupg \
lsb-release

$ sudo mkdir -p /etc/apt/keyrings

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

$ echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Docker Engine 설치 및 실행

$ sudo apt-get update

# 설치
$ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin

# 도커 실행
$ sudo service docker start

# 상태 확인
$ sudo service docker status

권한 설정

linux에서 root 권한이 아닌 상태로 docker를 실행하면 권한 문제가 발생할 수 있다.

[linux@localhost ]$ docker ps
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.40/containers/json: dial unix /var/run/docker.sock: connect: permi
ssion denied

이런 경우 매번 sudo로 커맨드를 실행해도 되지만, 번거롭기 때문에 docker group에 해당 유저를 추가해주면 해결할 수 있다.

# 보통은 docker group이 생겼을테지만, 만약 없으면 생성해준다.
$ sudo groupadd docker

# docker group에 해당 유저를 추가
$ sudo usermod -aG docker $USER

# 로그아웃 후 다시 로그인하거나 다음 명령어를 실행시켜야 적용이 된다.
$ newgrp docker

1. 네트워크 생성

# $ sudo docker system prune

$ docker network ls

# 네트워크 생성
$ docker network create --gateway 172.18.0.1 --subnet 172.18.0.0/16 naem-network

# 네트워크 목록 확인
$ docker network ls

# 특정 네트워크 상세 보기
$ docker network inspect naem-network

2. mysql 기동

1) init 스크립트 생성

mysql의 Dockerfile이 있는 위치에 mysql-init-files 디렉토리를 생성한 뒤, 그 안에서 create.sql 파일을 생성하자.

create.sql

CREATE DATABASE naem;

alter user 'root'@'localhost' identified with mysql_native_password by 'naem2524!';

create user 'root'@'%' identified by 'naem2524!';
grant all privileges on *.* to 'root'@'%';

flush privileges;

스크린샷 2022-10-20 오후 6 09 40

2) Dockerfile 작성

로컬에서 진행한다.
ec2 인스턴스에서 사용할 때에는 도커 허브에서 pull 받아서 사용한다.

FROM mysql

ADD ./mysql-init-files /docker-entrypoint-initdb.d

ENV MYSQL_ROOT_PASSWORD naem2524!
ENV MYSQL_DATABASE naem

EXPOSE 3306

3) 이미지 빌드 및 도커 허브에 업로드

로컬에서 진행한다.

# 이미지 파일 빌드
$ docker build \
--platform linux/x86_64 \
-t ln8847/naem_mysql:1.0 .

# 생성된 이미지 확인
$ docker images | grep naem_mysql

# 도커 허브에 업로드
$ docker push ln8847/naem_mysql:1.0

스크린샷 2022-10-20 오전 10 12 25

4) 도커 컨테이너 실행

vm 인스턴스에서 진행한다.
(컨테이너 실행 시, m1 Mac이 아니라면 --platform linux/x86_64 옵션은 빼도 된다.)

# 컨테이너 실행
$ docker run --platform linux/x86_64 -d -p 3306:3306 --network naem-network \
-v /home/ln8847/db:/var/lib/mysql \
--name mysql \
ln8847/naem_mysql:1.0

# 만약 컨테이너가 에러로 종료되었다면
$ docker system prune # 네트워크에 연결된 컨테이너가 없다면 네트워크가 삭제된다!

# 컨테이너 목록 확인
$ docker ps -a

# 네트워크 확인
$ docker network inspect naem-network

# 로그 확인
$ docker logs mysql

도커 컨테이너를 실행할 때 주의깊게 살펴볼 점은, -v /home/ln8847/db:/var/lib/mysql 옵션을 이용해 volume을 마운트 했다는 것이다.
호스트와 볼륨을 공유 방식인데, 호스트의 /home/ln8847/db 폴더와 컨테이너의 /var/lib/mysql 폴더를 동기화(연결)하겠다는 의미이다.
이때 호스트의 폴더 위치는 인스턴스 접속 후 pwd를 통해 확인하였다.
스크린샷 2022-10-24 오후 8 39 20

위 커맨드로 컨테이너를 실행한다.
스크린샷 2022-10-24 오후 8 25 54

지정한 위치에 db 폴더가 생긴 것을 확인할 수 있으며 디렉토리 안에는 아래와 같은 파일들이 있다.
스크린샷 2022-10-24 오후 8 26 08

네트워크를 확인해보자.
스크린샷 2022-10-20 오전 10 23 30

로그를 확인해보자.
스크린샷 2022-10-20 오전 10 23 19

🧐 참고
나는 이 글을 참고해 호스트와 볼륨을 공유하는 방식을 사용했지만,
이 글을 보면 호스트와 볼륨을 공유하는 방식 말고도
볼륨 컨테이너를 사용하거나 도커에서 제공하는 볼륨을 사용할 수도 있다.

5) db 접속 후 테이블 생성 및 권한 설정

redis 컨테이너를 삭제하고 다시 실행하면 아래 설정이 사라지기 때문에 매번 테이블을 생성하고 권할을 설정하기 번거롭다.
-> 1) 에서 init 스크립트를 만들었으면, 5) 내용은 필요없다.

mysql 컨테이너 내부에 접속한 뒤,
mydb 라는 데이터베이스에 접속해 usersorders 테이블이 만들어져 있는지 확인해보자.
그리고 mysql의 root 계정이 어떠한 IP Address로 접속한다 하더라도 접속 가능하도록 권한을 설정해보자.

$ docker exec -it mysql /bin/bash

# 맨 처음에는 비밀번호 없이 그냥 엔터
bash-4.4# mysql -uroot -p

# 데이터 베이스 확인
mysql> show databases;

# 사용하고자 하는 데이터베이스 생성
mysql> CREATE DATABASE naem;

스크린샷 2022-10-20 오후 5 05 55

이제 권한을 설정하자.

mysql> use mysql;

# user 조회
mysql> select host, user from user;

# 'root'@'%' 가 없는 경우!
mysql> create user 'root'@'%' identified by 'password_you_want';

# 권한 부여
mysql> grant all privileges on *.* to 'root'@'%';

# 적용
mysql> flush privileges;

# 권한 확인
mysql> show grants for 'root'@'%';

root 라는 계정의 어떤 IP Address로 접속하더라도, 모든 데이터베이스에 접속 가능하도록 권한을 부여하는 커맨드이다.
스크린샷 2022-10-20 오후 5 09 52

만약 패스워드 없이는 접속이 되는데, 패스워드를 입력했을 때 접속이 안된다면?
스크린샷 2022-10-20 오후 5 16 26

우선 패스워드 없이 접속한 뒤에 아래 커맨드를 진행하자.

mysql> use mysql;

mysql> alter user 'root'@'localhost' identified with mysql_native_password by 'new_password_you_want';

mysql> flush privileges;

이제 잘 접속된다.
스크린샷 2022-10-20 오후 5 18 56

6) 방화벽 설정

나중에 mysql 워크벤치로 접속하기 위해서 [방화벽] 설정에서 3306 포트를 열어두자!
스크린샷 2022-10-24 오후 5 46 12

3. redis 기동

1) Dockerfile 작성

FROM redis

EXPOSE 6379

2) 이미지 빌드 및 도커 허브에 업로드

로컬에서 진행한다.

# 이미지 파일 빌드
$ docker build \
--platform linux/x86_64 \
-t ln8847/naem_redis:1.0 .

# $ docker build -t ln8847/naem_redis:1.0 .

# 생성된 이미지 확인
$ docker images | grep naem_redis

# 도커 허브에 업로드
$ docker push ln8847/naem_redis:1.0

스크린샷 2022-10-20 오전 10 20 40

3) 도커 컨테이너 실행

vm 인스턴스에서 진행한다.
(컨테이너 실행 시, m1 Mac이 아니라면 --platform linux/x86_64 옵션은 빼도 된다.)

# 컨테이너 실행
$ docker run --platform linux/x86_64 -d -p 6379:6379 --network naem-network \
--name redis \
ln8847/naem_redis:1.0

# 컨테이너 목록 확인
$ docker ps -a

# 네트워크 확인
$ docker network inspect naem-network

# 로그 확인
$ docker logs redis

스크린샷 2022-10-20 오전 10 22 17

스크린샷 2022-10-20 오전 10 21 46

스크린샷 2022-10-20 오전 10 21 57

4. spring boot 기동

1) 방화벽 열기

이따가 8080 포트로 기동할 것이기 때문에 미리 8080 포트를 열어두자.

2) Dockerfile 작성

인텔리제이 터미널에서 진행한다.

FROM openjdk:11

# VOLUME /tmp

COPY build/libs/server-0.0.1-SNAPSHOT.jar Server.jar

ENTRYPOINT ["java","-jar","Server.jar"]

EXPOSE 8080

3) 이미지 빌드 및 도커 허브에 업로드

로컬에서 진행한다.

# 테스트 코드 제외하고 컴파일
# $ ./gradlew build -x test
$ ./gradlew bootJar -x test

# 이미지 파일 빌드
$ docker build \
--platform linux/x86_64 \
-t ln8847/naem-server:1.0  .

# 생성된 이미지 확인
$ docker images | grep naem-server

# 도커 허브에 업로드
$ docker push ln8847/naem-server:1.0

4) 도커 컨테이너 실행

vm 인스턴스에서 진행한다.
(컨테이너 실행 시, m1 Mac이 아니라면 --platform linux/x86_64 옵션은 빼도 된다.)

$ docker run --platform linux/x86_64 -d -p 8080:8080 --network naem-network \
-e "spring.datasource.url=jdbc:mysql://mysql:3306/naem?serverTimezone=Asia/Seoul&characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true" \
-e "spring.redis.host=redis" \
--name naem-server \
ln8847/naem-server:1.0

# 컨테이너 목록 확인
$ docker ps -a

# 네트워크 확인
$ docker network inspect naem-network

# 로그 확인
$ docker logs naem-server

로그를 실시간으로 확인하고 싶다면

$ docker logs -f naem-server

참고
지금은 볼륨을 지정하지 않았는데,
볼륨 옵션에 대해서는 이 글을 참고하자.

Trouble Shooting

naem-server 컨테이너 기동 시, mysql 컨테이너가 종료되는 문제

스크린샷 2022-10-20 오후 6 37 51
이 때, mysql 컨테이너의 STATUS를 보게되면, Exited (137)이라고 나와있는데,
이것은 OOM(Out of Memory) 에러로 컨테이너의 메모리가 부족하여 발생한다고 한다.

시도 1. docker desktop 에서 기존에 4G이던 메모리를 6G로 늘렸다.
스크린샷 2022-10-21 오후 2 29 28
하지만 해결되지 않았다.

시도 2. swap 파일 생성 -> 성공 👍

이 글을 참고했다.

# swap 확인
$ free -m

# Swap으로 사용할 디스크를 할당
$ sudo fallocate -l 4G /swapfile

# 파일 권한은 root로 제한
$ sudo chmod 600 /swapfile

$ ls -al /swapfile

# Swap file로 설정
$ sudo mkswap /swapfile

# Swap file을 시스템이 사용할 수 있도록 활성화
$ sudo swapon /swapfile

# 바로 위 커맨드에서 Invalid argument 에러가 발생하면 아래 3줄을 순서대로 실행 (아니면 3줄 넘어가기)
$ dd if=/dev/zero of=/swapfile bs=1M count=4096
$ sudo mkswap /swapfile
$ sudo swapon /swapfile

# Swap 파일의 UUID 확인
$ blkid /swapfile

$ sudo vi /etc/fstab
# 하단에 추가: UUID=cfa3658f-65b7-48ec-ba27-dd22e7277bda swap swap defaults 0 0

# OOM(Out of Memery) 가 발생할 때만, Swap File을 사용하도록 설정
$ sudo vi /etc/sysctl.conf
# vm.swappiness를 0으로 설정: vm.swappiness=0

# 제대로 Swap file이 생성되었는지 확인
$ free -m

현재 swap이 어떻게 잡혀있는지 확인해보자.
스크린샷 2022-10-24 오후 5 01 32
swap이 잡혀있지 않은 것을 확인할 수 있다.

Swap으로 사용할 디스크를 할당하자.
나는 4G를 할당하였다.
스크린샷 2022-10-24 오후 5 08 49

아래 명령어를 이용해 swap file로 설정하자.
스크린샷 2022-10-24 오후 5 10 14

그런데…
스크린샷 2022-10-24 오후 5 17 28
위와 같은 에러가 발생해 아래처럼 실행하였다.
(조금 기다려야 한다..!)
스크린샷 2022-10-24 오후 5 34 11

이제 두 개의 설정파일을 변경하자. 아래처럼 입력하면 된다.
스크린샷 2022-10-24 오후 5 34 29
/etc/fstab 설정
스크린샷 2022-10-24 오후 5 21 56

/etc/sysctl.conf 설정
스크린샷 2022-10-24 오후 5 24 07

이제 끝났다. Swap file이 제대로 생성되었는지 확인해보자.
스크린샷 2022-10-24 오후 5 34 40

mysql 컨테이너를 다시 실행해보니 더이상 Exited(137)로 종료돠지 않는다!
스크린샷 2022-10-24 오후 5 37 46



💛 개인 공부 기록용 블로그입니다. 👻

맨 위로 이동하기

태그:

카테고리:

업데이트: