webentwicklung-frage-antwort-db.com.de

Knoten und Andockfenster - wie wird mit Babel oder TypeScript Build gearbeitet?

Ich habe eine Knotenanwendung, die ich in einem Docker-Container hosten möchte. Dieser sollte direkt sein, wie in diesem Artikel dargestellt:

https://nodejs.org/de/docs/guides/nodejs-docker-webapp/

In meinem Projekt können die Quellen jedoch nicht direkt ausgeführt werden, sie müssen aus ES6 und/oder TypeScript kompiliert werden. Ich verwende gulp, um mit babel, browserify und tsify zu bauen - mit unterschiedlichen Einstellungen für Browser und Server.

Was wäre der beste Workflow für das Erstellen von und die Automatisierung von Docker-Images in diesem Fall? Gibt es im Web Ressourcen, die einen solchen Workflow beschreiben? Soll das Dockerimage das Gebäude nach npm install ausführen, oder sollte ich ein Shell-Skript erstellen, um all dies zu tun und die Dockerfile einfach alles zusammen packen lassen?

Wenn die Docker-Datei den Build ausführen sollte, müsste das Image alle dev-Abhängigkeiten enthalten, die nicht ideal sind.

Hinweis: Ich konnte einen Docker-Container einrichten und ausführen. Dafür mussten jedoch alle Dateien installiert und erstellt werden.

16
Jørgen Tvedt

Eine mögliche Lösung besteht darin, Ihren Build-Vorgang in ein spezielles Docker-Image zu packen. Es wird oft als Builder-Image bezeichnet. Es sollte all Ihre Build-Abhängigkeiten enthalten: nodejs, npm, gulp, babel, tsc usw. Es kapselt Ihren gesamten Build-Prozess und macht die Installation dieser Tools auf dem Host überflüssig.

Zuerst führen Sie das Builder-Image aus, und hängen das Quellcode-Verzeichnis als Volume an. Dasselbe oder ein separates Volume kann als Ausgabeverzeichnis verwendet werden .. Das erste Image nimmt Ihren Code und führt alle Buildbefehle aus.

Als ersten Schritt nehmen Sie Ihren eingebauten Code und packen ihn wie gewohnt in das Docker-Image der Produktionsumgebung.

Hier ist ein Beispiel eines Docker-Builder-Images für TypeScript: https://hub.docker.com/r/sandrokeil/TypeScript/

Es ist in Ordnung, den gleichen Docker-Builder für mehrere Projekte zu verwenden, da er normalerweise als allgemeiner Wrapper für einige gängige Tools konzipiert ist .. Es ist jedoch in Ordnung, eigene Tools zu erstellen, die kompliziertere Prozeduren beschreiben.

Das Gute am Builder-Image ist, dass Ihre Host-Umgebung nicht verschmutzt ist und Sie neuere Versionen von Compiler/verschiedenen Tools/Reihenfolge/Aufgaben ändern können, indem Sie die Dockerfile Ihres Builder-Images ändern. Sie können Ihr Experiment jederzeit mit dem Build-Verfahren rückgängig machen.

9
gerichhome

Ich persönlich bevorzuge es, dev-Abhängigkeiten nach dem Ausführen von babel während des Builds zu entfernen:

FROM node:7

# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

# Install app dependencies
COPY package.json /usr/src/app/
RUN npm install

# Copy app source
COPY src /usr/src/app/src

# Compile app sources
RUN npm run compile

# Remove dev dependencies
RUN npm Prune --production

# Expose port and CMD
EXPOSE 8080
CMD [ "npm", "start" ]
9

Folge diesen Schritten:

Schritt 1: Vergewissern Sie sich, dass Ihre Abhängigkeiten von Babel innerhalb von Dependencies not dev dependencies von package.json liegen. Fügen Sie auch ein Implementierungsskript hinzu, das aus dem Ordner "node_modules" auf "babel" verweist. Sie rufen dieses Skript in Docker .__ auf. So sieht meine package.json-Datei aus

{
  "name": "tmeasy_api",
  "version": "1.0.0",
  "description": "Trade made easy Application",
  "main": "build/index.js",
  "scripts": {    
     "build": "babel -w src/ -d build/ -s inline",
    "deploy" : "node_modules/babel-cli/bin/babel.js src/ -d build/",
  },
  "devDependencies": {   
    "nodemon": "^1.9.2"
  },
  "dependencies": {    
    "babel-cli": "^6.10.1",
    "babel-polyfill": "^6.9.1",
    "babel-preset-es2015": "^6.9.0",
    "babel-preset-stage-0": "^6.5.0",
    "babel-preset-stage-3": "^6.22.0"
  }
}

build ist für Ihre Entwicklungszwecke auf Ihrem lokalen Rechner vorgesehen, und deploy wird aus Ihrer Dockerfile aufgerufen.

Schritt 2: Da wir die Babael-Transformation selbst durchführen möchten, stellen Sie sicher, dass Sie den .dockerignore mit dem Build-Ordner hinzufügen, den Sie während der Entwicklung verwenden .. _.

    build
    node_modules    

Schritt 3. Erstellen Sie Ihre Docker-Datei. Unten sehen Sie ein Beispiel meiner Docker-Datei

FROM node:6

MAINTAINER stackoverflow

ENV NODE_ENV=production
ENV PORT=3000

# use changes to package.json to force Docker not to use the cache
# when we change our application's nodejs dependencies:

ADD package.json /tmp/package.json
RUN cd /tmp && npm install
RUN mkdir -p /var/www && cp -a /tmp/node_modules /var/www

# copy current working directory into docker; but it first checks for  
# .dockerignore so build will not be included.

COPY      . /var/www/
WORKDIR   /var/www/

# remove any previous builds and create a new build folder and then
# call our node script deploy

RUN rm -f build
RUN mkdir build
RUN chmod 777 /var/www/build
RUN npm run deploy

VOLUME    /var/www/uploads
EXPOSE $PORT


ENTRYPOINT ["node","build/index.js"]
5
Derese Getachew

Die moderne Empfehlung für solche Dinge (ab Docker 17.05) ist die Verwendung eines mehrstufigen Builds . Auf diese Weise können Sie alle Ihre dev/build-Abhängigkeiten in der einen Docker-Datei verwenden, das Endergebnis jedoch optimieren und frei von unnötigem Code. 

Ich bin nicht so vertraut mit TypeScript, aber hier ist eine Beispielimplementierung, die Garn und Babel verwendet. Mit dieser Docker-Datei können wir ein Entwicklungs-Image (mit docker build --target development .) erstellen, um Nodemon, Tests usw. lokal auszuführen. aber mit einem direkten docker build . erhalten wir ein schlankes, optimiertes Produktionsimage, das die App mit pm2 ausführt.

# common base image for development and production
FROM node:10.11.0-Alpine AS base
WORKDIR /app


# dev image contains everything needed for testing, development and building
FROM base AS development
COPY package.json yarn.lock ./

# first set aside prod dependencies so we can copy in to the prod image
RUN yarn install --pure-lockfile --production
RUN cp -R node_modules /tmp/node_modules

# install all dependencies and add source code
RUN yarn install --pure-lockfile
COPY . .


# builder runs unit tests and linter, then builds production code 
FROM development as builder
RUN yarn lint
RUN yarn test:unit --colors
RUN yarn babel ./src --out-dir ./dist --copy-files


# release includes bare minimum required to run the app, copied from builder
FROM base AS release
COPY --from=builder /tmp/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json ./
CMD ["yarn", "pm2-runtime", "dist/index.js"]
4
Greg

Ich habe gerade eine großartige Seed-App für TypeScript und Node.js mit Docker veröffentlicht. 

Sie finden es auf GitHub .

Das Projekt erläutert alle Befehle, die die Docker-Datei verwendet, und kombiniert tsc mit gulp, um einige zusätzliche Vorteile zu erzielen. 

Wenn Sie das Repo nicht überprüfen möchten, finden Sie hier die Details:

Dockerfile

FROM node:8

ENV USER=app

ENV SUBDIR=appDir

RUN useradd --user-group --create-home --Shell /bin/false $USER &&\
    npm install --global tsc-watch npm ntypescript TypeScript gulp-cli

ENV HOME=/home/$USER

COPY package.json gulpfile.js $HOME/$SUBDIR/

RUN chown -R $USER:$USER $HOME/*

USER $USER

WORKDIR $HOME/$SUBDIR

RUN npm install

CMD ["node", "dist/index.js"]

docker-compose.yml

version: '3.1'

services:
  app:
    build: .
    command: npm run build
    environment:
      NODE_ENV: development
    ports:
      - '3000:3000'
    volumes:
      - .:/home/app/appDir
      - /home/app/appDir/node_modules

package.json

{
  "name": "docker-node-TypeScript",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "build": "gulp copy; gulp watch & tsc-watch -p . --onSuccess \"node dist/index.js\"",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "Stephen Gardner ([email protected])",
  "license": "ISC",
  "dependencies": {
    "express": "^4.10.2",
    "gulp": "^3.9.1",
    "socket.io": "^1.2.0"
  },
  "devDependencies": {
    "@types/express": "^4.11.0",
    "@types/node": "^8.5.8"
  }
}

tsconfig.json

{
  "compileOnSave": false,
  "compilerOptions": {
    "outDir": "./dist/",
    "sourceMap": true,
    "declaration": false,
    "module": "commonjs",
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "ES6"
  },
  "include": [
    "**/*.ts"
  ],
  "exclude": [
    "node_modules",
    "**/*.spec.ts"
  ]
}

Um mehr auf die Antwort auf Ihre Frage einzugehen, wird das ts aus dem Aufruf von docker-compose.yml-Datei von npm run build zusammengestellt, der dann tsc aufruft. tsc kopiert dann unsere Dateien in den dist-Ordner, und ein einfacher node dist/index.js-Befehl führt diese Datei aus. Anstatt nodemon zu verwenden, verwenden wir tsc-watch und gulp.watch, um auf Änderungen in der App zu achten und node dist/index.js nach jeder erneuten Kompilierung erneut auszulösen.

Hoffe das hilft :) Wenn Sie Fragen haben, lassen Sie es mich wissen!

3
Augie Gardner

Im Moment verwende ich einen Workflow, in dem:

  1. npm install und tsd install lokal
  2. gulp lokal erstellen
  3. Kopieren Sie in Dockerfile alle Programmdateien, jedoch keine Eingaben/node_modules, in das Andockbild
  4. In Dockerfile npm install --production

Auf diese Weise bekomme ich nur die gewünschten Dateien im Bild, aber es wäre schöner, wenn die Dockerfile den Build selbst durchführen könnte.

Dockerfile:

FROM node:5.1

# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

# Bundle app
COPY package.json index.js /usr/src/app/
COPY views/ /usr/src/app/views/
COPY build/ /usr/src/app/build/
COPY public/ /usr/src/app/public/

# Install app dependencies
RUN npm install --production --silent

EXPOSE 3000
CMD [ "node", "index.js" ]

Ich schätze, eine vollständige Automatisierung des "Imaging-Prozesses" könnte dadurch erreicht werden, dass das Dockerimage-Skript eingebaut und die unerwünschten Dateien gelöscht werden, bevor die Installation erneut durchgeführt wird.

2
Jørgen Tvedt

In meinem Projekt können die Quellen jedoch nicht direkt ausgeführt werden, sie müssen aus ES6 und/oder TypeScript kompiliert werden. Mit gulp baue ich mit babel, browserify und tsify - mit verschiedenen Einstellungen für Browser und Server. Was wäre in diesem Fall der beste Workflow zum Erstellen und Automatisieren von Docker-Images?

Wenn ich Sie richtig verstehe, möchten Sie Ihre Web-App in einem Docker-Container bereitstellen und verschiedene Varianten für verschiedene Zielumgebungen bereitstellen (Sie haben verschiedene Browser und Server erwähnt). (1)

Wenn das Dockerfile den Build ausführen soll, muss das Image alle Dev-Abhängigkeiten enthalten, die nicht ideal sind.

Es hängt davon ab, ob. Wenn Sie ein sofort einsatzbereites Image bereitstellen möchten, muss es alles enthalten, was Ihre Web-App zum Ausführen benötigt. Ein Vorteil ist, dass Sie später nur noch den Container starten, einige Parameter übergeben und loslegen müssen.

Während der Entwicklungsphase ist dieses Image aufgrund Ihrer normalerweise vordefinierten Entwicklungsumgebung nicht unbedingt erforderlich. Es kostet Zeit und Ressourcen, wenn Sie nach jeder Änderung ein solches Image erzeugen.

Vorgeschlagener Ansatz: Ich würde ein Zwei-Wege-Setup vorschlagen:

  1. Während der Entwicklung: Verwenden Sie eine feste Umgebung, um Ihre App zu entwickeln. Die gesamte Software kann lokal oder in einem Docker/einer VM ausgeführt werden. Ich schlage vor, einen Docker-Container mit Ihrem Entwickler-Setup zu verwenden, besonders wenn Sie in einem Team arbeiten und jeder den gleichen Entwickler-Keller haben muss.
  2. Deploy Web App: Wie ich richtig verstanden habe (1), möchten Sie die App für verschiedene Umgebungen bereitstellen und müssen daher verschiedene Konfigurationen erstellen/bereitstellen. Um so etwas zu realisieren, könnten Sie mit einem Shell-Skript beginnen, das Ihre App in einen anderen Docker-Container packt. Sie führen das Skript vor der Bereitstellung aus. Wenn Sie Jekyll laufen haben, ruft es Ihr Shell-Skript nach jedem Commit auf, nachdem alle Tests gut gelaufen sind.

Docker-Container für die Entwicklungs- und Bereitstellungsphase: Ich möchte auf ein Projekt von mir und einen Kollegen verweisen: https: // github .com/k00ni/Docker-Nodejs-Umgebung

Dieser Docker bietet eine vollständige Entwicklungs- und Bereitstellungsumgebung, indem Folgendes verwaltet wird:

  • Node.js
  • NPM
  • Schluck
  • Babel (automatische Transpilation von ECMA6 nach JavaScript bei einem Dateiwechsel)
  • Webpack

und andere JavaScript-Helfer inside der Docker-Container. Sie verknüpfen Ihren Projektordner einfach über ein Volume im Docker-Container. Es initialisiert Ihre Umgebung (z. B. stellt alle Abhängigkeiten von package.json bereit) und Sie können loslegen.

Sie können es für Entwicklungszwecke verwenden, sodass Sie und Ihr Team dieselbe Umgebung verwenden (Node.js-Version, NPM-Version, ...) Der Vorteil ist, dass Dateiänderungen zu einer Neukompilierung von ECMA6/ReactJS/... -Dateien in JavaScript-Dateien führen (dies muss nicht nach jeder Änderung manuell erfolgen). Dafür benutzen wir Babel.

Erweitern Sie für Bereitstellungszwecke einfach dieses Docker-Image und ändern Sie die erforderlichen Teile. Anstatt Ihre App in den Container zu verlinken, können Sie sie über Git (oder so ähnlich) herunterladen. Sie werden für alle Ihre Arbeiten den gleichen Keller benutzen.

0
k00ni