일반적으로 MySQL 서버를 설치하고 클라이언트를 이용해서 접속할 때, 계정이 정상적으로 생성되고 패스워드가 정상적으로 등록되었고 접근을 허용하는 클라이언트 IP에 잘 설정되었다면 접속에 문제가 없다. 정리하자면 다음과 같다.
일반적으로 서버나 PC에 MySQL 서버를 설치하고 이와 같은 설정을 해주면 정상적으로 접근이 된다.
약간 예외적으로 로컬호스트에서 접속할 경우, mysql 클라이언트의 -h 옵션에 localhost를 사용하는지, 127.0.0.1을 사용하는지에 따라 서버 접속 방식이 살짝 달라진다.
요즘은 MySQL을 컨테이너로 설치하는 경우도 흔한데, 이런 경우 또 다른 문제가 발생할 수 있다.
docker pull mysql:latest
docker run -d -p 공개포트:3306 mysql:latest
이렇게만 실행해도 실행은 되지만, root 계정의 패스워드나 애플리케이션에서 사용할 일반 계정 및 패스워드를 지정하지 않았기 때문에 사실 상 사용이 어려워진다. 그러므로 root 계정의 패스워드, 일반 계정과 패스워드를 환경변수로 넘겨서 지정할 필요가 있다.
docker run -d -p 공개포트:3306 \
-e MYSQL_ROOT_PASSWORD=루트패스워드 \
-e MYSQL_DATABASE=다비이름 \
-e MYSQL_USER=계정이름 \
-e MYSQL_PASSWORD=패스워드 \
mysql:latest
컨테이너를 이용한다는 것은 좀 더 자동화를 하려는 목적이 있기 때문에, 컨테이너를 만들고 그 안에 테이블을 생성해두면 편리하다. 그래서 초기 SQL 스크립트를 실행할 필요가 있다.
docker run -d -p 공개포트:3306 \
-e MYSQL_ROOT_PASSWORD=루트패스워드 \
-e MYSQL_DATABASE=다비이름 \
-e MYSQL_USER=계정이름 \
-e MYSQL_PASSWORD=패스워드 \
-v $(dirname $(pwd))/init.sql:/docker-entrypoint-initdb.d/init.sql \
mysql:latest
현재 디렉토리의 init.sql 파일을 컨테이너 내부의 /docker-entrypoint-initdb.d 디렉토리의 파일로 볼륨 매핑하면 SQL 파일에 적혀있는 SQL 문장을 실행하여 테이블을 미리 생성할 수 있다. dirname과 pwd를 사용하는 이유는 볼륨 매핑 시 절대 경로로 지정해야 하기 때문이다.
CREATE TABLE ...중략...;
또한, 컨테이너 삭제 시에 데이터베이스 데이터를 유실할 수 있기 때문에 MySQL 데이터를 호스트 머신의 파일시스템에 남겨둘 필요도 있다. 호스트 머신의 mysql_data_dir 디렉토리와 컨테이너 내부에서 MySQL 서버가 데이터를 저장하기 위해 사용하는 /var/lib/mysql 디렉토리를 매핑하는 설정을 다음과 같이 추가한다.
docker run -d -p 공개포트:3306 \
-e MYSQL_ROOT_PASSWORD=루트패스워드 \
-e MYSQL_DATABASE=다비이름 \
-e MYSQL_USER=계정이름 \
-e MYSQL_PASSWORD=패스워드 \
-v $(dirname $(pwd))/init.sql:/docker-entrypoint-initdb.d/init.sql \
-v $(dirname $(pwd))/mysql_data_dir:/var/lib/mysql \
mysql:latest
이렇게 하면, 호스트 머신의 mysql_data_dir에 컨테이너 내부의 /var/lib/mysql 디렉토리 파일들이 저장되는 것을 확인할 수 있다.
볼륨 매핑을 통해서 파일시스템을 컨테이너와 공유하게 되면 권한 문제가 생기기도 한다.
docker run으로 mysql 서버 컨테이너를 실행했는데 바로 종료하는 경우가 있다. 다음 명령으로 로그를 살펴보자.
docker logs 컨테이너이름
chown: changing ownership of '/var/lib/mysql/': Operation not permitted
chown: changing ownership of '/var/lib/mysql': Operation not permitted
컨테이너의 로그에 이런 오류가 있다면 권한 문제이다. 이 경우, --user 옵션을 이용해서 docker run을 실행해주면 된다.
docker run -d -p 공개포트:3306 \
--name 컨테이너이름
--user "$(id -u):$(id -g)" \
-e MYSQL_ROOT_PASSWORD=루트패스워드 \
-e MYSQL_DATABASE=다비이름 \
-e MYSQL_USER=계정이름 \
-e MYSQL_PASSWORD=패스워드 \
-v $(dirname $(pwd))/init.sql:/docker-entrypoint-initdb.d/init.sql \
-v $(dirname $(pwd))/mysql_data_dir:/var/lib/mysql \
mysql:latest
컨테이너가 생성되면 일반적으로 호스트 머신과 네트웍이 분리되므로 IP를 이용해서 접속해야 한다.
mysql -h 127.0.0.1 -P 공개포트 -u 계정이름 디비이름 -p
docker exec -it 컨테이너이름 mysql -u 계정이름 디비이름 -p
첫번째 방법이 동작하지 않는 경우, 이 방법을 이용하면 root 계정으로 user 테이블을 조회한다든가 해서 계정이 정상적으로 생성되었는지 확인할 수 있다.
또는, 호스트 머신에 mysql 클라이언트가 설치되지 않았다면 이 방법을 이용할 수 있다.
mysql -h 컨테이너이름 -P 3306 -u 계정이름 디비이름 -p
호스트 옵션(-h)에 컨테이너이름을 사용하고, 포트번호 옵션(-P)에 3306을 사용하는 것에 주의해야 한다.
그런데, 아직 "컨테이너이름"을 지정하지 않았다. --name 옵션을 이용해서 지정할 필요가 있다.
docker run -d -p 공개포트:3306 \
--name 컨테이너이름
-e MYSQL_ROOT_PASSWORD=루트패스워드 \
-e MYSQL_DATABASE=다비이름 \
-e MYSQL_USER=계정이름 \
-e MYSQL_PASSWORD=패스워드 \
-v $(dirname $(pwd))/init.sql:/docker-entrypoint-initdb.d/init.sql \
-v $(dirname $(pwd))/mysql_data_dir:/var/lib/mysql \
mysql:latest
MySQL 서버 컨테이너를 한 번 설정하고 나면 그 이후에는 컨테이너를 재생성하려고 하면 여러가지 문제점이 발생한다.
docker: Error response from daemon: container create: creating container storage: the container name "디비이름" is already in use by 09b34302a6183b17ab291a0e1f26960f532aeff24383f7801e4e8c3ab89cb96d. You have to remove that container to be able to reuse that name: that name is already in use.
docker run 명령 실행 시, 이런 에러 메시지가 노출되기도 하는데, 이것은 컨테이너가 살아있거나 죽어있든 간에 같은 이름을 사용하고 있기 때문이며 아직 해당 이름의 컨테이너가 삭제되지 않았기 때문이다.
docker rm 컨테이너이름
docker rm 명령을 이용하면 죽어있는 컨테이너를 삭제할 수 있는데, -f 옵션을 사용하면 살아있는 컨테이너를 죽이고(docker kill) 삭제하는 것까지 한 번에 할 수도 있다.
docker rm -f 컨테이너이름
MySQL 서버가 정상 실행되고 나면 그 이후에는 설정이 잘 변경되지 않는다. 그 이유는 환경변수로 전달한 루트패스워드, 계정이름, 패스워드 등이 컨테이너 생성 시 최초 한 번만 적용되기 때문이다. 게다가 볼륨 매핑을 통해 호스트 머신의 파일시스템에 데이터가 저장되었기 때문에 이것을 삭제하지 않으면 설정이 변경되지 않기도 한다.
rm -rf mysql_data_dir