首页 文章

避免在弹性beanstalk中重建node_modules

提问于
浏览
49

我们有一个相当简单的node.js应用程序,但由于AWS Elastic Beanstalk部署机制,即使在单个文件提交后,也需要大约5分钟来推出新版本(通过 git aws.push ) .

即提交本身(和上传)很快(只有1个文件要推送),但随后Elastic Beanstalk从S3获取整个包,解压缩并运行 npm install ,这会导致node-gyp编译一些模块 . 安装/构建完成后,Elastic Beanstalk会擦除 /var/app/current 并将其替换为新的应用程序版本 .

毋庸置疑,不需要进行常规node_modules重建,并且在我的旧Macbook Air上重建需要30秒,在ec2.micro实例上花费大约5分钟,并不好玩 .

我在这里看到两种方法:

  • tweak /opt/containerfiles/ebnode.py 并使用node_modules位置以避免在部署时删除和重建 .

  • 在Elastic Beanstalk EC2实例上设置了一个git repo,基本上我们自己重写了部署过程,所以/ var / app / current仅在必要时接收推送并运行 npm install (这使得Elastic Beanstalk看起来像OpsWorks ..)

当Amazon更新其Elastic Beanstalk挂钩和架构时,这两个选项都缺乏优势并且容易出现问题 .

也许有人有更好的想法如何避免不断重建已存在于app dir中的node_modules?谢谢 .

5 回答

  • 38

    谢谢基里尔,这真的很有帮助!

    我只是为那些只看 npm install 简单解决方案的人分享我的配置文件 . 此文件需要放在项目的 .ebextensions 文件夹中,它更轻,因为它不包含节点安装的最新版本,并且可以使用 .

    它还会动态检查安装的节点版本,因此不需要将其包含在env.vars文件中 .

    .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
    
  • 40

    25/01/13注意:更新脚本以运行npm -g版本升级(仅在初始实例推出或重建时执行一次)并避免在EB配置更改期间进行NPM操作(当app目录不存在时,以避免错误并且加快配置更新) .

    好吧,Elastic Beanstalk与最近的node.js版本(包括大概支持的v.0.10.10)表现得很狡猾,所以我决定继续调整EB以执行以下操作:

    • 根据您的env.config安装任何node.js版本(包括AWS EB尚不支持的最新版本)

    • 以避免重建现有节点模块,包括应用程序内node_modules目录

    • 全局安装node.js(以及任何所需的模块) .

    基本上,我使用env.config来替换自定义的钩子和配置钩子(见下文) . 此外,在默认的EB容器设置中,缺少一些env变量(例如 $HOME ),并且 node-gyp 有时在重建期间因为它而失败(花了我2小时的谷歌搜索并重新安装libxmljs来解决这个问题) .

    以下是与您的构建一起包含的文件 . 你可以通过env.config注入它们作为内联代码或通过 source: URL (如本例所示)

    env.vars (此处和env.config中包含所需的节点版本和arch,见下文)

    export HOME=/root
    export NPM_CONFIG_LOGLEVEL=error
    export NODE_VER=0.10.24
    export ARCH=x86
    export PATH="$PATH:/opt/elasticbeanstalk/node-install/node-v$NODE_VER-linux-$ARCH/bin/:/root/.npm"
    

    40install_node.sh (fetch和ungzip所需的node.js版本,制作全局符号链接,更新全局npm版本)

    #!/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 (创建/ var / node_modules,将它符号链接到app dir并运行npm install . 你可以从这里全局安装任何模块,它们将落在/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 (此处也注意节点版本,为了安全起见,也将所需的节点版本放在AWS控制台的env配置中 . 我不确定哪些设置优先 . )

    packages:
      yum:
        git: []
        gcc: []
        make: []
        openssl-devel: []
    
    option_settings:
      - option_name: NODE_ENV
        value: production
      - option_name: RDS_HOSTNAME
        value: fill_me_in
      - option_name: RDS_PASSWORD
        value: fill_me_in
      - option_name: RDS_USERNAME
        value: fill_me_in
      - namespace: aws:elasticbeanstalk:container:nodejs
        option_name: NodeVersion
        value: 0.10.24
    
    files:
      "/opt/elasticbeanstalk/env.vars" :
        mode: "000775"
        owner: root
        group: users
        source: https://dl.dropbox.com/....
      "/opt/elasticbeanstalk/hooks/configdeploy/pre/40install_node.sh" :
        mode: "000775"
        owner: root
        group: users
        source: https://raw.github.com/....
      "/opt/elasticbeanstalk/hooks/appdeploy/pre/50npm.sh" :
        mode: "000775"
        owner: root
        group: users
        source: https://raw.github.com/....
      "/opt/elasticbeanstalk/hooks/configdeploy/pre/50npm.sh" :
        mode: "000666"
        owner: root
        group: users
        content: |
           #no need to run npm install during configdeploy
      "/opt/elasticbeanstalk/hooks/appdeploy/pre/40install_node.sh" :
        mode: "000775"
        owner: root
        group: users
        source: https://raw.github.com/....
    

    你有它:在t1.micro实例部署现在需要20-30秒而不是10-15分钟!如果您每天部署10次,这个调整将为您节省一年中的3(3)周 . 希望它有助于特别感谢AWS EB员工为我失去的周末:)

  • 1

    有's npm package that'通过截断以下文件来覆盖 npm install 命令的默认EB行为:

    • /opt/elasticbeanstalk/hooks/appdeploy/pre/50npm.sh

    • /opt/elasticbeanstalk/hooks/configdeploy/pre/50npm.sh

    https://www.npmjs.com/package/eb-disable-npm

    可能比仅仅从SO复制脚本更好,因为这个包被维护,并且可能在EB行为改变时更新 .

  • 5

    我找到了一个快速解决方案 . 我查看了Amazon正在使用的构建脚本,如果package.json存在,它们只运行 npm install . 因此,在初始部署后,您可以将其更改为 _package.json 并且 npm install 赢得了't run anymore! It'不是最好的解决方案,但如果您需要它,它可以快速解决!

  • -6

    我部署的时候有10分钟的构建时间 . 解决方案比其他人想象的要简单得多......只需将node_modules检查成git即可!有关推理,请参阅http://www.futurealoof.com/posts/nodemodules-in-git.html

相关问题