ฉันจะเริ่มต้นฐานข้อมูล MySQL ด้วยสคีมาในคอนเทนเนอร์ Docker ได้อย่างไร


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คำสั่งเท่านั้นที่ดำเนินการ

อย่างไรก็ตามมีวิธีการเริ่มต้นฐานข้อมูลด้วยสคีมาหรือฉันต้องดำเนินการเหล่านี้ด้วยตนเองหรือไม่


ฉันคิดว่าคุณต้องการสร้างภาพใหม่ด้วยฐานข้อมูลที่ seeded และพร้อมที่จะไปหรือไม่
เกร็ก

ใช่นั่นคือสิ่งที่ฉันต้องการจะทำ
Marcus Gomes


อธิบายที่นี่ด้วย: medium.com/@lvthillo/…
lvthillo

คำตอบ:


105

ฉันขอโทษสำหรับคำตอบที่ยาวมากนี้ แต่คุณมีวิธีเล็ก ๆ น้อย ๆ ที่จะไปถึงที่ที่คุณต้องการ ฉันจะบอกว่าปกติคุณจะไม่ใส่ที่เก็บข้อมูลสำหรับฐานข้อมูลในที่เก็บเดียวกันกับฐานข้อมูลเองคุณจะต้องเมานต์ไดรฟ์ข้อมูลโฮสต์เพื่อที่ว่าข้อมูลจะยังคงอยู่ในโฮสต์ของนักเทียบท่าหรืออาจใช้คอนเทนเนอร์ เก็บข้อมูล (/ var / lib / mysql) นอกจากนี้ฉันยังใหม่กับ mysql ดังนั้นนี่อาจไม่ได้มีประสิทธิภาพมากนัก ที่กล่าวว่า ...

ฉันคิดว่าอาจมีปัญหาเล็กน้อยที่นี่ Dockerfile ใช้เพื่อสร้างภาพ คุณต้องดำเนินการขั้นตอนการสร้าง อย่างน้อยที่สุดจากไดเรกทอรีที่มีไฟล์ Dockerfile คุณจะต้องทำสิ่งต่อไปนี้

docker build .

Dockerfile อธิบายภาพที่จะสร้าง ฉันไม่รู้มากเกี่ยวกับ mysql (ฉันเป็นแฟนตัวยง postgres) แต่ฉันค้นหารอบ interwebs สำหรับ 'ฉันจะเริ่มต้น 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 )

นี่คือไฟล์ / 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 พร้อมกับไดเรกทอรีไฟล์) จากนั้นฉันก็เรียกใช้คำสั่ง:

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
เฮ้แกรี่ขอบคุณมากที่ช่วยฉันก่อน ฉันทำตามคำแนะนำของคุณแล้ว แต่เมื่อฉันเรียกใช้งานนักสร้าง - ไม่มีแคช ฉันมีข้อผิดพลาดในการอนุญาตสำหรับ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 ของฉัน แต่ฉันพบปัญหาในการทำงานนี้หลังจากทำ Googling และทำตามตัวอย่างของผู้อื่น นี่คือวิธีที่ฉันจะแก้ไขมัน

1) ทิ้ง MySQL schema ของคุณไปยังไฟล์

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

2) ใช้คำสั่ง ADD เพื่อเพิ่มไฟล์สคีมาของคุณไปยัง/docker-entrypoint-initdb.dไดเรกทอรีในคอนเทนเนอร์ Docker docker-entrypoint.shไฟล์จะเรียกใช้ไฟล์ใด ๆ ในไดเรกทอรีนี้ลงท้ายด้วย".sql"กับฐานข้อมูลของ 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) เริ่มต้นอินสแตนซ์ Docker MySQL

docker-compose build
docker-compose up

ขอขอบคุณการตั้งค่า MySQL และการนำเข้าการถ่ายโอนข้อมูลภายใน Dockerfileสำหรับการแย่งฉันใน docker-entrypoint.sh และความจริงที่ว่ามันรันทั้ง SQL และเชลล์สคริปต์!


2
นี่คือคำตอบที่ดีกว่าแน่นอน การคัดลอก DDLs และสคริปต์เริ่มต้นไปยังไดเร็กทอรี /docker-entrypoint-initdb.d คือสิ่งที่ docer dockerhub mysql พูดกับสิ่งต่าง ๆ
chacewells

2
จะเกิดอะไรขึ้นเมื่อสิ่งที่เปลี่ยนแปลงschema.sql? ฉันต้องการ db ของฉันที่จะปรับปรุงตาม นอกจากนี้จะเกิดอะไรขึ้นเมื่อฉันสร้างคอนเทนเนอร์นี้เป็นครั้งที่สอง db จะถูกทำลายและสร้างอีกครั้งหรือไม่
Goga Koreli

1
@Goga Koreli Docker รันคำสั่ง init นี้เฉพาะในกรณีที่ไม่มีการป้อนข้อมูลใน / var / lib / mysql
medTech

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

อีกวิธีง่าย ๆ ให้ใช้นักเทียบท่าเขียนด้วยบรรทัดต่อไปนี้:

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

23

หลังจากวันที่ 4 สิงหาคม 2015 หากคุณใช้อิมเมจอย่างเป็นทางการของ mysql Docker คุณสามารถเพิ่ม / คัดลอกไฟล์ลงในไดเรกทอรี /docker-entrypoint-initdb.d/ และจะเริ่มต้นด้วยคอนเทนเนอร์ ดู github: https://github.com/docker-library/mysql/commit/14f165596ea8808dfeb2131f092aabe61c967225หากคุณต้องการนำไปใช้กับภาพคอนเทนเนอร์อื่น ๆ


1
นี่เป็นคำตอบที่ถูกต้องสำหรับอิมเมจ Docker MSQL รุ่นปัจจุบัน
NaN

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

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เพื่อดูข้อความแสดงข้อผิดพลาดหากคุณพบปัญหา
mainframer

ฉันไม่สามารถหาเส้นทางที่/tmp/to_be_imported.mysqlมาจาก เป็นเส้นทางบนโฮสต์ระบบปฏิบัติการหรือไม่ อยู่ที่ไหนCOPYหรือADDจะนำสิ่งต่าง ๆ ลงในระบบไฟล์ของคอนเทนเนอร์?
แรนดี้ L

@ the0ther คุณไม่ต้องการCOPY/ ADDเนื่องจาก / โฮสต์ / tmp โฮสต์ติดตั้งที่ / tmp ของคอนเทนเนอร์ -v /tmp:/tmpมองอย่างใกล้ชิดในคำสั่งมีเป็นส่วนหนึ่ง โดยส่วนตัวแล้วฉันจะไม่เมานต์โวลุ่มเพื่อให้ไฟล์พร้อมใช้งานในคอนเทนเนอร์ แต่ฉันคิดว่ามันเป็นตัวเลือกส่วนบุคคล
Willa

1
เพื่อความเป็นธรรมคุณไม่ควรใช้ภาพที่ไม่เป็นทางการเว้นแต่คุณจะต้องการให้เรื่องนี้เกิดขึ้นอีกครั้ง
Dragas

3

สำหรับสิ่งที่ไม่ต้องการสร้างสคริปต์จุดเข้าใช้งานเช่นฉันคุณสามารถเริ่ม mysqld ที่ build-time จากนั้นเรียกใช้คำสั่ง mysql ใน Dockerfile ของคุณดังนี้:

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

ด้านล่างนี้เป็น Dockerfile ที่ฉันใช้ในการติดตั้ง xampp สำเร็จสร้าง MariaDB ด้วยแบบแผนและเติมข้อมูลไว้ล่วงหน้าด้วยข้อมูลที่ใช้บนเซิร์ฟเวอร์ท้องถิ่น (usrs คำสั่งรูป ฯลฯ )

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

หลังจากต่อสู้กันเล็กน้อยแล้วลองดู Dockerfile โดยใช้โวลุ่มที่มีชื่อ (db-data) มันเป็นเรื่องสำคัญที่จะต้องประกาศให้ทราบถึงการเพิ่มที่ส่วนท้ายซึ่งฉันกล่าวถึงปริมาณนั้น[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.