Docker 컨테이너에서 스키마를 사용하여 MySQL 데이터베이스를 초기화하는 방법은 무엇입니까?


165

MySQL 데이터베이스가있는 컨테이너를 만들고이 데이터베이스에 스키마를 추가하려고합니다.

내 현재 Dockerfile은 다음과 같습니다.

FROM mysql
MAINTAINER  (me) <email>

# Copy the database schema to the /data directory
COPY files/epcis_schema.sql /data/epcis_schema.sql

# Change the working directory
WORKDIR data

CMD mysql -u $MYSQL_USER -p $MYSQL_PASSWORD $MYSQL_DATABASE < epcis_schema.sql

컨테이너를 만들려면 Docker에 제공된 설명서를 따르고이 명령을 실행합니다.

docker run --name ${CONTAINER_NAME} -e MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD} -e MYSQL_USER=${DB_USER} -e MYSQL_PASSWORD=${DB_USER_PASSWORD} -e MYSQL_DATABASE=${DB_NAME} -d mvpgomes/epcisdb

그러나이 명령을 실행하면 컨테이너가 생성되지 않고 컨테이너 상태에서 CMD가 성공적으로 실행되지 않았으며 실제로 mysql명령 만 실행되는 것을 볼 수 있습니다.

어쨌든 스키마를 사용하여 데이터베이스를 초기화하는 방법이 있습니까? 아니면 이러한 작업을 수동으로 수행해야합니까?


시드되고 갈 준비가 된 데이터베이스로 새 이미지를 만들고 싶다고 가정합니까?
Greg

네, 정확히 내가 원하는 것입니다.
Marcus Gomes


또한 여기에 설명했다 : medium.com/@lvthillo/…
lvthillo

답변:


105

이 매우 긴 답변에 대해 유감스럽게 생각하지만 원하는 곳으로 갈 수있는 약간의 방법이 있습니다. 필자는 일반적으로 데이터베이스 자체와 동일한 컨테이너에 데이터베이스 스토리지를 저장하지 않고 데이터를 도커 호스트에 유지하도록 호스트 볼륨을 마운트하거나 컨테이너를 사용하여 데이터를 보유하십시오 (/ var / lib / mysql). 또한, 나는 mysql을 처음 사용하기 때문에 매우 효율적이지 않을 수 있습니다. 그건 ...

여기에 몇 가지 문제가 있다고 생각합니다. Dockerfile은 이미지를 만드는 데 사용됩니다. 빌드 단계를 실행해야합니다. 최소한 Dockerfile이 들어있는 디렉토리에서 다음과 같이하십시오.

docker build .

Dockerfile은 만들 이미지를 설명합니다. 나는 mysql에 대해 잘 모른다 (나는 postgres fanboy이다). 그러나 나는 어떻게 mysql docker container를 초기화합니까? 먼저 작업 할 새 디렉토리를 만들고 mdir이라고 부르고 데이터베이스와 단일 테이블을 만드는 epcis_schema.sql 파일을 저장 한 파일 디렉토리를 작성했습니다.

create database test;
use test;

CREATE TABLE testtab
(
id INTEGER AUTO_INCREMENT,
name TEXT,
PRIMARY KEY (id)
) COMMENT='this is my test table';

그런 다음 파일 디렉토리에 init_db라는 스크립트를 작성했습니다.

#!/bin/bash

# Initialize MySQL database.
# ADD this file into the container via Dockerfile.
# Assuming you specify a VOLUME ["/var/lib/mysql"] or `-v /var/lib/mysql` on the `docker run` command
# Once built, do e.g. `docker run your_image /path/to/docker-mysql-initialize.sh`
# Again, make sure MySQL is persisting data outside the container for this to have any effect.

set -e
set -x

mysql_install_db

# Start the MySQL daemon in the background.
/usr/sbin/mysqld &
mysql_pid=$!

until mysqladmin ping >/dev/null 2>&1; do
  echo -n "."; sleep 0.2
done

# Permit root login without password from outside container.
mysql -e "GRANT ALL ON *.* TO root@'%' IDENTIFIED BY '' WITH GRANT OPTION"

# create the default database from the ADDed file.
mysql < /tmp/epcis_schema.sql

# Tell the MySQL daemon to shutdown.
mysqladmin shutdown

# Wait for the MySQL daemon to exit.
wait $mysql_pid

# create a tar file with the database as it currently exists
tar czvf default_mysql.tar.gz /var/lib/mysql

# the tarfile contains the initialized state of the database.
# when the container is started, if the database is empty (/var/lib/mysql)
# then it is unpacked from default_mysql.tar.gz from
# the ENTRYPOINT /tmp/run_db script

(이 스크립트의 대부분은 여기에서 해제되었습니다 : https://gist.github.com/pda/9697520 )

다음은 내가 만든 files / run_db 스크립트입니다.

# start db

set -e
set -x

# first, if the /var/lib/mysql directory is empty, unpack it from our predefined db
[ "$(ls -A /var/lib/mysql)" ] && echo "Running with existing database in /var/lib/mysql" || ( echo 'Populate initial db'; tar xpzvf default_mysql.tar.gz )

/usr/sbin/mysqld

마지막으로 Dockerfile은 모두 바인딩합니다.

FROM mysql
MAINTAINER  (me) <email>

# Copy the database schema to the /data directory
ADD files/run_db files/init_db files/epcis_schema.sql /tmp/

# init_db will create the default
# database from epcis_schema.sql, then
# stop mysqld, and finally copy the /var/lib/mysql directory
# to default_mysql_db.tar.gz
RUN /tmp/init_db

# run_db starts mysqld, but first it checks
# to see if the /var/lib/mysql directory is empty, if
# it is it is seeded with default_mysql_db.tar.gz before
# the mysql is fired up

ENTRYPOINT "/tmp/run_db"

그래서 mdir 디렉토리 (파일 디렉토리와 함께 Dockerfile이 있음)로 cd했습니다. 그런 다음 명령을 실행합니다.

docker build --no-cache .

다음과 같은 출력이 표시되어야합니다.

Sending build context to Docker daemon 7.168 kB
Sending build context to Docker daemon 
Step 0 : FROM mysql
 ---> 461d07d927e6
Step 1 : MAINTAINER (me) <email>
 ---> Running in 963e8de55299
 ---> 2fd67c825c34
Removing intermediate container 963e8de55299
Step 2 : ADD files/run_db files/init_db files/epcis_schema.sql /tmp/
 ---> 81871189374b
Removing intermediate container 3221afd8695a
Step 3 : RUN /tmp/init_db
 ---> Running in 8dbdf74b2a79
+ mysql_install_db
2015-03-19 16:40:39 12 [Note] InnoDB: Using atomics to ref count buffer pool pages
...
/var/lib/mysql/ib_logfile0
 ---> 885ec2f1a7d5
Removing intermediate container 8dbdf74b2a79
Step 4 : ENTRYPOINT "/tmp/run_db"
 ---> Running in 717ed52ba665
 ---> 7f6d5215fe8d
Removing intermediate container 717ed52ba665
Successfully built 7f6d5215fe8d

이제 이미지 '7f6d5215fe8d'가 있습니다. 이 이미지를 실행할 수 있습니다.

docker run -d 7f6d5215fe8d

이미지가 시작되면 인스턴스 문자열이 나타납니다.

4b377ac7397ff5880bc9218abe6d7eadd49505d50efb5063d6fab796ee157bd3

그런 다음 '중지'하고 다시 시작할 수 있습니다.

docker stop 4b377
docker start 4b377

로그를 보면 첫 번째 줄에 다음이 포함됩니다.

docker logs 4b377

Populate initial db
var/lib/mysql/
...

그런 다음 로그 끝에서 :

Running with existing database in /var/lib/mysql

이것은 / tmp / run_db 스크립트의 메시지이며, 첫 번째는 데이터베이스가 저장된 (초기) 버전에서 압축이 풀 렸음을 나타내고, 두 번째는 데이터베이스가 이미 존재 했으므로 기존 사본이 사용되었음을 나타냅니다.

다음은 위에서 설명한 디렉토리 구조의 ls -lR입니다. init_db 및 run_db는 실행 비트가 설정된 스크립트입니다.

gregs-air:~ gfausak$ ls -Rl mdir
total 8
-rw-r--r--  1 gfausak  wheel  534 Mar 19 11:13 Dockerfile
drwxr-xr-x  5 gfausak  staff  170 Mar 19 11:24 files

mdir/files:
total 24
-rw-r--r--  1 gfausak  staff   126 Mar 19 11:14 epcis_schema.sql
-rwxr-xr-x  1 gfausak  staff  1226 Mar 19 11:16 init_db
-rwxr-xr-x  1 gfausak  staff   284 Mar 19 11:23 run_db

3
게리, 도와 줘서 고마워 나는 당신의 지시를 따랐지만 docker build --no-cache를 실행할 때. init_db스크립트에 대한 권한 오류가 있습니다.
Marcus Gomes

나는 이미 RUN명령에 권한을 부여하여 문제를 해결하려고 시도 하고 문제가 분명히 해결되었습니다. 그러나 내가 실행할 때 스크립트 docker run와 동일한 문제가 run_db있습니다.
Marcus Gomes

1
init_db와 run_db는 0755 권한이어야합니다. (스크립트이고, 실행 비트 세트가 필요합니다. chmod + x를 수행하십시오. init_db run_db
Greg

각 파일에 대한 권한을 보여주는 디렉토리 목록으로 답변을 업데이트했습니다. 참고 : chmod + x files / * _ db는 필요한 권한을 수행합니다.
Greg

2
@Greg 위의 단계를 시도했지만 오류가 발생합니다. ([오류] 치명적인 오류 : mysqld를 root로 실행하는 방법은 설명서의 "보안"섹션을 참조하십시오!) 어떤 제안?
Binish John

121

MySQL Docker 인스턴스의 스키마를 초기화하려는 것과 동일한 문제가 있었지만 일부 인터넷 검색을 수행하고 다른 사람들의 예를 따르면이 작업을 수행하는 데 어려움을 겪었습니다. 내가 해결 한 방법은 다음과 같습니다.

1) MySQL 스키마를 파일로 덤프하십시오.

mysqldump -h <your_mysql_host> -u <user_name> -p --no-data <schema_name> > schema.sql

2) ADD 명령을 사용하여 스키마 파일을 /docker-entrypoint-initdb.dDocker 컨테이너 의 디렉토리에 추가하십시오 . docker-entrypoint.sh파일로 끝나는이 디렉토리에있는 파일을 실행합니다 ".sql"MySQL 데이터베이스에 대한.

도커 파일 :

FROM mysql:5.7.15

MAINTAINER me

ENV MYSQL_DATABASE=<schema_name> \
    MYSQL_ROOT_PASSWORD=<password>

ADD schema.sql /docker-entrypoint-initdb.d

EXPOSE 3306

3) Docker MySQL 인스턴스를 시작하십시오.

docker-compose build
docker-compose up

docker-entrypoint.sh에 대한 정보와 SQL 및 셸 스크립트를 모두 실행한다는 사실을 알려준 Dockerfile 내에서 MySQL설정하고 덤프를 가져 와서 감사합니다 !


2
이것이 가장 좋은 대답입니다. DDL 및 초기화 스크립트를 /docker-entrypoint-initdb.d 디렉토리에 복사하는 것은 dockerhub mysql 문서가 그러한 일을하는 것입니다.
chacewells

2
무언가가 바뀌면 schema.sql어떻게 되나요? DB가 그에 따라 업데이트되기를 원합니다. 이 컨테이너를 두 번째로 빌드하면 어떻게됩니까? db가 파괴되어 다시 생성됩니까?
Goga Koreli

1
은 / var / lib 디렉토리 / mysql을에 데이터 항목이없는 경우에만 @Goga Koreli 도커이 init 명령을 실행
의료 기술

38

이전에 서버 응답을 병합 한 또 다른 방법은 다음과 같습니다.

도커 작성 파일 :

version: "3"
services:
    db:
      container_name: db
      image: mysql
      ports:
       - "3306:3306"  
      environment:
         - MYSQL_ROOT_PASSWORD=mysql
         - MYSQL_DATABASE=db

      volumes:
         - /home/user/db/mysql/data:/var/lib/mysql
         - /home/user/db/mysql/init:/docker-entrypoint-initdb.d/:ro

여기서 /home/user..은 호스트의 공유 폴더입니다.

그리고 /home/user/db/mysql/init.. 폴더 에 다음 과 같은 이름을 가진 하나의 sql 파일을 드롭하십시오 init.sql.

CREATE DATABASE mydb;
GRANT ALL PRIVILEGES ON mydb.* TO 'myuser'@'%' IDENTIFIED BY 'mysql';
GRANT ALL PRIVILEGES ON mydb.* TO 'myuser'@'localhost' IDENTIFIED BY 'mysql';
USE mydb
CREATE TABLE CONTACTS (
    [ ... ]
);
INSERT INTO CONTACTS VALUES ...
[ ... ]

공식 mysql 문서 에 따르면 , 하나 이상의 sql 파일을 docker-entrypoint-initdb.d알파벳 순서로 실행합니다.


28

다른 간단한 방법은 다음 줄과 함께 docker-compose를 사용하십시오.

mysql:
  from: mysql:5.7
  volumes:
    - ./database:/tmp/database
  command: mysqld --init-file="/tmp/database/install_db.sql"

데이터베이스 스키마를 ./database/install_db.sql에 넣으십시오. 컨테이너를 빌드 할 때마다 install_db.sql이 실행됩니다.


26

나는 성공을 거두지 않은 Greg의 대답을 시도했지만 모든 단계 후에 데이터베이스에 데이터가 없기 때문에 뭔가 잘못했을 것입니다. 만약을 대비하여 MariaDB의 최신 이미지를 사용하고있었습니다.

그런 다음 공식 MariaDB 이미지 의 진입 점을 읽고 간단한 도커 작성 파일 을 생성하는 데 사용했습니다 .

database:
  image: mariadb
  ports:
     - 3306:3306
  expose:
     - 3306
  volumes:
     - ./docker/mariadb/data:/var/lib/mysql:rw
     - ./database/schema.sql:/docker-entrypoint-initdb.d/schema.sql:ro
  environment:
     MYSQL_ALLOW_EMPTY_PASSWORD: "yes"

이제 데이터를 유지하고 내 스키마로 데이터베이스를 생성 할 수 있습니다!


1
안녕, 나도 같은 노력을 기울이고 있지만 스크립트는 실행되지 않습니다. 제공해야 할 다른 매개 변수가 있습니까? 방금 mariadb-./database/schema.sql:/docker-entrypoint-initdb.d/schema.sql:ro에이 볼륨을 추가했습니다. 감사합니다
bilak

참고 : 컨테이너 초기화 중에는 스크립트가 한 번만 실행됩니다. 나중에 새 스크립트를 추가하면 실행되지 않습니다.
ALex_hha


11

가장 쉬운 해결책은 tutum / mysql 을 사용하는 것입니다

1 단계

docker pull tutum/mysql:5.5

2 단계

docker run -d -p 3306:3306 -v /tmp:/tmp  -e STARTUP_SQL="/tmp/to_be_imported.mysql" tutum/mysql:5.5

3 단계

CONTAINER_ID를 초과 한 다음 docker logs생성 된 비밀번호 정보를 보려면 명령 을 실행 하십시오.

docker logs #<CONTAINER_ID>

성공적으로 실행하기 위해 이것을 얻었습니까? 나는 몇 주 동안 tutum / mysql로 ​​성공하지 못했습니다.
Iammesol 5

2
예. 나는 그것을 사용 tutum/mysql:5.5하고 성공했다. docker run -d -p 3306:3306 -v /tmp:/tmp -e MYSQL_PASS="admin" -e STARTUP_SQL="/tmp/mysqldump.mysql" tutum/mysql:5.5. docker logs CONTAINER_ID문제가 발생한 경우 항상 명령 을 실행 하여 오류 메시지를 볼 수 있습니다 .
메인 프레임

경로 /tmp/to_be_imported.mysql가 어디에서 왔는지 알 수 없습니다 . 호스트 OS의 경로입니까? 컨테이너의 파일 시스템에 COPY또는 ADD을 넣을 위치는 어디 입니까?
랜디 L

@ the0ther 당신이 할 필요가 없습니다 COPY/ ADD/ tmp를 호스트 디렉토리에 / 컨테이너의 tmp에 장착되기 때문이다. 부분이있는 명령을 자세히 살펴보십시오 -v /tmp:/tmp. 개인적으로 컨테이너에 파일을 제공하기 위해 볼륨을 마운트하지는 않지만 개인적인 선택이라고 생각합니다.
Willa

1
공정하게하기 위해, 당신 이 이것을 다시 원치 않는 한, 비공식 이미지를 사용해서는 안됩니다 .
Dragas

3

나와 같은 진입 점 스크립트를 생성하지 않으려는 경우 실제로 빌드 타임에 mysqld를 시작한 다음 Dockerfile에서 다음과 같이 mysql 명령을 실행할 수 있습니다.

RUN mysqld_safe & until mysqladmin ping; do sleep 1; done && \
    mysql -uroot -e "CREATE DATABASE somedb;" && \
    mysql -uroot -e "CREATE USER 'someuser'@'localhost' IDENTIFIED BY 'somepassword';" && \
    mysql -uroot -e "GRANT ALL PRIVILEGES ON somedb.* TO 'someuser'@'localhost';"

여기서 중요한 점은 mysqld_safe를 단일 &부호 가있는 백그라운드로 보내는 것 입니다.


1

아래는 xampp를 설치하고, 스키마를 사용하여 MariaDB를 만들고 로컬 서버에서 사용되는 정보로 미리 채워진 Dockerfile입니다 (usrs, pics order 등).

FROM ubuntu:14.04

COPY Ecommerce.sql /root

RUN apt-get update \
 && apt-get install wget -yq \
 && apt-get install nano \
 && wget https://www.apachefriends.org/xampp-files/7.1.11/xampp-linux-x64-7.1.11-0-installer.run \
 && mv xampp-linux-x64-7.1.11-0-installer.run /opt/ \
 && cd /opt/ \
 && chmod +x xampp-linux-x64-7.1.11-0-installer.run \
 && printf 'y\n\y\n\r\n\y\n\r\n' | ./xampp-linux-x64-7.1.11-0-installer.run \
 && cd /opt/lampp/bin \
 && /opt/lampp/lampp start \
 && sleep 5s \

 && ./mysql -uroot -e "CREATE DATABASE Ecommerce" \
 && ./mysql -uroot -D Ecommerce < /root/Ecommerce.sql \
 && cd / \
 && /opt/lampp/lampp reload \
 && mkdir opt/lampp/htdocs/Ecommerce

COPY /Ecommerce /opt/lampp/htdocs/Ecommerce

EXPOSE 80

0

그것에 약간의 어려움을 겪은 후, 명명 된 볼륨 (db-data)을 사용하여 Dockerfile을 살펴보십시오. 마지막 부분에 플러스를 선언하는 것이 중요합니다.[external]

모두 이런 식으로 잘 작동했습니다!

version: "3"

services:

  database:
    image: mysql:5.7
    container_name: mysql
    ports:
      - "3306:3306"
    volumes:
      - db-data:/docker-entrypoint-initdb.d
    environment:
      - MYSQL_DATABASE=sample
      - MYSQL_ROOT_PASSWORD=root

volumes:
  db-data:
    external: true
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.