26

Ich habe viele Beispiele für die Erstellung von Docker-Containern für Rails-Anwendungen gesehen. In der Regel führen sie einen Rails-Server aus und haben einen CMD, der Migrationen/Setup ausführt und dann den Rails-Server aufruft.Ausführen von Migrationen mit Rails in einem Docker-Container mit mehreren Containerinstanzen

Wenn ich 5 dieser Container zur gleichen Zeit spawne, wie behandelt Rails mehrere Prozesse, die versuchen, die Migrationen zu initiieren? Ich kann sehen, Rails die aktuelle Schemaversion in dem allgemeinen Abfrage Protokoll überprüft hat (es ist eine MySQL-Datenbank):

SELECT `schema_migrations`.`version` FROM `schema_migrations` 

Aber ich kann eine Race-Bedingung hier sehen, ob dies auf verschiedene Rails Instanzen zur gleichen Zeit passiert.

Wenn man bedenkt, dass DDL in MySQL nicht transaktional ist und ich keine Sperren im allgemeinen Abfrageprotokoll während der Ausführung von Migrationen sehe (abgesehen von den pro-Migration-Transaktionen), würde es scheinen, dass sie parallel ausgeführt werden eine schlechte Idee. In der Tat, wenn ich dies dreimal lokal abbringe, kann ich zwei der Schienen-Instanzen beim Versuch, eine Tabelle zu erstellen, abstürzen sehen, weil sie bereits existiert, während die dritte Schienen-Instanz die Migrationen glücklicherweise abschließt. Wenn dies eine Migration wäre, die etwas in die Datenbank einfügt, wäre das ziemlich unsicher.

Ist es dann eine bessere Idee, einen einzelnen Container auszuführen, der Migrationen/Setup ausführt und dann zum Beispiel eine Unicorn-Instanz erzeugt, die wiederum mehrere Rails-Workers hervorbringt?

Sollte ich N Rails Container und einen "Migrationscontainer" generieren, der die Migration ausführt, wird die Migration beendet?

Gibt es eine bessere Option?

+0

Dies scheint relevant http://blog.carbonfive.com/2015/03/17/docker-rails-docker-compose-gether-in-your-development-workflow/ –

+0

@MaxWilliams aus dem Aussehen seiner Dockerfile es ist ein gutes Beispiel dafür, wie man das Problem unwissentlich verursacht, enthält aber keine Lösung. Sein Beispiel funktioniert gut zum Testen (aber vielleicht langsam). Ich kann nicht glauben, dass jeder einen einzigen Schienenserver in der Produktion betreibt! –

+0

Hmm yeah du hast Recht, sorry:/Es ist definitiv nicht der Fall, dass jeder einen einzigen Rails-Server in Produktion hat! Zum Beispiel haben wir drei Boxen, jede eine Amazon-Instanz, mit einigen freigegebenen Ordnern und jeder läuft 12 Monster, wir haben tatsächlich 36 Schienen Server über 3 Boxen. Wir verwenden docker tho nicht :) –

Antwort

6
docker run <container name> rake db:migrate 

Startet Sie Standard-Container-Anwendung, aber nicht das CMD (rails server) laufen, aber rake db:migrate

UPDATE: von Roman Vorgeschlagen, würde der Befehl nun sein:

docker exec <container> rake db:migrate 
+0

Der Befehl wäre jetzt "docker exec Rake db: migrate". – Roman

+4

Wenn ich mich nicht irre, führt Exec einen Befehl in einem bereits laufenden Container aus. Sie müssten also den Anwendungscontainer ohne die Migrationen starten und die Migrationen später anwenden. Dies könnte Probleme verursachen. Es wäre viel sauberer, zuerst die Migrationen anzuwenden (via run) und danach den Anwendungscontainer zu starten. Docker komponieren könnte dort helfen. – brejoc

21

Besonders mit Rails habe ich keine Erfahrung, aber schauen wir mal von einem Docker- und Software-Engineering-Standpunkt aus.

Das Docker-Team befürwortet, manchmal sehr aggressiv, dass es bei Containern um Versandanwendungen geht. Jerome Petazzoni sagt in this really great statement, dass es um die Trennung von Sorgen geht. Ich denke, das ist genau der Punkt, den Sie bereits herausgefunden haben.

Das Ausführen eines Rails-Containers, der eine Migration oder Einrichtung startet, ist möglicherweise für die Erstinstallation geeignet und wird möglicherweise während der Entwicklung häufig benötigt. Wenn Sie jedoch in Produktion gehen, sollten Sie wirklich darüber nachdenken, die Bedenken zu trennen.

Also würde ich sagen, haben Sie ein Bild, das Sie verwenden, um N-Schienen-Container ausführen und fügen Sie eine Tools/Migration/Setup was auch immer Container, die Sie für administrative Aufgaben verwenden. Werfen Sie einen Blick, was die Entwickler aus dem official rails image dazu sagen:

Es ist sowohl verwendet werden als Wegwerfbehälter (montieren Sie Ihren Quellcode und starten Sie den Container Ihrer App starten), sowie die Basis, um andere Bilder zu erstellen.

Wenn Sie sich dieses Bild ansehen, gibt es keinen Setup- oder Migrationsbefehl. Es ist völlig dem Benutzer überlassen, wie man es benutzt. Also, wenn Sie mehrere Container laufen müssen, gehen Sie einfach voran.

Aus meiner Erfahrung mit Mysql funktioniert das gut. Sie können einen reinen Datencontainer ausführen, um die Daten zu hosten, einen Container mit dem mysql-Server ausführen und schließlich einen Container für administrative Aufgaben wie Sicherung und Wiederherstellung ausführen. Für alle drei Container können Sie das gleiche Bild verwenden. Jetzt haben Sie Zugriff auf Ihre Datenbank von sagen wir mehrere Wordpress Container. Dies bedeutet eine klare Trennung der Anliegen. Wenn Sie docker-compose verwenden, ist es nicht so schwierig, all diese Container zu verwalten. Sicherlich gibt es bereits viele Third-Party-Container und Tools, die Sie auch beim Aufbau einer komplexen Anwendung aus mehreren Containern unterstützen.

Schließlich sollten Sie entscheiden, ob Docker und der Mikro-Service-Architektur für Ihr Problem richtig ist. Wie in this article dargelegt, gibt es einige Gründe dagegen. Eines der Kernprobleme ist, dass es eine ganz neue Komplexitätsebene hinzufügt. Dies ist jedoch der Fall bei vielen Lösungen und ich denke, dass Sie sich dessen bewusst sind und bereit sind, es zu vermeiden.