MeaNstack on Docker 
-- Daniel Ku (http://kjunine.net/)
MEAN Stack? 
— MongoDB: NoSQL 데이터베이스 
— Express: 웹 어플리케이션 프레임워크 
— AngularJS: 프런트엔드 프레임워크 
— Node.js: 어플리케이션 서버
스타트업을 위한 기술 스택 
— JavaScript 하나면 된다. 
— 시작하기 쉽다. 
— 빠른 MVP 개발이 가능하다.
개발 환경 
— NPM: 백엔드 라이브러리 관리 
— Yeoman: 프로젝트 스캐폴딩 도구 
— Bower: 프런트엔드 라이브러리 관리 
— Grunt: 빌드 도구
실행 환경 
— PM2: Node.js Application 실행 도구 
모니터링/백업 서비스 
— MMS: MongoDB Management Service 
— New Relic: Application Monitoring Service
MeaNstack on Docker 
— MongoDB 
— Node.js
주의사항 
여기서 소개하는 내용은 베스트 프랙티스가 아니다. 
현재까지 경험한 내용을 정리한 것이며, 
개선될 여지가 많이 남아 있다.
시스템 구성
실제 구성 on AWS 
— ELB 
— Application Layer: n Application Servers 
— n x Application 
— Database Layer: 1 MongoDB Replica Set 
— 2 x MongoDB Server + MongoDB Arbiter 
— MongoDB ReplSet Configurator 
— MMS Monitoring/Backup Agent
도커 컴포넌트 도출 
— MongoDB Server 
— MongoDB ReplSet Configurator 
— // MMS Monitoring Agent 
— // MMS Backup Agent 
— Sample Application
데모 구성 on Vagrant 
— 1 MongoDB Replica Set (192.168.7.10) 
— 2 x MongoDB Server + MongoDB Arbiter 
— MongoDB ReplSet Configurator 
— 1 Sample Application (192.168.7.20)
MongoDB
MongoDB Server 
FROM kjunine/ubuntu 
MAINTAINER Daniel Ku "kjunine@gmail.com" 
RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10 &&  
echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' |  
tee /etc/apt/sources.list.d/mongodb.list &&  
apt-get update &&  
apt-get install -y mongodb-org 
VOLUME "/data" 
WORKDIR /data 
EXPOSE 27017 
ENTRYPOINT ["mongod", "--dbpath", "/data"]
Build 
$ docker build -t kjunine/mongodb .
Run 
$ docker run -it -p 27017:27017 -v /data  
--name mongodb1 --entrypoint=mongod  
kjunine/mongodb --dbpath /data --replSet mnod 
$ docker run -it -p 27018:27017 -v /data  
--name mongodb2 --entrypoint=mongod  
kjunine/mongodb --dbpath /data --replSet mnod 
$ docker run -it -p 27019:27017 -v /data  
--name mongodb3 --entrypoint=mongod  
kjunine/mongodb --dbpath /data --replSet mnod
Client Run 
$ docker run -it --rm  
--entrypoint=mongo  
kjunine/mongodb 192.168.7.10:27017
MongoDB ReplSet Configurator 
MongoDB의 Replica Set을 MongoDB Shell에 접속하지 않고 설 
정할 수 있는 프로그램이다. 
https://github.com/kjunine/mongodb-replset-configurator
FROM kjunine/nodejs:latest 
MAINTAINER Daniel Ku "kjunine@gmail.com" 
ADD . /mrsc 
WORKDIR /mrsc 
RUN npm install 
ENV MRSC_RECONFIG false 
ENTRYPOINT ["node", "index.js"]
환경 변수 
— MRSC_ID (필수): Replica Set의 ID 
— MRSC_SERVERS (필수): ','로 구분되는 서버 주소들 
— MRSC_ARBITERS: ','로 구분되는 Arbiter 서버 주소들 
— MRSC_RECONFIG: 재설정하려면 'true'
Build 
$ docker build -t kjunine/mongodb-replset-configurator . 
Run 
$ docker run -it --rm -e MRSC_ID=mnod  
-e MRSC_SERVERS=192.168.7.10:27017,192.168.7.10:27018  
-e MRSC_ARBITERS=192.168.7.10:27019  
kjunine/mongodb-replset-configurator
Demo
MMS Monitoring Agent 
FROM kjunine/ubuntu 
MAINTAINER Daniel Ku "kjunine@gmail.com" 
RUN curl -OL https://mms.mongodb.com/download/agent/monitoring/mongodb-mms-monitoring-agent_2.5.0.116-1_amd64.deb &&  
dpkg -i mongodb-mms-monitoring-agent_2.5.0.116-1_amd64.deb 
ENV MMS_API_KEY CHANGE_ME 
ADD ./setup.sh /root/ 
ADD ./run.sh /root/ 
WORKDIR /root 
CMD ./setup.sh && ./run.sh
setup.sh 
#!/bin/bash 
sed -i -e "s/^(mmsApiKey=)$/1${MMS_API_KEY}/"  
/etc/mongodb-mms/monitoring-agent.config 
run.sh 
#!/bin/bash 
/usr/bin/mongodb-mms-monitoring-agent  
-conf /etc/mongodb-mms/monitoring-agent.config
Build 
$ docker build -t kjunine/mms-monitoring-agent . 
Run 
$ docker run -it --rm  
-e MMS_API_KEY=CHANGE_ME  
--name mms-monitoring-agent kjunine/mms-monitoring-agent
MMS Backup Agent 
FROM kjunine/ubuntu 
MAINTAINER Daniel Ku "kjunine@gmail.com" 
RUN curl -OL https://mms.mongodb.com/download/agent/backup/mongodb-mms-backup-agent_2.5.0.164-1_amd64.deb &&  
dpkg -i mongodb-mms-backup-agent_2.5.0.164-1_amd64.deb 
ENV MMS_API_KEY CHANGE_ME 
ADD ./setup.sh /root/ 
ADD ./run.sh /root/ 
WORKDIR /root 
CMD ./setup.sh && ./run.sh
setup.sh 
#!/bin/bash 
sed -i -e "s/^(mmsApiKey=)$/1${MMS_API_KEY}/"  
/etc/mongodb-mms/backup-agent.config 
run.sh 
#!/bin/bash 
/usr/bin/mongodb-mms-backup-agent  
-c /etc/mongodb-mms/backup-agent.config
Build 
$ docker build -t kjunine/mms-backup-agent . 
Run 
$ docker run -it --rm  
-e MMS_API_KEY=CHANGE_ME  
--name mms-backup-agent kjunine/mms-backup-agent
Node.js
Node.js with Binary 
FROM kjunine/ubuntu 
MAINTAINER Daniel Ku "kjunine@gmail.com" 
RUN wget http://nodejs.org/dist/v0.10.31/node-v0.10.31-linux-x64.tar.gz &&  
tar xzf node-v0.10.31-linux-x64.tar.gz &&  
rm node-v0.10.31-linux-x64.tar.gz &&  
mv node-v0.10.31-linux-x64 node &&  
mv node /usr/share/node &&  
ln -s /usr/share/node/bin/node /usr/bin/node &&  
ln -s /usr/share/node/bin/npm /usr/bin/npm
Node.js with NVM 
FROM kjunine/ubuntu 
MAINTAINER Daniel Ku "kjunine@gmail.com" 
RUN apt-get install -y man &&  
git clone https://github.com/creationix/nvm.git ~/.nvm &&  
/bin/bash -c '. ~/.nvm/nvm.sh && nvm install 0.10' &&  
ln -s ~/.nvm/current/bin/node /usr/bin/node &&  
ln -s ~/.nvm/current/bin/npm /usr/bin/npm
Build 
$ docker build -t kjunine/nodejs .
Sample Application
생성 
generator-angular-fullstack을 이용해 샘플 프로젝트 생성 
$ npm install -g yo bower grunt-cli 
$ npm install -g generator-angular-fullstack 
$ mkdir mnod.source 
$ cd mnod.source 
$ yo angular-fullstack
테스트 & 서버 실행 & 빌드 
$ npm install 
$ bower install 
$ grunt test 
$ grunt serve 
$ grunt build
New Relic 설정 
$ npm install newrelic --save 
$ cp node_modules/newrelic/newrelic.js . 
server/app.js 상단에 다음 내용 추가 
if ('production' === process.env.NODE_ENV) { 
require('newrelic'); 
}
Workarounds 
— 빌드 시 bower_components 폴더를 그대로 복사 
=> docker build context 7MB 이상 
=> bower_components 폴더 복사하지 않게 함 
— connect-mongo 모듈이 MongoDB 다중 서버를 지원하지 않음 
=> 해당 모듈 사용하지 않음
FROM kjunine/nodejs:latest 
MAINTAINER Daniel Ku "kjunine@gmail.com" 
ADD . /mnod 
WORKDIR /mnod 
RUN npm install -g pm2 && npm install 
ENV NODE_ENV production 
ENV PORT 8080 
ENV MONGOHQ_URL mongodb://localhost/mnod 
ENV NEW_RELIC_APP_NAME MeaNstackOnDocker 
ENV NEW_RELIC_LICENSE_KEY CHANGE_ME 
EXPOSE 8080 
CMD pm2 start server/app.js -i max --name mnod --no-daemon
Build 
$ grunt build 
$ cd dist 
$ docker build -t kjunine/mnod . 
Run 
$ docker run -it --rm -p 8080:8080  
-e MONGOHQ_URL=mongodb://192.168.7.10:27017,192.168.7.10:27018/mnod?replicaSet=mnod  
-e NEW_RELIC_LICENSE_KEY=CHANGE_ME  
--name mnod kjunine/mnod
#!/usr/bin/env bash 
VERSION=X.Y.Z 
npm install 
bower install 
rm -rf dist 
mkdir dist 
grunt build 
... 
cd dist 
git init 
git checkout --orphan release 
git add --all 
git ci -m "$VERSION" 
git remote add origin git@github.com:kjunine/mnod.release.git 
git push origin release --force 
git checkout -b $VERSION 
git push origin $VERSION 
cd ..
Demo
Vagrant with Docker 
Provisioner
Base Box 
config.vm.box = "ubuntu/trusty64" 
config.vm.define "base" do |base| 
base.vm.provision :file, source: "docker", destination: "~/docker" 
base.vm.provision :shell, 
inline: "cp /home/vagrant/docker /etc/default/docker" 
base.vm.provision :docker, 
images: [ 
"kjunine/mongodb:latest", 
"kjunine/mongodb-replset-configurator:latest", 
"kjunine/nodejs:latest", 
"kjunine/mnod:latest" 
] 
end 
DOCKER_OPTS="-H unix:// -H tcp://0.0.0.0:2375"
Demo Vagrant 
config.vm.box = "mnod/base" 
config.vm.define "database" do |database| 
database.vm.hostname = "database" 
database.vm.network "private_network", ip: "192.168.7.10" 
database.vm.network "forwarded_port", guest: 2375, host: 2376 
... 
end 
config.vm.define "application" do |application| 
application.vm.hostname = "application" 
application.vm.network "private_network", ip: "192.168.7.20" 
application.vm.network "forwarded_port", guest: 2375, host: 2377 
application.vm.network "forwarded_port", guest: 8080, host: 8080 
... 
end
Database VM Provision 
database.vm.provision :docker do |docker| 
docker.run "mongodb1", 
image: "kjunine/mongodb", 
args: "-p 27017:27017 -v /data --entrypoint=mongod", 
cmd: "--dbpath /data --replSet mnod" 
... 
docker.run "kjunine/mongodb-replset-configurator", 
daemonize: false, 
args: "--rm -e MRSC_ID=mnod  
-e MRSC_SERVERS=192.168.7.10:27017,192.168.7.10:27018  
-e MRSC_ARBITERS=192.168.7.10:27019" 
end
Application VM Provision 
application.vm.provision :docker do |docker| 
docker.run "kjunine/mnod", 
args: "-p 8080:8080  
-e MONGOHQ_URL=mongodb://192.168.7.10:27017,192.168.7.10:27018/mnod?replicaSet=mnod  
-e NEW_RELIC_LICENSE_KEY=CHANGE_ME" 
end
vagrant up !
Demo
끝
Going Futher 
— MMS 
— Adding MongoDB user and password 
— Sharding MongoDB 
— Fully Automated Build/Deploy 
— Private Docker Repository 
— Monitoring and Logging
Dockerfile Sources 
https://github.com/kjunine?tab=repositories 
Docker Hub Repository 
https://registry.hub.docker.com/repos/kjunine/
Sample Source 
https://github.com/kjunine/mnod.source 
Sample Release 
https://github.com/kjunine/mnod.release 
Vagrant Provisioning 
https://github.com/kjunine/mnod.provision
Thank You!

MeaNstack on Docker

  • 1.
    MeaNstack on Docker -- Daniel Ku (http://kjunine.net/)
  • 2.
    MEAN Stack? —MongoDB: NoSQL 데이터베이스 — Express: 웹 어플리케이션 프레임워크 — AngularJS: 프런트엔드 프레임워크 — Node.js: 어플리케이션 서버
  • 3.
    스타트업을 위한 기술스택 — JavaScript 하나면 된다. — 시작하기 쉽다. — 빠른 MVP 개발이 가능하다.
  • 4.
    개발 환경 —NPM: 백엔드 라이브러리 관리 — Yeoman: 프로젝트 스캐폴딩 도구 — Bower: 프런트엔드 라이브러리 관리 — Grunt: 빌드 도구
  • 5.
    실행 환경 —PM2: Node.js Application 실행 도구 모니터링/백업 서비스 — MMS: MongoDB Management Service — New Relic: Application Monitoring Service
  • 6.
    MeaNstack on Docker — MongoDB — Node.js
  • 7.
    주의사항 여기서 소개하는내용은 베스트 프랙티스가 아니다. 현재까지 경험한 내용을 정리한 것이며, 개선될 여지가 많이 남아 있다.
  • 8.
  • 9.
    실제 구성 onAWS — ELB — Application Layer: n Application Servers — n x Application — Database Layer: 1 MongoDB Replica Set — 2 x MongoDB Server + MongoDB Arbiter — MongoDB ReplSet Configurator — MMS Monitoring/Backup Agent
  • 10.
    도커 컴포넌트 도출 — MongoDB Server — MongoDB ReplSet Configurator — // MMS Monitoring Agent — // MMS Backup Agent — Sample Application
  • 11.
    데모 구성 onVagrant — 1 MongoDB Replica Set (192.168.7.10) — 2 x MongoDB Server + MongoDB Arbiter — MongoDB ReplSet Configurator — 1 Sample Application (192.168.7.20)
  • 12.
  • 13.
    MongoDB Server FROMkjunine/ubuntu MAINTAINER Daniel Ku "kjunine@gmail.com" RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10 && echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | tee /etc/apt/sources.list.d/mongodb.list && apt-get update && apt-get install -y mongodb-org VOLUME "/data" WORKDIR /data EXPOSE 27017 ENTRYPOINT ["mongod", "--dbpath", "/data"]
  • 14.
    Build $ dockerbuild -t kjunine/mongodb .
  • 15.
    Run $ dockerrun -it -p 27017:27017 -v /data --name mongodb1 --entrypoint=mongod kjunine/mongodb --dbpath /data --replSet mnod $ docker run -it -p 27018:27017 -v /data --name mongodb2 --entrypoint=mongod kjunine/mongodb --dbpath /data --replSet mnod $ docker run -it -p 27019:27017 -v /data --name mongodb3 --entrypoint=mongod kjunine/mongodb --dbpath /data --replSet mnod
  • 16.
    Client Run $docker run -it --rm --entrypoint=mongo kjunine/mongodb 192.168.7.10:27017
  • 17.
    MongoDB ReplSet Configurator MongoDB의 Replica Set을 MongoDB Shell에 접속하지 않고 설 정할 수 있는 프로그램이다. https://github.com/kjunine/mongodb-replset-configurator
  • 18.
    FROM kjunine/nodejs:latest MAINTAINERDaniel Ku "kjunine@gmail.com" ADD . /mrsc WORKDIR /mrsc RUN npm install ENV MRSC_RECONFIG false ENTRYPOINT ["node", "index.js"]
  • 19.
    환경 변수 —MRSC_ID (필수): Replica Set의 ID — MRSC_SERVERS (필수): ','로 구분되는 서버 주소들 — MRSC_ARBITERS: ','로 구분되는 Arbiter 서버 주소들 — MRSC_RECONFIG: 재설정하려면 'true'
  • 20.
    Build $ dockerbuild -t kjunine/mongodb-replset-configurator . Run $ docker run -it --rm -e MRSC_ID=mnod -e MRSC_SERVERS=192.168.7.10:27017,192.168.7.10:27018 -e MRSC_ARBITERS=192.168.7.10:27019 kjunine/mongodb-replset-configurator
  • 21.
  • 22.
    MMS Monitoring Agent FROM kjunine/ubuntu MAINTAINER Daniel Ku "kjunine@gmail.com" RUN curl -OL https://mms.mongodb.com/download/agent/monitoring/mongodb-mms-monitoring-agent_2.5.0.116-1_amd64.deb && dpkg -i mongodb-mms-monitoring-agent_2.5.0.116-1_amd64.deb ENV MMS_API_KEY CHANGE_ME ADD ./setup.sh /root/ ADD ./run.sh /root/ WORKDIR /root CMD ./setup.sh && ./run.sh
  • 23.
    setup.sh #!/bin/bash sed-i -e "s/^(mmsApiKey=)$/1${MMS_API_KEY}/" /etc/mongodb-mms/monitoring-agent.config run.sh #!/bin/bash /usr/bin/mongodb-mms-monitoring-agent -conf /etc/mongodb-mms/monitoring-agent.config
  • 24.
    Build $ dockerbuild -t kjunine/mms-monitoring-agent . Run $ docker run -it --rm -e MMS_API_KEY=CHANGE_ME --name mms-monitoring-agent kjunine/mms-monitoring-agent
  • 25.
    MMS Backup Agent FROM kjunine/ubuntu MAINTAINER Daniel Ku "kjunine@gmail.com" RUN curl -OL https://mms.mongodb.com/download/agent/backup/mongodb-mms-backup-agent_2.5.0.164-1_amd64.deb && dpkg -i mongodb-mms-backup-agent_2.5.0.164-1_amd64.deb ENV MMS_API_KEY CHANGE_ME ADD ./setup.sh /root/ ADD ./run.sh /root/ WORKDIR /root CMD ./setup.sh && ./run.sh
  • 26.
    setup.sh #!/bin/bash sed-i -e "s/^(mmsApiKey=)$/1${MMS_API_KEY}/" /etc/mongodb-mms/backup-agent.config run.sh #!/bin/bash /usr/bin/mongodb-mms-backup-agent -c /etc/mongodb-mms/backup-agent.config
  • 27.
    Build $ dockerbuild -t kjunine/mms-backup-agent . Run $ docker run -it --rm -e MMS_API_KEY=CHANGE_ME --name mms-backup-agent kjunine/mms-backup-agent
  • 28.
  • 29.
    Node.js with Binary FROM kjunine/ubuntu MAINTAINER Daniel Ku "kjunine@gmail.com" RUN wget http://nodejs.org/dist/v0.10.31/node-v0.10.31-linux-x64.tar.gz && tar xzf node-v0.10.31-linux-x64.tar.gz && rm node-v0.10.31-linux-x64.tar.gz && mv node-v0.10.31-linux-x64 node && mv node /usr/share/node && ln -s /usr/share/node/bin/node /usr/bin/node && ln -s /usr/share/node/bin/npm /usr/bin/npm
  • 30.
    Node.js with NVM FROM kjunine/ubuntu MAINTAINER Daniel Ku "kjunine@gmail.com" RUN apt-get install -y man && git clone https://github.com/creationix/nvm.git ~/.nvm && /bin/bash -c '. ~/.nvm/nvm.sh && nvm install 0.10' && ln -s ~/.nvm/current/bin/node /usr/bin/node && ln -s ~/.nvm/current/bin/npm /usr/bin/npm
  • 31.
    Build $ dockerbuild -t kjunine/nodejs .
  • 32.
  • 33.
    생성 generator-angular-fullstack을 이용해샘플 프로젝트 생성 $ npm install -g yo bower grunt-cli $ npm install -g generator-angular-fullstack $ mkdir mnod.source $ cd mnod.source $ yo angular-fullstack
  • 34.
    테스트 & 서버실행 & 빌드 $ npm install $ bower install $ grunt test $ grunt serve $ grunt build
  • 35.
    New Relic 설정 $ npm install newrelic --save $ cp node_modules/newrelic/newrelic.js . server/app.js 상단에 다음 내용 추가 if ('production' === process.env.NODE_ENV) { require('newrelic'); }
  • 36.
    Workarounds — 빌드시 bower_components 폴더를 그대로 복사 => docker build context 7MB 이상 => bower_components 폴더 복사하지 않게 함 — connect-mongo 모듈이 MongoDB 다중 서버를 지원하지 않음 => 해당 모듈 사용하지 않음
  • 37.
    FROM kjunine/nodejs:latest MAINTAINERDaniel Ku "kjunine@gmail.com" ADD . /mnod WORKDIR /mnod RUN npm install -g pm2 && npm install ENV NODE_ENV production ENV PORT 8080 ENV MONGOHQ_URL mongodb://localhost/mnod ENV NEW_RELIC_APP_NAME MeaNstackOnDocker ENV NEW_RELIC_LICENSE_KEY CHANGE_ME EXPOSE 8080 CMD pm2 start server/app.js -i max --name mnod --no-daemon
  • 38.
    Build $ gruntbuild $ cd dist $ docker build -t kjunine/mnod . Run $ docker run -it --rm -p 8080:8080 -e MONGOHQ_URL=mongodb://192.168.7.10:27017,192.168.7.10:27018/mnod?replicaSet=mnod -e NEW_RELIC_LICENSE_KEY=CHANGE_ME --name mnod kjunine/mnod
  • 39.
    #!/usr/bin/env bash VERSION=X.Y.Z npm install bower install rm -rf dist mkdir dist grunt build ... cd dist git init git checkout --orphan release git add --all git ci -m "$VERSION" git remote add origin git@github.com:kjunine/mnod.release.git git push origin release --force git checkout -b $VERSION git push origin $VERSION cd ..
  • 40.
  • 41.
    Vagrant with Docker Provisioner
  • 42.
    Base Box config.vm.box= "ubuntu/trusty64" config.vm.define "base" do |base| base.vm.provision :file, source: "docker", destination: "~/docker" base.vm.provision :shell, inline: "cp /home/vagrant/docker /etc/default/docker" base.vm.provision :docker, images: [ "kjunine/mongodb:latest", "kjunine/mongodb-replset-configurator:latest", "kjunine/nodejs:latest", "kjunine/mnod:latest" ] end DOCKER_OPTS="-H unix:// -H tcp://0.0.0.0:2375"
  • 43.
    Demo Vagrant config.vm.box= "mnod/base" config.vm.define "database" do |database| database.vm.hostname = "database" database.vm.network "private_network", ip: "192.168.7.10" database.vm.network "forwarded_port", guest: 2375, host: 2376 ... end config.vm.define "application" do |application| application.vm.hostname = "application" application.vm.network "private_network", ip: "192.168.7.20" application.vm.network "forwarded_port", guest: 2375, host: 2377 application.vm.network "forwarded_port", guest: 8080, host: 8080 ... end
  • 44.
    Database VM Provision database.vm.provision :docker do |docker| docker.run "mongodb1", image: "kjunine/mongodb", args: "-p 27017:27017 -v /data --entrypoint=mongod", cmd: "--dbpath /data --replSet mnod" ... docker.run "kjunine/mongodb-replset-configurator", daemonize: false, args: "--rm -e MRSC_ID=mnod -e MRSC_SERVERS=192.168.7.10:27017,192.168.7.10:27018 -e MRSC_ARBITERS=192.168.7.10:27019" end
  • 45.
    Application VM Provision application.vm.provision :docker do |docker| docker.run "kjunine/mnod", args: "-p 8080:8080 -e MONGOHQ_URL=mongodb://192.168.7.10:27017,192.168.7.10:27018/mnod?replicaSet=mnod -e NEW_RELIC_LICENSE_KEY=CHANGE_ME" end
  • 46.
  • 47.
  • 50.
  • 51.
    Going Futher —MMS — Adding MongoDB user and password — Sharding MongoDB — Fully Automated Build/Deploy — Private Docker Repository — Monitoring and Logging
  • 52.
    Dockerfile Sources https://github.com/kjunine?tab=repositories Docker Hub Repository https://registry.hub.docker.com/repos/kjunine/
  • 53.
    Sample Source https://github.com/kjunine/mnod.source Sample Release https://github.com/kjunine/mnod.release Vagrant Provisioning https://github.com/kjunine/mnod.provision
  • 54.