Nodejs 애플리케이션 개발 가이드

1. 문서 개요

1.1. 목적

본 문서(node.js 애플리케이션 개발 가이드)는 개방형 플랫폼 프로젝트의 서비스팩(Mysql, Cubrid, MongoDB, RabbitMQ, Radis, GlusterFS)을 Node.js 애플리케이션과 연동하여서비스를 사용하고 애플리케이션을 배포하는 방법에 대해 제시하는 문서이다.

1.2. 범위

본 문서의 범위는 개방형 플랫폼 프로젝트의 Node.js 애플리케이션 개발과 서비스팩 연동에 대한 내용으로 한정되어 있다.

1.3. 참고자료

2. 개발환경 구성

Open PaaS에 등록된 다양한 서비스팩을 Node.js언어로 작성된 애플리케이션과 바인딩하고해당 애플리케이션에 바인딩된 환경정보(VCAP_SERVICES)에서 각 서비스별 접속정보를 획득하여 애플리케이션에 적용하여 이용 할 수 있도록 Windows 환경에서 Node.js 애플리케이션을 작성 할 수 있도록한다.
Node.js 애플리케이션 개발을 위해 다음과 같은 환경으로 개발환경을 구성 한다.
    BuildPack: v1.3.4
    OS : Windows 7 64bit
    Node.js : v0.12.4
    npm : v2.10.1

2.1. Node.js 및 npm 설치

1. Node.js 다운로드

    아래의 주소로 접속한 후 node-v0.12.4-x64.msi를 다운받는다.

2. Node.js 설치

    다운받은 폴더에서 node-v0.12.4-x64.msi를 더블클릭하여 설치를 시작한다.
    "실행"버튼을 클릭하여 계속 진행한다.
    "Next"버튼을 클릭하여 계속 진행한다.
    "I accept the terms in the License Agreement"를 체크하여 라이센스에 동의한 후 "Next"버튼을 클릭하여 계속 진행한다.
    설치경로를 입력 혹은 선택한 후 "Next"버튼을 클릭하여 계속 진행한다.
    여기서는 C:\Program Files\nodejs 를 설치경로로 설정하였다.
    설치할 항목을 선택한 후 "Next"버튼을 클릭하여 계속 진행한다.
    여기서는 선택하여 Node.js, npm, doc을 설치하고 환경변수 PATH까지 추가하였다.
    "Install"버튼을 클릭하여 설치한다.
    "Finish"버튼을 클릭하여 설치를 완료한다.
    '윈도우키+R' 또는 '시작->실행'아이콘을 클릭하여 실행창을 띄운 후 'cmd'를 입력하고 "확인"버튼을 눌러 커맨드창을 연다.
    커맨드창에 아래의 명령어를 입력하여 node.js와 npm의 버젼과 제대로 설치되었는지 여부를 확인한다.
>node -v
>npm -v
개발도구 Node.js는 javascript기반의 언어로 Notepad++, Sublim Text, EditPlus등 문서편집기를 개발도구로 사용할 수 있다. 또한 Eclipse의 플러그인 Nodeclipse를 설치하여 사용할 수도있다.

3. 개발

샘플 애플리케이션에의 데이터 관리는 MySQL, CubridDB, MongoDB 중에 하나를 이용하기 때문에 API 요청시 요청 본문에 DBType 값을 가지고 결정한다.

3.1. Node.js Express애플리케이션 생성

1. 'express-generator'를 이용하여 Express 애플리케이션을 생성

    커맨드 창에서 개발을 진행할 경로로 이동후 아래의 명령어를 입력하여 'express-generator' npm을 설치한다.
>npm install express-generator
    Express 애플리케이션을 생성한다. '-e'옵션은 view enjine을 ejs를 사용한다는 것이고 default view enjin은 jade이다.
>.\node_modules.bin\express -e

2. npm 설치

    Express 애플리케이션에 기본적으로 포함되어있는 npm을 설치한다. 설치할 npm에 대한 정의는 package.json에 정의되어있다.
>npm install

3. Node.js Express 어플리캐이션 실행

    아래의 두 명령어중 하나를 이용해 애플리케이션 실행한다.
>npm start
>node bin/www
    브라우저로 아래의 주소로 접속하여 애플리케이션이 제대로 동작하는지 확인한다.

3.2. Node.js 샘플 애플리케이션

1. Node.js 샘플 애플리케이션 다운로드

    완성된 샘플 애플리케이션은 아래 링크의 /OpenPaaSSample/node-sample-app 에서 받을 수 있다.

2. Node.js 샘플 애플리케이션 경로로 이동

    다운받은 경로아래에 Node.js 샘플 애플리케이션 경로로 이동한다.
>cd node-sample-app

3. Node.js 샘플 애플리케이션 디렉토리구조

파일/폴더
목적
package.json
node.js 어플리케이션에 필요한 npm의 의존성 정보를 기술하는데 사용 한다. npm install 명령을 실행시 install 뒤에 아무런 정보를 입력하지 않으면 이 파일의 정보를 이용하여 npm을 설치한다.
app.js
Express에 대한 설정을 한다. http요청에 대한 라우팅 정보 또한 이곳에서 정의한다.
bin/www
실질적으로 node.js 샘플 애플리케이션의 시작점이며, http서버를 설정한다. 서버가 구동될 때 사용할 Port를 여기서 설정할 수 있다.
routes/
app.js에서 라우팅 후 실제 수행할 내용이 작성되어있다. 서비스 연결에 대한 내용도 이곳에 있다.
public/
외부에서 접근가능한 디렉토리이다. css, js등 웹서비스에 필요한 정적파일들이 있다. 외부에서 접근가능한 디렉토리에 대한 설정은 app.js파일에서 설정한다.
views/
ejs파일들이 위치하는 곳이다. ejs파일은 html을 좀더 쉽게 작성할 수 있게 도와주는 template enjin 이며 express의 view enjin을 ejs로 설정했을시 사용하는 파일이다. render() 메소드를 이용하여 ejs파일을 html로 변환하여 보여준다.
test/
mocha test를 작성한 디렉토리이다.
(node_modules)
위의 그림에서는 보이지 않지만 npm install로 모듈설치시 이 디렉토리아래에 설치가 된다. 여기에 설치되어있는 npm모듈들을 애플리케이션에서 require로 불러와서 사용할 수 있다.
Makefile
linux에서 좀더 쉽게 mocha 테스트를 실행하기위한 파일이다.
manifest.yml
개방형 플랫폼에 배포시 애플리케이션에 대한 설정이다. 애플리케이션의 이름, 배보될 경로, 인스턴스 수 등을 정의할 수 있다.
.cfignore
개방형 플랫폼에 배포시 포함되지않을 디렉토리, 혹은 파일을 기술한다.
.gitignore
git에 배포시 포함되지않을 디렉토리, 혹은 파일을 기술한다.
README.md
Node.js 샘플 애플리케이션에 대한 간략한 설명이 기술되어 있다.

3.3. 애플리케이션 환경설정

이 샘플은 Node.js version 0.12.4, npm version 2.10.1.을 기준으로 각 모듈의 버전을 명시적으로 선택하여 설치하였다. package.json 수정(설정)시 설치된 Node.js의 버전에 맞는 모듈을 설치하는 것을 권장한다.
1) ./package.json
    애플리케이션에서 필요한 모듈을 정의한다.
1
{
2
"name": "node-sample-app",
3
"version": "0.8.0",
4
"private": true,
5
"scripts": {
6
"start": "node ./bin/www"
7
},
8
"dependencies": {
9
"body-parser": "1.13.2",
10
"cookie-parser": "1.3.5",
11
"debug": "2.2.0",
12
"morgan": "1.6.1",
13
"serve-favicon": "2.3.0",
14
"express": "4.13.1",
15
"ejs": "2.3.4",
16
"generic-pool": "2.2.1",
17
"mysql": "2.9.0",
18
"node-cubrid":"2.2.5",
19
"mongodb":"2.0.48",
20
"redis":"2.4.2",
21
"uuid":"2.0.1",
22
"amqp":"0.2.4",
23
"pkgcloud":"1.2.0-alpha.0",
24
"formidable":"1.0.17",
25
"mocha":"2.3.4",
26
"should":"7.1.1",
27
"supertest":"1.1.0"
28
},
29
"engines": {
30
"node": "0.12.4",
31
"npm": "2.10.1"
32
}
33
}
Copied!
name
애플리케이션 이름
version
애플리케이션 버젼
private
npm에 게시할것인지 여부를 설정한다. (true: 게시하지않음)
scripts.start
npm start 명령어로 실행될 명령어(애플리케이션 구동 명령어)
    dependencies
body-parser
Express프레임워크에서 기본적으로 사용하는 모듈들.
cookie-parser
debug
morgan
serve-favicon
express
ejs
generic-pool
connection pool생성 및 관리 모듈
mysql
mysql 모듈
node-cubrid
cubrid 모듈
mongodb
mongodb 모듈
redis
redis 모듈
uuid
고유식별자를 생성해주는 모듈
amqp
rabbitMQ 사용 모듈
pkgcloud
swift, glusterfs 사용 모듈
formidable
form data를 파싱해주는 모듈
mocha
node.js test 모듈
should
mocha test에 사용되는 모듈
supertes
rest test에 사용되는 모듈
    engines
node
애플리케이션에서 사용할 node.js 모듈 버젼. 개방형 플랫폼에 배포하여 사용시 Node Buildpack에서 지원하는 Node.js 버젼에 따라 사용할 수 있는 버젼에 제약이 있다. - https://github.com/cloudfoundry/nodejs-buildpack/blob/master/CHANGELOG
npm
애플리케이션에서 사용할 npm 버젼 Node.js와 마찬가지로 Node Buildpack에서 지원하는 버젼에 따라 사용할 수 있는 버젼에 제약이 있다.
2) 모듈 설치
    pakage.json에 정의된 모듈을 설치한다. 모듈이름을 지정하지 않으면 package.json의 depencencies의 모든 모듈을 설치한다.
    1
    >npm install
    Copied!
3) ./bin/www
    HTTP서버가 사용할 PORT를 개방형 플랫폼이 제공하는 PORT를 사용하게 설정한다. 개방형 플랫폼은 이 값을 이용하여 애플리케이션이 제대로 동작하고 있는지 감지하는데 사용한다. 이 값 외의 다른 PORT를 사용하면 애플리케이션이 제대로 동작하지 않는다.
1
#!/usr/bin/env node
2
3
/**
4
* Module dependencies.
5
*/
6
7
var app = require('../app');
8
var debug = require('debug')('node-sample-app:server');
9
var http = require('http');
10
11
/**
12
* Get port from environment and store in Express.
13
* port 환경변수를 얻어와서 변수에 담는다.
14
* 'process.env.PORT'는 Cloud에서 사용하는 환경변수.
15
*/
16
17
var port = normalizePort(process.env.PORT || '3000');
18
app.set('port', port);
19
20
/**
21
* Create HTTP server.
22
* HTTP 서버 생성.
23
*/
24
25
var server = http.createServer(app).listen(app.get('port'), function(){
26
console.log('Express server listening on port ' + app.get('port'));
27
});
28
29
/**
30
* Listen on provided port, on all network interfaces.
31
* 서버가 사용할 port를 설정한다.
32
*/
33
34
server.listen(port);
35
server.on('error', onError);
36
server.on('listening', onListening);
37
...(생략)
Copied!
4) ./app.js
    Request URL 매핑 설정
1
var express = require('express');
2
var path = require('path');
3
var favicon = require('serve-favicon');
4
var logger = require('morgan');
5
var cookieParser = require('cookie-parser');
6
var bodyParser = require('body-parser');
7
8
var routes = require('./routes/index');
9
var users = require('./routes/users');
10
11
var app = express();
12
13
// URL 매핑 후 수행할 js 파일들
14
var org_chart_mysql = require('./routes/rest/org_chart/mysql')
15
, org_chart_mongo = require('./routes/rest/org_chart/mongo')
16
, org_chart_cubrid = require('./routes/rest/org_chart/cubrid')
17
, orgs_mysql = require('./routes/rest/orgs/mysql')
18
, orgs_mongo = require('./routes/rest/orgs/mongo')
19
, orgs_cubrid = require('./routes/rest/orgs/cubrid')
20
, groups_mysql = require('./routes/rest/groups/mysql')
21
, groups_mongo = require('./routes/rest/groups/mongo')
22
, groups_cubrid = require('./routes/rest/groups/cubrid')
23
, login = require('./routes/rest/login/login')
24
, image = require('./routes/rest/image/image')
25
, page = require('./routes/page/page_processing');
26
27
// view engine setup
28
// 뷰 엔진 설정
29
app.set('views', path.join(__dirname, 'views/'));
30
app.set('view engine', 'ejs');
31
32
// uncomment after placing your favicon in /public
33
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
34
app.use(logger('dev'));
35
app.use(bodyParser.json());
36
app.use(bodyParser.urlencoded({ extended: false }));
37
app.use(cookieParser());
38
// 정적파일 위치 설정
39
app.use(express.static(path.join(__dirname, 'public')));
40
41
/*
42
* URL 매핑 설정
43
*/
44
app.use( '/', routes);
45
app.use( '/users', users);
46
47
// page
48
app.get( '/login', page.login);
49
app.get( '/manage', page.manage);
50
app.get( '/main/:id', page.main);
51
52
// org-chart
53
app.get( '/org-chart/:org_id/mysql', org_chart_mysql.index);
54
app.get( '/org-chart/:org_id/cubrid', org_chart_cubrid.index);
55
app.get( '/org-chart/:org_id/mongo', org_chart_mongo.index);
56
app.get( '/org-chart/:org_id/status/mysql', org_chart_mysql.status);
57
app.get( '/org-chart/:org_id/status/cubrid', org_chart_cubrid.status);
58
app.get( '/org-chart/:org_id/status/mongo', org_chart_mongo.status);
59
60
//orgs
61
// mysql
62
app.get( '/orgs/mysql', orgs_mysql.index);
63
app.post( '/orgs/mysql', orgs_mysql.create);
64
app.get( '/orgs/:org_id/mysql', orgs_mysql.show);
65
app.put( '/orgs/:org_id/mysql', orgs_mysql.update);
66
app.delete('/orgs/:org_id/mysql', orgs_mysql.destroy);
67
..(생략)
Copied!

3.4. VCAP_SERVICES 환경설정 정보

개방형 플랫폼에 배포되는 애플리케이션이 바인딩된서비스별 접속 정보를 얻기 위해서는 애플리케이션별로 등록되어있는 VCAP_SERVICES 환경설정 정보를 읽어들여정보를 획득 할 수 있다.
1) 개방형 플랫폼의 애플리케이션 환경정보
    서비스를 바인딩하면 JSON 형태로 환경설정 정보가 애플리케이션 별로 등록된다.
1
{
2
"VCAP_SERVICES": {
3
"CubridDB": [
4
{
5
"credentials": {
6
"host": "10.30.60.23::",
7
"hostname": "10.30.60.23",
8
"jdbcurl": "jdbc:cubrid:10.30.60.23::fccf1d7869ff72ce:b2f6b4af1e7bd7d8:45f179c648ee60a5:",
9
"name": "fccf1d7869ff72ce",
10
"password": "45f179c648ee60a5",
11
"port": "",
12
"uri": "cubrid:10.30.60.23::fccf1d7869ff72ce:b2f6b4af1e7bd7d8:45f179c648ee60a5:",
13
"username": "b2f6b4af1e7bd7d8"
14
},
15
"label": "CubridDB",
16
"name": "sample-cubrid-instance",
17
"plan": "utf8",
18
"tags": [
19
"cubrid",
20
"document"
21
]
22
}
23
],
24
..(이하 생략)..
Copied!
2) Node.js에서 개방형 플랫폼의 애플리케이션 환경정보에 접근하는 방법
    시스템환경변수의 VCAP_SERVICES값을 읽어서 접근 할 수 있다.
    1
    process.env.VCAP_SERVICES
    Copied!

3.5. Mysql 연동

1) ./route/db/mysql/db_pooling.js
    개방형 플랫폼의 애플리케이션 환경정보에 접근하여 mysql Connection Pool을 생성
    ```javascript
    /**
      generic-pool 연동
      mysql 풀 모듈 구현
      */
var generic_pool = require("generic-pool"); var mysql = require("mysql");
config = {}; if (process.env.VCAP_SERVICES) { // cloud env 설정. 데이터 구조는 2.3.4 VCAP_SERVICES 환경정보 참고 var cloud_env = JSON.parse(process.env.VCAP_SERVICES); var mysql_env = cloud_env["Mysql-DB"][0]["credentials"];
config = { host:mysql_env.hostname, user:mysql_env.username, password:mysql_env.password, database:mysql_env.name }; } else { // local env config = { host:'10.30.40.63', user:'cESTBl9QpxGVF5Xa', password:'aVu1ynInBnaEeFY0', database:'cf_ea68784e_3de6_439d_afc1_d51b4e95627b' }; }
var pooling = generic_pool.Pool({ name:"mysql", create:function(cb){ // create Connection var conn = mysql.createConnection(config); conn.connect(function(err){ if( err) console.log("mysql 연결오류"); else { // console.log("mysql 연결성공"); } cb(err, conn); // 콜백함수를 통해 풀링에 커넥션 객체를 던짐 }); }, destroy:function(myConn){ myConn.end(function(err){ if( err) console.log("mysql 연결해제오류"); // else console.log("mysql 연결해제성공"); }); }, min:3, max:5, idleTimeoutMillis:1000*500, log:false
});
process.on("exit", function(){ pooling.drain(function(){ pooling.destroyAllNow(); }); });
module.exports = pooling;
1
### 3.6. Cubrid 연동
2
1) ./route/db/cubrid/db_pooling.js
3
- 개방형 플랫폼의 애플리케이션 환경정보에 접근하여 cubrid Connection Pool을 생성
4
5
```javascript
6
/**
7
* generic-pool 연동
8
* cubrid 풀 모듈 구현
9
*/
10
11
var generic_pool = require("generic-pool");
12
var cubrid = require("node-cubrid");
13
14
var database
15
, port
16
, hostname
17
, username
18
, password;
19
if (process.env.VCAP_SERVICES) {
20
// cloud env 설정. 데이터 구조는 2.3.4 VCAP_SERVICES 환경정보 참고
21
var cloud_env = JSON.parse(process.env.VCAP_SERVICES);
22
var cubrid_env = cloud_env["CubridDB"][0]["credentials"];
23
24
database = cubrid_env.name
25
port = cubrid_env.port
26
hostname = cubrid_env.hostname
27
username = cubrid_env.username
28
password = cubrid_env.password;
29
} else {
30
// local env
31
database = 'fccf1d7869ff72ce'
32
port = ''
33
hostname = '10.30.60.23'
34
username = 'b2f6b4af1e7bd7d8'
35
password = '45f179c648ee60a5';
36
}
37
var pooling = generic_pool.Pool({
38
name:"cubrid",
39
create:function(cb){
40
// console.log("cubrid_env.uri:" + cubrid_env.uri);
41
var conn = cubrid.createCUBRIDConnection(hostname, port, username, password, database);
42
// create Connection
43
conn.connect(function(err){
44
if( err) console.log("cubrid 연결오류");
45
else{
46
// console.log("cubrid 연결성공");
47
cb(err, conn);
48
}
49
// 콜백함수를 통해 풀링에 커넥션 객체를 던짐
50
});
51
},
52
destroy:function(myConn){
53
myConn.end(function(err){
54
if( err) console.log("cubrid 연결해제오류");
55
// else console.log("cubrid 연결해제성공");
56
});
57
},
58
min:3,
59
max:5,
60
idleTimeoutMillis:1000*50,
61
log:false,
62
63
});
64
65
process.on("exit", function(){
66
pooling.drain(function(){
67
pooling.destroyAllNow();
68
});
69
});
70
71
module.exports = pooling;
Copied!

3.7. MongoDB 연동

1) ./route/db/mongo/db_pooling.js
    개방형 플랫폼의 애플리케이션 환경정보에 접근하여 mongodb Connection Pool을 생성
1
/**
2
* generic-pool 연동
3
* mongo 풀 모듈 구현
4
*/
5
6
var generic_pool = require("generic-pool");
7
var mongoClient = require("mongodb").MongoClient;
8
9
var url = '';
10
if (process.env.VCAP_SERVICES) {
11
// cloud env. 설정. 데이터 구조는 2.3.4 VCAP_SERVICES 환경정보 참고
12
var cloud_env = JSON.parse(process.env.VCAP_SERVICES);
13
var mongo_env = cloud_env["Mongo-DB"][0]["credentials"];
14
15
url = mongo_env.uri;
16
17
} else {
18
// local env.
19
url = 'mongodb://d3e35ad5-9f49-43ae-bc85-08e39ec1d8eb:[email protected]:27017/e37e541c-75de-4f01-8196-63e2d902e768';
20
}
21
22
var pooling = generic_pool.Pool({
23
name:"mongo",
24
create:function(cb){
25
// create Connection
26
mongoClient.connect(url, function(err, db){
27
if (err) console.log("mongo 연결오류");
28
else {
29
cb(err, db);
30
}
31
});
32
},
33
destroy:function(myDb){
34
myDb.close(function(err){
35
if( err) console.log("mysql 연결해제오류");
36
// else console.log("mysql 연결해제성공");
37
});
38
},
39
min:3,
40
max:5,
41
idleTimeoutMillis:1000*500,
42
log:false
43
44
});
45
46
47
module.exports = pooling;
Copied!

3.8. Redis 연동

1) ./route/redis/redis.js
    개방형 플랫폼의 애플리케이션 환경정보에 접근하여 redis Connection을 생성
1
var redis = require("redis");
2
3
var options = {};
4
if (process.env.VCAP_SERVICES) {
5
// cloud env. 설정. 데이터 구조는 2.3.4 VCAP_SERVICES 환경정보 참고
6
var services = JSON.parse(process.env.VCAP_SERVICES);
7
var redisConfig = services["redis-sb"];
8
9
if (redisConfig) {
10
var node = redisConfig[0];
11
options = {
12
host: node.credentials.host,
13
port: node.credentials.port,
14
pass: node.credentials.password,
15
};
16
}
17
18
} else {
19
// local env.
20
options = {
21
host: '10.30.40.71',
22
port: '34838',
23
pass: 'c239b721-d986-4ee3-8816-b5f5fa9f3ffb',
24
};
25
}
26
27
var client = null;
28
exports.open = function(cb) {
29
// console.log(JSON.stringify(options));
30
//create Client
31
client = redis.createClient(options);
32
// get auth.
33
client.auth(options.pass);
34
35
cb(client);
36
}
37
exports.close = function(){
38
client.end();
39
}
Copied!

3.9. RabbitMQ연동

1) ./route/rabbitMQ/rabbitMQ.js
    개방형 플랫폼의 애플리케이션 환경정보에 접근하여 rabbirMQ Connection을 생성
1
var amqp = require('amqp');
2
3
var url = '';
4
if (process.env.VCAP_SERVICES) {
5
// cloud env. 설정. 데이터 구조는 2.3.4 VCAP_SERVICES 환경정보 참고
6
var services = JSON.parse(process.env.VCAP_SERVICES);
7
var rabbitMQConfig = services["p-rabbitmq"];
8
9
if (rabbitMQConfig) {
10
var node = rabbitMQConfig[0];
11
url = node.credentials.uri;
12
}
13
} else {
14
// local env.
15
url = 'amqps://14b1ab93-4cdb-46af-8cdd-8d8073bbe282:[email protected]:5671/6ffb4d8a-8748-4f00-a338-80e6eadee822';
16
}
17
18
exports.open = function(cb){
19
// create connection.
20
var conn = amqp.createConnection({url: url});
21
22
// it must be cb(callback) after the 'ready' event.
23
conn.on('ready', function(){
24
cb(conn);
25
});
26
}
27
28
// not used.
29
/*
30
exports.close = function(){
31
conn.disconnect();
32
}
33
*/
Copied!

3.10. GlusterFS 연동

1) ./route/glusterfs/glusterfs.js
    개방형 플랫폼의 애플리케이션 환경정보에 접근하여 glusterfs Connection을 생성
1
var pkgcloud = require('pkgcloud');
2
var http = require('http');
3
var url = require('url');
4
5
var credentials = {};
6
var container_name = 'node_container';
7
if (process.env.VCAP_SERVICES) {
8
// cloud env. 설정. 데이터 구조는 2.3.4 VCAP_SERVICES 환경정보 참고
9
var services = JSON.parse(process.env.VCAP_SERVICES);
10
var glusterfsConfig = services["glusterfs"];
11
12
if (glusterfsConfig) {
13
var config = glusterfsConfig[0];
14
credentials = {
15
provider: 'openstack', //
16
username: config.credentials.username,
17
password: config.credentials.password,
18
authUrl: config.credentials.auth_url.substring(0, config.credentials.auth_url.lastIndexOf('/')),
19
region: 'RegionOne' //
20
};
21
}
22
} else {
23
// local env.
24
credentials = {
25
provider: 'openstack',
26
username: 'cf13d551d997458e',
27
password: 'b45cc01d53a4f0e0',
28
authUrl: 'http://54.199.136.22:5000/',
29
region: 'RegionOne'
30
};
31
}
32
33
// create Client
34
var client = pkgcloud.storage.createClient(credentials);
35
36
// delete container for test
37
/*
38
client.destroyContainer(container_name, function(err, result){
39
if (err) console.log(err);
40
else console.log(result);
41
});
42
*/
43
44
// check container
45
client.getContainer(container_name, function(err, container){
46
if (err)
47
{
48
// if container not exist
49
if (err.statusCode === 404)
50
{
51
// create container
52
client.createContainer({name:container_name}, function(create_err, create_container){
53
if (create_err) console.log(err);
54
else
55
{
56
// if container created successfully, setting a readable member(X-Contaner-Read: .r:*)
57
// 컨테이너가 성공적으로 생성되었다면 컨테이너를 누구나 읽을 수 있게 설정한다.(X-Contaner-Read: .r:*)
58
// There is a bug in the code(pkgcloud). so i used api call.
59
// pkgcloud 모듈에서 metadata를 넣을 경우 prefix가 붙는 로직때문에 제대로 위의 값이 입력이 안되므로 api를 통해서 설정.
60
var serviceUrl = url.parse(create_container.client._serviceUrl);
61
var option = {
62
host: serviceUrl.hostname,
63
port: serviceUrl.port,
64
path: serviceUrl.path+'/'+container_name,
65
method: 'POST',
66
headers: {
67
'X-Auth-Token': create_container.client._identity.token.id,
68
'X-Container-Read': '.r:*' // ACL form
69
}
70
};
71
var req = http.request(option, function(res){
72
});
73
req.end();
74
}
75
76
});
77
}
78
else console.log(err);
79
}
80
});
81
82
module.exports = client;
Copied!

4. 배포

개방형 플랫폼에 애플리케이션을 배포하면 배포한 애플리케이션과 개방형 플랫폼이 제공하는 서비스를 연결하여 사용할 수 있다. 개방형 플랫폼상에서 실행을 해야만 개방형 플랫폼의 애플리케이션 환경변수에 접근하여 서비스에 접속할 수 있다.

4.1. 개방형 플랫폼 로그인

아래의 과정을 수행하기 위해서 개방형 플랫폼에 로그인
$ cf api --skip-ssl-validation https://api.cf.open-paas.com # 개방형 플랫폼 TARGET 지정

cf api [target url]

$ cf login -u testUser -o sample_test -s sample_space # 로그인 요청

cf login –u [user name] –o [org name] –s [space name]

4.2. 서비스 생성

애플리케이션에서 사용할 서비스를 개방형 플랫폼을 통하여 생성한다. 별도의 서비스 설치과정 없이 생성할 수 있으며, 애플리케이션과 바인딩과정을 통해 접속정보를 얻을 수있다.
    서비스 생성 (cf marketplace 명령을 통해 서비스 목록과 각 서비스의 플랜을 조회할 수 있다.
# cf create-service SERVICE PLAN SERVICE_INSTANCE [-c PARAMETERS_AS_JSON] [-t TAGS]
$ cf create-service p-mysql 100mb node-mysql
$ cf create-service CubridDB utf8 node-cubrid
$ cf create-service Mongo-DB default-plan node-mongodb
$ cf create-service redis-sb shared-vm node-redis
$ cf create-service glusterfs glusterfs-5Mb node-glusterfs
$ cf create-service p-rabbitmq standard node-rabbitmq

4.3. 애플리케이션 배포

애플리케이션을 개방형 플랫폼에 배포한다. 배포된 애플리케이션은 생성된 서비스와 바인드하여 서비스를 사용할 수 있다.
    cf push 명령시 현재 디렉토리의 manifest.yml을 참조하여 배포가 진행된다.

1. manifest.yml 생성

1
---
2
applications:
3
- name: node-sample-app # 애플리케이션 이름
4
memory: 512M # 애플리케이션 메모리 사이즈
5
instances: 1 # 애플리케이션 인스턴스 개수
6
command: npm start # 애플리케이션 실행 명령어
7
path: ./ # 배포될 애플리케이션의 위치
Copied!

2. Mysql, Cubrid 테이블 생성

    Sample App의 조직관리 기능을 위해 DB에 테이블을 생성해 주어야 한다.
    Mysql과 Cubrid에 테이블을 추가하는 방법은 OpenPaaS Mysql, Cubrid 서비스팩 설치 가이드의 'Client 툴 접속'을 참고한다.
    Client 툴을 이용하여 아래의 테이블 생성 sql를 각각 실행한다. (Mysql과 Cubrid 양쪽다 동일한 sql로 생성가능하다.)
1
DROP TABLE IF EXISTS ORG_TBL;
2
DROP TABLE IF EXISTS GROUP_TBL;
3
4
5
CREATE TABLE ORG_TBL (
6
id INT AUTO_INCREMENT PRIMARY KEY
7
, label VARCHAR(40) NOT NULL
8
, `desc` VARCHAR(150)
9
, url VARCHAR(500) DEFAULT '#'
10
, created TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
11
, modified TIMESTAMP
12
);
13
14
CREATE TABLE GROUP_TBL (
15
id INT AUTO_INCREMENT PRIMARY KEY
16
, org_id INTEGER NOT NULL
17
, parent_id INTEGER
18
, label VARCHAR(40) NOT NULL
19
, `desc` VARCHAR(150)
20
, thumb_img_name VARCHAR(256)
21
, thumb_img_path VARCHAR(512)
22
, url VARCHAR(500) DEFAULT '#'
23
, created TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
24
, modified TIMESTAMP
25
);
26
27
ALTER TABLE GROUP_TBL
28
ADD FOREIGN KEY(org_id)
29
REFERENCES ORG_TBL(id)
30
ON DELETE CASCADE;
31
32
ALTER TABLE GROUP_TBL
33
ADD FOREIGN KEY(parent_id)
34
REFERENCES GROUP_TBL(id)
35
ON DELETE CASCADE;
Copied!

3. 애플리케이션 배포

    cf push 명령으로 배포한다. 별도의 값을 넣지않으면 manifest.yml의 설정을 사용한다. 아직 서비스를 연결하지 않았기 때문에 --no-start 옵션으로 배포후 실행은 하지않는다.
$ cf push --no-start

4.4. 애플리케이션, 서비스 연결

애플리케이션과 서비스를 연결하는 과정을 '바인드(bind)라고 하며, 이 과정을 통해 서비스에 접근할 수 있는 접속정보를 생성한다.
    애플리케이션과 서비스 연결
cf bind-service APP_NAME SERVICE_INSTANCE [-c PARAMETERS_AS_JSON]
$ cf bind-service node-sample-app node-mysql
$ cf bind-service node-sample-app node-cubrid
$ cf bind-service node-sample-app node-mongodb
$ cf bind-service node-sample-app node-redis
$ cf bind-service node-sample-app node-glusterfs
$ cf bind-service node-sample-app node-rabbitmq
연결확인
$ cf services

4.5. 애플리케이션 실행

서비스 바인드 과정을 통해 생성된 접속정보 환경변수를 가지고 어플리케이션이 실행된다.
$ cf start node-sample-app

5. 테스트

샘플 어플리케이션은 REST 서비스로 구현되어있으며 REST 테스트를 위해서 mocha 모듈을 사용하였다. 테스트를 진행하기 위해서는 mocha 모듈을 포함한 package.json 안의 모듈들이 설치 되어 있어야한다. (npm install)

1. Makefile

    매번 bin파일에 접근하여 실행하는 불편함을 해결하기 위해 작성. 리눅스 운영체제에서 사용할 수 있다.
1
test:
2
@./node_modules/.bin/mocha -u tdd
3
4
.PHONY: test
Copied!

2. 테스트 실행

    test디렉토리 아래에 있는 테스트를 실행한다.
2.1. 윈도우
> .\node_modules.bin\mocha -u tdd test
2.2. 리눅스
$ make test
Last modified 1yr ago