Docker与npm全局安装angular-cli构build时间长

我遇到了一个非常奇怪的情况,想知道是否有人能够说明情况。 简而言之,使用npm install -g angular-cli@1.0.0-beta.16以及其他应用程序步骤需要永久构build。 docker build在自己的图像中单独docker build ,然后docker build FROM第一个图像docker build应用程序的其余部分,一起或单独地花费那么长时间。 当我说了很长时间,我的意思是2小时。 个人需要大约5至7分钟的时间来build设。

所以在我放下所有的代码之前,请注意几点。 我已经在OS X 10.10.5,OS X 10.11.X,OS X 10.12.X,Arch Linux 4.5.1-1-ARCH,Ubuntu 14.04 LTS(在stream浪盒子和AWS中)以及有些朋友在他们的机器上帮助了我。 所有相同的结果。 我正在运行Docker 1.12.1。 我正在修buildFROM alpine:3.4node的版本是v6.2.0npm 3.8.9(来自高山包)。 我也试过这个图像,我从源码构build了nodejs v5.11.1和npm 3。

 FROM alpine:3.4 MAINTAINER First Lastname <user@example.com> ARG ENV #Set environment vars ENV HOME=/home \ APP_DIR=/root/app \ DIST_DIR=/var/www \ ENV=${ENV} \ AWS_REGION=us-east-1 \ NPM_CONFIG_LOGLEVEL=info \ LANG=en_US.UTF-8 \ LC_ALL=C.UTF-8 \ LANGUAGE=en_US.UTF-8 #Install runtime packages RUN apk --no-cache add \ ca-certificates \ nodejs \ nginx #Install build time packages RUN apk --no-cache add \ --virtual build-dependencies \ busybox \ build-base \ bzip2 \ git \ python-dev \ libffi-dev RUN mkdir -p ${APP_DIR} WORKDIR ${APP_DIR} COPY . ${APP_DIR} #Bug https://github.com/npm/npm/issues/9863 RUN cd $(npm root -g)/npm && \ npm install fs-extra && \ sed -i -es/graceful-fs/fs-extra/ -es/fs\.rename/fs.move/ ./lib/utils/rename.js && \ rm -fr ${APP_DIR}/node_modules #install node packages RUN npm install -g angular-cli@1.0.0-beta.16 && \ npm install -g typescript@2.0.3 && \ npm install && npm install -g --save process-nextick-args && npm cache clean | tee /tmp/npm-install.log #build project RUN ng build --environment=${ENV} RUN mv dist ${DIST_DIR} #clean up RUN rm -fr ${APP_DIR} RUN apk del build-dependencies #nginx config COPY ./nginx/nginx.conf /etc/nginx/ RUN mkdir -p /etc/nginx/sites-available /etc/nginx/sites-enabled/ && \ chmod -R 755 /etc/nginx/sites-* RUN ln -sf /dev/stdout /var/log/nginx/access.log && \ ln -sf /dev/stderr /var/log/nginx/error.log COPY ./nginx/account-curation.conf /etc/nginx/sites-available/ RUN ln -s /etc/nginx/sites-available/account-curation.conf /etc/nginx/sites-enabled/ #app port EXPOSE 80 81 #start nginx ENTRYPOINT [ "nginx" ] 

和package.json看起来像

 { "name": "app-name", "version": "0.0.0", "license": "MIT", "angular-cli": {}, "scripts": { "start": "ng serve", "lint": "tslint \"src/**/*.ts\"", "test": "ng test", "pree2e": "webdriver-manager update", "e2e": "protractor" }, "private": true, "dependencies": { "@angular/common": "2.0.0", "@angular/compiler": "2.0.0", "@angular/core": "2.0.0", "@angular/forms": "2.0.0", "@angular/http": "2.0.0", "@angular/platform-browser": "2.0.0", "@angular/platform-browser-dynamic": "2.0.0", "@angular/router": "3.0.0", "@angular2-material/button": "2.0.0-alpha.8-2", "@angular2-material/card": "2.0.0-alpha.8-2", "@angular2-material/checkbox": "2.0.0-alpha.8-2", "@angular2-material/core": "2.0.0-alpha.8-2", "@angular2-material/grid-list": "2.0.0-alpha.8-2", "@angular2-material/icon": "2.0.0-alpha.8-2", "@angular2-material/input": "2.0.0-alpha.8-2", "@angular2-material/input": "2.0.0-alpha.8-2", "@angular2-material/list": "2.0.0-alpha.8-2", "@angular2-material/progress-circle": "2.0.0-alpha.8-2", "@angular2-material/tabs": "2.0.0-alpha.8-2", "@angular2-material/toolbar": "2.0.0-alpha.8-2", "angular2-modal": "2.0.0-beta.13", "core-js": "2.4.1", "es6-shim": "0.35.1", "hammerjs": "2.0.8", "jquery": "3.1.0", "jstree": "3.3.1", "localStorage": "1.0.3", "rxjs": "5.0.0-beta.12", "ts-helpers": "1.1.1", "zone.js": "0.6.25" }, "devDependencies": { "@types/hammerjs": "^2.0.33", "@types/jasmine": "^2.2.30", "@types/jquery": "^2.0.32", "@types/jstree": "^3.3.32", "angular-cli": "1.0.0-beta.16", "codelyzer": "0.0.26", "jasmine-core": "2.4.1", "jasmine-spec-reporter": "2.5.0", "karma": "1.2.0", "karma-chrome-launcher": "2.0.0", "karma-cli": "1.0.1", "karma-jasmine": "1.0.2", "karma-remap-istanbul": "0.2.1", "protractor": "4.0.9", "ts-node": "1.2.1", "tslint": "3.13.0", "typescript": "2.0.3" } } 

我指出了这一点,因为它已经有了我想要全局安装的所有软件包(相同的版本),但是安装的时候要快得多。 所以这需要大约2个小时来build立。 疯了吧? 所以经过这么多天,我搞不明白为什么。 我决定根据时间来build立一个全局安装的基础映像,然后FROM那个映像build立项目映像。 这样CI构build作业就不需要花费几个小时就可以完成这个存储库分支。 但是当我这样做的时候,神奇地变得更快了。 基本图像大约7分钟,应用图像大约5分钟。 它看起来像这样。

基本图像:

 FROM alpine:3.4 MAINTAINER First Lastname <user@example.com> #Set environment vars ENV NPM_CONFIG_LOGLEVEL=info \ LANG=en_US.UTF-8 \ LC_ALL=C.UTF-8 \ LANGUAGE=en_US.UTF-8 #Install runtime packages RUN apk --no-cache add \ ca-certificates \ nodejs #Install build time packages RUN apk --no-cache add \ --virtual build-dependencies \ busybox \ build-base \ bzip2 \ git \ python-dev \ libffi-dev #Bug https://github.com/npm/npm/issues/9863 RUN cd $(npm root -g)/npm && \ npm install fs-extra && \ sed -i -es/graceful-fs/fs-extra/ -es/fs\.rename/fs.move/ ./lib/utils/rename.js #install node packages RUN npm install -g angular-cli@1.0.0-beta.16 && \ npm install -g typescript@2.0.3 && \ npm install -g --save process-nextick-args && npm cache clean | tee /tmp/npm-global-install.log RUN apk del build-dependencies ENTRYPOINT [ "/bin/ash" ] 

应用程序映像

 FROM company/application_base:latest MAINTAINER First Lastname <user@example.com> ARG ENV #Set environment vars ENV APP_DIR=/root/app \ DIST_DIR=/var/www \ ENV=${ENV} \ AWS_REGION=us-east-1 \ NPM_CONFIG_LOGLEVEL=info \ LANG=en_US.UTF-8 \ LC_ALL=C.UTF-8 \ LANGUAGE=en_US.UTF-8 #Install runtime packages RUN apk --no-cache add \ ca-certificates \ nginx #Install build time packages RUN apk --no-cache add \ --virtual build-dependencies \ busybox \ build-base \ bzip2 \ git \ python-dev \ libffi-dev RUN mkdir -p ${APP_DIR} COPY . ${APP_DIR} WORKDIR ${APP_DIR} #install node packages RUN npm install && npm cache clean | tee /tmp/npm-install.log #build project RUN ng build && mv dist ${DIST_DIR} #clean up RUN rm -fr ${APP_DIR} && apk del build-dependencies #nginx config COPY ./nginx/nginx.conf /etc/nginx/ RUN mkdir -p /etc/nginx/sites-available /etc/nginx/sites-enabled/ && \ chmod -R 755 /etc/nginx/sites-* && \ ln -sf /dev/stdout /var/log/nginx/access.log && \ ln -sf /dev/stderr /var/log/nginx/error.log COPY ./nginx/account-curation.conf /etc/nginx/sites-available/ RUN ln -s /etc/nginx/sites-available/account-curation.conf /etc/nginx/sites-enabled/ #app port EXPOSE 80 81 #start nginx ENTRYPOINT [ "nginx" ] 

我不知道nodejs那么好,所以我试图避免安装angular-cli两次,是npm installpackage.json npm install一个,然后将它从/path/to/app/node_modules/.bin/ng mv/usr/bin也只是添加/path/to/app/node_modules/.bin到我的path,都导致ng not found

不知道这是相关的,但我会打电话给任何人,我不断收到这个恼人的npm gyp权限问题只适用于全球安装的软件包。 gyp WARN EACCES user "nobody" does not have permission to access the dev dir他们只是警告,但我想我会谷歌,看看它是什么。 只是为了排除可能性,我尝试了build议的方法来解决,从像https://docs.npmjs.com/getting-started/fixing-npm-permissions和https://github.com/nodejs/node-gyp/issues / 454我找不到工作。

我尝试过的其他东西是与Docker可以利用的RAM和CPU的数量混杂在一起。 如docker build --build-arg ENV=dev --cpuset-cpus "0-5" --no-cache -t company/app_name:0.1.0 .

我真的不想维护两个Dockerfile ,特别是当我觉得有什么愚蠢的东西我错过了。 因为我知道他们分开工作会好很多。 当它们在一起的时候,什么都可能导致这个时间增加很多。

由于execSyncnode-zopfli构build本地模块的问题非常缓慢,因此“全部”映像构build需要很长时间。 两者都是可选的依赖关系,因此安装可以让他们无法正常工作,但他们需要一段时间才能失败。

分割的图像构build使得这两个包不能快速构build。 我真的不确定这是怎么发生的,因为似乎有一些变化,可能会导致他们无法迅速build立。

execAsync

execSync模块不应该存在,它是为节点0.10。 如果我从Dockerfile删除npm错误修复,那么execAsync构build会立即失败,而不是花费很长时间才能失败。

节点zopfli

要删除权限问题,请使用npm install --unsafe-perm允许构build以容器中的root用户身份运行。

devDependencies

使用devDependencies或全局安装,而不是两个。 npm install --production将从应用程序安装中删除devDependencies ,这意味着angular-cli不会再被复制。 如果你需要更多的devDependencies来完成应用程序的构build,那么你可能需要另一种方式,而不是全局安装,而只依靠devDepenencies( ./node_modules/.bin/ng .bin/ ./node_modules/.bin/ng

其他说明

使用FROM mhart/alpine-node:6获取node / npm的最新版本,不要通过apk安装nodejs

尽可能晚地设置ARG ENVENV ENV (即在使用它的ng命令之前),以便环境更改不会触发完整的图像重build。

在稍后的Dockerfile命令中运行清理步骤时,没有图像大小可以获得(或者真的丢失),如RUN apk del build-dependencies 。 这时文件已经被提交到前一个图像层。

在进行重复的docker镜像构build时,可以使用像verdacio / npm-register用于npm和/或apt-cacher-ng用于通用os包。 他们将移除大多数重复的docker构build的networking开销。

Dockerfile

所以你最终得到这样的东西:

 FROM mhart/alpine-node:6.7 MAINTAINER First Lastname <user@example.com> # Set environment vars ENV HOME=/root \ APP_DIR=/root/app \ DIST_DIR=/var/www \ AWS_REGION=us-east-1 \ NPM_CONFIG_LOGLEVEL=info \ LANG=en_US.UTF-8 \ LC_ALL=C.UTF-8 \ LANGUAGE=en_US.UTF-8 # Install packages RUN apk --no-cache add \ --virtual build-dependencies \ ca-certificates \ nginx \ build-base \ bzip2 \ git \ python-dev \ libffi-dev RUN mkdir -p ${APP_DIR} WORKDIR ${APP_DIR} COPY . ${APP_DIR} # Install node packages RUN set -uex ;\ npm install -g angular-cli@1.0.0-beta.16 typescript@2.0.3 process-nextick-args ;\ npm install --production --unsafe-perm ;\ npm cache clean ARG ENV ENV ENV=${ENV} # Build project RUN set -uex ;\ ng build --environment=${ENV} ;\ mv dist ${DIST_DIR} ;\ rm -fr ${APP_DIR} # nginx config COPY ./nginx/nginx.conf /etc/nginx/ RUN set -uex ;\ mkdir -p /etc/nginx/sites-available /etc/nginx/sites-enabled/ ;\ chmod -R 755 /etc/nginx/sites-* ;\ ln -sf /dev/stdout /var/log/nginx/access.log ;\ ln -sf /dev/stderr /var/log/nginx/error.log COPY ./nginx/account-curation.conf /etc/nginx/sites-available/ RUN ln -s /etc/nginx/sites-available/account-curation.conf /etc/nginx/sites-enabled/ # App port EXPOSE 80 81 # Start nginx ENTRYPOINT [ "nginx" ] 

有两个Dockerfiles也没有问题。 因为每个人都应该做自己的事情,而不是重复别人的行为。 您通常只需要在从一个基本图像构build多个图像时执行此操作。

值得指出的是, 可能相关的是在npm安装步骤之前添加这个:

 RUN npm config set maxsockets 10 

在旧版本的npm上是无限的,在新的版本上是50。当我明确地把它设置为10时,我得到了巨大的速度提升(依稀记得有人说25对他有​​好处)。