MySQL kurma ve Dockerfile içinde dökümü içe aktarma


127

LAMP projem için bir Dockerfile kurmaya çalışıyorum, ancak MySQL'i başlatırken birkaç sorun yaşıyorum. Dockerfile dosyamda aşağıdaki satırlar var:

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

Ama şu hatayı alıyorum:

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

Dockerfile derlemesi sırasında veritabanı oluşturmanın nasıl kurulacağı ve içe aktarmanın nasıl aktarılacağı hakkında herhangi bir fikriniz var mı?


Bunun nedeni, her RUNkomutun farklı bir kapta yürütülmesidir. Burada iyi açıklanmıştır: stackoverflow.com/questions/17891669/…
Kuhess

Bu sadece RUN komutlarının farklı bağlamlara sahip olduğunu açıklar. Ama bir artalan sürecine bağlıyım, bağlama değil.
vinnylinux

1
Evet, ancak bu MySQL'e neden bağlanamadığınızı açıklıyor. Bunun nedeni, sadece ilk RUNsatırınızda çalışıyor olmasıdır.
Kuhess

SQL ifadelerinizi yürütmek için, MySQL'i başlatmanız ve MySQL istemcisini aynı kapsayıcıda kullanmanız gerekir: biri RUNbirkaç adımda. Bir yazılımın çok adımlı kurulumunun bir örneğini burada bulabilirsiniz: stackoverflow.com/questions/25899912/install-nvm-in-docker/…
Kuhess

Ayrıca docker-compose ile hizmete göz atabilirsiniz : docs.docker.com/compose/wordpress/#build-the-project bununla mysql uygulamanıza eklenebilir
aurny2420289

Yanıtlar:


121

A'daki her RUNkomut Dockerfilefarklı bir katmanda yürütülür ( belgelerindeRUN açıklandığı gibi ).

Gözlerinde farklı Dockerfile, üç sahip RUNtalimatları. Sorun, MySQL sunucusunun yalnızca ilkinde başlatılmasıdır. Diğerlerinde hiçbir MySQL çalışmıyor, bu yüzden mysqlistemciyle bağlantı hatası alıyorsunuz .

Bu sorunu çözmek için 2 çözümünüz var.

1.Çözüm: Tek satır kullanın 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.Çözüm: Bir komut dosyası kullanın

Çalıştırılabilir bir komut dosyası oluşturun 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

Bu satırları şuranıza ekleyin Dockerfile:

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

Bu bilgiyi nasıl saklayabileceğime dair bir fikriniz var mı? Dockerfile derlemesinde oluşturduğum veritabanları ve tablolar, konteynerler üzerinde bir şeyler çalıştırdığımda kullanılamıyor. :(
vinnylinux

1
Israrla ne demek istediğine bağlı. Verilerin birkaç docker runyürütmede kalıcı olmasını istiyorsanız , birimleri bağlamanız gerekir. Eğer sadece dökümü ile bir kapsayıcı olmasını istiyorum, ama başka modifikasyonlar devam etmek istemiyorsanız, size kurtulabilirsiniz VOLUMEGözlerinde farklı talimat Dockerfile.
Kuhess

16
Elde ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)günlükleri sonrasında Çözüm 1. çalışırken mysqld_safe Starting mysqld daemon with databases from /var/lib/mysqlvemysqld_safe mysqld from pid file /var/run/mysqld/mysqld.pid ended
Vituel

1
Başlangıçta mysql'in bir veritabanı oluşturup oluşturmadığını görmek için bir komut dosyası kontrolü yaptırmanın çok daha iyi olduğunu düşünüyorum. Varsa, bırakın, aksi takdirde mysql_init_dbveritabanı yapınızda çalıştırın ve yükleyin. Bu, test sırasında veritabanını otomatik olarak sıfırlama esnekliğine izin verir, ancak farklı veri kümelerini sürdürmesini veya test etmesini istiyorsanız, / var / lib / mysql kullanarak bir birimi bağlamanız yeterlidir docker run -v ....
tu-Reinstate Monica-dor duh

1
@trevorgrayson - Bu da işe yaramıyor. Şimdi ERROR 2003 (HY000) hatası veriyor: '127.0.0.1' (111) üzerinde MySQL sunucusuna bağlanılamıyor
Derin

166

Resmi mysql docker görüntüsünün en son sürümü , başlangıçta verileri içe aktarmanıza olanak tanır. İşte docker-compose.yml'im

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

Burada, docker/datadocker-compose'un çalıştığı klasöre göre veri-dump.sql'im var . Bu sql dosyasını /docker-entrypoint-initdb.dkonteyner üzerindeki bu dizine bağlıyorum.

Bunun nasıl çalıştığını merak ediyorsanız docker-entrypoint.sh, GitHub'da bir göz atın . Verilerin içe aktarılmasına izin vermek için bu bloğu eklediler

    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

Ek bir not, mysql kapsayıcısı durdurulduktan ve kaldırıldıktan sonra bile verilerin kalıcı olmasını istiyorsanız, docker-compose.yml'de gördüğünüz gibi ayrı bir veri kabına sahip olmanız gerekir. Veri taşıyıcısı Dockerfile'ın içeriği çok basittir.

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

VOLUME /var/lib/mysql

CMD ["true"]

Veri kabının kalıcı olması için başlangıç ​​durumunda bile olması gerekmez.


1
Bu daha iyi cevap IMHO. Kendi kendimize bir imaj yaratmamıza izin verir. Bu ipucu için teşekkürler.
Metal3d

5
- ./docker/data:/docker-entrypoint-initdb.dBirimler için küçük bir değişiklik: .- konteyner dizininin önünden kaldırıldı .
David Sinclair

7
Bu doğru prosedür olsa da, kullanım durumunu çok iyi ele almıyor. Docker'ın avantajlarından biri, bir ortamı çok hızlı bir şekilde çalıştırabilmenizdir. Docker başlatma sırasında bir MySQL DB alırken 3-4 dakika beklemeniz gerekiyorsa, bu avantajı kaybedersiniz. Amaç, veri tabanındaki verileri zaten içeren bir konteynere sahip olmaktır, böylece mümkün olan en hızlı şekilde kullanabilirsiniz.
Garreth McDaid

3
Bu cevap hala en son sürümlerle çalışıyor mu? artık işe yaramıyor gibi görünüyor
Daniel

2
Buradaki docker-compose örneğinin v2 değil v3 olduğuna dikkat edin. "volumes_from:" v3'te desteklenmez.
Ernest

37

Yaptığım şey, sql dökümümü bir "db-dump" klasörüne indirip eklemekti:

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

docker-compose upİlk kez çalıştırdığımda , döküm db'de geri yüklenir.


3
+1, bir ilaveyle
Tom Imrei

6
en son mysql, dökülen sql dosyasını yüklemiyor gibi görünüyor ve 5.6'yı kullanırken bile InnoDb depolama motorlarında sorun yaşıyorum.
2016

1
burada da aynı, böyle bir talimatı var ve günlüğe kaydetmede init dosyalarını yüklediğini gördüm, ancak db boş!
holms

11

Docker-entrypoint-initdb.d yaklaşımını kullandım (@Kuhess sayesinde) Ama benim durumumda DB'mi .env dosyasında tanımladığım bazı parametrelere göre oluşturmak istiyorum, bu yüzden bunları yaptım

1) Öncelikle docker kök proje dizinimde .env dosyasını buna benzer bir şey tanımlıyorum

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

2) Ardından docker-compose.yml dosyamı tanımlıyorum. Bu yüzden ortam değişkenlerimi tanımlamak için args direktifini kullandım ve onları .env dosyasından ayarladım

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) Daha sonra Dockerfile içeren bir mysql klasörü tanımlıyorum. Yani Dockerfile bu

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) Şimdi db'mi dökmek ve data.sql'yi mysql klasörüne koymak için mysqldump kullanıyorum

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

Dosya sadece normal bir sql dökümü dosyasıdır, ancak başlangıçta 2 satır ekliyorum, böylece dosya şöyle görünecektir

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

Öyleyse, MYSQL_DATABASEyer tutucuyu içinde ayarladığım DB'min adıyla değiştirmek için "RUN sed -i 's / MYSQL_DATABASE /' $ MYSQL_DATABASE '/ g' /etc/mysql/data.sql" komutunu kullandım .env dosyası.

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

Artık konteynerinizi oluşturmaya ve çalıştırmaya hazırsınız


.envDosya kullanma yaklaşımını seviyorum . Ancak göre bu , .envkullandığınızda dosya özellik sadece docker-compose upkomuta ve çalışmaz docker stack deploy. Bu nedenle, .envdosyayı üretimde kullanmak istemeniz durumunda , ile sunulan docker gizli dizilerine göz atmak isteyebilirsiniz docker 17.06. Sonra .env dosyanızı hem geliştirme hem de docker compose upüretim docker stack deployaşamalarında sırlarla birlikte kullanabilirsiniz
ira

Güzel bir yaklaşım ama önerdiğiniz komut yerine RUN sed -i '1s/^/CREATE DATABASE IF NOT EXISTS $ MYSQL_DATABASE ;\nUSE $ MYSQL_DATABASE kullanmanızı öneririm . Bu şekilde, sahip olduğunuz herhangi bir döküm dosyasını kullanabilirsiniz - büyük miktarda veriyle çalışıyorsanız kullanışlıdır :);\n/' data.sqlsed
Tomasz Kapłoński

9

İşte kullanarak bir çalışma versiyonudur v3arasında docker-compose.yml. Anahtar, hacimler yönergesidir:

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

Sahip olduğum dizinde , döküm dosyalarını içeren docker-compose.ymlbir datadizinim var .sql. Bu güzel çünkü .sqltablo başına bir döküm dosyasına sahip olabilirsiniz .

Ben sadece koşarım docker-compose upve gitmeye hazırım. Veriler, duraklar arasında otomatik olarak kalır. Verileri kaldırmak ve yeni .sqldosyaları "emmek" istiyorsanız, docker-compose downo zaman çalıştırın docker-compose up.

mysqlDocker'ın /docker-entrypoint-initdb.d, birimi kaldırmadan dosyaları nasıl yeniden işleyeceğini bilen biri varsa , lütfen bir yorum bırakın ve bu yanıtı güncelleyeceğim.


2
bu cevap bana yardımcı oldu. docker-compose downdocker-compose uygulamasını yeniden başlatmamıza rağmen hiçbir değişiklik görmediğim için üzerindeki not çok önemliydi. MYSQL_DATABASE bu durumda gerekli bir değişkendir
nxmohamad

0

düzenleme: Buradaki soruyu yanlış anladım. Aşağıdaki cevabım, sql komutlarının konteyner oluşturma sırasında nasıl çalıştırılacağını açıklıyor , ancak OP tarafından istenen görüntü oluşturma zamanında değil .

Kuhess'in kabul ettiği yanıtı pek sleep 5sevmiyorum çünkü mysql db arka plan programının bu zaman çerçevesinde doğru şekilde yüklendiğini varsaydığı için bana biraz hilekâr geliyor. Bu bir varsayım, garanti yok. Ayrıca, sağlanan bir mysql docker görüntüsünü kullanırsanız, görüntünün kendisi sunucuyu başlatmaya zaten özen gösterir; Ben buna bir gelenekle karışmam /usr/bin/mysqld_safe.

Buradaki diğer cevapları takip ettim /docker-entrypoint-initdb.d/ve mysql görüntü sağlayıcısı tarafından açıkça amaçlanan yol olduğu için bash ve sql betiklerini docker container içindeki klasöre kopyaladım . Bu klasördeki her şey, db arka plan programı hazır olduğunda çalıştırılır, dolayısıyla ona güvenebilmelisiniz.

Diğerlerine ek olarak - başka hiçbir cevap bundan açıkça bahsetmediğinden: sql betiklerinin yanı sıra, bash betiklerini bu klasöre kopyalayabilirsiniz, bu da size daha fazla kontrol sağlayabilir.

Örneğin, bir dökümü içe aktarmam gerektiğinden ihtiyacım olan şey buydu, ancak döküm tek başına yeterli değildi çünkü hangi veritabanına içe aktarılması gerektiğini sağlamıyordu. Benim durumumda db_custom_init.shbu içeriğe sahip bir komut dosyam var:

mysql -u root -p$MYSQL_ROOT_PASSWORD -e 'create database my_database_to_import_into'
mysql -u root -p$MYSQL_ROOT_PASSWORD my_database_to_import_into < /home/db_dump.sql

ve bu Dockerfile bu betiği kopyalıyor:

FROM mysql/mysql-server:5.5.62
ENV MYSQL_ROOT_PASSWORD=XXXXX
COPY ./db_dump.sql /home/db_dump.sql
COPY ./db_custom_init.sh /docker-entrypoint-initdb.d/
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.