Docker + MySQL 원격 접속

Kyojun Jin·2022년 3월 8일
5

왜?

집에 데스크톱과 안 쓰는 노트북이 있는데,
노트북을 컴퓨터 서버로 이용하기로 하였다.
데스크톱으로 개발이 완료된 서버를 노트북에서 돌려 배포하고
젠킨스로 자동화 하는 작업을 하고 싶었다.

그러기 위해선 일단 노트북에 데이터베이스를 설치하고
개발 도중엔 데스크톱에서 DB에 원격으로 접속하는 일을 해야 한다.

원래 노트북에 WSL2가 있어서 거기서 원격 접속하면 되지만
최근에 데스크톱을 초기화하면서 WSL2이 아닌 도커 기반으로 개발 환경을 바꿨기 때문에
이번에도 도커를 이용하고 싶었다.

사전지식

도커

리눅스를 오래 사용해왔는데
컴퓨터를 초기화하거나 바꿀 때마다 그때그때 mysql이며 python이며 깔아줘야 했었다.
일일히 버전도 관리해야 하고, 설치할 때 다른 리눅스 설정이랑 충돌도 나고 할 일이 많았다.
하지만 도커를 사용하고 나서 스트레스가 사라졌다.

도커는 가상화를 이용해서 mysql, openjdk, python
프로그래밍에 쓰이는 환경들을 독립적으로 운용할 수 있다.
더이상 설치하고 설정하는 일을 반복하고 충돌을 걱정할 필요 없이,
그저 현재 사용 중인 운영체제 위에 가상의 공간을 만든 뒤
그곳에서 프로그램이나 환경 등을 동작시킬 수 있다.

이 프로그램 또는 환경을 도커에선 이미지라고 하며
이들이 올라가 실행되는 곳을 컨테이너라고 한다.
한 컨테이너에는 한 이미지가 들어있다.

도커의 장점은, 컨테이너 실행의 오버헤드가 없다는 것이다.
기존 가상머신 해결책은 컨테이너마다 이를 관리하는 OS(사진에서의 Guest OS)가 있었어야 했다.
컴퓨터 위에 가상으로 격리된 머신 하나를 띄우는 방식이었기 때문이다.
하지만 도커는 머신을 통째로 띄우는 게 아니라 프로세스를 띄운다.
이 프로세스는 아주 잘 격리되어 있기 때문에
마치 다른 컴퓨터를 사용하는 것처럼 완전히 격리된 상태로 사용할 수 있다.
또한 속도도 아주 빠르다.

윈도우에서의 도커

보통 도커는 리눅스에서 활용되지만 윈도우에서도 사용할 수 있다.
도커 데스크톱을 설치하면 WSL2 를 활용해서 도커를 사용할 수 있다.
윈도우 10 프로 이상은 안 써도 되긴 한데 WSL2를 쓰면 더 좋은 성능에 쓸 수 있다고 한다.

다음은 도커 레퍼런스의 설명이다.

도커 데스크톱은 자원 사용을 크게 향상시키기 위해서 WSL 2의 동적 메모리 할당 기능을 사용한다. 즉, 도커 데스크톱은 CPU와 메모리 자원을 필요할 때에 필요한 만큼만 사용해서, 컨테이너를 빌드하는 것과 같이 CPU와 메모리를 많이 사용하는 작업들을 훨씬 빠르게 돌릴 수 있다.

즉 윈도우에서 도커를 사용하려면 WSL 2를 사용하는 것이 좋다.

도커 허브

깃허브처럼, 도커에도 이미지를 공유할 수 있는 허브가 있다.
개발자들이 공식적으로 배포하는 이미지도 있고, 개인이 편의를 위해서 만들어놓은 이미지도 있다.
예를 들어 C언어 개발 환경을 위한 이미지가 있는데, 이 이미지를 만들기는 쉽지가 않다.
일단 리눅스 이미지를 기반으로, gcc, g++, make 등 설치할 게 많다.
도커는 설정 파일을 이용해서 이미지를 실행하고,
컨테이너에서 그 이미지를 이용해 할 일을 미리 지정할 수 있다.
리눅스에서 배시 스크립트 같은 것이다.
이런 파일을 이용해서 만든 커스텀 이미지를 도커 허브에서 공유할 수 있다.

도커파일과 도커 컴포즈

도커 허브에서 받을 수 있는 이미지는 아주 간단한 이미지들이다.
특히 공식 이미지들은 아무런 설정이 되어 있지 않다.
또한 개발이 그렇듯 이미지 하나만으로 프로그램을 만들 수 없다.
간단한 스프링 서버 하나만 만든다 쳐도 openjdkmysql 두 이미지가 필요하다.

그래서 실제로 사용을 하려면 이미지 실행 후 할 일을 지정하거나,
여러 이미지들을 실행하는 방법을 저장하는 파일을 만들어 사용하는 것이 편하다.
이 중 전자는 도커파일, 후자는 도커컴포즈이다.

저장소 관리

도커에서 저장소를 관리하는 두 가지 방법이 있다.
볼륨(volume)과 바인드 마운트(bind mount)가 그것이다.
볼륨은 도커 자체적으로 따로 저장공간을 마련해놓는 것인 반면 (따라서 도커에 의해 관리될 수 있는)
바인드 마운트는 현재 도커를 사용하는 (호스팅 하는) OS에 있는 디렉토리를 컨테이너와 연결하는 것이다.
연결한다는 말은 그 컨테이너가 그 디렉토리를 참조할 수 있도록 한다는 것이다.

두 가지 기능이 있다는 것은 분명, 둘의 장단점이 있다는 것이다.
볼륨의 장점은 도커를 이용해 관리할 수 있다는 점, (안전성)
따라서 백업과 복구가 쉽다는 것이며 좀 더 도커의 철학과 맞다는 점이다. (격리)
반면 바인드 마운트 방법의 장점은 기존에 있는 파일들을 그대로 사용할 수 있다는 점이다.

방법은 두 가지가 있지만 도커는 공식적으로 볼륨을 추천한다.

도커 컨테이너가 생성하고 사용하는 데이터를 유지하는 데엔 볼륨 메커니즘을 사용할 것을 권한다.
바인드 마운트는 디렉토리 구조와 호스트 머신의 운영체제에 의존하는 반면,
볼륨은 도커가 온전히 관리하기 때문이다.
볼륨은 바인드 마운트에 비해 여러 장점이 있다:

볼륨은 바인드 마운트에 비해 백업하고 옮기기가 쉽다.
도커 CLI 커맨드나 도커 API로 볼륨을 관리할 수 있다.
볼륨은 리눅스와 윈도우 컨테이너에서 둘 다 사용할 수 있다.
볼륨은 여러 컨테이너들끼리 더 안전하게 공유할 수 있다.
볼륨 드라이버는 볼륨 내용을 암호화하거나 다른 기능을 덧붙이기 위해 원격 호스트나 클라우드 제공자에 볼륨을 저장할 수 있다.
새 볼륨은 컨테이너 이전에 미리 내용물을 담을 수가 있다.
도커 데스크톱의 볼륨은 맥과 윈도우 호스트에서 바인드 마운트를 사용하는 것보다 훨씬 좋은 성능을 보인다.

추가로, 볼륨은 컨테이너의 수정 가능한 레이어에 있는 데이터를 유지하는 데 좋은 선택지이다. 볼륨은 이를 사용하는 컨테이너의 크기를 늘리지 않으며, 볼륨의 내용물은 해당 컨테이너의 생명주기의 바깥에 존재하기 때문이다.

시나리오

  1. 노트북에 도커를 설치한다.
  2. 노트북에 mysql 이미지를 설치한다.
  3. DB의 각종 설정을 바꾼다.
  4. 컨테이너가 종료되어도 데이터는 살아있도록 한다.
  5. 외부 접속하게 한다.

도커 설치

도커를 설치하기 전에, 바이오스에서 Hyper-V를 사용하는 것으로 설정해줘야 하고
윈도우 기준 <제어판-프로그램-Windows 기능 켜기/끄기>에서 Hyper-V 사용으로 체크해줘야 한다.

도커 데스크톱은 여기서 설치할 수 있다.

설치 도중 WSL 2를 설치하는 것이 나오는데 이것을 체크하고 설치를 진행한다.
설치가 완료되면 컴퓨터를 껐다가 끈다. (혹은 재로그인)

참고로 WSL 은 Window Subsystem for Linux 의 줄임말로
윈도우 위에서 가상화 기능을 통해 리눅스를 돌리는 것이다.
즉 도커 혹은 WSL만 있으면 윈도우에서도 리눅스 프로그래밍을 할 수 있다.

cmd 창에서 wsl -l -v를 하면 docker-desktop과 docker-desktop-data라는 두 시스템이 나온다.
이들 각각을 wsl에선 '배포'라고 표현하는 것 같다.

도커 옮기기 (선택)

wsl는 무조건 기본값으로 C드라이브에 깔린다.
C드라이브에 뭔가 설치하는 것을 싫어한다면 도커 저장소를 옮기면 된다.

옮기는 과정은 다음과 같다.

  1. 배포를 tar 파일로 백업
  2. 배포 등록 해제
  3. 1번에서 백업했던 파일을 import
  4. tar 삭제

CMD 창을 켠 후 (관리자일 필욘 없다)
wsl --export docker-desktop {tar 파일을 저장할 위치} 로 백업
wsl --unregister docker-desktop로 등록해제
wsl --import docker-desktop {tar 파일 위치} {배포를 저장할 위치}로 임포트한다.
tar 파일은 그냥 지워주면 된다.

이 작업을 docker-desktop과 docker-desktop-data 에 반복해주면 된다.
주의할 점은, export 하면 무조건 파일이름이 ext4.vhdx 라고 나오는데
따라서 두 배포를 같은 디렉토리에 저장할 수 없다.
배포마다 각각 디렉토리를 생성해주고 거기다가 생성해야 한다.

도커 컴포즈로 MySQL 컨테이너 생성

mysql 이미지를 받는 것은 문제가 없다.
왜냐면 그냥 공식 이미지를 받으면 되기 때문이다.

mysql 이미지는 docker pull mysql로 받을 수 있다.
그러면 알아서 자동으로 latest 태그를 달아서 받아질 것이다.
태그는 도커의 변경 가능한 이름이다.
깃에서의 브랜치처럼, 같은 이미지더라도 다른 버전으로 받을 수 있다.

그러나 도커 컴포즈를 이용해서 이를 좀 더 간편하게 실행할 수 있다.
도커 컴포즈의 파일은 무조건 docker-compose.yml이어야 한다. (혹은 yaml)
(여기서 알 수 있는 사실은 도커 컴포즈의 파일은 폴더로 구분해야 한다는 것이다.)

도커 컴포즈로 여러 이미지를 여러 설정과 함께 실행할 수 있다.
이번에 도커 컴포즈를 사용하는 이유는 mysql을 실행할 때 옵션을 걸기 위해서이다.
(그게 아니라면 이미지를 실행하는 커맨드가 엄청 길어질 것이고 보기 싫을 것이다.)

딸랑 이미지 하나인데 도커파일이 아닌 도커 컴포즈를 사용하는 이유는
도커 파일은 이미지가 올라간 후 할 일을 예약해놓는 것이고
도커 컴포즈는 이미지를 실행하는 방법을 설정하는 것이기 때문이다.
나는 mysql을 실행할 때 볼륨을 연결하고 옵션을 많이 걸어줘야 한다.
옵션을 거는 것은 실행 후에 하는 것은 매우 복잡하고 (my.cnf 수정 등)
볼륨 연결은 불가능하다.
따라서 도커 파일이 아닌 도커 컴포즈를 써야 하는 것이다.

다음은 내가 사용 중인 도커 컴포즈 파일의 내용이다.

version: "3.8"

volumes:
        볼륨 이름:
            external: true
            name: 볼륨 이름

services:
    db:
        image: mysql
        container_name: 컨테이너 이름
        ports: 
            - "3306:3306"
        environment:
            - MYSQL_ROOT_PASSWORD=비밀번호
            - TZ=Asia/Seoul
        command: 
            - --default-authentication-plugin=mysql_native_password
            - --character-set-server=utf8mb4
            - --collation-server=utf8mb4_unicode_ci
            - --skip-character-set-client-handshake
        volumes:
            - 볼륨 이름:/var/lib/mysql

위에서 차근차근 이 파일이 무엇을 뜻하는지를 알아보자.

volumes:
        볼륨 이름:
            external: true
            name: 볼륨 이름

이는 top-level 에 들어가야 한다.
이 파일에서 쓸 볼륨을 미리 선언하는 것이라고 보면 된다.
외부에 이미 있는 볼륨 이름이란 볼륨을 쓴다는 뜻이다.
이거 없이 밑에서 볼륨을 쓰면 임시 볼륨을 생성한다.
임시 볼륨은 메모리에서 동작하므로 컨테이너가 멈추면 볼륨도 메모리에서 사라지기 때문에
데이터가 다 날아갈 수 있다.

services라는 것은 이미지들을 의미한다.
도커 컴포즈가 여러 이미지를 조합하기 위한 것으로,
하나의 컨테이너가 일을 하는 것을 서비스라고 칭하며
이 서비스들을 명시해주는 공간이다.

db라는 이름을 사용하는 서비스가 있으며
그것의 베이스 이미지는 mysql이다.
(설치된 이미지가 이미 있으면 그것을 쓴다. 없다면 latest로 받는다. 특정 태그를 지정해줄 수도 있다.)

이미지가 실행되면 각 컨테이너에 실어질텐데 그것에 대해 이름을 또 지정해야 한다.
안 그러면 도커가 알아서 이름을 정할 것이고,
docker ps라는 명령어로 내가 조종할 컨테이너의 이름을 일일히 찾아봐야 할 것이다.
그래서 container_name에 컨테이너의 이름을 명시한다.
물론 이때 이름은 다른 컨테이너의 이름과 겹치면 안 된다.

port로 해당 컨테이너의 포트포워딩을 해준다.
지금은 외부에서 3306으로 들어오는 것을 내부의 3306로 연결해주었다.
이게 없으면 포트가 지멋대로 바뀌어서 외부 접근이 불가능하다.
(포트를 모르면 로컬호스트에서도 접근이 불가능할 것이다.)

다음 environment로 mysql 의 환경변수를 설정해준다.
패스워드와 시간대를 설정해준다.

command는 mysql에 다는 옵션이다.
첫째 줄은 보안 방식을 비밀번호를 이용하는 방식을 이용하는 옵션
2~4번째 줄은 캐릭터셋을 utf8mb4로 이용하는 것이다.
utf8mb4 인코딩 방식은 요즘 많이 사용되는 이모지까지도 표현 가능한 아주 넓은 범위의 문자셋이다.
특히 4번째 줄이 없으면 클라이언트의 시스템 인코딩을 사용하는데
윈도우의 경우 euckr로 설정될 수 있으므로 해줘야 한다.

마지막으로 volumes에서 사용할 볼륨 (위에서 정한) 을 연결해준다.
바인드 마운트의 경우 맨 위에 volumes를 따로 정할 필요 없이 여기서

volumes:
    - 드라이브/마운트/할/경로:/var/lib/mysql

만 해줘도 된다.

이렇게 하고, 이 파일이 지정된 위치에서 docker-compose up -d를 하면
파일에 명시된 대로 이미지가 컨테이너로 올라가 실행된다.

upbuild하고 자동으로 실행까지 해주는 명령어이다.
-d 옵션은 컨테이너를 백그라운드에서 실행해주는 옵션이다.

MySQL 실행

docker exec -it [컨테이너 이름] bash 로 실행 중인 컨테이너에 접근할 수 있다.
docker exec은 컨테이너 내에 명령어를 전달하는 명령어이다. 여기선 bash를 전달한 것이다.
it옵션은 i는 interactive의 약자로, 입출력을 stdin, stdout로 사용할 수 있도록 한다.
말 그대로 사용자와 컨테이너가 상호작용할 수 있는 환경을 만들어 준다.
t 는 tty의 약자로, 터미널 환경을 조성해준다.
bash는 배시를 실행하는, 그러니까 그 컨테이너를 조작할 수 있는 배시 셸을 여는 것인데
이를 일반적으로 리눅스 터미널처럼 쓸 수 있도록 하는 것이다.

그래서 결론적으로
docker exec -it [컨테이너 이름] bash를 사용하면
일반적으로 리눅스 화면이 나오고 거기서 mysql -u root -p로 mysql을 사용할 수 있다.

원격 접속 허용

grant all privileges on *.* to 'root'@'%';으로 원격 접속을 허용할 수 있다.

모든 ip주소에서 접근하는 Root라는 이름을 가진 사용자에게 모든 데이터베이스의 모든 테이블에 대한 모든 권한을 부여한다는 것이다.

나(root)는 믿을 수 있으므로 원격 접속에 대해 모든 권한을 주었다.

create user '사용자 이름'@'ip주소' identified by '비밀번호';로 사용자를 추가해서
권한과 접근 위치를 세분화 할 수 있다.

테스트

데스크톱 화면

(참고로 데스크톱 <-- 공유기 --> 노트북 이라서 노트북을 고정 아이피로 사용해야 한다.)
노트북의 고정 아이피는 172.30.1.201으로 해놓았다.

노트북 화면

삼불원 이모지까지 잘 나오는 것을 확인할 수 있다.

컨테이너를 삭제했다가 다시 docker-compose up -d로 만들어도
심지어 노트북을 껐다 켜도,
docker start [이름] 하나면 DB를 정상적으로 확인할 수 있다.

1개의 댓글

comment-user-thumbnail
2023년 3월 28일

너무 좋은 글 감사합니다. 많은 도움이 되었습니다!

답글 달기