Wie setze ich eine Mongo-Datenbank mit Docker-Compose?

77

Ich versuche, eine Reihe verbundener Anwendungen zu verteilen, die in mehreren verknüpften Containern ausgeführt werden. Dazu gehört eine Mongo-Datenbank, die Folgendes benötigt:

  • verteilt werden, die einige Startdaten enthalten;
  • Benutzer können zusätzliche Daten hinzufügen.

Im Idealfall werden die Daten auch in einem verknüpften Datenvolumencontainer gespeichert.

Ich kann die Daten mongomithilfe einer mongoBasisinstanz, die keine Volumes bereitstellt (Dockerhub-Image: psychemedia/mongo_nomount- Dies ist im Wesentlichen die Basis-Mongo-Docker-Datei ohne die VOLUME /data/dbAnweisung), und einer DockerfileKonfiguration in der folgenden Richtung in den Container übertragen :

ADD . /files
WORKDIR /files
RUN mkdir -p /data/db && mongod --fork --logpath=/tmp/mongodb.log && sleep 20 && \
mongoimport  --db testdb --collection testcoll  --type csv --headerline --file ./testdata.csv  #&& mongod --shutdown

wo ./testdata.csvbefindet sich im selben Verzeichnis ( ./mongo-with-data) wie die Docker-Datei.

Meine Docker-Compose-Konfigurationsdatei enthält Folgendes:

mongo:
  #image: mongo
  build: ./mongo-with-data
  ports:
    - "27017:27017"
  #Ideally we should be able to mount this against a host directory
  #volumes:
  #  - ./db/mongo/:/data/db
  #volumes_from:
  #  - devmongodata

#devmongodata:
#    command: echo created
#    image: busybox
#    volumes: 
#       - /data/db

Wann immer ich versuche, ein VOLUME zu mounten, scheint es, als ob die ursprünglichen gesetzten Daten - die in gespeichert sind /data/db- gelöscht werden. Ich denke, wenn ein Volume darauf gemountet wird, /data/dbersetzt es alles, was gerade vorhanden ist.

Der Docker-Benutzerleitfaden schlägt jedoch Folgendes vor: Volumes werden beim Erstellen eines Containers initialisiert. Wenn das Basis-Image des Containers Daten am angegebenen Einhängepunkt enthält, werden diese vorhandenen Daten bei der Volume-Initialisierung in das neue Volume kopiert . Ich habe also erwartet, dass die Daten bestehen bleiben, wenn ich den Befehl VOLUME nach dem Seeding- RUNBefehl platziere.

Also, was mache ich falsch?

Die lange Sicht ist, dass ich den Build mehrerer verknüpfter Container automatisieren und dann eine Vagrantfile/ docker-compose YAML-Datei verteilen möchte, die eine Reihe verknüpfter Apps startet, die eine vorab gesetzte mongoDatenbank mit einer (teilweise vorab ausgefüllten) Datenbank enthält ) persistenter Datencontainer.

Psychemedien
quelle
Ich denke, was ich in der Erstellungsphase tun möchte, ist, den Datenbankcontainer auf einen neuen Datenvolumencontainer zu mounten, sodass die Daten im Datenbankcontainerverzeichnis in das Datenvolumen eingefügt werden, anstatt den Datenvolumencontainer in den Datenbankcontainer zu mounten. Das überschreibt die Daten, die ich gerade importiert habe.
Psychemedia
Nachdem ich einen Datenvolumencontainer mit ursprünglich gesetzten Daten eingerichtet habe, kann ich den ursprünglichen Datenbankcontainer zerstören und dann einfach einen einfachen Mongodb-Container mit dem Datenvolumencontainer für den Endbenutzer verbinden. Das Herzstück der ursprünglichen Frage lautet nun: Was ist der einfachste Weg, einen Datenvolumencontainer zu erstellen und zu füllen, mit dem ein Mongod-Container eine Verbindung herstellen könnte?
Psychemedia
Mit Railsich benutzedocker-compose run container_name rake db:seed
albttx
Wenn die Verwendung von Docker-Compose nicht erforderlich ist, können Sie ein abgeleitetes Mongo-Image erstellen, das die Datenbank einschließlich der Startdaten bei der Initialisierung konfiguriert. Diese Lösung funktioniert gut für mich.
Steve Tarver

Antworten:

107

Ich mache das mit einem anderen Docker-Container, dessen einziger Zweck darin besteht, Mongo zu säen und dann zu verlassen. Ich vermute, dass dies die gleiche Idee ist wie die von ebaxt , aber als ich nach einer Antwort darauf suchte, wollte ich nur ein schnelles und schmutziges, aber unkompliziertes Beispiel sehen. Also hier ist meins:

docker-compose.yml

mongodb:
  image: mongo
  ports:
    - "27017:27017"

mongo-seed:
  build: ./mongo-seed
  links:
    - mongodb

# my webserver which uses mongo (not shown in example)
webserver:
  build: ./webserver
  ports:
    - "80:80"
  links:
    - mongodb

Mongo-Seed / Dockerfile

FROM mongo

COPY init.json /init.json
CMD mongoimport --host mongodb --db reach-engine --collection MyDummyCollection --type json --file /init.json --jsonArray

mongo-seed / init.json

[
  {
    "name": "Joe Smith",
    "email": "[email protected]",
    "age": 40,
    "admin": false
  },
  {
    "name": "Jen Ford",
    "email": "[email protected]",
    "age": 45,
    "admin": true
  }
]
Jeff Fairley
quelle
1
Was sind die Vor- und Nachteile der Verwendung eines externen Dockers zum Säen?
Augustin Riedinger
4
Ich ziehe es vor, die Dinge getrennt und einfach zu halten, und ich habe festgestellt, dass dies normalerweise die größte Flexibilität bietet ... Zum Beispiel ... wenn ich etwas in meiner Seed-Datei ändern möchte, muss ich es erneut erstellen. Wenn mein Startwert dasselbe Image wie meine laufende Mongo-Instanz wäre, würde ich meine Mongo-Daten aufgrund des Zurücksetzens verlieren. Natürlich könnte ich exportieren und importieren, aber das ist mehr Arbeit.
Jeff Fairley
1
Sind Sie auf Probleme gestoßen, bei denen Sie Ihre Datenbank mehrmals in verschiedenen Läufen gesät haben?
Vasif
1
@ Vasif, eigentlich habe ich das gesehen. Ich habe jedoch nie herausgefunden, warum es passiert. Meine Seed-Datei erstellt sogar eine eindeutige Einschränkung, die durch ein zweites Importieren von Daten verletzt werden sollte, die Daten jedoch weiterhin eingehen ... Es ist ein Head-Scratcher.
Jeff Fairley
7
Camilo: Das Problem kann sein, dass die Datenbank im Mongodb-Container beim Starten von Mongo-Seed nicht vollständig gestartet wurde. Ich würde ein "abhängiges_on: mongodb" in die mongo-seed-Konfiguration einfügen. Dies wartet jedoch nur auf den Start des Mongodb-Containers, nicht auf die eigentliche Datenbank. Ein Befehl "restart: on-fail" in der Mongo-Seed-Konfiguration veranlasst es erneut, wenn die Datenbank nicht verfügbar ist. Ich habe es drei- oder viermal versucht, bevor die Datenbank verfügbar ist.
k7n4n5t3w4rt
15

Ich habe festgestellt, dass es nützlich ist, benutzerdefinierte Docker-Images und Volumes zu verwenden, anstatt einen weiteren Container für das Seeding zu erstellen.

Dateistruktur

.
├── docker-compose.yml
├── mongo
│   ├── data
│   ├── Dockerfile
│   └── init-db.d
│       └── seed.js

Jeder in Dockerfile/ erwähnte Dateispeicherort docker-compose.ymlist relativ zum Speicherort vondocker-compose.yml

DOCKERFILE

FROM mongo:3.6

COPY ./init-db.d/seed.js /docker-entrypoint-initdb.d

docker-compose.yml

version: '3'

services:
  db:
    build: ./mongo
    restart: always
    volumes:
      - ./mongo/data:/data/db #Helps to store MongoDB data in `./mongo/data`
    environment:
      MONGO_INITDB_ROOT_USERNAME: {{USERNAME}}
      MONGO_INITDB_ROOT_PASSWORD: {{PWD}}
      MONGO_INITDB_DATABASE: {{DBNAME}}

seed.js

// Since Seeding in Mongo is done in alphabetical order... It's is important to keep
// file names alphabetically ordered, if multiple files are to be run.

db.test.drop();
db.test.insertMany([
  {
    _id: 1,
    name: 'Tensor',
    age: 6
  },
  {
    _id: 2,
    name: 'Flow',
    age: 10
  }
])

docker-entrypoint-initdb.dkann zum Erstellen verschiedener Benutzer und Dinge verwendet werden, die mit der Mongodb-Administration zu tun haben. Erstellen Sie einfach ein alphabetisch geordnetes, benanntes js-Skript, umcreateUser ...

Weitere Informationen zum Anpassen des MongoDB Docker-Dienstes finden Sie hier

Es ist auch gut, Ihre Passwörter und Benutzernamen vor Public zu schützen. Drücken Sie KEINE Anmeldeinformationen auf Public Git , sondern verwenden Sie Docker Secrets . Lesen Sie auch dieses Tutorial über Geheimnisse

Beachten Sie, dass es nicht erforderlich ist, in den Docker-Schwarm-Modus zu wechseln , um Geheimnisse zu verwenden. "Dateien erstellen" unterstützt auch Geheimnisse. Überprüfen Sie dies

Geheimnisse können auch in MongoDB Docker Services verwendet werden

Phönisx
quelle
Könnten Sie klarstellen, wo Sie dbaufgenommen werden db.test.drop();?
while1pass
1
@ while1pass Bitte überprüfen Sie docs.mongodb.com/manual/tutorial/… . Sie können Ihre eigene dbVerbindung erstellen oder die Standardverbindung verwenden, die während der Ausführung des Skripts bereitgestellt wird (ich denke, dies ist der Root-Benutzer für das Init-Skript hier).
Phoenix
5

Aktuelle Antwort basierend auf @ Jeff Fairley Antwort und aktualisiert nach neuen Docker docs

docker-compose.yml

version: "3.5"

services:
  mongo:
    container_name: mongo_dev
    image: mongo:latest
    ports:
      - 27017:27017
    networks:
      - dev

  mongo_seed:
    container_name: mongo_seed
    build: .
    networks:
      - dev
    depends_on:
      - mongo

networks:
  dev:
    name: dev
    driver: bridge

Dockerfile

FROM mongo:latest
COPY elements.json /elements.json
CMD mongoimport --host mongo --db mendeleev --collection elements --drop --file /elements.json --jsonArray

Sie müssen wahrscheinlich aktuelle Bilder neu erstellen.

while1pass
quelle
2

Hier ist eine Beschreibung, wie wir Einwegbehälter verwenden, um Bilder zu reinigen und zu säen. Https://blog.ardoq.com/dynamic-database-seeding-with-docker

ebaxt
quelle
1
Bitte teilen Sie die wichtigsten Punkte aus dem Blog-Beitrag mit, anstatt nur einen Link zu veröffentlichen. Auf diese Weise ist dies viel nützlicher.
Per Lundberg
1

Sie können das Mongo Seeding Docker-Image verwenden .

Warum?

  • Sie haben das Docker-Image bereit
  • Sie sind nicht an JSON-Dateien gebunden - JavaScript- und TypeScript-Dateien werden ebenfalls unterstützt (einschließlich optionaler Modellvalidierung mit TypeScript).

Beispiel für die Verwendung mit Docker Compose:

version: '3'
services:
  database:
    image: 'mongo:3.4.10'
    ports:
    - '27017:27017'
  api:
    build: ./api/
    command: npm run dev
    volumes: 
    - ./api/src/:/app/src/
    ports:
    - '3000:3000'
    - '9229:9229'
    links:
    - database
    depends_on:
    - database
    - data_import
    environment: 
    - &dbName DB_NAME=dbname
    - &dbPort DB_PORT=27017 
    - &dbHost DB_HOST=database
  data_import:
    image: 'pkosiec/mongo-seeding:3.0.0'
    environment:
    - DROP_DATABASE=true
    - REPLACE_ID=true
    - *dbName
    - *dbPort
    - *dbHost
    volumes:
    - ./data-import/dev/:/data-import/dev/
    working_dir: /data-import/dev/data/
    links:
    - database
    depends_on:
    - database

Haftungsausschluss: Ich bin der Autor dieser Bibliothek.

pkosiec
quelle
@psychemedia Ich habe das Beispiel für die neueste Version von Mongo Seeding aktualisiert. Viel Spaß beim Säen!
pkosiec
Unterstützt dieses Tool das Hinzufügen von Indizes und anderen Funktionen oder nur von Dokumenten? Ich habe Ihr Repo überprüft und in Dokumenten oder Beispielen keine Erwähnung gefunden.
PJH
@PJH Sorry, ich habe deinen Kommentar verpasst. Derzeit unterstützt Mongo Seeding nur Dokumente, aber Sie können
gerne
0

Sie können dieses Bild verwenden , das Docker-Container für viele Jobs (Import, Export, Dump) bereitstellt.

Schauen Sie sich das Beispiel mit Docker-Compose an

bwnyasse
quelle
0

Um meine eigene Frage zu beantworten:

  • einfache YAML-Datei zum Erstellen eines einfachen Mongo-Containers, der mit einem Datenvolumen-Container verknüpft ist, der von Vagrant Docker Compose ausgelöst wurde.
  • Code in der Vagrant-Datei wie folgt:

config.vm.provision :shell, :inline => <<-SH docker exec -it -d vagrant_mongo_1 mongoimport --db a5 --collection roads --type csv --headerline --file /files/AADF-data-minor-roads.csv SH

um die Daten zu importieren.

Verpacken Sie die Box.

Verteilen Sie die Box.

Für den Benutzer eine einfache Vagrant-Datei zum Laden der Box und Ausführen eines einfachen Docker-Compose-YAML-Skripts, um die Container zu starten und die Mongo-Datenbank gegen den Datenvolumen-Container zu mounten.

Psychemedien
quelle