Bagaimana saya bisa menginisialisasi database MySQL dengan skema dalam wadah Docker?

165

Saya mencoba membuat wadah dengan database MySQL dan menambahkan skema ke database ini.

Dockerfile saya saat ini adalah:

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

Untuk membuat wadah, saya mengikuti dokumentasi yang disediakan di Docker dan menjalankan perintah ini:

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

Tetapi ketika saya menjalankan perintah ini, Container tidak dibuat dan dalam status Container, dimungkinkan untuk melihat bahwa CMD tidak dieksekusi dengan sukses, pada kenyataannya hanya mysqlperintah yang dieksekusi.

Lagi pula, apakah ada cara untuk menginisialisasi database dengan skema atau apakah saya perlu melakukan operasi ini secara manual?

Marcus Gomes
sumber
saya berasumsi bahwa Anda ingin membuat gambar baru dengan database yang diunggulkan dan siap untuk digunakan?
Greg
Ya, itulah yang ingin saya lakukan.
Marcus Gomes
Dijelaskan di sini juga: medium.com/@lvthillo/…
lvthillo

Jawaban:

105

Saya minta maaf atas jawaban super panjang ini, tetapi, Anda memiliki sedikit cara untuk pergi ke tempat yang Anda inginkan. Saya akan mengatakan bahwa biasanya Anda tidak akan menempatkan penyimpanan untuk database dalam wadah yang sama dengan database itu sendiri, Anda akan me-mount volume host sehingga data tetap ada pada host buruh pelabuhan, atau, mungkin sebuah wadah dapat digunakan untuk tahan data (/ var / lib / mysql). Juga, saya baru di mysql, jadi, ini mungkin tidak super efisien. Yang mengatakan ...

Saya pikir mungkin ada beberapa masalah di sini. Dockerfile digunakan untuk membuat gambar. Anda perlu menjalankan langkah pembangunan. Minimal, dari direktori yang berisi Dockerfile Anda akan melakukan sesuatu seperti:

docker build .

Dockerfile menjelaskan gambar yang akan dibuat. Saya tidak tahu banyak tentang mysql (saya seorang fanboy postgres), tetapi, saya melakukan pencarian di sekitar jalinan untuk 'bagaimana saya menginisialisasi wadah buruh pelabuhan mysql'. Pertama saya membuat direktori baru untuk bekerja, saya menyebutnya mdir, lalu saya membuat direktori file yang saya simpan file epcis_schema.sql yang membuat database dan satu tabel:

create database test;
use test;

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

Kemudian saya membuat skrip bernama init_db di direktori file:

#!/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

(sebagian besar skrip ini diangkat dari sini: https://gist.github.com/pda/9697520 )

Berikut ini skrip file / run_db yang saya buat:

# 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

Akhirnya, Dockerfile mengikat semuanya:

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"

Jadi, saya pindah ke direktori mdir saya (yang memiliki Dockerfile bersama dengan direktori file). Saya kemudian menjalankan perintah:

docker build --no-cache .

Anda akan melihat output seperti ini:

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

Anda sekarang memiliki gambar '7f6d5215fe8d'. Saya dapat menjalankan gambar ini:

docker run -d 7f6d5215fe8d

dan gambar dimulai, saya melihat string contoh:

4b377ac7397ff5880bc9218abe6d7eadd49505d50efb5063d6fab796ee157bd3

Saya kemudian bisa 'menghentikannya', dan memulai kembali.

docker stop 4b377
docker start 4b377

Jika Anda melihat log, baris pertama akan berisi:

docker logs 4b377

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

Kemudian, di akhir log:

Running with existing database in /var/lib/mysql

Ini adalah pesan-pesan dari skrip / tmp / run_db, yang pertama menunjukkan bahwa basis data dibongkar dari versi yang disimpan (awal), yang kedua menunjukkan bahwa basis data sudah ada di sana, sehingga salinan yang ada digunakan.

Berikut ini adalah ls-lR dari struktur direktori yang saya jelaskan di atas. Perhatikan bahwa init_db dan run_db adalah skrip dengan set bit eksekusi:

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
Greg
sumber
3
Hai Gary, terima kasih dulu atas bantuannya. Saya mengikuti instruksi Anda, tetapi ketika saya menjalankan buruh pelabuhan --no-cache. , Saya memiliki kesalahan izin untuk init_dbskrip.
Marcus Gomes
Saya sudah mencoba untuk memperbaikinya dengan memberikan izin pada RUNperintah dan masalahnya ternyata terpecahkan. Tetapi kemudian ketika saya mengeksekusi docker runsaya memiliki masalah yang sama dengan run_dbskrip.
Marcus Gomes
1
init_db dan run_db harus berupa izin 0755 (itu adalah skrip, mereka harus memiliki bit eksekusi. Lakukan chmod + x init_db run_db
Greg
Saya memperbarui jawabannya dengan daftar direktori yang menunjukkan izin pada masing-masing file. Catatan: chmod + x file / * _ db akan memenuhi izin yang diperlukan.
Greg
2
@Greg Saya mencoba langkah-langkah di atas namun saya mendapatkan kesalahan ([GALAT] Kesalahan fatal: Harap baca bagian "Keamanan" dari manual untuk mengetahui cara menjalankan mysqld sebagai root!). Ada saran?
Binish John
121

Saya memiliki masalah yang sama di mana saya ingin menginisialisasi skema instance MySQL Docker saya, tetapi saya mengalami kesulitan mendapatkan ini bekerja setelah melakukan beberapa Googling dan mengikuti contoh orang lain. Inilah cara saya menyelesaikannya.

1) Buang skema MySQL Anda ke file.

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

2) Gunakan perintah ADD untuk menambahkan file skema Anda ke /docker-entrypoint-initdb.ddirektori dalam wadah Docker. The docker-entrypoint.shFile akan menjalankan file apapun dalam direktori ini berakhir dengan ".sql"terhadap database MySQL.

Dockerfile:

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) Mulai instance Docker MySQL.

docker-compose build
docker-compose up

Terima kasih untuk Menyiapkan MySQL dan mengimpor dump di dalam Dockerfile karena petunjuk saya tentang di docker-entrypoint.sh dan fakta bahwa ia menjalankan skrip SQL dan shell!

Brett Cooper
sumber
2
Ini jelas jawaban yang lebih baik. Menyalin DDL dan skrip inisialisasi ke direktori /docker-entrypoint-initdb.d adalah apa yang dikatakan dockerhub mysql docs terkait dengan hal-hal seperti itu.
chacewells
2
Apa yang terjadi ketika sesuatu berubah schema.sql? Saya ingin db saya diperbarui sesuai. Juga apa yang terjadi ketika saya membangun wadah ini untuk kedua kalinya? Akankah db dihancurkan dan dibuat lagi?
Goga Koreli
1
@Goga Koreli Docker menjalankan perintah init ini hanya jika tidak ada entri data di / var / lib / mysql
medTech
38

Cara lain berdasarkan gabungan respons serveral di sini sebelumnya:

file komposisi buruh pelabuhan:

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

di mana /home/user.. adalah folder bersama di host

Dan di /home/user/db/mysql/initfolder .. cukup letakkan satu file sql, dengan nama apa saja, misalnya init.sqlberisi:

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 ...
[ ... ]

Menurut dokumentasi resmi mysql , Anda dapat menempatkan lebih dari satu file sql di docker-entrypoint-initdb.d, mereka dieksekusi dalam urutan abjad

phico
sumber
28

Cara sederhana lainnya, gunakan docker-compose dengan baris berikut:

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

Masukkan skema basis data Anda ke file ./database/install_db.sql. Setiap kali ketika Anda membangun wadah Anda, install_db.sql akan dieksekusi.

Balázs Zámbó
sumber
26

Saya sudah mencoba jawaban Greg dengan nol keberhasilan, saya pasti telah melakukan sesuatu yang salah karena database saya tidak memiliki data setelah semua langkah: Saya menggunakan gambar terbaru MariaDB, untuk berjaga-jaga.

Kemudian saya memutuskan untuk membaca entri untuk gambar resmi MariaDB , dan menggunakannya untuk menghasilkan file komposisi buruh pelabuhan yang sederhana :

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"

Sekarang saya dapat menyimpan data saya DAN menghasilkan database dengan skema saya sendiri!

mrArias
sumber
1
Hai, saya mencoba juga melakukan hal yang sama, tetapi skrip tidak pernah dieksekusi. Apakah ada parameter lain yang perlu disediakan? Saya baru saja menambahkan volume ini untuk mariadb - ./database/schema.sql:/docker-entrypoint-initdb.d/schema.sql:ro. Terima kasih
bilak
Catatan: skrip akan dieksekusi hanya sekali, selama inisialisasi wadah. Jika nanti Anda menambahkan skrip baru, skrip itu tidak akan dijalankan.
ALex_hha
23

Setelah 4 Agustus 2015, jika Anda menggunakan gambar Docker mysql resmi, Anda bisa menambahkan / menyalin file ke direktori /docker-entrypoint-initdb.d/ dan itu akan berjalan dengan wadah diinisialisasi. Lihat github: https://github.com/docker-library/mysql/commit/14f165596ea8808dfeb2131f092aabe61c967225 jika Anda ingin menerapkannya pada gambar wadah lain

JDWatkins
sumber
1
Ini adalah jawaban yang benar untuk versi gambar Docker MSQL saat ini.
NaN
11

Solusi termudah adalah dengan menggunakan tutum / mysql

Langkah 1

docker pull tutum/mysql:5.5

Langkah 2

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

Step3

Dapatkan CONTAINER_ID di atas dan kemudian jalankan perintah docker logsuntuk melihat informasi kata sandi yang dihasilkan.

docker logs #<CONTAINER_ID>
mainframer
sumber
Sudahkah Anda berhasil menjalankan ini? Saya telah mengotak-atik tutum / mysql selama berminggu-minggu tanpa hasil.
Iammesol
2
Iya. Saya menggunakan tutum/mysql:5.5dan berhasil. docker run -d -p 3306:3306 -v /tmp:/tmp -e MYSQL_PASS="admin" -e STARTUP_SQL="/tmp/mysqldump.mysql" tutum/mysql:5.5. Anda selalu dapat menjalankan perintah docker logs CONTAINER_IDuntuk melihat pesan kesalahan jika Anda menemui masalah.
mainframer
saya tidak tahu dari mana jalan /tmp/to_be_imported.mysqlitu berasal. apakah itu jalan pada OS host? di mana a COPYatau ADDuntuk meletakkan sesuatu ke sistem file wadah?
Randy L
@ the0ther Anda tidak perlu COPY/ ADDkarena direktori host / tmp sudah terpasang ke / tmp dari wadah. Perhatikan baik-baik perintah yang ada di sana -v /tmp:/tmp. Secara pribadi saya tidak akan memasang volume hanya untuk membuat file tersedia untuk wadah tetapi saya kira itu adalah pilihan pribadi.
Willa
1
Agar adil, Anda tidak harus menggunakan gambar non-resmi, kecuali jika Anda ingin ini terjadi lagi.
Dragas
3

Bagi yang tidak ingin membuat skrip entrypoint seperti saya, Anda sebenarnya dapat memulai mysqld pada waktu build dan kemudian menjalankan perintah mysql di Dockerfile Anda seperti:

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';"

Kuncinya di sini adalah mengirim mysqld_safe ke latar belakang dengan satu &tanda.

roothahn
sumber
1

Di bawah ini adalah Dockerfile yang saya gunakan dengan sukses untuk menginstal xampp, membuat MariaDB dengan skema dan diisi sebelumnya dengan info yang digunakan pada server lokal (usrs, foto pesanan, dll.)

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
Paddy Popeye
sumber
0

Setelah berjuang sedikit dengan itu, lihat Dockerfile menggunakan volume bernama (db-data). Sangat penting menyatakan nilai tambah pada bagian akhir, di mana saya menyebutkan volume itu[external]

Semua bekerja sangat baik dengan cara ini!

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
allysson vieira
sumber