Dockerize MySQL (1)

2 minute read

Dockerize MySQL


이전에 매번 MySQL 계정 및 데이터베이스 설정하는 게 귀찮아 Github에 올렸던 적이 있다. 이제 데이터 쌓는 것까지 너무 귀찮아서 데이터까지 통째로 포함하여 Docker 컨테이너를 pull/push하려고 한다.

일단 내 Docker Hub에 이미지 올렸던 경험은 있는데 데이터까지 말아서 올릴 수 있는지는 아직 확인해보지 않았다.


MySQL 컨테이너 구동

$ docker pull mysql
$ docker run --name mysql-db -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -d mysql


e 옵션은 Environment Variables의 약어로서 총 4개의 변수를 포함한다.


MYSQL_ROOT_PASSWORD (필수)

MYSQL_DATABASE: 데이터베이스 생성 시 사용

MYSQL_USER, MYSQL_PASSWORD: 사용자를 생성하고 생성된 데이터베이스의 권한을 얻음

MYSQL_ONETIME_PASSWORD: 1회성 패스워드 생성


$ docker exec -it mysql-db bash


CLI로 들어왔으면 MySQL에 접속해서 데이터베이스와 사용자를 생성해준다.

여기서 잠깐! CLI로 매번 사용자 권한과 데이터베이스 생성이 귀찮으므로 위에서 언급했던 변수들을 사용하여 컨테이너를 띄울 것이다. 접속해서 CLI로 조회해보면 사용자와 데이터베이스가 잘 생성되어 있다.

$ docker run --name mysql-db -p 3306:3306 -d \
-e MYSQL_ROOT_PASSWORD=root \
-e MYSQL_USER=yoon \
-e MYSQL_PASSWORD=yoon \
-e MYSQL_DATABASE=flaboard \
-d yoon4480/mysql-db-custom:0.1


외부에서의 컨테이너 접속

이제 내가 구축한 서버에서 이 MySQL 컨테이너로 접속하려면 이 컨테이너의 가상 IP를 알아내야 한다. 아래 커맨드는 특정 컨테이너의 네트워크 정보를 조회하는 것이다. json. 다음에 띄어쓰기 꼭 넣어! 객체 참조가 아니라 인자로 받는 것이다.

$ docker inspect mysql-db -f ""
{
	"bridge": {
		"IPAMConfig": null,
		"Links": null,
		"Aliases": null,
		"NetworkID": "8b21c5994c4eb65a3ec24af1d68c1c171553049741d1262e4a23b1de630782a1",
		"EndpointID": "adb3c07e49cd454c04de20de69a964af3f52350513ea544d4216894cce24ea2a",
		"Gateway": "172.17.0.1",
		"IPAddress": "172.17.0.2",
		"IPPrefixLen": 16,
		"IPv6Gateway": "",
		"GlobalIPv6Address": "",
		"GlobalIPv6PrefixLen": 0,
		"MacAddress": "02:42:ac:11:00:02",
		"DriverOpts": null
	}
}

예쁘지 않다. 아프다. 눈이.

$ docker inspect mysql-db -f "" | json_pp
{                                                     
	"bridge": {
		"Links": null,
		"IPAddress": "172.17.0.2",
		"Gateway": "172.17.0.1",
		"DriverOpts": null,
		"EndpointID": "adb3c07e49cd454c04de20de69a964af3f52350513ea544d4216894cce24ea2a",
		"IPAMConfig": null,
		"Aliases": null,
		"MacAddress": "02:42:ac:11:00:02",
		"IPv6Gateway": "",
		"IPPrefixLen": 16,
		"GlobalIPv6PrefixLen": 0,
		"GlobalIPv6Address": "",
		"NetworkID": "8b21c5994c4eb65a3ec24af1d68c1c171553049741d1262e4a23b1de630782a1"
	}
}

bridge 네트워크 상에서 구동되고 있는 모든 컨테이너들의 네트워크 정보를 조회하는 커맨드이다.

$ docker network inspect bridge -f "" | json_pp
{
   "b60f020034cbb7675e4c28007f5722a6389c7fe6c4fac1a3555be02b812d3f81" : {
      "Name" : "mysql-db",
      "MacAddress" : "02:42:ac:11:00:02",
      "EndpointID" : "6ee2ffd48893a047c9f68f962e1c7792b85eb3d364b7045c828edd72be121533",
      "IPv6Address" : "",
      "IPv4Address" : "172.17.0.2/16"
   }
}

위의 IP로 MySQL 컨테이너에 접속을 테스트해봤는데 실패했다. Flask에서 migrate도 먹히질 않는다. 왜지. 방화벽인가. 인바운드 때문인가. 컨테이너를 생성할 때마다 초기 CIDR 설정에 의해 자동으로 할당되는 IP 때문인 것 같은데 정확한 원인은 알아봐야겠다.

DB 접속 정보를 localhost에서 127.0.0.1로 바꿔서 IP 주소를 명시해줬더니 신기하게도 접속이 된다. localhost로 접속했하는 경우 MySQL이 포트 번호를 무시해버린다. 관련 내용을 좀 알아보았다.

On Unix, MySQL programs treat the host name localhost specially, in a way that is likely different from what you expect compared to other network-based programs. For connections to localhost, MySQL programs attempt to connect to the local server by using a Unix socket file. This occurs even if a –port or -P option is given to specify a port number. To ensure that the client makes a TCP/IP connection to the local server, use –host or -h to specify a host name value of 127.0.0.1, or the IP address or name of the local server. You can also specify the connection protocol explicitly, even for localhost, by using the –protocol=TCP option.

위 내용은 MySQL 공식 문서 내용 일부를 발췌한 것이다.

Unix에서의 MySQL은 localhost를 우리가 일반적으로 알고 있는 것과 다른 방식으로 접속한다. TCP/IP 방식으로 접속하지 않고 소켓 방식으로 연결하는데 --port, -p 옵션으로 포트 번호를 지정해도 localhost라는 호스트 이름은 무시된다. TCP/IP 방식으로 연결하려면 --host, -h 옵션 뒤에 127.0.0.1 또는 IP 주소를 명시해줘야 한다. localhost 사용이 불가능한 것은 아니다. --protocol=localhost라고 명시해주면 되긴 하는데, 앞으로 혹시 모를 또다른 충돌을 미연에 방지하기 위해 localhost 대신 127.0.0.1로 설정하는 습관을 들여야겠다.

Categories:

Updated: