如何使用METEOR_SETTINGS环境变量在AWS / EBS上配置Meteor

时间:2016-01-13 08:21:30

标签: amazon-web-services meteor elastic-beanstalk amazon-elastic-beanstalk

尝试在AWS / EBS(Amazon Web Services,Elastic Beanstalk)环境中设置Meteor。

Meteor dev-run可以传递命令行标志:--settings settings.json其中settings.json是包含服务器/客户端密钥/值配置的文件(作为格式正确的JSON)。

Meteor的部署使用METEOR_SETTINGS环境变量,而不是在命令行中传递配置文件。如果提供,则应包含json文档,例如settings.json的内容,例如:

$ METEOR_SETTINGS=$(cat settings.json)
$ echo $METEOR_SETTINGS
{ "public": { "s3path": "https://d2v4p3rms9rvi3.cloudfront.net" } }

问题是当我在EBS控制台中将METEOR_SETTINGS的值设置为此值时:

(screenshot)

AWS / EBS丢弃引号,转义斜杠(如屏幕截图所示),然后发送Meteor:

{public:{s3path:https:\/\/d2v4p3rms9rvi3.cloudfront.net}}

如节点启动错误所示:

-------------------------------------
/var/log/nodejs/nodejs.log
-------------------------------------
npm WARN deprecated backwards-incompatible changes made to `npm run-script` and
npm WARN deprecated semver behavior.

> meteor-dev-bundle@0.0.0 start /var/app/current
> node main.js


/var/app/current/programs/server/boot.js:283
}).run();
   ^
Error: METEOR_SETTINGS are not valid JSON: {public:{s3path:https:\/\/d2v4p3rms9rvi3.cloudfront.net}}
    at packages/meteor/packages/meteor.js:21:1
    at Package (packages/meteor/packages/meteor.js:42:1)
    at /var/app/current/programs/server/packages/meteor.js:1277:4
    at /var/app/current/programs/server/packages/meteor.js:1286:3
    at /var/app/current/programs/server/boot.js:242:10
    at Array.forEach (native)
    at Function._.each._.forEach (/var/app/current/node_modules/underscore/underscore.js:79:11)
    at /var/app/current/programs/server/boot.js:137:5

碰到这个问题我在值字段中尝试了JSON对象的各种变体: 转义引号,用单引号括起整个json部分,用单引号替换双引号,以及其他尝试 - 都没有解决它。

问题是:

如何设置METEOR_SETTINGS以便Meteor rcv&正确解析它?

注意:其中一个要求是相同的构建部署到开发,登台和生产环境。需要为每个环境单独设置配置,因此,如果有另一种方法将设置注入EBS环境,而不修改也将解决它的构建。

3 个答案:

答案 0 :(得分:2)

在使用AWS支持讨论此问题后,我意识到AWS / EBS不支持在环境变量中存储JSON。这是因为环境变量在未编码的JSON中存储为键/值字符串(显然,在CloudFormation中)。这里的底线有点令人失望:

METEOR_SETTINGS不能在AWS / EBS控制台中使用

这确实很不幸,但有一些解决方法。

第一次解决方法

将json配置移动到s3存储桶中,并将以下内容放在.ebextensions/app.config文件中:

container_commands: 
  01_setvariable: 
    command: "aws s3 cp s3://<bucket-name>/nodejs.conf /tmp/deployment/config/#etc#init#nodejs.conf 

这将完全覆盖从您的s3存储桶中检索到的内容/etc/init/nodejs.conf。当然,有机会使用微调/花哨的bash脚本来设置/覆盖个别设置。

我最终没有选择这种方法,因为它涉及另一个实体(一个S3存储桶),而开发迭代需要一个新版本的部署,这个速度并不快。

第二次解决方法

注意:这是我想出的一个简单的代码破解。它似乎把所有这些混乱放在一边,而不需要太多的努力。

我最初的需求是将AWS / EBS env变量传播到客户端,因此我决定绕过METEOR_SETTINGS变量并直接使用来自节点{{1的env变量'填充Meteor.settings.public }} 空间。白名单由简单列表管理。添加process.env文件:

server/lib/config.js

Hurray,您的客户可以访问您选择的env vars!

例如,通过此更改,可以在客户端上以Meteor.startup(function () { // public settings that need to be exposed to the client can be added here var publicEnvs = { S3_PATH: 's3path' }; var modified; _.each(publicEnvs, (value, key) => { let envValue = process.env[key]; if (envValue) { Meteor.settings.public[value] = envValue; modified = true; } }); if (modified) { __meteor_runtime_config__.PUBLIC_SETTINGS = Meteor.settings.public; } }); 访问EBS控制台中定义的S3_PATH环境变量。非常简单,没有很多活动部件:)

答案 1 :(得分:1)

测试了另一种解决方法。

meteor build --directory后的

编辑main.js如下

process.argv.splice(2, 0, 'program.json');
var settingfilename = './settings.json';
if (process.env.METEOR_SETTING_FILE)
  settingfilename = process.env.METEOR_SETTING_FILE;
var settings = require(settingfilename);
if (settings) {
  try {
    process.env.METEOR_SETTINGS = JSON.stringify(settings);
  } catch (e) {
    console.error(e);
  }
}
process.chdir(require('path').join(__dirname, 'programs', 'server'));
require('./programs/server/boot.js');

并将settings.json复制到bundle/eb init以及eb deploy

您可以通过在EB控制台的“配置”选项卡中的“环境属性”中添加METEOR_SETTING_FILE来设置其他设置文件。

每次构建后都需要

编辑文件。

添加了补丁文件,以便在ed - ../build/bundle/main.js < main.js.patch

等构建脚本中使用

main.js.patch

8a
var settingfilename = './settings.json';
if (process.env.METEOR_SETTING_FILE)
  settingfilename = process.env.METEOR_SETTING_FILE;
var settings = require(settingfilename);
if (settings) {
  try {
    process.env.METEOR_SETTINGS = JSON.stringify(settings);
  } catch (e) {
    console.error(e);
  }
}
// console.log (JSON.stringify(process.env));
.
w

答案 2 :(得分:1)

新解决方案

这是我能够更轻松的方式。我已经创建了一个bash脚本,可以自动生成项目的压缩版本并集成设置文件,因此您不需要做任何事情。

在运行此脚本之前

在你的meteor项目中创建./lib/beanstalk-settings-fix.js

/*==============================================================================
 * Globals
 *============================================================================*/
/*global process*/
/*global Meteor*/
/*global Npm*/


if (Meteor.isProduction){
  var meteorFile = process.env.METEOR_SETTINGS_FILE;
  if(meteorFile == undefined) throw new Error(
    'METEOR_SETTINGS_FILE env variable must be defined in production.')
  var fs = Npm.require('fs');
  var pjsonBuf = fs.readFileSync( meteorFile );
  Meteor.settings = JSON.parse( pjsonBuf.toString().trim());
}

如何使用

  1. 将下一个代码复制到文本文件并将其另存为build.sh
  2. 编辑常量。
  3. 授予执行权限并运行它。
  4. 你将以project-name.zip之类的东西结束,准备将它上传到你的beanstalk环境。我希望你觉得它很有用!

    此解决方案基于AWS forums。如果您想查看旧解决方案,请查看编辑历史记录。

    #!/bin/bash
    
    #===============================================================================
    # DESCRIPTION:
    #===============================================================================
    # This script creates a build of the project ready to be uploaded to beanstalk.
    # Requires pyton 2.7.x
    
    #===============================================================================
    # COMMON ISSUES:
    #===============================================================================
    # -If you upload the output to a sample application, it will fail.
    # -Version format must be 0.0.0
    
    #===============================================================================
    # CONSTANTS
    #===============================================================================
    CURRENT_VERSION="1.0.0"
    OUTPUT_NAME="file-name-without-extension"
    PRODUCTION_SETTINGS_JSON="./your-project-directory/settings-prod.json"
    PROJECT_DIRECTORY="./your-project-directory"
    OUTPUT_DIRECTORY="./the-output-directory"
    ROOT_URL="http://www.SOMEENVIRONMENT-env.us-west-2.elasticbeanstalk.com"
    MONGO_URL="none"
    
    #===============================================================================
    # SAY HELLO
    #===============================================================================
    initial_directory=$(pwd)  #  This file's local path
    clear
    echo "COOKING OUTPUT"
    echo "========================================================="
    
    #===============================================================================
    # RAW PROJECT BUILD
    #===============================================================================
    echo "> BUILDING RAW PROJECT"
    cd $initial_directory
    cd $PROJECT_DIRECTORY
    rm -f -R "../build/bundle"
    meteor build --directory ../build/
    
    #===============================================================================
    # SET PRODUCTION ENVIRONMENT VARIABLES
    #===============================================================================
    cd $initial_directory
    json=`cat $PRODUCTION_SETTINGS_JSON`
    cd $OUTPUT_DIRECTORY/bundle
    mkdir -p .ebextensions
    echo "option_settings:" >> .ebextensions/environment.config
    echo "  - option_name: MONGO_URL" >> .ebextensions/environment.config
    echo "    value: $MONGO_URL" >> .ebextensions/environment.config
    echo "option_settings:" >> .ebextensions/environment.config
    echo "  - option_name: ROOT_URL" >> .ebextensions/environment.config
    echo "    value: "$ROOT_URL"" >> .ebextensions/environment.config
    echo "files:" >> .ebextensions/environment.config
    echo " '/tmp/settings.json':" >> .ebextensions/environment.config
    echo "    content : |" >> .ebextensions/environment.config
    echo "        "$json >> .ebextensions/environment.config
    echo "option_settings:" >> .ebextensions/environment.config
    echo "  - namespace:  aws:elasticbeanstalk:application:environment" >> .ebextensions/environment.config
    echo "    option_name: METEOR_SETTINGS_FILE" >> .ebextensions/environment.config
    echo "    value: '/tmp/settings.json'" >> .ebextensions/environment.config
    chmod 444 .ebextensions/environment.config
    echo "> ADDING 'settings.json' AS ENV VAR"
    
    #===============================================================================
    # CREATE PACKAGE.JSON
    #===============================================================================
    cd $initial_directory
    cd $OUTPUT_DIRECTORY/bundle
    
    # Write base package.json
    echo '{
      "name": "'$OUTPUT_NAME'",
      "version": "'$CURRENT_VERSION'",
      "scripts": {
        "start": "node main.js"
      },
      "dependencies": {
      }
    }' > ./package.json
    
    # Add dependencies from meteor in packages.json
    # Then add extra dependencies defined by us.
    EXTRA_DEPENDENCIES='{"forever": "*"}'
    meteor_packages=$(cat ./programs/server/package.json)
    packages=$(cat ./package.json)
    packages_updated=`python <<END
    import json;
    # We cannot operate directly bash variables, so we make a copy.
    a = $packages
    b = $meteor_packages
    a['dependencies'] = b['dependencies']
    for key, value in $EXTRA_DEPENDENCIES.iteritems():
        a['dependencies'].update({key: value})
    print json.dumps(a, sort_keys=False, indent=4, separators=(',', ': '));
    END`
    echo "$packages_updated" > ./package.json
    chmod 444 ./package.json
    echo "> ADDING 'package.json'"
    
    #===============================================================================
    # ZIP OUTPUT
    #===============================================================================
    cd $initial_directory
    cd $OUTPUT_DIRECTORY/bundle
    zip -FSrq "../$OUTPUT_NAME-$CURRENT_VERSION.zip" .
    echo "> ZIP THE OUTPUT"
    
    #===============================================================================
    # CLEAN THE HOUSE
    #===============================================================================
    cd $initial_directory
    cd $OUTPUT_DIRECTORY
    rm -R -f ./bundle
    echo "> CLEAN THE HOUSE"
    
    #===============================================================================
    # SAY GOODBYE
    #===============================================================================
    echo "========================================================="
    echo "YOU CAN UPLOAD THE PROJECT TO A BEANSTALK ENVIRONMENT NOW"
    

    一些额外的帮助:如果您想检查一切正常,您可以在/ebextensions/environment.config下的压缩输出中找到最终设置,并在/下的/的package.json