Oracle Application Container Cloudで環境変数に入らない特殊文字をパラメータとして設定できるようにする方法


Node.jsのPaaSではアクセストークンのような秘匿性の高い情報はソースコードに埋め込まず、環境変数によってソースとは切り離し、外から設定できる形にするのが一般的だと思います。

この仕様は将来変わる可能性もありますが、現在Oracle Application Container Cloudでは一部の特殊文字（+とか^とか）を環境変数の値として入力することができません。なんでやねん。

これでは結構困るので、ワークアラウンドをメモっておこうと思います。

結論からいうと、Developer Cloud側でBuild Parameterとして必要な環境変数をすべて設定し、その値をBuild時にGulpで反映する、というやり方になります。

## environment_variables.jsを作成し、環境変数をすべて列挙する

このファイルは環境変数名を列挙したファイルになります。後ほどprocess.env.環境変数名の部分がGulpで置換されることになります。

```javascript:/environment_variables.js
exports.ACCESS_TOKEN = process.env.ACCESS_TOKEN;
exports.CLIENT_ID = process.env.CLIENT_ID;
```

## 環境変数を利用するファイルでenvironment_variables.jsをロードする

下記ではExpress Generatorがデフォルトで生成するルーター設定に環境変数を利用しています。
process.envの代わりにapp_envオブジェクトを利用する形になります。app_envの名前は何でもOKです。

```javascript:/routes/index.js
'use strict';

let express = require('express');
let router = express.Router();
let app_env = require('../environment_variables');

router.get('/', function(req, res, next) {
    res.render('index', {
    	title: 'Express',
    	access_token: app_env.ACCESS_TOKEN,
    	client_id: app_env.CLIENT_ID
    });
});

module.exports = router;
```

この環境変数を画面に出力するようにしておきます。

```html:/views/index.ejs
<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
    <h1><%= title %></h1>
    <p>Welcome to node-bootcamp</p>
    <p>Access Token: <%= access_token %></p>
    <p>Client Id: <%= client_id %></p>
  </body>
</html>
```

## Gulpでenvironment_variables.jsを置換する

Gulpのデフォルトタスクとしてenvironment_variables.jsファイルのprocess.env.環境変数を実際の値に置換するタスクを作成します。さらに、その置換完了後にApplication Container Cloudへデプロイするためのartifact.zipを生成しています。

```javascript:/gulpfile.js
'use strict';

var gulp = require('gulp');
var replace = require('gulp-replace');
var zip = require('gulp-zip');
var debug = require('debug')('compile');

gulp.task('default', function(){
    // process.env.VARIABLE_NAMEを実際の値に置換します。
    debug('Compiling environment_variables.js...');
    var stream = gulp.src(['environment_variables.js']);
    for (var environment_variable_key of Object.keys(process.env)){
        debug('Replacing process.env.' + environment_variable_key + ' to ' + process.env[environment_variable_key] + '...');
        stream = stream.pipe(replace('process.env.' + environment_variable_key, "'" + process.env[environment_variable_key] + "'"));
    }
    stream.pipe(gulp.dest('./'));
    debug('Done.');

    // すべてのファイルをartifact.zipとして圧縮します。
    debug('Creating artifact.zip...');
    return gulp.src('./**')
        .pipe(zip('artifact.zip'))
        .pipe(gulp.dest('./'));
});
```

## Developer CloudでBuild設定をおこなう

左サイドバーからBuildを選択し、任意のBuild設定の「Build Parameters」タブを選択します。
一つの環境変数につき、Add Parameterプルダウンメニューから「String Parameter」を選択して変数名と値を入力していきます。
![スクリーンショット_2017-03-28_15_44_25.png](https://qiita-image-store.s3.amazonaws.com/0/26079/41a067ea-e126-0c08-66f0-4338fb940f34.png "スクリーンショット_2017-03-28_15_44_25.png")

次にBuild Stepタブを選択し、gulpコマンドを投入して先ほど作成した置換・圧縮タスクが実行されるようにします。
![スクリーンショット_2017-03-28_15_44_42.png](https://qiita-image-store.s3.amazonaws.com/0/26079/7b5675eb-e55d-037d-83d1-2005fea8b0d8.png "スクリーンショット_2017-03-28_15_44_42.png")

これでビルドを実行します。
![スクリーンショット_2017-03-28_15_50_29.png](https://qiita-image-store.s3.amazonaws.com/0/26079/80860e7d-1e57-ecf0-2ba3-9614c5e44353.png "スクリーンショット_2017-03-28_15_50_29.png")

ビルドが完了するとartifact.zipが生成されますので、これをダウンロードして展開し、environment_variables.jsが下記のように環境変数の実際の値で置換されていることを確認してください。

```javascript:environment_variables.js
exports.CLIENT_ID = 'client_id-hogeHOGE1234+^!?=';
exports.ACCESS_TOKEN = 'access_token-hogeHOGE1234+^!?=';
```

## デプロイする

あとはApplication Container Cloudへデプロイするだけです。Application Container Cloud側では一切環境変数を設定する必要はありません。

## 他のPaaSでもこのまま動きます

今回環境変数のリストとして作成したenvironment_variables.jsでは置換対処文字例をprocess.env.環境変数名としているため、環境変数をすべて設定できる環境であれば置換タスクを走らせなくてもこのまま動かすことができます。

したがってOracle Application Container Cloudで動かすときはgulpを実行して置換をおこなう。他の環境では環境変数を設定すればそれがそのまま反映されるという形でどのPaaSでも稼働させることができます。