Vermeiden Sie den Neuaufbau von node_modules in Elastic Beanstalk
Lesezeit: 12 Minuten
Kyrill Kay
Wir haben eine ziemlich einfache node.js-App, aber aufgrund des AWS Elastic Beanstalk-Bereitstellungsmechanismus dauert es etwa 5 Minuten, um eine neue Version (über git aws.push) auch nach einem Commit einer einzelnen Datei.
Das heißt, das Commit selbst (und das Hochladen) ist schnell (nur 1 Datei zum Pushen), aber dann holt Elastic Beanstalk das ganze Paket von S3, entpackt es und führt es aus npm install, wodurch node-gyp einige Module kompiliert. Nach der Installation/Baufertigstellung löscht Elastic Beanstalk /var/app/current und ersetzt sie durch die neue App-Version.
Unnötig zu erwähnen, dass ein ständiger Neuaufbau von node_modules nicht erforderlich ist, und ein Neuaufbau, der auf meinem alten Macbook Air 30 Sekunden dauert, dauert auf einer ec2.micro-Instanz> 5 Minuten, was keinen Spaß macht.
Ich sehe hier zwei Ansätze:
zwicken /opt/containerfiles/ebnode.py und spielen Sie mit dem Speicherort von node_modules, um zu vermeiden, dass es bei der Bereitstellung entfernt und neu erstellt wird.
Richten Sie ein Git-Repo auf der Elastic Beanstalk EC2-Instance ein und schreiben Sie die Bereitstellungsprozedur grundsätzlich selbst um, sodass /var/app/current Pushes und Runs empfängt npm install nur bei Bedarf (wodurch Elastic Beanstalk wie OpsWorks aussieht..)
Beiden Optionen mangelt es an Anmut und sie sind anfällig für Probleme, wenn Amazon seine Elastic Beanstalk-Hooks und -Architektur aktualisiert.
Vielleicht hat jemand eine bessere Idee, wie man den ständigen Neuaufbau von node_modules vermeiden kann, die bereits im App-Verzeichnis vorhanden sind? Danke schön.
Eine bessere Idee habe ich leider nicht. Ich hatte damit zu kämpfen, zusammen mit einer Liste anderer Probleme (keine Unterstützung für neuere Node-Versionen, nicht deterministische Bereitstellungsergebnisse), und am Ende ging ich stattdessen den selbstverwalteten EC2-Weg.
– Jorge Aranda
18. Januar 14 um 5:28 Uhr
Danke für deinen Beitrag. Gibt es Best Practices zur Automatisierung der Bereitstellung von node.js in EC2 über Git-Hooks und dergleichen? Was ist mit automatisierter Skalierung, Überwachung und all dem Jazz, mit dem ELB prahlt?
– Kyrill Kay
18. Januar 14 um 5:36 Uhr
Hinweis: Amazon Elastic Load Balancing (ELB) unterscheidet sich von AWS Elastic Beanstalk. Ich musste diesen Beitrag ein paar Mal erneut lesen und mich fragen, warum Sie mit dem Load Balancer herumspielen. 🙂
– Ryan Parman
18. Januar 14 um 8:30 Uhr
Mein Fehler, es ist leicht, sich in AWS-Abkürzungen zu verlieren 🙂
– Kyrill Kay
18. Januar 14 um 9:42 Uhr
Danke Kirill, es war wirklich hilfreich!
Ich teile nur meine Konfigurationsdatei für Leute, die nur die einfache Lösung für das suchen npm install. Diese Datei muss im abgelegt werden .ebextensions Ordner des Projekts, es ist leichter, da es nicht die letzte Version der Knoteninstallation enthält, und einsatzbereit.
Es überprüft auch dynamisch die installierte Knotenversion, sodass sie nicht in die Datei env.vars aufgenommen werden muss.
.ebextensions/00_deploy_npm.config
files:
"/opt/elasticbeanstalk/env.vars" :
mode: "000775"
owner: root
group: users
content: |
export NPM_CONFIG_LOGLEVEL=error
export NODE_PATH=`ls -td /opt/elasticbeanstalk/node-install/node-* | head -1`/bin
"/opt/elasticbeanstalk/hooks/appdeploy/pre/50npm.sh" :
mode: "000775"
owner: root
group: users
content: |
#!/bin/bash
. /opt/elasticbeanstalk/env.vars
function error_exit
{
eventHelper.py --msg "$1" --severity ERROR
exit $2
}
#install not-installed yet app node_modules
if [ ! -d "/var/node_modules" ]; then
mkdir /var/node_modules ;
fi
if [ -d /tmp/deployment/application ]; then
ln -s /var/node_modules /tmp/deployment/application/
fi
OUT=$([ -d "/tmp/deployment/application" ] && cd /tmp/deployment/application && $NODE_PATH/npm install 2>&1) || error_exit "Failed to run npm install. $OUT" $?
echo $OUT
"/opt/elasticbeanstalk/hooks/configdeploy/pre/50npm.sh" :
mode: "000666"
owner: root
group: users
content: |
#no need to run npm install during configdeploy
vielen Dank für Ihren Kommentar. Ja, ich denke, die meisten Leute, die nur die Wiederherstellungszeiten von npm beschleunigen möchten, werden von Ihrer Konfiguration profitieren. Ich werde es zu einer Standardantwort machen, aber falls jemand eine ausgefeiltere Lösung möchte, lesen Sie bitte meine Antwort oder besser-schneller-elastische-Beanstalk-Repo: github.com/kopurando/better-faster-elastic-beanstalk
– Kyrill Kay
23. April 14 um 16:04 Uhr
@ Tronix117 Wenn Sie dies direkt aus der Box ausführen, erhalten wir ERROR: Failed to run npm install. /usr/bin/env: node: No such file or directory Irgendeine Idee, was das verursachen könnte?
– Trugbild
11. Oktober 16 um 13:42 Uhr
@Mirage Es scheint, dass npm nicht gestartet werden kann, da der Knoten kein bekannter Befehl auf dem System ist, scheint ein PATH-Problem zu sein. Sie können es durch Ändern beheben $NODE_PATH/npm install zu $NODE_PATH/node $NODE_PATH/npm install mit der zu zwingen node binär innerhalb der $NODE_PATH starten npm
– Tronix117
11. Oktober 16 um 21:11 Uhr
Ich habe das versucht, es gab eine ganze Reihe anderer Fehler mit verweigerter Berechtigung (konnte nicht in Protokolle schreiben, hatte keinen Zugriff auf die NPM_TOKEN-Umgebungsvariable) und so weiter und so weiter. Beschlossen, das Caching vorerst zu überspringen.
– Trugbild
12. Oktober 16 um 10:04 Uhr
Bei mir ist dies mit Fehler fehlgeschlagen /usr/bin/env: node: No such file or directory, ich habe es durch Hinzufügen behoben PATH="$PATH:$NODE_PATH" in Zeile 29, eine Zeile darüber OUT=$(...).
– Benutzer12341234
14. Mai 17 um 17:55 Uhr
25/01/13 HINWEIS: Skripte wurden aktualisiert, um ein npm -g-Versions-Upgrade auszuführen (nur einmal, beim ersten Rollout oder Neuaufbau der Instanz) und um NPM-Vorgänge während der EB-Konfigurationsänderung zu vermeiden (wenn App-Verzeichnis nicht vorhanden ist, um Fehler zu vermeiden und um Beschleunigung von Konfigurationsaktualisierungen).
Okay, Elastic Beanstalk verhält sich bei den neuesten node.js-Builds (einschließlich der vermutlich unterstützten v.0.10.10) zwielichtig, also habe ich mich entschieden, weiterzumachen und EB zu optimieren, um Folgendes zu tun:
um JEDE node.js-Version gemäß Ihrer env.config zu installieren (einschließlich der neuesten, die noch nicht von AWS EB unterstützt werden)
um zu vermeiden, dass vorhandene Knotenmodule neu erstellt werden, einschließlich des In-App-Verzeichnisses node_modules
um node.js global zu installieren (und auch jedes gewünschte Modul).
Grundsätzlich verwende ich env.config, um deploy&config-Hooks durch angepasste zu ersetzen (siehe unten). Außerdem fehlen in einem standardmäßigen EB-Container-Setup einige Umgebungsvariablen ($HOME zum Beispiel) und node-gyp schlägt manchmal während des Neuaufbaus fehl (ich brauchte 2 Stunden, um libxmljs zu googeln und neu zu installieren, um dies zu beheben).
Unten sind die Dateien, die zusammen mit Ihrem Build enthalten sein müssen. Sie können sie über env.config als Inline-Code oder über einfügen source: URL (wie in diesem Beispiel)
env.vars (gewünschte Node-Version & Arch sind hier und in env.config enthalten, siehe unten)
#!/bin/bash
#source env variables including node version
. /opt/elasticbeanstalk/env.vars
function error_exit
{
eventHelper.py --msg "$1" --severity ERROR
exit $2
}
#UNCOMMENT to update npm, otherwise will be updated on instance init or rebuild
#rm -f /opt/elasticbeanstalk/node-install/npm_updated
#download and extract desired node.js version
OUT=$( [ ! -d "/opt/elasticbeanstalk/node-install" ] && mkdir /opt/elasticbeanstalk/node-install ; cd /opt/elasticbeanstalk/node-install/ && wget -nc http://nodejs.org/dist/v$NODE_VER/node-v$NODE_VER-linux-$ARCH.tar.gz && tar --skip-old-files -xzpf node-v$NODE_VER-linux-$ARCH.tar.gz) || error_exit "Failed to UPDATE node version. $OUT" $?.
echo $OUT
#make sure node binaries can be found globally
if [ ! -L /usr/bin/node ]; then
ln -s /opt/elasticbeanstalk/node-install/node-v$NODE_VER-linux-$ARCH/bin/node /usr/bin/node
fi
if [ ! -L /usr/bin/npm ]; then
ln -s /opt/elasticbeanstalk/node-install/node-v$NODE_VER-linux-$ARCH/bin/npm /usr/bin/npm
fi
if [ ! -f "/opt/elasticbeanstalk/node-install/npm_updated" ]; then
/opt/elasticbeanstalk/node-install/node-v$NODE_VER-linux-$ARCH/bin/ && /opt/elasticbeanstalk/node-install/node-v$NODE_VER-linux-$ARCH/bin/npm update npm -g
touch /opt/elasticbeanstalk/node-install/npm_updated
echo "YAY! Updated global NPM version to `npm -v`"
else
echo "Skipping NPM -g version update. To update, please uncomment 40install_node.sh:12"
fi
50npm.sh (erstellt /var/node_modules, verknüpft es symbolisch mit dem App-Verzeichnis und führt npm install aus. Sie können jedes Modul von hier aus global installieren, sie landen in /root/.npm)
#!/bin/bash
. /opt/elasticbeanstalk/env.vars
function error_exit
{
eventHelper.py --msg "$1" --severity ERROR
exit $2
}
#install not-installed yet app node_modules
if [ ! -d "/var/node_modules" ]; then
mkdir /var/node_modules ;
fi
if [ -d /tmp/deployment/application ]; then
ln -s /var/node_modules /tmp/deployment/application/
fi
OUT=$([ -d "/tmp/deployment/application" ] && cd /tmp/deployment/application && /opt/elasticbeanstalk/node-install/node-v$NODE_VER-linux-$ARCH/bin/npm install 2>&1) || error_exit "Failed to run npm install. $OUT" $?
echo $OUT
env.config (Notieren Sie auch hier die Knotenversion, und geben Sie sicherheitshalber auch die gewünschte Knotenversion in env config in der AWS-Konsole ein. Ich bin mir nicht sicher, welche dieser Einstellungen Vorrang haben wird.)
Da haben Sie es: Auf der Instanz t1.micro dauert die Bereitstellung jetzt 20–30 Sekunden statt 10–15 Minuten! Wenn Sie 10 Mal am Tag bereitstellen, sparen Sie mit dieser Optimierung 3 (drei) Wochen im Jahr. Hoffe, es hilft und besonderen Dank an die Mitarbeiter von AWS EB für mein verlorenes Wochenende 🙂
Vielen Dank, dass Sie sich die Zeit genommen haben, eine ausführliche Folge zu Ihrer eigenen Frage zu schreiben, unglaublich hilfreich!
– Elliot Chong
02.03.14 um 20:17 Uhr
Danke für das tolle Schreiben. Schnelle Klarstellung … wenn Sie sagen, “um zu vermeiden, dass vorhandene Knotenmodule neu erstellt werden, einschließlich des In-App-Verzeichnisses node_modules”, sagen Sie damit, dass Sie Ihre Anwendung node_modules zur Quellcodeverwaltung hinzugefügt haben? Danke!
– Mveermann
12. März 14 um 14:15 Uhr
Ich meinte, diese Hooks vermeiden unnötigen Neuaufbau von Binärdateien (dh Ausführen von node-gyp) innerhalb von NPM-Modulen, die global und lokal (innerhalb des App-Verzeichnisses) installiert sind. Aktualisierte Modulversionen werden weiterhin installiert und (falls erforderlich) neu erstellt, aber wenn sich seit der letzten Bereitstellung nichts in der Datei „package.json“ geändert hat, werden von NPM keine zusätzlichen Aktionen ausgeführt, und die Bereitstellung dauert weniger als eine Minute (auf der Instanz „t1.micro“). .
– Kyrill Kay
13. März 14 um 15:27 Uhr
Ich habe eine erstellt Kern damit wir das verbessern können. Ich habe –production zu npm install hinzugefügt, da keine Testframeworks auf dem Server installiert werden müssen. Außerdem wurde export NPM_CONFIG_PRODUCTION=true hinzugefügt, was dasselbe tut. Wusste nicht welche Methode besser ist
– Steve17
29. März ’14 um 20:00 Uhr
schöne Ergänzung! Ich habe meine Hooks irgendwie Open-Source gemacht, da sie immer ausgefeilter werden und ich ein öffentliches Repo brauchte, um die aktuellen Dateien für jede Instanz von Elastic Beanstalk verfügbar zu halten. Zögern Sie nicht zu forken oder mitzumachen: github.com/kopurando/better-faster-elastic-beanstalk Es ist eine gute Idee, meine Hooks für Ihre eigenen Zwecke zu forken, da ich immer wieder Dinge hinzufüge, die wahrscheinlich nur für mein eigenes Projekt benötigt werden.
– Kyrill Kay
31. März 14 um 5:26 Uhr
Es gibt ein npm-Paket, das das standardmäßige EB-Verhalten überschreibt npm install Befehl durch Abschneiden der folgenden Dateien:
Könnte besser sein, als nur das Skript von SO zu kopieren, da dieses Paket gepflegt wird und wahrscheinlich aktualisiert wird, wenn sich das EB-Verhalten ändert.
Peter
Ich habe dafür eine schnelle Lösung gefunden. Ich habe die Build-Skripte durchgesehen, die Amazon verwendet, und sie werden nur ausgeführt npm install wenn package.json vorhanden ist. Nach Ihrer ersten Bereitstellung können Sie es also ändern in _package.json und npm install läuft nicht mehr! Es ist nicht die beste Lösung, aber es ist eine schnelle Lösung, wenn Sie eine brauchen!
Ich hatte mehr als 10 Minuten Builds, als ich bereitstellen würde. Die Lösung war viel einfacher, als andere sich ausgedacht haben … Checken Sie einfach node_modules in git! Sehen http://www.futurealoof.com/posts/nodemodules-in-git.html für die begründung
Elastic Beanstalk scheint den Neuaufbau mit NPM aufzurufen. Ich weiß nicht, ob dies eine kürzliche Änderung ist, aber für kompiliertes Zeug würde das nicht wirklich helfen, soweit ich das beurteilen kann.
– Brad
23. Juli 14 um 15:02 Uhr
Dies funktioniert nicht für kompilierte Bibliotheken – Beispiel: zmq. Wenn Sie auf Mac bauen, wird es nicht auf Linux bereitgestellt. Nur etwas zu beachten.
– Brad Gunn
27. Februar 15 um 16:35 Uhr
Mein node_modules für eine einfache webpack+react+koa-App beträgt 500 MB. Bestehen. Der Schmerz, den ich durch das Remote-Dep-Management empfunden habe, könnte dies jedoch rechtfertigen.
– vaughn
20. Mai ’15 um 17:13 Uhr
Der Link ist gestorben. Das scheint bei uns gut zu funktionieren. Unsere Lösung im Detail bestand darin, 1) Module einzuschließen, die nicht über „npm install“ in .gitignore ausgeführt werden sollen, 2) diese Module in packages.json in den Abschnitt „devDependencies“ zu verschieben, 3) npm install ohne das Flag „–production“ auszuführen auf dem Deployment-Rechner, 4) Deployment auf EB
– h-kippo
29. September 15 um 10:25 Uhr
Elastic Beanstalk scheint den Neuaufbau mit NPM aufzurufen. Ich weiß nicht, ob dies eine kürzliche Änderung ist, aber für kompiliertes Zeug würde das nicht wirklich helfen, soweit ich das beurteilen kann.
– Brad
23. Juli 14 um 15:02 Uhr
Dies funktioniert nicht für kompilierte Bibliotheken – Beispiel: zmq. Wenn Sie auf Mac bauen, wird es nicht auf Linux bereitgestellt. Nur etwas zu beachten.
– Brad Gunn
27. Februar 15 um 16:35 Uhr
Mein node_modules für eine einfache webpack+react+koa-App beträgt 500 MB. Bestehen. Der Schmerz, den ich durch das Remote-Dep-Management empfunden habe, könnte dies jedoch rechtfertigen.
– vaughn
20. Mai ’15 um 17:13 Uhr
Der Link ist gestorben. Das scheint bei uns gut zu funktionieren. Unsere Lösung im Detail bestand darin, 1) Module einzuschließen, die nicht über „npm install“ in .gitignore ausgeführt werden sollen, 2) diese Module in packages.json in den Abschnitt „devDependencies“ zu verschieben, 3) npm install ohne das Flag „–production“ auszuführen auf dem Deployment-Rechner, 4) Deployment auf EB
– h-kippo
29. September 15 um 10:25 Uhr
.
6284200cookie-checkVermeiden Sie den Neuaufbau von node_modules in Elastic Beanstalkyes
Eine bessere Idee habe ich leider nicht. Ich hatte damit zu kämpfen, zusammen mit einer Liste anderer Probleme (keine Unterstützung für neuere Node-Versionen, nicht deterministische Bereitstellungsergebnisse), und am Ende ging ich stattdessen den selbstverwalteten EC2-Weg.
– Jorge Aranda
18. Januar 14 um 5:28 Uhr
Danke für deinen Beitrag. Gibt es Best Practices zur Automatisierung der Bereitstellung von node.js in EC2 über Git-Hooks und dergleichen? Was ist mit automatisierter Skalierung, Überwachung und all dem Jazz, mit dem ELB prahlt?
– Kyrill Kay
18. Januar 14 um 5:36 Uhr
Hinweis: Amazon Elastic Load Balancing (ELB) unterscheidet sich von AWS Elastic Beanstalk. Ich musste diesen Beitrag ein paar Mal erneut lesen und mich fragen, warum Sie mit dem Load Balancer herumspielen. 🙂
– Ryan Parman
18. Januar 14 um 8:30 Uhr
Mein Fehler, es ist leicht, sich in AWS-Abkürzungen zu verlieren 🙂
– Kyrill Kay
18. Januar 14 um 9:42 Uhr