> ## Documentation Index
> Fetch the complete documentation index at: https://villagesql.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Docker에서 MySQL 실행하기

> Docker에서 MySQL 8.4 또는 VillageSQL을 실행하는 방법 — 공식 이미지 설정, 영구 명명된 볼륨, Docker Compose 다중 서비스 구성, 컨테이너 간 네트워킹, 그리고 네이티브 설치나 관리형 클라우드보다 Docker가 올바른 배포 선택인 경우입니다.

> [card] [VillageSQL is a drop-in replacement for MySQL with extensions.](https://villagesql.com/docs/en/8.4/stable/install-server.md)
>
> All examples on this page work on VillageSQL. Install Now →

공식 MySQL Docker 이미지는 완전히 구성된 MySQL 서버를 컨테이너에서 실행하게 해줍니다. 환경 변수를 통해 초기화, 사용자 생성, 데이터 디렉터리 설정을 자동으로 처리합니다.

## 빠른 시작

```bash theme={null}
docker run --name mysql-dev \
  -e MYSQL_ROOT_PASSWORD=rootpass \
  -e MYSQL_DATABASE=myapp \
  -e MYSQL_USER=appuser \
  -e MYSQL_PASSWORD=apppass \
  -p 3306:3306 \
  -d mysql:8.4
```

호스트 머신에서 연결하기:

```bash theme={null}
mysql -h 127.0.0.1 -P 3306 -u appuser -p myapp
```

또는 컨테이너 안에서 연결하기:

```bash theme={null}
docker exec -it mysql-dev mysql -u root -p
```

## 환경 변수

| 변수 | 필수 | 설명 |
| :- | :- | :- |
| `MYSQL_ROOT_PASSWORD` | 예(또는 `ALLOW_EMPTY_PASSWORD` 사용) | root 사용자 비밀번호 |
| `MYSQL_DATABASE` | 아니요 | 시작 시 만들 데이터베이스 |
| `MYSQL_USER` | 아니요 | 생성할 root 이외의 사용자 |
| `MYSQL_PASSWORD` | 아니요 | `MYSQL_USER`의 비밀번호 |
| `MYSQL_ALLOW_EMPTY_PASSWORD` | 아니요 | 빈 root 비밀번호를 허용하려면 `yes`로 설정(개발 전용) |
| `MYSQL_RANDOM_ROOT_PASSWORD` | 아니요 | 무작위 root 비밀번호를 생성하려면 `yes`로 설정(stdout에 기록됨) |
| `MYSQL_ONETIME_PASSWORD` | 아니요 | 첫 로그인 시 비밀번호 변경을 요구하려면 `yes`로 설정 |

`MYSQL_USER`와 `MYSQL_PASSWORD`는 함께 설정해야 합니다. 만들어진 사용자는 `MYSQL_DATABASE`에 대한 전체 접근 권한을 받습니다.

## 볼륨으로 데이터 유지하기

볼륨이 없으면 컨테이너를 제거할 때 모든 데이터가 사라집니다. 데이터 디렉터리를 유지하려면 볼륨을 마운트하세요:

```bash theme={null}
docker run --name mysql-dev \
  -e MYSQL_ROOT_PASSWORD=rootpass \
  -v mysql-data:/var/lib/mysql \
  -p 3306:3306 \
  -d mysql:8.4
```

명명된 볼륨(`mysql-data`)은 컨테이너 재시작과 제거에 걸쳐 유지됩니다. 대신 호스트 디렉터리를 사용하려면:

```bash theme={null}
-v /path/on/host:/var/lib/mysql
```

데이터 디렉터리는 MySQL의 데이터와 로그를 소유합니다. 실행 중인 두 MySQL 컨테이너 사이에 볼륨을 절대 공유하지 마세요.

## 이미지와 볼륨 전략 선택하기

| | 공식 `mysql:8.4` | `villagesql/server:latest` |
| :- | :- | :- |
| 기반 | MySQL 8.4 | MySQL 8.4 추적 포크 |
| 확장 | 내장 없음 | VEF 프레임워크; `.veb` 번들 설치 |
| 드롭인 대체 | — | 예 — 같은 와이어 프로토콜, 같은 클라이언트 도구 |
| 이미지 제공 | Docker Hub | Docker Hub(`villagesql/server`) |
| 사용 시점 | 표준 MySQL 워크로드 | 사용자 정의 타입, VDF 함수, VEF 확장이 필요할 때 |

| 볼륨 유형 | 지속성 | 성능 | 이식성 |
| :- | :- | :- | :- |
| 명명된 볼륨(`-v mysql-data:/var/lib/mysql`) | `docker rm` 후에도 유지 | Docker가 관리; 모든 플랫폼에서 양호 | `docker volume` 명령으로 백업하기 쉬움 |
| 바인드 마운트(`-v /host/path:/var/lib/mysql`) | 컨테이너 제거 후에도 유지 | macOS/Windows에서 느림(파일 시스템 변환) | 호스트에서 직접 접근; 파일 검사가 쉬움 |
| 볼륨 없음(컨테이너 계층) | `docker rm` 시 손실 | 가장 빠른 쓰기(임시) | 개발/테스트 전용 — 보존하려는 데이터에는 절대 사용 금지 |

대부분의 워크로드에서 명명된 볼륨이 올바른 기본값입니다. 바인드 마운트는 호스트에서 데이터 디렉터리를 직접 검사하거나 편집해야 할 때 유용하지만, macOS와 Windows에서는 성능 비용이 중요합니다.

## Docker Compose

여러 서비스가 있는 개발 환경에서는 Docker Compose가 표준 접근법입니다:

```yaml theme={null}
services:
  db:
    image: mysql:8.4
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: myapp
      MYSQL_USER: appuser
      MYSQL_PASSWORD: apppass
    volumes:
      - mysql-data:/var/lib/mysql
    ports:
      - "3306:3306"
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-prootpass"]
      interval: 10s
      timeout: 5s
      retries: 5

  app:
    build: .
    environment:
      DB_HOST: db
      DB_PORT: 3306
      DB_NAME: myapp
      DB_USER: appuser
      DB_PASSWORD: apppass
    depends_on:
      db:
        condition: service_healthy

volumes:
  mysql-data:
```

`depends_on: condition: service_healthy`와 함께 쓰는 `healthcheck`는 MySQL이 단지 시작된 것이 아니라 연결을 받아들일 준비가 될 때까지 애플리케이션 컨테이너가 시작되지 않게 보장합니다.

## 사용자 정의 구성

사용자 정의 `my.cnf`를 마운트해서 전달하세요:

```bash theme={null}
docker run --name mysql-dev \
  -e MYSQL_ROOT_PASSWORD=rootpass \
  -v /path/to/my.cnf:/etc/mysql/conf.d/custom.cnf:ro \
  -d mysql:8.4
```

또는 명령 인수로 옵션을 직접 설정하세요:

```bash theme={null}
docker run --name mysql-dev \
  -e MYSQL_ROOT_PASSWORD=rootpass \
  -d mysql:8.4 \
  --innodb-buffer-pool-size=512M \
  --max-connections=200
```

## 초기화 스크립트

컨테이너는 첫 시작 시(데이터 디렉터리가 비어 있을 때) `/docker-entrypoint-initdb.d/`에 놓인 모든 `.sql` 또는 `.sh` 파일을 실행합니다:

```bash theme={null}
docker run --name mysql-dev \
  -e MYSQL_ROOT_PASSWORD=rootpass \
  -v /path/to/init-scripts:/docker-entrypoint-initdb.d:ro \
  -d mysql:8.4
```

SQL 파일은 root로 실행됩니다. 셸 스크립트는 컨테이너 환경에서 실행됩니다. 이 스크립트들은 맨 처음 초기화에서만 실행됩니다 — 이후의 컨테이너 시작에서는 실행되지 않습니다.

## 애플리케이션에서 연결하기

Docker Compose 네트워크 안에서 컨테이너는 서비스 이름으로 MySQL에 연결합니다:

```
DB_HOST=db   # service name in docker-compose.yml
DB_PORT=3306
```

호스트 머신에서는 `127.0.0.1`로 연결하세요(`localhost`가 아닙니다 — MySQL의 소켓은 호스트에서 사용할 수 없습니다):

```
DB_HOST=127.0.0.1
DB_PORT=3306
```

## Docker에서 MySQL을 실행해야 할 때

| 시나리오 | Docker | 네이티브 설치 | 관리형 클라우드(RDS, Cloud SQL) |
| :- | :- | :- | :- |
| 로컬 개발 | 최선의 선택 — 격리되고, 재현 가능하며, 쉽게 정리 가능 | 동작하지만 초기화가 더 어려움 | 과함; 비용과 네트워크 지연 추가 |
| CI/CD 파이프라인 | 최선의 선택 — 실행마다 새 인스턴스 기동 | 가능하지만 프로비저닝이 더 느림 | 가능; 실행마다 비용 추가 |
| 스테이징 환경 | 좋음 — Compose로 프로덕션 토폴로지 반영 | 호스트가 전용이면 괜찮음 | 프로덕션도 관리형이면 좋음 |
| 프로덕션(단일 서버) | 명명된 볼륨 + 적절한 백업이면 괜찮음 | 괜찮음; 운영이 약간 더 단순 | 관리형 백업, HA, 장애 조치 추가 |
| 프로덕션(고가용성) | 오케스트레이션 필요(Kubernetes, Swarm) | 수동 복제 설정 | 최선의 선택 — HA 내장 |
| VillageSQL 확장 필요 | `villagesql/server` 이미지 사용 | 소스에서 빌드 | 관리형 서비스에서는 사용 불가 |
| 규정 준수 / 데이터 상주 | 정책 확인 — 데이터는 호스트에 남음 | 명확 — 데이터는 호스트에 남음 | 제공자 리전 구성에 따라 다름 |

## 프로덕션 고려 사항

몇 가지 주의 사항만 지키면 Docker는 프로덕션의 MySQL에 잘 동작합니다:

* **데이터 지속성**: 명명된 볼륨이나 바인드 마운트를 사용하세요. MySQL 데이터를 컨테이너 계층에 두지 마세요.
* **메모리 제한**: MySQL이 호스트 메모리를 소진하지 않도록 Docker에서 `--memory`를 설정하고, 그에 맞게 `innodb_buffer_pool_size`를 조정하세요.
* **백업**: `mysqldump`는 컨테이너 안에서 동작합니다: `docker exec mysql-dev mysqldump -u root -p myapp > backup.sql`
* **로깅**: Docker에서 MySQL 로그는 stdout/stderr로 갑니다. `docker logs mysql-dev`를 사용하거나 로깅 드라이버를 구성하세요.
* **업그레이드**: 새 이미지 태그를 pull하고, 옛 컨테이너를 중지하고, 같은 볼륨으로 새 컨테이너를 시작하세요. MySQL의 업그레이드 프로세스는 더 새로운 버전으로 첫 시작할 때 자동으로 실행됩니다.

## 자주 묻는 질문

#### 호스트에서 `mysql -h localhost`로 왜 연결할 수 없나요?

Linux와 macOS에서 `localhost`는 MySQL 클라이언트가 Unix 소켓으로 연결을 시도하게 하는데, 그 소켓은 호스트에서 사용할 수 없습니다. `127.0.0.1`을 명시적으로 사용하세요: `mysql -h 127.0.0.1 -P 3306`.

#### Docker에서 MySQL 데이터를 어떻게 유지하나요?

컨테이너를 시작할 때 명명된 볼륨을 `/var/lib/mysql`에 마운트하세요: `-v mysql-data:/var/lib/mysql`. 이것이 없으면 모든 데이터가 컨테이너의 쓰기 가능 계층에 저장되고 `docker rm`을 실행할 때 사라집니다. 명명된 볼륨은 컨테이너 제거 후에도 남고 Docker가 관리합니다 — `docker volume ls`로 나열하고 `docker volume inspect mysql-data`로 저장 위치를 찾으세요. Docker Compose에서는 최상위 `volumes:` 키 아래에 볼륨을 선언하고 서비스의 `volumes:` 목록에서 참조하세요(위의 Docker Compose 섹션 예제가 이 패턴을 보여줍니다).

#### Docker Compose의 컨테이너는 MySQL에 어떻게 연결하나요?

같은 Compose 프로젝트의 컨테이너는 기본 네트워크를 공유합니다. 애플리케이션 컨테이너는 서비스 이름을 호스트 이름으로 사용해 MySQL에 연결합니다 — 데이터베이스 서비스 이름이 `db`라면 연결 문자열은 `host=db port=3306`입니다. 컨테이너 사이에 포트를 노출할 필요는 없습니다. 포트 매핑(`-p 3306:3306`)은 호스트 머신에서의 연결에만 필요합니다. MySQL이 준비되기 전에 애플리케이션이 시작되는 것을 막으려면 MySQL 서비스의 `healthcheck`와 함께 `depends_on: condition: service_healthy`를 사용하세요.

#### 실행 중인 컨테이너에 SQL 파일을 어떻게 실행하나요?

```bash theme={null}
docker exec -i mysql-dev mysql -u root -p myapp < /path/to/script.sql
# or from within the container:
docker exec -it mysql-dev mysql -u root -p myapp -e "SOURCE /tmp/script.sql"
```

## 문제 해결

| 문제 | 해결 방법 |
| :- | :- |
| 컨테이너가 즉시 종료됨 | `docker logs mysql-dev`를 확인 — `MYSQL_ROOT_PASSWORD` 누락 또는 볼륨 권한 문제 |
| `ERROR 2002: Can't connect to local MySQL server through socket` | 소켓이 아니라 TCP(`-h 127.0.0.1`)로 연결 — Unix 소켓은 호스트에 없음 |
| MySQL이 준비되기 전에 애플리케이션이 시작됨 | Compose에 `healthcheck`를 추가하고 `depends_on: condition: service_healthy`를 사용 |
| `docker rm` 후 데이터 손실 | 볼륨이 마운트되지 않았음 — `-v mysql-data:/var/lib/mysql`로 컨테이너를 다시 만들기 |
| 초기화 스크립트가 실행되지 않음 | 데이터 디렉터리가 비어 있을 때(최초 설정)만 실행됨 — 다시 초기화하려면 볼륨을 제거하고 재시작 |

이 페이지의 모든 것은 `villagesql/server` 이미지에서도 동작합니다. VillageSQL은 MySQL의 드롭인 대체품이면서 확장 기능을 갖추고 있으므로, 위의 compose 파일, 볼륨, 헬스 체크는 이미지 이름 하나만 바꾸면 그대로 적용됩니다. [Docker에서 사용해 보기](https://villagesql.com/install).

## 함께 보기

* [MySQL 복제 기초](https://villagesql.com/docs/ko/guides/replication-basics.md) — Docker Compose에서 소스/복제본 쌍 실행하기
* [MySQL 백업 전략](https://villagesql.com/docs/ko/guides/backup-strategies.md) — 컨테이너화된 MySQL의 데이터 볼륨 백업하기
* [MySQL에서 업그레이드하기](https://villagesql.com/docs/ko/guides/upgrade.md) — 컨테이너를 MySQL에서 VillageSQL로 옮기기
* [Kubernetes에서 MySQL 실행하기](https://villagesql.com/docs/ko/guides/mysql-on-kubernetes.md) — 컨테이너 오케스트레이션의 다음 단계
* [MySQL 튜토리얼을 위한 서버 설치하기](https://villagesql.com/docs/ko/tutorial/install-mysql.md) — SQL을 배울 서버 준비하기


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.