Налаштування MySQL та імпорт дампа в Dockerfile


127

Я намагаюся налаштувати Dockerfile для мого проекту LAMP, але у мене є кілька проблем при запуску 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

Щоб виконати ваші оператори SQL, потрібно запустити MySQL і використовувати клієнт MySQL в одному контейнері: один RUNз декількома кроками. Ви можете знайти приклад з багатоетапної установки програмного забезпечення на тут: stackoverflow.com/questions/25899912/install-nvm-in-docker / ...
Kuhess

Ви також можете ознайомитись із сервісом докер-композиту: docs.docker.com/compose/wordpress/#build-the-project з цим, mysql можна приєднати до вашого додатка
aurny2420289

Відповіді:


122

Кожна RUNінструкція в a Dockerfileвиконується в іншому шарі (як це пояснено в документаціїRUN ).

У Dockerfileвас є три RUNвказівки. Проблема полягає в тому, що сервер MySQL запускається лише перший. В інших, жоден MySQL не працює, тому ви отримуєте помилку підключення з mysqlклієнтом.

Для вирішення цієї проблеми у вас є 2 рішення.

Рішення 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

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): Неможливо підключитися до сервера MySQL на '127.0.0.1' (111)
Deep

166

Остання версія офіційного зображення докера mysql дозволяє імпортувати дані при запуску. Ось мій 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

Тут у мене є мій data-dump.sql, під docker/dataяким відносно папки, з якої працює докер-композиція. Я монтую цей sql-файл у цей каталог /docker-entrypoint-initdb.dна контейнері.

Якщо вам цікаво подивитися, як це працює, подивіться на їхню інформацію docker-entrypoint.shв GitHub. Вони додали цей блок, щоб дозволити імпорт даних

    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
Це краща відповідь ІМХО. Це дозволяє НЕ створювати образ самі. Дякую за цю пораду.
Metal3d

5
Одна незначна зміна томів: - - ./docker/data:/docker-entrypoint-initdb.dвидалено .перед каталогом контейнерів.
Девід Сінклер

7
Хоча це правильна процедура, вона не дуже добре розглядає випадок використання. Однією з переваг Docker є те, що ви можете дуже швидко створити середовище. Якщо вам доведеться почекати 3-4 хвилини, поки Docker імпортує DB MySQL під час запуску, ви втрачаєте цю перевагу. Мета полягає в тому, щоб у базі даних був контейнер, який вже містить дані, щоб ви могли ним скоріше скористатися.
Гаррет Макдейд

3
ця відповідь все ще працює з останніми версіями? здається, більше не працює
Даніель

2
Зауважте, що прикладом докер-композиції тут є v2, а не v3. "volumes_from:" не підтримується в v3.
Ернест

37

Що я зробив, це завантажити свій sql-дамп у папку "db-dump" та встановити його:

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
+1, з одним доповненням: посилання на сценарій запускається для кращого розуміння того, що насправді відбувається: github.com/docker-library/mariadb/blob/…
Том Імрей

6
Останнє, mysqlздається, не завантажує скинутий файл sql, і навіть за допомогою 5.6 У мене проблеми з двигунами зберігання InnoDb.
Зінкінг

1
Тут же є така інструкція, і я навіть бачив в журналі, що завантажує init файли, але db порожній!
холм

11

Я використовував підхід docker-entrypoint-initdb.d (спасибі @Kuhess) Але в моєму випадку я хочу створити свою БД на основі деяких параметрів, які я визначив у файлі .env, тому я це зробив

1) Спочатку я визначаю .env файл такого подібного в моєму каталозі кореневих проектів docker

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) Потім я визначаю папку mysql, яка включає Dockerfile. Отже, 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

Файл - це просто звичайний файл-дамп, але я додаю 2 рядки на початку, щоб файл виглядав так

--
-- 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заповнювач місця на ім'я моєї БД, в яку я його встановив .env файл.

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

Тепер ви готові створити і запустити контейнер


Мені подобається підхід до використання .envфайлу. Однак відповідно до цього , .envфункція файлу працює лише тоді, коли ви використовуєте docker-compose upкоманду і не працює docker stack deploy. Таким чином, у випадку, якщо ви хочете використовувати .envфайл у виробництві, ви, можливо, захочете перевірити секрети докера, які були введені в docker 17.06. Тоді ви можете використовувати .env файл у поєднанні з секретами як на етапах розробки, так docker compose upі на виробництвіdocker stack deploy
ira

Хороший підхід, але я б запропонував використовувати RUN sed -i '1s/^/CREATE DATABASE IF NOT EXISTS $ MYSQL_DATABASE ;\nUSE $ MYSQL_DATABASE ;\n/' data.sqlзамість sedкоманди, яку ви запропонували. Таким чином ви можете використовувати будь-який файл, який ви маєте, - це корисно, якщо ви працюєте з великою кількістю даних :)
Tomasz 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.ymlмене є datadir, який містить .sqlдамп-файли. Це приємно, тому що ви можете мати .sqlдамп-файл на стіл.

Я просто бігаю docker-compose upі мені добре йти. Дані автоматично зберігаються між зупинками. Якщо ви хочете видалити дані та .sqlзапустити нові файли, docker-compose downтоді запустіть docker-compose up.

Якщо хтось знає, як змусити mysqlдокера повторно обробити файли, /docker-entrypoint-initdb.dне виймаючи том, залиште коментар, і я оновлю цю відповідь.


2
ця відповідь мені допомогла. Примітка docker-compose downбула дуже важливою, оскільки я не бачив змін, незважаючи на перезапуск докер-композиції. MYSQL_DATABASE - необхідна змінна в цьому випадку
nxmohamad
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.