我有一个节点应用程序,我想在Docker容器中托管,这应该是直截了当的,如本文所示:
https://nodejs.org/en/docs/guides/nodejs-docker-webapp/
但是,在我的项目中,源不能直接运行,必须从ES6和/或Typescript编译。我使用gulp与babel,browserify和tsify一起构建 - 使用不同的浏览器和服务器设置。
在这种情况下,构建和自动化 docker镜像的最佳工作流程是什么?网络上是否有描述此类工作流程的资源?如果Dockerimage在npm install
之后执行构建,或者我应该创建一个shell脚本来完成所有这些并且只需将Dockerfile打包在一起吗?
如果Dockerfile应该进行构建 - 图像需要包含所有不依赖的dev依赖项吗?
注意:我已经能够设置一个docker容器并运行它 - 但这需要事先安装和构建所有文件。
答案 0 :(得分:9)
一种可能的解决方案是将构建过程包装在特殊的docker镜像中。它通常被称为 Builder图像。它应该包含所有构建依赖项:nodejs,npm,gulp,babel,tsc等。它封装了所有构建过程,无需在主机上安装这些工具。
首先运行构建器映像,将源代码目录作为卷安装。可以使用相同或单独的卷作为输出目录。 第一个图像采用您的代码并运行所有构建命令。
作为第一步,您可以像现在一样将构建的代码打包到生产泊坞窗映像中。
以下是TypeScript的泊坞窗构建器图像示例:https://hub.docker.com/r/sandrokeil/typescript/
对于多个项目,可以使用相同的docker builder,因为它通常被设计为围绕一些常用工具的通用包装器。 但建立自己的描述更复杂的程序是可以的。
关于构建器映像的好处是您的主机环境保持未受污染,您可以通过修改构建器映像的Dockerfile来自由地尝试更新版本的编译器/不同工具/更改顺序/执行任务。您可以随时使用构建过程回滚实验。
答案 1 :(得分:9)
我个人更喜欢在构建期间运行babel之后删除dev依赖项:
$link = mysqli_real_connect ($db, '10.1.1.1', 'root', 'xxxxxx', 'mysql', 3306, NULL, MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT);
答案 2 :(得分:6)
对于这种事情(从Docker 17.05开始),现代的建议是使用multi-stage build。这样,您可以在一个Dockerfile中使用所有dev / build依赖关系,但最终结果得到了优化,并且没有不必要的代码。
我对打字稿不是很熟悉,但这是一个使用yarn和babel的示例实现。使用此Dockerfile,我们可以构建一个开发映像(使用docker build --target development .
)以在本地运行nodemon,测试等。但是使用直线docker build .
可以得到一个精简,优化的生产图像,该图像可以使用pm2运行该应用程序。
# 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"]
答案 3 :(得分:5)
请按照以下步骤操作:
第1步:确保在package.json上的依赖项而非 dev dependencies 中包含您的babel依赖项。还要添加从node_modules文件夹引用babel的部署脚本。你将从docker中调用这个脚本 这是我的package.json文件的样子
{
"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用于本地计算机上的开发目的,部署是从dockerfile中调用的。
第2步:因为我们想要自己进行babael转换,所以请确保将.dockerignore添加到您在开发期间使用的构建文件夹中。 这就是我的.dockerignore文件。
build
node_modules
步骤3.构建dockerfile。下面是我的泊坞文件的样本
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"]
答案 4 :(得分:3)
我刚刚使用Docker为Typescript和Node.js发布了一个很棒的种子应用程序。
您可以在GitHub找到它。
该项目解释了Dockerfile使用的所有命令,并将tsc
与gulp
结合起来,以获得一些额外的好处。
如果您不想查看回购,请参阅以下详细信息:
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"]
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
{
"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 (opensourceaugie@gmail.com)",
"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"
}
}
{
"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"
]
}
为了更好地回答您的问题 - ts正在从docker-compose.yml
文件调用npm run build
编译,然后调用tsc
。 tsc
然后将我们的文件复制到dist
文件夹,一个简单的node dist/index.js
命令运行此文件。我们使用tsc-watch
和gulp.watch
来监视应用中的更改,并在每次重新编译后再次触发node dist/index.js
,而不是使用nodemon。
希望有所帮助:)如果您有任何疑问,请告诉我们!
答案 5 :(得分:2)
目前,我正在使用以下工作流程:
npm install
和tsd install
本地gulp
本地构建npm install --production
这样我只能获得图像中所需的文件,但如果Dockerfile可以自行构建,那就更好了。
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" ]
我想通过在Dockerimage脚本中构建然后在再次安装之前删除不需要的文件,可以建立“映像过程”中的完全自动化。
答案 6 :(得分:0)
但是,在我的项目中,源不能直接运行,必须从ES6和/或Typescript编译。我使用gulp与babel,browserify和tsify一起构建 - 使用不同的浏览器和服务器设置。 在这种情况下构建和自动化泊坞窗图像的最佳工作流程是什么?
当我理解你的时候,你想在Docker容器中部署你的web应用程序,并为不同的目标环境提供不同的风格(你提到了不同的浏览器和服务器)。的(1)强>
如果Dockerfile应该进行构建 - 图像需要包含所有不依赖的dev依赖项吗?
这取决于。如果您想提供随时可用的图像,它必须包含您的Web应用程序运行所需的所有内容。一个优点是,您以后只需要启动容器,传递一些参数就可以了。
在开发阶段,由于您通常预先定义了开发环境,因此该图像并不是必需的。如果您在每次更改后生成此类图像,则会花费时间和资源。
建议的方法:我建议采用双向设置:
开发和部署阶段的Docker容器:我想参考我的项目和同事:https://github.com/k00ni/Docker-Nodejs-environment
此docker通过维护:
提供整个开发和部署环境和其他JavaScript助手在 docker容器中。您只需通过docker容器内的卷链接项目文件夹。它初始化你的环境(例如从package.json部署所有依赖项),你很高兴。
您可以将其用于开发目的,以便您和您的团队使用相同的环境(Node.js版本,NPM版本......)另一个优点是,文件更改导致将ECMA6 / ReactJS / ...文件重新编译为JavaScript文件(每次更改后无需手动执行此操作)。我们使用Babel。
对于部署,只需扩展此Docker镜像并更改所需的部分。您可以通过Git(或类似的东西)将其拉出来,而不是将您的应用程序链接到容器中。您将使用相同的地下室进行所有工作。
答案 7 :(得分:0)
我发现这篇文章可以在开发和生产阶段为您提供指导:https://www.sentinelstand.com/article/docker-with-node-in-development-and-production
<块引用>在本文中,我们将为一个生产环境创建一个 Docker 镜像 节点/快递应用程序。我们还将在开发过程中添加 Docker 使用 Docker Compose 这样我们就可以轻松启动我们的服务,包括 Node 应用程序本身,在我们本地机器上的一个隔离和 可重现的方式。
该应用程序将使用较新的 JavaScript 语法编写以演示 Babel 如何包含在构建过程中。您当前的节点 版本可能不支持某些现代 JavaScript 功能,例如 ECMAScript 模块(导入和导出),所以 Babel 将用于 将代码转换为向后兼容的版本。