Làm cách nào tôi có thể khởi tạo cơ sở dữ liệu MySQL với lược đồ trong bộ chứa Docker?


165

Tôi đang cố gắng tạo một thùng chứa với cơ sở dữ liệu MySQL và thêm một lược đồ vào các cơ sở dữ liệu này.

Dockerfile hiện tại của tôi là:

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

Để tạo vùng chứa, tôi làm theo tài liệu được cung cấp trên Docker và thực hiện lệnh này:

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

Nhưng khi tôi thực thi lệnh này, Container không được tạo và trong trạng thái Container, có thể thấy rằng CMD không được thực thi thành công, thực tế chỉ có mysqllệnh được thực thi.

Dù sao, có cách nào để khởi tạo cơ sở dữ liệu với lược đồ hay tôi cần thực hiện các thao tác này một cách thủ công?


Tôi giả sử rằng bạn muốn tạo một hình ảnh mới với cơ sở dữ liệu đã được khởi tạo và sẵn sàng hoạt động?
Greg

Vâng, đó là chính xác những gì tôi muốn làm.
Marcus Gomes


Giải thích ở đây nữa: Medium.com/@lvthillo/ từ
lvthillo

Câu trả lời:


105

Tôi xin lỗi vì câu trả lời siêu dài này, nhưng, bạn có một cách nhỏ để đi đến nơi bạn muốn. Tôi sẽ nói rằng thông thường bạn sẽ không đặt bộ lưu trữ cho cơ sở dữ liệu vào cùng một bộ chứa với cơ sở dữ liệu, bạn sẽ gắn một khối lượng máy chủ để dữ liệu vẫn tồn tại trên máy chủ docker, hoặc, có lẽ một container có thể được sử dụng để giữ dữ liệu (/ var / lib / mysql). Ngoài ra, tôi chưa quen với mysql, vì vậy, điều này có thể không siêu hiệu quả. Mà nói...

Tôi nghĩ rằng có thể có một vài vấn đề ở đây. Dockerfile được sử dụng để tạo một hình ảnh. Bạn cần thực hiện bước xây dựng. Tối thiểu, từ thư mục chứa Dockerfile, bạn sẽ làm một cái gì đó như:

docker build .

Dockerfile mô tả hình ảnh để tạo. Tôi không biết nhiều về mysql (Tôi là một fanboy hậu kỳ), nhưng, tôi đã thực hiện một tìm kiếm xung quanh các interwebs để 'làm thế nào để tôi khởi tạo một container docker mysql'. Đầu tiên tôi tạo một thư mục mới để làm việc, tôi gọi nó là mdir, sau đó tôi tạo một thư mục tệp mà tôi đã gửi một tệp epcis_schema.sql tạo cơ sở dữ liệu và một bảng duy nhất:

create database test;
use test;

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

Sau đó, tôi đã tạo một tập lệnh có tên init_db trong thư mục tập tin:

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

(hầu hết các tập lệnh này đã được gỡ bỏ từ đây: https://gist.github.com/pda/9697520 )

Đây là tập tin / run_db script mà tôi đã tạo:

# 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

Cuối cùng, Dockerfile để ràng buộc tất cả:

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"

Vì vậy, tôi đã gửi thư mục mdir của mình (có Dockerfile cùng với thư mục tệp). Sau đó tôi chạy lệnh:

docker build --no-cache .

Bạn sẽ thấy đầu ra như thế này:

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

Bây giờ bạn có một hình ảnh '7f6d5215fe8d'. Tôi có thể chạy hình ảnh này:

docker run -d 7f6d5215fe8d

và hình ảnh bắt đầu, tôi thấy một chuỗi ví dụ:

4b377ac7397ff5880bc9218abe6d7eadd49505d50efb5063d6fab796ee157bd3

Sau đó tôi có thể 'dừng lại' và khởi động lại nó.

docker stop 4b377
docker start 4b377

Nếu bạn nhìn vào nhật ký, dòng đầu tiên sẽ chứa:

docker logs 4b377

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

Sau đó, ở phần cuối của bản ghi:

Running with existing database in /var/lib/mysql

Đây là các thông báo từ tập lệnh / tmp / run_db, thông báo đầu tiên cho biết cơ sở dữ liệu đã được giải nén từ phiên bản đã lưu (ban đầu), cơ sở thứ hai chỉ ra rằng cơ sở dữ liệu đã có sẵn, vì vậy bản sao hiện có đã được sử dụng.

Đây là một ls -lR của cấu trúc thư mục tôi mô tả ở trên. Lưu ý rằng init_db và run_db là các tập lệnh với tập bit thực thi:

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
Này Gary, đầu tiên cảm ơn vì đã giúp tôi. Tôi đã làm theo hướng dẫn của bạn, nhưng khi tôi thực hiện docker build --no-cache. , Tôi có một lỗi cho phép cho init_dbkịch bản.
Marcus Gomes

Tôi đã cố gắng khắc phục điều đó bằng cách cấp quyền trong RUNlệnh và vấn đề rõ ràng đã được giải quyết. Nhưng sau đó khi tôi thực thi docker runtôi có cùng một vấn đề với run_dbkịch bản.
Marcus Gomes

1
init_db và run_db cần phải có quyền 0755 (chúng là tập lệnh, chúng cần phải có tập bit thực thi. Thực hiện chmod + x init_db run_db
Greg

Tôi đã cập nhật câu trả lời với một danh sách thư mục hiển thị các quyền trên mỗi tệp. Lưu ý: chmod + x files / * _ db sẽ thực hiện các quyền cần thiết.
Greg

2
@Greg Tôi đã thử các bước trên tuy nhiên tôi đang gặp lỗi ([LRI] Lỗi nghiêm trọng: Vui lòng đọc phần "Bảo mật" trong hướng dẫn để tìm hiểu cách chạy mysqld với quyền root!). Bất kỳ đề xuất ?
Binish John

121

Tôi đã gặp vấn đề tương tự khi tôi muốn khởi tạo lược đồ MySQL Docker của tôi, nhưng tôi gặp khó khăn khi làm việc này sau khi thực hiện một số Google và làm theo các ví dụ của người khác. Đây là cách tôi giải quyết nó.

1) Kết xuất lược đồ MySQL của bạn vào một tệp.

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

2) Sử dụng lệnh ADD để thêm tệp lược đồ của bạn vào /docker-entrypoint-initdb.dthư mục trong bộ chứa Docker. Các docker-entrypoint.shtập tin sẽ chạy bất kỳ tập tin trong thư mục này kết thúc với ".sql"chống lại cơ sở dữ liệu 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) Khởi động phiên bản Docker MySQL.

docker-compose build
docker-compose up

Nhờ thiết lập MySQL và nhập kết xuất trong Dockerfile để gợi ý cho tôi về docker-entrypoint.sh và thực tế là nó chạy cả SQL và shell script!


2
Đây chắc chắn là câu trả lời tốt hơn. Sao chép DDL và tập lệnh khởi tạo vào thư mục /docker-entrypoint-initdb.d là những gì tài liệu myser của dockerhub nói để làm với những điều đó.
chacewells

2
Điều gì xảy ra khi một cái gì đó thay đổi trong schema.sql? Tôi muốn db của tôi được cập nhật tương ứng. Ngoài ra điều gì xảy ra khi tôi xây dựng container này lần thứ hai? Db sẽ bị phá hủy và tạo lại?
Goga Koreli

1
@Goga Koreli Docker chỉ chạy lệnh init này nếu không có mục nhập dữ liệu trong / var / lib / mysql
medTech

38

Một cách khác dựa trên sự hợp nhất các phản hồi của máy chủ ở đây trước đây:

tập tin docker-compose:

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

trong đó /home/user.. là một thư mục được chia sẻ trên máy chủ

Và trong /home/user/db/mysql/initthư mục .. chỉ cần thả một tệp sql, với bất kỳ tên nào, ví dụ init.sqlcó chứa:

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

Theo tài liệu chính thức của mysql , bạn có thể đặt nhiều hơn một tệp sql vào docker-entrypoint-initdb.d, chúng được thực hiện theo thứ tự bảng chữ cái


28

Một cách đơn giản khác, sử dụng docker-compose với các dòng sau:

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

Đặt lược đồ cơ sở dữ liệu của bạn vào ./database/install_db.sql. Mỗi khi bạn xây dựng vùng chứa của mình, install_db.sql sẽ được thực thi.


26

Tôi đã thử câu trả lời của Greg không thành công, tôi chắc chắn đã làm gì đó sai vì cơ sở dữ liệu của tôi không có dữ liệu sau tất cả các bước: Tôi đang sử dụng hình ảnh mới nhất của MariaDB, chỉ trong trường hợp.

Sau đó, tôi quyết định đọc điểm vào cho hình ảnh MariaDB chính thức và sử dụng nó để tạo một tệp soạn thảo docker đơn giản :

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"

Bây giờ tôi có thể duy trì dữ liệu của mình VÀ tạo cơ sở dữ liệu bằng lược đồ của riêng tôi!


1
Xin chào, tôi cũng đang cố gắng làm điều tương tự, nhưng kịch bản không bao giờ được thực thi. Có bất kỳ tham số nào khác cần được cung cấp? Tôi vừa thêm tập này cho mariadb - ./database/schema.sql:/docker-entrypoint-initdb.d/schema.sql:ro. Cảm ơn
bilak

Lưu ý: tập lệnh sẽ chỉ được thực thi một lần, trong quá trình khởi tạo vùng chứa. Nếu sau này bạn thêm một tập lệnh mới thì nó sẽ không được thực thi.
ALex_hha

23

Sau ngày 4 tháng 8 năm 2015, nếu bạn đang sử dụng hình ảnh Docker chính thức của mysql, bạn chỉ cần THÊM / SAO một tệp vào thư mục /docker-entrypoint-initdb.d/ và nó sẽ chạy với vùng chứa được khởi tạo. Xem github: https://github.com/docker-l Library / mysql / common / 14f165596ea8808dfeb2131f092aabe61c967225 nếu bạn muốn triển khai nó trên các hình ảnh chứa khác


1
Đây là câu trả lời chính xác cho các phiên bản hiện tại của hình ảnh MSQL Docker chính thức.
NaN

11

Giải pháp đơn giản nhất là sử dụng tutum / mysql

Bước 1

docker pull tutum/mysql:5.5

Bước 2

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

Bước 3

Nhận trên CONTAINER_ID và sau đó thực hiện lệnh docker logsđể xem thông tin mật khẩu được tạo.

docker logs #<CONTAINER_ID>

Bạn đã nhận được điều này để chạy thành công? Tôi đã đấu tranh với tutum / mysql trong nhiều tuần nhưng không thành công.
Iammesol

2
Đúng. Tôi sử dụng tutum/mysql:5.5và nó đã thành công. docker run -d -p 3306:3306 -v /tmp:/tmp -e MYSQL_PASS="admin" -e STARTUP_SQL="/tmp/mysqldump.mysql" tutum/mysql:5.5. Bạn luôn có thể thực thi lệnh docker logs CONTAINER_IDđể xem các thông báo lỗi nếu bạn gặp sự cố.
máy tính lớn

tôi không thể tìm ra con đường /tmp/to_be_imported.mysqlđến từ đâu. đó có phải là một đường dẫn trên hệ điều hành máy chủ không? một COPYhoặc ADDđể đặt mọi thứ vào hệ thống tập tin của container?
Randy L

@ the0ther bạn không cần COPY/ ADDvì / thư mục máy chủ / tmp được gắn vào / tmp của container. Nhìn kỹ vào lệnh có phần -v /tmp:/tmp. Cá nhân tôi sẽ không gắn một khối lượng đơn giản để làm cho tập tin có sẵn cho container nhưng tôi đoán đó là một lựa chọn cá nhân.
Willa

1
Để công bằng, bạn không nên sử dụng hình ảnh không chính thức, trừ khi bạn muốn điều này xảy ra một lần nữa.
Dragas

3

Đối với những người không muốn tạo tập lệnh entrypoint như tôi, bạn thực sự có thể bắt đầu mysqld tại thời điểm xây dựng và sau đó thực thi các lệnh mysql trong Dockerfile của bạn như vậy:

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

Chìa khóa ở đây là gửi mysqld_safe đến nền với một &dấu hiệu duy nhất .


1

Dưới đây là Dockerfile tôi đã sử dụng thành công để cài đặt xampp, tạo MariaDB với lược đồ và được điền trước với thông tin được sử dụng trên máy chủ cục bộ (đơn đặt hàng, ảnh, v.v.)

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

Sau khi đấu tranh một chút với điều đó, hãy xem Dockerfile bằng cách sử dụng các khối lượng được đặt tên (dữ liệu db). Điều quan trọng là tuyên bố một điểm cộng ở phần cuối cùng, trong đó tôi đã đề cập đến khối lượng đó là[external]

Tất cả đều hoạt động tuyệt vời theo cách này!

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.