Thiết lập MySQL và nhập kết xuất trong Dockerfile


126

Tôi đang cố gắng thiết lập Dockerfile cho dự án LAMP của mình, nhưng tôi gặp một vài vấn đề khi khởi động MySQL. Tôi có các dòng folowing trên Dockerfile của mình:

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

Nhưng tôi cứ bị lỗi này:

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

Bạn có ý tưởng nào về cách thiết lập cơ sở dữ liệu tạo và kết xuất nhập trong quá trình xây dựng Dockerfile không?


Điều này là do thực tế là mỗi RUNlệnh được thực thi trong một thùng chứa khác nhau. Nó cũng được giải thích ở đây: stackoverflow.com/questions/17891669/
Khăn

Điều này chỉ giải thích rằng các lệnh RUN có bối cảnh khác nhau. Nhưng tôi phụ thuộc vào một daemon, không phải bối cảnh.
vinnylinux

1
Có, nhưng điều đó giải thích tại sao bạn không thể kết nối với MySQL. Đó là bởi vì, nó chỉ chạy trong RUNdòng đầu tiên của bạn .
Kuhess

Để thực thi các câu lệnh SQL của bạn, bạn cần khởi động MySQL và sử dụng máy khách MySQL trong cùng một thùng chứa: một RUNvới nhiều bước. Bạn có thể tìm thấy một ví dụ với cài đặt phần mềm gồm nhiều bước tại đây: stackoverflow.com/questions/25899912/install-nvm-in-docker/
Lỗi

Bạn cũng có thể xem dịch vụ với docker -compose: docs.docker.com/compose/wordpress/#build-the-project với điều đó, mysql có thể được đính kèm vào ứng dụng của bạn
aurny2420289

Câu trả lời:


122

Mỗi RUNlệnh trong một Dockerfileđược thực thi trong một lớp khác nhau (như được giải thích trong tài liệu củaRUN ).

Trong của bạn Dockerfile, bạn có ba RUNhướng dẫn. Vấn đề là máy chủ MySQL chỉ được khởi động trong lần đầu tiên. Trong những trường hợp khác, không có MySQL nào đang chạy, đó là lý do tại sao bạn gặp lỗi kết nối với mysqlmáy khách.

Để giải quyết vấn đề này bạn có 2 giải pháp.

Giải pháp 1: sử dụng một dòng 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

Giải pháp 2: sử dụng tập lệnh

Tạo một tập lệnh thực thi 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

Thêm những dòng này vào Dockerfile:

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

Bạn có biết làm thế nào tôi có thể duy trì thông tin đó? Các cơ sở dữ liệu và bảng tôi đang tạo trên bản dựng Dockerfile không khả dụng khi tôi chạy các công cụ trên các thùng chứa. :(
vinnylinux

1
Nó phụ thuộc vào những gì bạn có nghĩa là kiên trì. Nếu bạn muốn dữ liệu được duy trì trong một số lần docker runthực thi, bạn cần phải gắn kết khối lượng. Nếu bạn chỉ muốn có một thùng chứa với bãi chứa của mình, nhưng bạn không muốn tiếp tục sửa đổi thêm, bạn có thể thoát khỏi VOLUMEhướng dẫn trong Dockerfile.
Kuhess

16
Tôi nhận được ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)khi dùng thử Giải pháp 1. Theo dõi nhật ký mysqld_safe Starting mysqld daemon with databases from /var/lib/mysqlmysqld_safe mysqld from pid file /var/run/mysqld/mysqld.pid ended
Vituel

1
Tôi thấy tốt hơn nhiều khi kiểm tra tập lệnh khi khởi động để xem mysql đã tạo cơ sở dữ liệu chưa. Nếu có, hãy để nó một mình, nếu không thì chạy mysql_init_dbvà tải trong cấu trúc cơ sở dữ liệu của bạn. Điều này cho phép linh hoạt thiết lập lại cơ sở dữ liệu tự động khi kiểm tra, nhưng nếu bạn muốn nó tồn tại hoặc kiểm tra các bộ dữ liệu khác nhau, bạn chỉ cần gắn một ổ đĩa tại / var / lib / mysql bằng cách sử dụng docker run -v ....
tu-Tái lập Monica-dor duh

1
@trevorgrayson - Điều đó cũng không hoạt động. Bây giờ nó báo lỗi ERROR 2003 (HY000): Không thể kết nối với máy chủ MySQL vào '127.0.0.1' (111)
Sâu

166

Phiên bản mới nhất của hình ảnh docker mysql chính thức cho phép bạn nhập dữ liệu khi khởi động. Đây là docker-compose.yml của tôi

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

Ở đây, tôi có data-dump.sql bên dưới docker/dataliên quan đến thư mục mà docker-compose đang chạy. Tôi đang gắn tập tin sql đó vào thư mục này /docker-entrypoint-initdb.dtrên container.

Nếu bạn quan tâm để xem cách thức hoạt động của nó, hãy xem docker-entrypoint.shGitHub của họ . Họ đã thêm khối này để cho phép nhập dữ liệu

    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

Một lưu ý bổ sung, nếu bạn muốn dữ liệu được duy trì ngay cả sau khi bộ chứa mysql bị dừng và xóa, bạn cần phải có một bộ chứa dữ liệu riêng như bạn thấy trong docker-compose.yml. Nội dung của Dockerfile chứa dữ liệu rất đơn giản.

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

VOLUME /var/lib/mysql

CMD ["true"]

Bộ chứa dữ liệu thậm chí không phải ở trạng thái bắt đầu để duy trì.


1
Đây là câu trả lời tốt hơn IMHO. Nó cho phép KHÔNG tạo ra một hình ảnh của chúng ta. Cảm ơn vì lời khuyên này.
Metal3d

5
Một thay đổi nhỏ cho âm lượng: - ./docker/data:/docker-entrypoint-initdb.dTập trung .vào phía trước thư mục container.
David Sinclair

7
Mặc dù đây là quy trình đúng nhưng nó không giải quyết được trường hợp sử dụng rất tốt. Một trong những lợi thế của Docker là bạn có thể tạo ra một môi trường rất nhanh. Nếu bạn phải đợi 3-4 phút trong khi Docker nhập MySQL DB trong khi khởi động, bạn sẽ mất lợi thế này. Mục tiêu là có một thùng chứa đã chứa dữ liệu trong cơ sở dữ liệu, để bạn có thể sử dụng nó càng nhanh càng tốt.
Garreth McDaid

3
câu trả lời này có còn hoạt động với các phiên bản mới nhất không? dường như không còn hoạt động nữa
Daniel

2
Lưu ý rằng ví dụ soạn thảo docker ở đây là v2 chứ không phải v3. "volume_from:" không được hỗ trợ trong v3.
Ernest

37

Những gì tôi đã làm là tải xuống sql dump của tôi trong thư mục "db-dump" và gắn nó:

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

Khi tôi chạy docker-compose uplần đầu tiên, kết xuất được khôi phục trong db.


3
+1, với một bổ sung: liên kết đến tập lệnh đang được chạy để hiểu rõ hơn về những gì đang thực sự xảy ra: github.com/docker-l
Library / mediadb / blog / Lỗi

6
mới nhất mysqldường như không tải tập tin sql bị đổ và thậm chí sử dụng 5.6 tôi gặp vấn đề với các công cụ lưu trữ InnoDb.
nhấp nháy

1
Tương tự ở đây, nó có hướng dẫn như vậy và tôi thậm chí đã thấy khi đăng nhập tải tệp init, nhưng db trống!
thánh

11

Tôi đã sử dụng cách tiếp cận docker-entrypoint-initdb.d (Cảm ơn @Kuhess) Nhưng trong trường hợp của tôi, tôi muốn tạo DB của mình dựa trên một số tham số tôi đã xác định trong tệp .env vì vậy tôi đã làm những điều này

1) Đầu tiên tôi định nghĩa tệp .env giống như thế này trong thư mục dự án gốc docker của tôi

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

2) Sau đó, tôi xác định tệp docker-compose.yml. Vì vậy, tôi đã sử dụng chỉ thị args để xác định các biến môi trường của mình và tôi đặt chúng từ tệp .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) Sau đó, tôi xác định một thư mục mysql bao gồm Dockerfile. Vì vậy, Dockerfile là đây

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) Bây giờ tôi sử dụng mysqldump để kết xuất db của mình và đặt data.sql trong thư mục mysql

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

Tệp chỉ là một tệp kết xuất sql bình thường nhưng tôi thêm 2 dòng ở đầu để tệp sẽ trông như thế này

--
-- 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 ...;
...
...
...

Vì vậy, điều xảy ra là tôi đã sử dụng lệnh "RUN sed -i '/ MYSQL_DATABASE /' $ MYSQL_DATABASE '/ g' /etc/mysql/data.sql" để thay thế MYSQL_DATABASEtrình giữ chỗ bằng tên DB của tôi mà tôi đã đặt tập tin .env.

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

Bây giờ bạn đã sẵn sàng để xây dựng và chạy container của bạn


Tôi thích cách tiếp cận của việc sử dụng một .envtập tin. Tuy nhiên, theo điều này , .envtính năng tệp chỉ hoạt động khi bạn sử dụng docker-compose uplệnh và không hoạt động docker stack deploy. Vì vậy, trong trường hợp bạn muốn sử dụng .envtệp trong sản xuất, bạn có thể muốn kiểm tra các bí mật docker được giới thiệu docker 17.06. Sau đó, bạn có thể sử dụng tệp .env của mình để kết hợp với các bí mật trong cả hai giai đoạn phát triển docker compose upvà sản xuấtdocker stack deploy
ira

Cách tiếp cận đẹp nhưng tôi khuyên bạn nên sử dụng RUN sed -i '1s/^/CREATE DATABASE IF NOT EXISTS $ MYSQL_DATABASE ;\nUSE $ MYSQL_DATABASE ;\n/' data.sqlthay vì sedlệnh bạn đề xuất. Bằng cách này, bạn có thể sử dụng bất kỳ tệp kết xuất nào bạn có - thật hữu ích nếu bạn đang làm việc với lượng dữ liệu lớn :)
Tomasz Kapłoński

8

Đây là một phiên bản làm việc sử dụng v3của docker-compose.yml. Điều quan trọng là chỉ thị khối lượng :

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

Trong thư mục mà tôi có, tôi docker-compose.ymlcó một datathư mục chứa .sqlcác tệp kết xuất. Điều này là tốt bởi vì bạn có thể có một.sql tệp kết xuất trên mỗi bảng.

Tôi chỉ đơn giản là chạy docker-compose upvà tôi tốt để đi. Dữ liệu tự động tồn tại giữa các điểm dừng. Nếu bạn muốn xóa dữ liệu và "hút" các .sqltệp mới chạy docker-compose downthìdocker-compose up .

Nếu bất cứ ai biết làm thế nào để đưa mysqldocker xử lý lại các tập tin /docker-entrypoint-initdb.dmà không cần xóa âm lượng, vui lòng để lại nhận xét và tôi sẽ cập nhật câu trả lời này.


2
Câu trả lời này đã giúp tôi. lưu ý trên docker-compose downlà rất quan trọng vì tôi đã không thấy thay đổi nào mặc dù khởi động lại docker-compose. MYSQL_DATABASE là một biến bắt buộc trong trường hợp này
nxmohamad
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.