Docker로 MySQL 컨테이너 구축 및 외부 접속 설정하기 – 5분 완성 가이드

1. Docker로 MySQL을 구축하는 이유

1.1 로컬 설치 vs 컨테이너: 왜 Docker인가?

처음 MySQL을 배울 때 저는 Windows에 직접 설치했습니다. 설치 파일 다운로드하고, 경로 설정하고, 환경변수 등록하고… 한 시간은 걸렸던 것 같습니다. 그런데 나중에 프로젝트마다 다른 MySQL 버전이 필요해지면서 문제가 시작됐습니다. 버전 관리가 너무 복잡했거든요.

Docker를 사용하면 이런 고민이 사라집니다. MySQL 컨테이너 구축 및 외부 접속 설정하기는 docker-compose 파일 하나면 5분 안에 끝나니까요. 필요 없어지면 컨테이너만 삭제하면 되고, 다른 버전이 필요하면 이미지 태그만 바꾸면 됩니다.

항목 로컬 설치 Docker 컨테이너
설치 시간 30분~1시간 5분 이내
버전 관리 매우 복잡 이미지 태그로 간단 전환
삭제/재설치 레지스트리 잔여물 남음 컨테이너만 삭제하면 깔끔
팀 환경 공유 각자 설치 과정 필요 docker-compose.yml 공유로 동일 환경

1.2 개발 환경 통일과 빠른 구축의 장점

팀 프로젝트를 해보신 분은 아실 겁니다. “어? 제 컴퓨터에서는 되는데요?”라는 말을 얼마나 많이 하게 되는지요. 특히 데이터베이스는 버전, 문자셋 설정, 타임존 등 환경 차이가 크게 영향을 미칩니다.

docker-compose.yml 파일 하나를 Git에 올려두면 팀원 모두가 정확히 같은 MySQL 환경을 실행할 수 있습니다. 신입 개발자가 합류해도 “Docker 설치하고 docker-compose up만 실행하세요”라고 안내하면 끝입니다.

1.3 실무에서 컨테이너 DB를 사용하는 경우

실무에서는 보통 프로덕션 DB는 RDS나 클라우드 매니지드 서비스를 사용합니다. 하지만 로컬 개발 환경, CI/CD 테스트 환경, 스테이징 환경에서는 컨테이너 DB를 적극 활용합니다. 특히 자동화 테스트를 돌릴 때 매번 깨끗한 DB 환경을 만들어야 하는데, 이때 컨테이너는 정말 강력합니다.

2. docker-compose로 MySQL 컨테이너 구축하기

2.1 docker-compose.yml 기본 구조

본격적으로 MySQL 컨테이너 구축 및 외부 접속 설정하기를 시작해봅시다. 먼저 프로젝트 폴더에 docker-compose.yml 파일을 만듭니다. 저는 처음에 YAML 문법을 몰라서 들여쓰기 오류로 한참 헤맸습니다. YAML은 탭이 아니라 스페이스 2칸으로 들여쓰기해야 한다는 점 꼭 기억하세요.

기본 구조는 이렇습니다:

version: '3.8'
services:
  mysql:
    image: mysql:8.0
    container_name: my-mysql
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword123
      MYSQL_DATABASE: myapp_db
      MYSQL_USER: appuser
      MYSQL_PASSWORD: apppass123
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
      
volumes:
  mysql_data:
  

2.2 필수 환경변수 설정 (MYSQL_ROOT_PASSWORD, MYSQL_DATABASE 등)

환경변수 중에서 MYSQL_ROOT_PASSWORD는 필수입니다. 이걸 빼먹으면 컨테이너가 아예 시작되지 않습니다. 저는 처음에 이걸 몰라서 “컨테이너가 계속 재시작되는데 왜 그러지?” 하면서 한 시간을 허비했습니다.

보안을 고려한다면 root 계정 대신 일반 사용자 계정을 만드는 게 좋습니다. MYSQL_USER와 MYSQL_PASSWORD를 설정하면 컨테이너 시작 시 자동으로 해당 사용자가 생성되고, MYSQL_DATABASE에 지정한 데이터베이스에 대한 모든 권한이 부여됩니다.

환경변수 필수 여부 설명
MYSQL_ROOT_PASSWORD 필수 root 계정 비밀번호 (없으면 컨테이너 실행 안 됨)
MYSQL_DATABASE 선택 초기 생성할 데이터베이스 이름
MYSQL_USER 선택 일반 사용자 계정명 (보안 권장)
MYSQL_PASSWORD 선택* 일반 사용자 비밀번호 (*USER 설정 시 필수)

2.3 포트 포워딩 설정: 외부 접속의 핵심

이 부분이 MySQL 컨테이너 구축 및 외부 접속 설정하기에서 가장 중요합니다. ports 설정을 빼먹으면 컨테이너 내부에서는 MySQL이 잘 돌아가지만, 외부에서는 절대 접속할 수 없습니다.

“3306:3306″의 의미는 “호스트의 3306 포트를 컨테이너의 3306 포트로 연결한다”는 뜻입니다. 만약 호스트에 이미 MySQL이 설치되어 있어서 3306 포트가 사용 중이라면 “3307:3306” 같은 식으로 바꿔야 합니다. 저는 이걸 몰라서 “Address already in use” 오류를 보고 당황했던 기억이 있습니다.

2.4 볼륨 마운트로 데이터 영속성 보장하기

처음에 저는 볼륨 설정 없이 컨테이너를 사용했습니다. 그런데 컨테이너를 재시작했더니 입력했던 데이터가 전부 날아갔더군요. 컨테이너는 기본적으로 삭제되면 내부 데이터도 함께 사라집니다.

volumes 설정은 컨테이너의 /var/lib/mysql 디렉터리(MySQL이 데이터를 저장하는 곳)를 호스트의 볼륨과 연결해줍니다. 이렇게 하면 컨테이너를 삭제하고 다시 만들어도 데이터가 보존됩니다. 실제로 개발하다 보면 컨테이너를 재생성할 일이 생각보다 많은데, 볼륨 설정은 필수입니다.

MySQL 컨테이너 구축 및 외부 접속 설정하기 관련 이미지

3. 외부 접속을 위한 필수 설정

3.1 포트 포워딩이 필요한 이유와 설정 방법

Docker 컨테이너는 기본적으로 격리된 네트워크 환경에서 실행됩니다. 마치 독립된 작은 컴퓨터처럼요. 그래서 컨테이너 안에서 MySQL이 3306 포트로 실행되더라도, 호스트 컴퓨터에서는 그 포트에 접근할 수 없습니다. 포트 포워딩은 이 벽에 문을 뚫어주는 작업입니다.

이미 위 docker-compose.yml에 ports 설정을 넣었다면 별도 작업이 필요 없습니다. 하지만 만약 docker run 명령어로 직접 실행한다면 -p 옵션을 꼭 추가해야 합니다:

docker run -d -p 3306:3306 --name my-mysql -e MYSQL_ROOT_PASSWORD=rootpass mysql:8.0

3.2 보안을 고려한 사용자 계정 생성 전략

root 계정으로 외부에서 접속하는 건 편하지만 보안상 좋지 않습니다. 실무에서는 절대 그렇게 하면 안 됩니다. 저는 처음에 편의를 위해 root로 다 접속했는데, 나중에 보안 감사에서 지적받고 전부 수정했던 아픈 경험이 있습니다.

권장하는 방법은 애플리케이션용 전용 계정을 만드는 것입니다. docker-compose.yml에 MYSQL_USER와 MYSQL_PASSWORD를 설정하면 자동으로 생성되지만, 더 세밀한 권한 제어가 필요하다면 컨테이너에 접속해서 직접 생성할 수도 있습니다:

docker exec -it my-mysql mysql -uroot -p

-- MySQL 프롬프트에서
CREATE USER 'appuser'@'%' IDENTIFIED BY 'strong_password_123!';
GRANT SELECT, INSERT, UPDATE, DELETE ON myapp_db.* TO 'appuser'@'%';
FLUSH PRIVILEGES;
  

3.3 호스트 권한 설정 (‘%’ vs ‘특정 IP’)

MySQL의 사용자 계정은 ‘아이디@호스트’ 형태로 관리됩니다. ‘appuser’@’localhost’와 ‘appuser’@’%’는 완전히 다른 계정입니다. MySQL 컨테이너 구축 및 외부 접속 설정하기에서 자주 놓치는 부분이 바로 이겁니다.

‘%’는 모든 호스트에서의 접속을 허용합니다. 로컬 개발 환경에서는 편하지만, 운영 환경에서는 위험합니다. 가능하다면 특정 IP 대역만 허용하는 게 좋습니다:

호스트 설정 접속 가능 범위 사용 시나리오
‘appuser’@’localhost’ 같은 서버 내부만 컨테이너 내부 애플리케이션
‘appuser’@’%’ 모든 곳에서 접속 가능 로컬 개발 환경 (편의성)
‘appuser’@’192.168.1.%’ 특정 IP 대역만 사내 네트워크 제한
‘appuser’@’192.168.1.100’ 특정 IP만 프로덕션 환경 (최고 보안)

3.4 방화벽 설정 확인 및 해제

포트도 열었고, 사용자도 만들었는데 접속이 안 된다? 저도 겪었습니다. 알고 보니 호스트 컴퓨터의 방화벽이 3306 포트를 막고 있었습니다.

Windows라면 Windows Defender 방화벽에서 3306 포트를 허용해야 하고, Linux라면 iptables나 ufw 설정을 확인해야 합니다. 클라우드 환경(AWS, Azure 등)이라면 보안 그룹이나 네트워크 ACL 설정도 확인해야 합니다.

Ubuntu 예시:

sudo ufw allow 3306/tcp
sudo ufw status
  

4. 한글 데이터 처리를 위한 문자셋 설정

4.1 utf8 vs utf8mb4: 올바른 선택은?

MySQL에서 utf8이라고 부르는 문자셋은 사실 진짜 UTF-8이 아닙니다. 최대 3바이트까지만 지원해서 이모지나 일부 특수 문자가 깨집니다. 저는 이걸 몰라서 사용자가 입력한 이모지가 전부 ‘?’ 로 저장되는 참사를 겪었습니다.

utf8mb4가 진짜 UTF-8입니다. 4바이트까지 지원해서 이모지도 문제없습니다. 2026년 현재는 무조건 utf8mb4를 사용하는 게 정답입니다. 위 docker-compose.yml에 이미 command 옵션으로 넣어뒀으니 그대로 사용하시면 됩니다.

4.2 character-set과 collation 설정 방법

character-set은 문자를 저장하는 방식이고, collation은 문자를 비교하고 정렬하는 방식입니다. utf8mb4_unicode_ci가 가장 범용적인 선택입니다. ‘ci’는 case-insensitive(대소문자 구분 안 함)를 의미합니다.

만약 이미 실행 중인 컨테이너에 접속해서 확인하고 싶다면:

docker exec -it my-mysql mysql -uroot -p

SHOW VARIABLES LIKE 'character_set%';
SHOW VARIABLES LIKE 'collation%';
  

4.3 기존 DB의 문자셋 확인 및 변경

이미 생성된 데이터베이스나 테이블의 문자셋을 변경하는 건 조금 복잡합니다. 특히 데이터가 이미 들어있다면 더욱 조심해야 합니다. MySQL 컨테이너 구축 및 외부 접속 설정하기 초기 단계에서 미리 설정하는 게 가장 좋습니다.

그래도 변경이 필요하다면:

Editor’s Pick

휴대용 노트북 거치대
개발자 필수 거북목 방지 아이템

자세히 보기

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

-- 데이터베이스 문자셋 변경
ALTER DATABASE myapp_db CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;

-- 테이블 문자셋 변경 (기존 데이터는 변환 안 됨)
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
  

5. 실전 트러블슈팅 FAQ

5.1 “Can’t connect to MySQL server” 오류 해결

이 오류는 정말 다양한 원인이 있습니다. 제가 실제로 겪었던 케이스들을 정리해봤습니다:

  • 컨테이너가 실제로 실행 중인지 확인: docker ps로 상태 확인. “Restarting” 상태라면 로그 확인 필요
  • 포트 포워딩 설정 확인: docker-compose.yml에 ports가 제대로 설정되었는지
  • 방화벽 확인: 호스트 방화벽, 클라우드 보안 그룹 모두 확인
  • 접속 정보 확인: 호스트는 localhost 또는 127.0.0.1, 포트는 설정한 포트 번호

로그 확인 방법:

docker logs my-mysql

5.2 한글이 깨져서 보이는 경우

문자셋 설정을 했는데도 한글이 깨진다면 두 가지를 확인하세요. 첫째, 서버 레벨의 문자셋 설정이 제대로 적용됐는지. 둘째, 클라이언트 연결 시 문자셋을 명시했는지입니다.

Python에서 연결할 때:

import pymysql
conn = pymysql.connect(
    host='localhost',
    user='appuser',
    password='apppass123',
    database='myapp_db',
    charset='utf8mb4'  # 이 부분 필수!
)
  

Node.js에서 연결할 때:

const mysql = require('mysql2');
const connection = mysql.createConnection({
  host: 'localhost',
  user: 'appuser',
  password: 'apppass123',
  database: 'myapp_db',
  charset: 'utf8mb4'  // 이 부분 필수!
});
  

5.3 컨테이너는 실행되는데 접속이 안 되는 경우

저도 이 상황에서 한참 헤맸습니다. docker ps로 보면 컨테이너가 “Up” 상태인데 접속이 안 되더라고요. 알고 보니 MySQL 서버가 초기화되는 데 시간이 좀 걸려서 그랬습니다. 특히 처음 실행할 때는 데이터 디렉터리를 초기화하느라 20~30초 정도 걸립니다.

컨테이너 내부에서 MySQL이 정말 실행 중인지 확인:

docker exec -it my-mysql mysqladmin ping -uroot -p
  

“mysqld is alive” 메시지가 나와야 정상입니다.

5.4 root 계정으로 외부 접속이 거부되는 경우

MySQL 8.0부터는 보안이 강화되어 root 계정의 기본 호스트가 ‘localhost’로 제한됩니다. 외부에서 root로 접속하려면 별도로 권한을 부여해야 합니다. 하지만 앞서 말했듯이 보안상 권장하지 않습니다.

그래도 개발 환경에서 꼭 필요하다면:

docker exec -it my-mysql mysql -uroot -p

-- MySQL 프롬프트에서
CREATE USER 'root'@'%' IDENTIFIED BY 'rootpassword123';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
  

하지만 다시 한번 강조하지만, 일반 사용자 계정을 만들어 사용하는 게 훨씬 안전합니다.

자주 묻는 질문 (FAQ)

Q. docker-compose up 후 바로 접속했는데 “Connection refused” 오류가 나요

MySQL 컨테이너가 완전히 시작되려면 초기화 시간이 필요합니다. 특히 처음 실행할 때는 데이터 디렉터리를 생성하고 시스템 테이블을 만드느라 더 오래 걸립니다. docker logs my-mysql을 실행해서 “ready for connections” 메시지가 나올 때까지 기다려보세요. 보통 20~30초 정도면 준비됩니다.

Q. 호스트 컴퓨터에 이미 MySQL이 설치되어 있어서 포트 충돌이 나는데 어떻게 하나요?

docker-compose.yml의 ports 설정을 “3307:3306″처럼 변경하세요. 앞의 숫자가 호스트 포트이므로 사용 중이지 않은 포트로 바꾸면 됩니다. 그러면 외부에서 접속할 때 localhost:3307로 접속하면 됩니다. 컨테이너 내부에서는 여전히 3306 포트를 사용하지만, 호스트에서는 3307로 매핑되는 구조입니다.

Q. 볼륨 데이터를 완전히 초기화하고 싶은데 어떻게 하나요?

컨테이너를 삭제해도 볼륨은 남아있기 때문에 데이터가 보존됩니다. 완전히 처음부터 다시 시작하고 싶다면 볼륨도 함께 삭제해야 합니다. docker-compose down -v 명령어를 사용하면 컨테이너와 볼륨이 모두 삭제됩니다. 주의할 점은 데이터가 완전히 사라진다는 것이니 신중하게 사용하세요.

Q. DBeaver나 MySQL Workbench 같은 GUI 툴로 접속이 안 돼요

GUI 툴에서 접속할 때는 호스트를 localhost 또는 127.0.0.1로, 포트는 docker-compose.yml에 설정한 포트(보통 3306)로 입력해야 합니다. 사용자명과 비밀번호는 MYSQL_USER, MYSQL_PASSWORD에 설정한 값을 사용하세요. 만약 SSL 관련 오류가 나온다면 연결 설정에서 SSL을 비활성화하거나 “require”가 아닌 “prefer” 모드로 변경해보세요.

Q. 프로덕션 환경에서도 Docker로 MySQL을 운영해도 되나요?

가능은 하지만 권장하지 않습니다. 프로덕션 데이터베이스는 AWS RDS, Google Cloud SQL, Azure Database 같은 매니지드 서비스를 사용하는 게 훨씬 안전합니다. 이런 서비스들은 자동 백업, 장애 복구, 모니터링, 보안 패치를 전부 제공하거든요. Docker MySQL 컨테이너는 로컬 개발, 테스트, 스테이징 환경에서 사용하는 게 적합합니다.

6. 마치며: 실무 적용 시 체크리스트

6.1 보안 설정 최종 점검 사항

MySQL 컨테이너 구축 및 외부 접속 설정하기를 마무리하기 전에 보안 체크리스트를 확인해봅시다:

  • root 계정 비밀번호는 충분히 복잡한가? (최소 16자, 특수문자 포함)
  • 애플리케이션용 별도 계정을 만들었는가?
  • 사용자 권한이 필요 최소한으로 제한되어 있는가?
  • 호스트 설정이 ‘%’로 되어 있다면 정말 필요한가?
  • .env 파일을 사용해서 비밀번호를 docker-compose.yml에 직접 쓰지 않았는가?
  • .gitignore에 .env 파일과 볼륨 디렉터리가 등록되어 있는가?

특히 Git에 비밀번호를 올리는 실수는 정말 조심해야 합니다. 저는 .env 파일을 사용해서 민감한 정보를 분리하는 걸 습관화했습니다.

6.2 프로덕션 환경 적용 시 주의사항

로컬 개발 환경에서 잘 돌아가던 설정을 그대로 프로덕션에 적용하면 안 됩니다. 몇 가지 반드시 변경해야 할 점들:

  • 비밀번호를 더 강력하게 변경
  • 호스트 권한을 특정 IP로 제한
  • 불필요한 포트는 외부에 노출하지 않기 (Docker 네트워크 활용)
  • 백업 전략 수립 (볼륨 백업, mysqldump 자동화)
  • 로그 모니터링 및 알림 설정
  • 리소스 제한 설정 (메모리, CPU 제한)

솔직히 말하면, 프로덕션 환경에서는 컨테이너 MySQL보다는 매니지드 서비스를 강력히 추천합니다. 비용은 좀 더 들지만 운영 부담이 엄청나게 줄어듭니다.

6.3 다음 단계: 백업 및 모니터링

데이터베이스를 구축했다면 다음은 백업입니다. 백업이 없으면 언젠가 꼭 후회하게 됩니다. 저도 한 번 경험했습니다… 다행히 개발 환경이었지만 하루치 작업이 날아갔을 때의 그 허탈함이란.

간단한 백업 스크립트 예시:

#!/bin/bash
# backup.sh
DATE=$(date +%Y%m%d_%H%M%S)
docker exec my-mysql mysqldump -uroot -prootpassword123 myapp_db > backup_$DATE.sql
  

이걸 cron으로 매일 실행하도록 설정하면 됩니다. 더 나아가서는 백업 파일을 S3 같은 외부 스토리지에 저장하고, 오래된 백업은 자동으로 삭제하는 스크립트를 만들 수 있습니다.

모니터링도 중요합니다. 컨테이너가 갑자기 죽지는 않는지, 디스크 사용량은 괜찮은지, 슬로우 쿼리는 없는지 확인해야 합니다. Grafana + Prometheus 조합이 인기 있지만, 처음에는 단순히 로그만 주기적으로 확인하는 것부터 시작해도 좋습니다.

MySQL 컨테이너 구축 및 외부 접속 설정하기는 생각보다 간단하지만, 디테일이 중요합니다. 포트 포워딩, 사용자 권한, 문자셋 설정 등 하나라도 놓치면 접속 오류나 한글 깨짐 같은 문제를 겪게 됩니다. 이 글에서 소개한 설정을 그대로 따라하시면 대부분의 문제를 피할 수 있을 겁니다.

처음에는 어려워 보이지만 몇 번 해보면 금방 익숙해집니다. docker-compose.yml 템플릿을 잘 만들어두면 새 프로젝트를 시작할 때마다 5분 안에 MySQL 환경을 구축할 수 있습니다. 저는 지금 개인 프로젝트용, 업무용, 실험용 등 용도별로 템플릿을 여러 개 만들어두고 재활용하고 있습니다.

여러분도 이 글을 참고해서 빠르게 MySQL 컨테이너를 구축하고, 외부 접속도 문제없이 설정하셔서 본격적인 개발에 집중하시길 바랍니다. 혹시 막히는 부분이 있다면 댓글로 남겨주세요. 함께 해결해봅시다!

MySQL 컨테이너 구축 및 외부 접속 설정하기 상세 정보

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤