MySQL 설정 및 Dockerfile 내에서 덤프 가져 오기


127

LAMP 프로젝트에 Dockerfile을 설정하려고하는데 MySQL을 시작할 때 몇 가지 문제가 있습니다. 내 Dockerfile에 다음 줄이 있습니다.

VOLUME ["/etc/mysql", "/var/lib/mysql"]
ADD dump.sql /tmp/dump.sql
RUN /usr/bin/mysqld_safe & sleep 5s
RUN mysql -u root -e "CREATE DATABASE mydb"
RUN mysql -u root mydb < /tmp/dump.sql

하지만이 오류가 계속 발생합니다.

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (111)

Dockerfile 빌드 중에 데이터베이스 생성 및 덤프 가져 오기를 설정하는 방법에 대한 아이디어가 있습니까?


이는 각 RUN명령이 다른 컨테이너에서 실행되기 때문입니다. 여기에 잘 설명되어 있습니다 : stackoverflow.com/questions/17891669/…
Kuhess

이것은 RUN 명령이 다른 컨텍스트를 가지고 있음을 설명합니다. 그러나 나는 문맥이 아니라 데몬에 의존하고 있습니다.
vinnylinux

1
예,하지만 이것이 MySQL에 연결할 수없는 이유를 설명합니다. 첫 번째 RUN줄 에서만 실행되기 때문 입니다.
Kuhess 2014 년

SQL 문을 실행하려면 MySQL을 시작하고 동일한 컨테이너 ( RUN여러 단계가있는 하나)에서 MySQL 클라이언트를 사용해야 합니다. 여기에서 소프트웨어의 다단계 설치에 대한 예를 찾을 수 있습니다. stackoverflow.com/questions/25899912/install-nvm-in-docker/…
Kuhess

당신은 또한 고정 표시기-작성과 서비스를 볼 수 있습니다 : docs.docker.com/compose/wordpress/#build-the-project 그와를, MySQL은이 앱에 첨부 할 수 있습니다
aurny2420289

답변:


122

의 각 RUN명령 Dockerfile문서에RUN 설명 된대로 다른 계층에서 실행됩니다 .

에는 Dockerfile세 가지 RUN지침이 있습니다. 문제는 MySQL 서버가 처음에만 시작된다는 것입니다. 다른 것에서는 MySQL이 실행되고 있지 않으므로 mysql클라이언트 와의 연결 오류가 발생 합니다.

이 문제를 해결하려면 두 가지 해결책이 있습니다.

해결 방법 1 : 한 줄 사용 RUN

RUN /bin/bash -c "/usr/bin/mysqld_safe --skip-grant-tables &" && \
  sleep 5 && \
  mysql -u root -e "CREATE DATABASE mydb" && \
  mysql -u root mydb < /tmp/dump.sql

해결 방법 2 : 스크립트 사용

실행 가능한 스크립트 생성 init_db.sh:

#!/bin/bash
/usr/bin/mysqld_safe --skip-grant-tables &
sleep 5
mysql -u root -e "CREATE DATABASE mydb"
mysql -u root mydb < /tmp/dump.sql

다음 줄을 추가하십시오 Dockerfile.

ADD init_db.sh /tmp/init_db.sh
RUN /tmp/init_db.sh

그 정보를 어떻게 유지할 수 있는지 아십니까? Dockerfile 빌드에서 생성중인 데이터베이스와 테이블은 컨테이너에서 항목을 실행할 때 사용할 수 없습니다. :(
vinnylinux

1
그것은 당신이 지속한다는 의미에 달려 있습니다. 여러 docker run실행에 걸쳐 데이터를 유지 하려면 볼륨을 마운트해야합니다. 당신은 당신의 덤프와 용기를 갖고 싶어하지만 추가 수정을 유지하지 않으려면, 당신은 제거 할 수 VOLUME귀하의 명령 Dockerfile.
Kuhess 2014 년

16
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)해결 방법 1을 시도 하면 얻을 수 있습니다 . 로그 mysqld_safe Starting mysqld daemon with databases from /var/lib/mysqlmysqld_safe mysqld from pid file /var/run/mysqld/mysqld.pid ended
따르고

1
mysql이 데이터베이스를 생성했는지 확인하기 위해 시작시 스크립트를 확인하는 것이 훨씬 낫다는 것을 알았습니다. 있는 경우 그대로 두십시오. 그렇지 않으면 mysql_init_db데이터베이스 구조에서 실행 하고로드하십시오. 이를 통해 테스트 할 때 데이터베이스를 자동으로 재설정 할 수있는 유연성을 제공하지만 다른 데이터 세트를 유지하거나 테스트하려면을 사용하여 / var / lib / mysql에 볼륨을 마운트하면됩니다 docker run -v ....
tu-Reinstate Monica-dor duh

1
@trevorgrayson-그것도 작동하지 않습니다. 이제 오류 ERROR 2003 (HY000) : '127.0.0.1'(111)에서 MySQL 서버에 연결할 수 없습니다
Deep

166

공식 mysql Docker 이미지 의 최신 버전을 사용하면 시작시 데이터를 가져올 수 있습니다. 여기 내 docker-compose.yml이 있습니다.

data:
  build: docker/data/.
mysql:
  image: mysql
  ports:
    - "3307:3306"
  environment:
    MYSQL_ROOT_PASSWORD: 1234
  volumes:
    - ./docker/data:/docker-entrypoint-initdb.d
  volumes_from:
    - data

여기 docker/data에는 docker-compose가 실행되는 폴더에 상대적인 data-dump.sql 이 있습니다. /docker-entrypoint-initdb.d컨테이너 의이 디렉토리 에 해당 SQL 파일을 마운트 하고 있습니다.

이것이 어떻게 작동하는지 알고 싶다면 docker-entrypoint.shGitHub 에서 살펴보십시오 . 데이터 가져 오기를 허용하기 위해이 블록을 추가했습니다.

    echo
    for f in /docker-entrypoint-initdb.d/*; do
        case "$f" in
            *.sh)  echo "$0: running $f"; . "$f" ;;
            *.sql) echo "$0: running $f"; "${mysql[@]}" < "$f" && echo ;;
            *)     echo "$0: ignoring $f" ;;
        esac
        echo
    done

추가 참고 사항, mysql 컨테이너가 중지되고 제거 된 후에도 데이터가 유지되도록하려면 docker-compose.yml에서 볼 수 있듯이 별도의 데이터 컨테이너가 있어야합니다. 데이터 컨테이너 Dockerfile의 내용은 매우 간단합니다.

FROM n3ziniuka5/ubuntu-oracle-jdk:14.04-JDK8

VOLUME /var/lib/mysql

CMD ["true"]

데이터 컨테이너는 지속성을 위해 시작 상태 일 필요도 없습니다.


1
이것이 더 나은 대답 IMHO입니다. 우리 스스로 이미지를 만들 수 없습니다. 이 팁에 감사드립니다.
Metal3d 2015

5
볼륨에 대한 하나의 작은 변화는 - ./docker/data:/docker-entrypoint-initdb.d: 를 -removed .컨테이너 디렉토리의 앞에.
데이비드 싱클레어

7
이것이 올바른 절차이지만 사용 사례를 잘 다루지는 않습니다. Docker의 장점 중 하나는 환경을 매우 빠르게 가동 할 수 있다는 것입니다. Docker가 시작하는 동안 MySQL DB를 가져 오는 동안 3-4 분 동안 기다려야하는 경우이 이점을 잃게됩니다. 목표는 가능한 한 빨리 사용할 수 있도록 데이터베이스에 데이터가 이미 포함 된 컨테이너를 갖는 것입니다.
Garreth McDaid

3
이 답변은 여전히 ​​최신 버전에서 작동합니까? 더 이상 작동하지 않는 것 같습니다
Daniel

2
여기서 docker-compose 예제는 v3이 아니라 v2입니다. "volumes_from :"은 v3에서 지원되지 않습니다.
Ernest

37

내가 한 것은 "db-dump"폴더에 SQL 덤프를 다운로드하고 마운트하는 것입니다.

mysql:
 image: mysql:5.6
 environment:
   MYSQL_ROOT_PASSWORD: pass
 ports:
   - 3306:3306
 volumes:
   - ./db-dump:/docker-entrypoint-initdb.d

내가 달릴 때 docker-compose up처음 하면 덤프가 db에 복원됩니다.


3
하나는, 하나 개의 추가와 함께 : 스크립트에 대한 링크는 더 나은 실제로 무슨 일이 일어나고 있는지 이해하기위한 실행되는 : github.com/docker-library/mariadb/blob/...
톰 Imrei

6
latest mysql는 덤프 된 sql 파일을로드하지 않는 것 같고 5.6을 사용하더라도 InnoDb 스토리지 엔진에 문제가 있습니다.
zinking

1
여기에서 똑같이, 그것은 그러한 지시를 가지고 있고 심지어 초기화 파일을 로딩하는 로깅에서도 보았지만 db는 비어 있습니다!
holms

11

나는 docker-entrypoint-initdb.d 접근 방식을 사용했습니다 (@Kuhess에게 감사드립니다)하지만 제 경우에는 .env 파일에서 정의한 일부 매개 변수를 기반으로 DB를 만들고 싶습니다.

1) 먼저 도커 루트 프로젝트 디렉토리에 이와 같은 .env 파일을 정의합니다.

MYSQL_DATABASE=my_db_name
MYSQL_USER=user_test
MYSQL_PASSWORD=test
MYSQL_ROOT_PASSWORD=test
MYSQL_PORT=3306

2) 그런 다음 docker-compose.yml 파일을 정의합니다. 그래서 args 지시문을 사용하여 환경 변수를 정의하고 .env 파일에서 설정했습니다.

version: '2'
services:
### MySQL Container
    mysql:
        build:
            context: ./mysql
            args:
                - MYSQL_DATABASE=${MYSQL_DATABASE}
                - MYSQL_USER=${MYSQL_USER}
                - MYSQL_PASSWORD=${MYSQL_PASSWORD}
                - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
        ports:
            - "${MYSQL_PORT}:3306"

3) 그런 다음 Dockerfile을 포함하는 mysql 폴더를 정의합니다. 그래서 Dockerfile은

FROM mysql:5.7
RUN chown -R mysql:root /var/lib/mysql/

ARG MYSQL_DATABASE
ARG MYSQL_USER
ARG MYSQL_PASSWORD
ARG MYSQL_ROOT_PASSWORD

ENV MYSQL_DATABASE=$MYSQL_DATABASE
ENV MYSQL_USER=$MYSQL_USER
ENV MYSQL_PASSWORD=$MYSQL_PASSWORD
ENV MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD

ADD data.sql /etc/mysql/data.sql
RUN sed -i 's/MYSQL_DATABASE/'$MYSQL_DATABASE'/g' /etc/mysql/data.sql
RUN cp /etc/mysql/data.sql /docker-entrypoint-initdb.d

EXPOSE 3306

4) 이제 mysqldump를 사용하여 db를 덤프하고 data.sql을 mysql 폴더에 넣습니다.

mysqldump -h <server name> -u<user> -p <db name> > data.sql

파일은 일반적인 SQL 덤프 파일이지만 처음에 두 줄을 추가하여 파일이 다음과 같이 보일 것입니다.

--
-- Create a database using `MYSQL_DATABASE` placeholder
--
CREATE DATABASE IF NOT EXISTS `MYSQL_DATABASE`;
USE `MYSQL_DATABASE`;

-- Rest of queries
DROP TABLE IF EXISTS `x`;
CREATE TABLE `x` (..)
LOCK TABLES `x` WRITE;
INSERT INTO `x` VALUES ...;
...
...
...

그래서 무슨 일이 일어나고 있는지 "RUN sed -i 's / MYSQL_DATABASE /'$ MYSQL_DATABASE '/ g'/etc/mysql/data.sql"명령을 사용하여 MYSQL_DATABASE자리 표시자를 내가 설정 한 DB의 이름으로 대체 했습니다. .env 파일.

|- docker-compose.yml
|- .env
|- mysql
     |- Dockerfile
     |- data.sql

이제 컨테이너를 빌드하고 실행할 준비가되었습니다.


나는 .env파일 을 사용하는 접근 방식을 좋아 합니다. 그러나에 따라 .env당신이 사용하는 경우 파일 기능은 작동 docker-compose up명령과 작동하지 않습니다 docker stack deploy. 따라서, 경우에 당신은 사용하려면 .env, 당신은 체크 아웃 할 수 있습니다 생산에 파일을 고정 표시기 비밀 도입 docker 17.06. 그런 다음 개발 docker compose up및 생산 docker stack deploy단계 모두에서 비밀과 함께 .env 파일을 사용할 수 있습니다.
ira

좋은 접근 방식이지만 제안한 명령 대신 RUN sed -i '1s/^/CREATE DATABASE IF NOT EXISTS $ MYSQL_DATABASE ;\nUSE $ MYSQL_DATABASE 를 사용하는 것이 좋습니다 . 당신이 어떤 덤프 파일을 사용할 수있는이 방법은, 당신은 - 당신이 :) 데이터의 큰 양의 작업을하는 경우는 유용;\n/' data.sqlsed
토마스 Kapłoński에게

9

여기에 사용하여 작업 버전 v3의이 docker-compose.yml. 핵심은 볼륨 지시문입니다.

mysql:
  image: mysql:5.6
  ports:
    - "3306:3306"
  environment:
    MYSQL_ROOT_PASSWORD: root
    MYSQL_USER: theusername
    MYSQL_PASSWORD: thepw
    MYSQL_DATABASE: mydb
  volumes:
    - ./data:/docker-entrypoint-initdb.d

내 디렉토리 에 덤프 파일 이 포함 docker-compose.ymldata디렉토리가 있습니다 .sql. .sql테이블 당 덤프 파일을 가질 수 있기 때문에 좋습니다 .

나는 단순히 뛰고 docker-compose up갈 수 있습니다. 데이터는 정류장 사이에 자동으로 유지됩니다. 데이터를 제거하고 새 .sql파일을 "흡입" 하려면 docker-compose down다음을 실행하십시오 docker-compose up.

볼륨을 제거하지 않고도 mysql커가 파일을 다시 처리하도록 하는 방법을 아는 사람이 있다면 /docker-entrypoint-initdb.d댓글을 남겨 주시면이 답변을 업데이트하겠습니다.


2
이 대답은 나를 도왔습니다. docker-compose downdocker-compose를 다시 시작 했음에도 불구하고 변경 사항이 없었기 때문에 에 대한 메모 는 매우 중요했습니다. 이 경우 MYSQL_DATABASE는 필수 변수입니다.
nxmohamad
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.