앱을 여러 컨테이너에서 실행할 수 있도록 공부해보자.
지금까지 단일 컨테이너 애플리케이션을 사용해왔습니다. 이제는 애플리케이션 스택에 MySQL을 추가해봅시다.
그럼 MySQL도 별도의 컨테이너에서 실행해야 할까요? 일반적으로는 그렇게 하는 것이 좋습니다.
그 이유는 여러 이유가 있는데요.
프론트엔드, 백엔드, DB 등등 애플리케이션을 위한 각 구성 요소들은 모두 다 같이 확장되기보다는 각각 다른 시점에서 확장될 확률이 높습니다. 따라서 각각 독립적으로 확장할 수 있도록 별도의 컨테이너에서 실행하는 것이 좋습니다.
별도의 컨테이너들에 앱을 실행하면 독립적으로 버전을 업데이트하고 관리할 수 있습니다.
따라서 각각을 개별적으로 업그레이드 하거나 롤백할 수 있는 유연성을 가질 수 있습니다.
개발 환경에서는 로컬 컨테이너로 데이터베이스를 운영할 수 있지만, 실제 운영 환경에서는 더 안정적인 데이터베이스 서비스(AWS RDS, GCP SQL 등)를 사용할 수 있습니다.
로컬, 개발 환경에서는 컨테이너를 사용하다가 운영 환경에서는 관리형 서비스로 쉽게 전환할 수 있는 유연성을 가질 수 있습니다.
여러 프로세스를 실행해야 할 경우, 프로세스 관리자가 필요하게 됩니다(컨테이너는 기본적으로 하나의 프로세스만 시작합니다).
이는 컨테이너의 시작과 종료를 복잡하게 만들 수 있습니다.
결국, 여러 컨테이너를 사용하는 것은 각각의 컴포넌트를 독립적으로 운영하고 최적화할 수 있게 해주며, 전체 시스템을 더 안정적으로 만들어 줍니다. 이는 개발과 운영 모두에서 많은 이점을 제공합니다.
컨테이너 간의 네트워킹은 컨테이너들이 서로 통신할 수 있게 하는 중요한 기능입니다.
기본적으로 각 컨테이너는 독립적으로 실행되며, 다른 프로세스나 컨테이너들과는 별개로 작동합니다.
컨테이너가 서로 통신하려면 같은 네트워크에 있어야 합니다.
컨테이너를 네트워크에 연결하는 두 가지 방법이 있습니다.
여기서는 네트워크를 먼저 생성한 후에, MySQL 컨테이너를 시작할 때 해당 네트워크에 연결하도록 하겠습니다.
docker network create todo-app
MySQL 컨테이너를 생성하는데 사용될 몇 가지 환경 변수를 정의하면서, MySQL 컨테이너를 네트워크에 연결합니다.
MySQL 환경변수 참조
docker run -d \
--network todo-app --network-alias mysql \
-v todo-mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=todos \
--name mysql \
mysql:8.0
--network-alias
-v
: /var/lib/mysql
에 마운트된 todo-mysql-data
라는 볼륨을 사용했습니다.(MySQL이 데이터를 저장하는 위치)별도로 docker volume create
명령을 실행하지 않았지만 Docker는 명시된 이름의 볼륨을 자동으로 생성합니다.
docker exec -it mysql mysql -u root -p
-i
(또는 --interactive): 이 옵션은 컨테이너와 상호 작용(interactive)을 가능하게 합니다.-t
(또는 --tty): 이 옵션은 명령어 실행에 터미널 할당(tty)을 추가합니다. -t 옵션은 컨테이너 내부에서 명령어를 실행할 때 텍스트 기반의 인터페이스를 제공하며, 명령어 실행 결과를 보기 좋게 표시하도록 도와줍니다. 특히, 쉘 접속이나 인터랙티브 콘솔 프로그램을 사용할 때 유용합니다.결합하여 사용할 때, -it 플래그는 컨테이너 내에서 명령어를 마치 로컬 터미널에서 실행하는 것처럼 입력을 받고 결과를 출력할 수 있도록 해줍니다.
연결까지 확인을 마쳤습니다.
MySQL은 이제 준비가 완료되었습니다. 이제 다른 컨테이너에서 MySQL 서버와 연결할 수 있어야 합니다.
같은 네트워크 상에 있는 다른 컨테이너가 MySQL 컨테이너를 어떻게 찾을 수 있을까요?
각 컨테이너는 고유의 IP 주소를 가지고 있는데 Docker 네트워크에서는 이름을 통해서 서로를 찾을 수 있습니다.
네트워킹을 확인하기 위해 nicolaka/netshoot
이미지를 사용하는 컨테이너를 사용하겠습니다.
docker run -it --network todo-app nicolaka/netshoot
dig mysql
ANSWER SECTION을 보면 mysql의 ip 주소가 172.23.0.2 A 레코드로 해석된 것을 볼 수 있습니다.
이 주소는 --network-alias
옵션으로 지정한 네트워크 별칭을 가진 컨테이너의 IP 주소입니다.
MySQL을 연결하기 위해서는 mysql
이라는 호스트 이름을 사용해서 연결하면 됩니다. 이렇게 하면 애플리케이션이 MySQL 서버와 통신할 수 있게 됩니다.
docker run -dp 127.0.0.1:3000:3000 \
-w /app -v "$(pwd):/app" \
--network todo-app \
-e MYSQL_HOST=mysql \
-e MYSQL_USER=root \
-e MYSQL_PASSWORD=secret \
-e MYSQL_DB=todos \
node:18-alpine \
sh -c "yarn install && yarn run dev"
앱과 MySQL을 연결하기 위해 환경 변수를 지정하여 주었습니다. 개발환경에서는 일반적으로 이렇게 사용하기는 하지만, 운영 환경에서는 이 방법을 추천하지 않습니다.
docker history
명령어 등으로 확인이 가능하기 때문에 보안적인 측면에서 좋지 않습니다.
(secret을 위해 환경 변수를 사용하지 말아야 하는 이유)
앱이 잘 실행되었는지 확인하고, 위와 같이 투두 리스트들을 추가해줬습니다.
docker exec -it mysql mysql -p todos
한글로 입력한 건 깨진거 보니 table 설정이 utf-8이 아닌 듯 하지만 제대로 저장된 것 같으니 일단 넘어갑시다.
하나의 컨테이너에서 여러 프로세스를 실행하는 것보다, 각각의 컨테이너에서 각 서비스를 실행하는 것이 좋은 선택입니다.
컨테이너들을 같은 네트워크에 묶어서 실행하면 ip 주소 대신 Host name(--network-alias
로 지정한 이름)으로 참조할 수 있습니다.
https://docs.docker.com/network/
https://docs.docker.com/reference/cli/docker/