<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Node.js &#8211; WONIZZ.LOG</title>
	<atom:link href="https://blog.wonizz.com/category/tech/nodejs/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.wonizz.com</link>
	<description>AI 자동화를 직접 굴려 본 개발자의 실무 교훈</description>
	<lastBuildDate>Fri, 21 Aug 2026 15:46:29 +0000</lastBuildDate>
	<language>ko-KR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.2</generator>

<image>
	<url>https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2026/08/wz-siteicon-512.png?fit=32%2C32&#038;ssl=1</url>
	<title>Node.js &#8211; WONIZZ.LOG</title>
	<link>https://blog.wonizz.com</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">152411368</site>	<item>
		<title>[Rundeck] 배포 개선 내용 공유</title>
		<link>https://blog.wonizz.com/2019/10/08/rundeck-deploy/</link>
					<comments>https://blog.wonizz.com/2019/10/08/rundeck-deploy/#respond</comments>
		
		<dc:creator><![CDATA[워니즈]]></dc:creator>
		<pubDate>Tue, 08 Oct 2019 08:48:54 +0000</pubDate>
				<category><![CDATA[Node.js]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[DevOps]]></category>
		<guid isPermaLink="false">http://blog.wonizz.tk/?p=839</guid>

					<description><![CDATA[<p>The standard Lorem Ipsum passage, used since the 1500s<br />
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
<p>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p>
<p>1914 translation by H. Rackham<br />
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"</p>
<p>Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."</p>
<p>1914 translation by H. Rackham<br />
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</p>
<p>안녕하세요? 정리하는 개발자 워니즈입니다. 이번시간에는 Rundeck 을 활용하여 배포 개선 작업을 했던 내용을 공유 하려고자 합니다. 필자가 속한 프로젝트는 CD(Continuous Deploy) 툴로 Rundeck을 사용하고 있습니다. 또한, 특수한 솔루션을 사용하다보니, 기존의 Spring Framework처럼 war파일을 배포하는것이 아닌, zip파일을 해당 서버에 명령어를 활용하여 설치하는 개념으로 되어있는데요. 배포 작업 시, 이러한 zip파일이 여러개 있고, 또한 각 zip파일마다 배포되어야 할&#8230;&#160;</p>
<p>The post <a rel="nofollow" href="https://blog.wonizz.com/2019/10/08/rundeck-deploy/">[Rundeck] 배포 개선 내용 공유</a> appeared first on <a rel="nofollow" href="https://blog.wonizz.com">WONIZZ.LOG</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The standard Lorem Ipsum passage, used since the 1500s<br />
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
<p>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p>
<p>1914 translation by H. Rackham<br />
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"</p>
<p>Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."</p>
<p>1914 translation by H. Rackham<br />
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</p>
안녕하세요? 정리하는 개발자 워니즈입니다. 이번시간에는 Rundeck 을 활용하여 <code>배포 개선</code> 작업을 했던 내용을 공유 하려고자 합니다.

필자가 속한 프로젝트는 CD(Continuous Deploy) 툴로 Rundeck을 사용하고 있습니다. 또한, 특수한 솔루션을 사용하다보니, 기존의 Spring Framework처럼 war파일을 배포하는것이 아닌, zip파일을 해당 서버에 명령어를 활용하여 설치하는 개념으로 되어있는데요.

배포 작업 시, 이러한 zip파일이 여러개 있고, 또한 각 zip파일마다 배포되어야 할 서버들이 각기 다르다면, 이것을 런덱에서 수행하게 되면 <code>작업자 실수</code>를 유발하게 됩니다.

<h1>1. 기존 배포 방식</h1>

우선 기존에 프로세스는 아래의 순서로 진행이 됩니다.

<ul>
<li>소스 pull</li>
<li>빌드</li>
<li>태그 생성</li>
</ul>

위의 방식으로 진행하기 위해서는 내용이 담겨있는 job이 생성이 되어있어야 하는데요.  제가 속한 프로젝트에서는 <code>Jenkins</code>로 빌드를 수행하고 나온 Tag를 <code>Rundeck</code>으로 보내주고 있습니다.

이렇게 한 이유는 내부 IDC에 소스를 관리하고있는데 pull + build는 내부에서 진행하고 Deploy는 AWS에 있는 서버들에 해주기 때문에 jenkins와 Deploy를 나눠놨습니다.

스프링 프레임워크와는 다르게 해당 소스만 추출하여 빌드가 가능하다 보니, 아래와같이 <code>filter</code>라는 개념으로 해당 소스를 업데이트하여 <code>hotfix</code>가 가능하도록 되어있습니다.

캡쳐된 이미지처럼, 입력해야될 파라미터들이 많이 있고, 직접 TYPING을 하다보니, 작업자 실수를 유발하기도 합니다.

<ul>
<li>빌드job</li>
</ul>

<pre><code class="line-numbers">#패키지 생성
curl -s -u admin:$ADMIN_PW -X POST $IPADDRESS:$PORT/crx/packmgr/service/.json/etc/packages/HOTFIX/hotfix_${SR_NUM}_${WHO}_${TIMESTAMP}?cmd=create -d packageName=hotfix_${SR_NUM}_${WHO}_${TIMESTAMP} -d groupName=HOTFIX

echo "package create"

#패키지 필터 업데이트
curl -s -u admin:$ADMIN_PW -X POST $IPADDRESS:$PORT/crx/packmgr/update.jsp -F path=/etc/packages/HOTFIX/hotfix_${SR_NUM}_${WHO}_${TIMESTAMP}.zip -F packageName=hotfix_${SR_NUM}_${WHO}_${TIMESTAMP} -F groupName=HOTFIX -F filter="$FILTER_JSON" -F '_charset_=UTF-8'

echo "package update"

#패키지 빌드
curl -s -u admin:$ADMIN_PW -X POST $IPADDRESS:$PORT/crx/packmgr/service/.json/etc/packages/HOTFIX/hotfix_${SR_NUM}_${WHO}_${TIMESTAMP}.zip?cmd=build

echo "package build"

#패키지 다운로드
curl -s -u admin:$ADMIN_PW $IPADDRESS:$PORT/etc/packages/HOTFIX/hotfix_${SR_NUM}_${WHO}_${TIMESTAMP}.zip > /deploy/archive/build_archive/prd/hotfix/hotfix_${SR_NUM}_${WHO}_${TIMESTAMP}.zip
</code></pre>

<ul>
<li>deploy job</li>
</ul>

<img decoding="async" src="D:\업무정리\01_업무\06_System(19년)\05_블로그이미지\DEPLOY_ASIS2.png" alt="Rundeck 배포 개선 내용 공유 설명 이미지 1" />

<h6> </h6>

캡쳐된 이미지의 <code>빨강 박스</code>에서 보듯이 Deploy job 역시 1) 해당 태그 와 2) 타겟 서버를 직접 입력해주어야 합니다. 배포 작업하는날에 단일배포면 좋겠지만, 수많은 태그와 각기 다른 타겟서버로 작업실수가 굉장히 많았습니다.

<img data-recalc-dims="1" height="362" width="1024" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/10/DEPLOY_ASIS3.png?resize=1024%2C362&#038;ssl=1" alt="DEPLOY_ASIS3" />

기존에는 위의 엑셀과 같이 수기로 배포 현황을 관리했으며, 작업 인수인계시에 해당 엑셀까지 같이 인수인계를 해야되는 번거로움이 있었습니다.

<h1>2. 배포 대시 보드 구축</h1>

해당 엑셀 파일과 동일한 효과를 내는 배포 대시 보드를 구축하기로 마음을 먹고 기술스택을 정리했습니다.

<ul>
<li>Node.js</li>
<li>express</li>
<li>file DB</li>
<li>jquery opensource (grid, ajax&#8230;)</li>
</ul>

우선 핵심은 Node.js + express로 웹사이트를 올리는것이였습니다. 그리고 front ui를 입히고 테이블처럼 만들어서, 버튼을 클릭하게 되면, Rundeck API를 호출하는 구조로 만들었습니다.

<ul>
<li><a href="https://github.com/t-edson/bootstable" target="_blank" rel="noopener">대시 보드 UI</a></li>
</ul>

<h2>2-1. 서버</h2>

<pre><code class="line-numbers">var express = require('express');
var app = express();
var bodyParser = require('body-parser')
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended:true}))
var router = require('./router/main')(app);
var fs = require('fs');


app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.engine('html', require('ejs').renderFile);

app.use(express.static('public'));

var server = app.listen(3030, function(){
    console.log("Express server has started on port 3030")
})
</code></pre>

서버는 Node.js 로 구축을 하고 <code>3030</code> 포트로 웹을 올렸습니다. 그 외 필요한 부분은 Router를 이용하여 구현하였습니다.

<ul>
<li>Router</li>
</ul>

<pre><code class="line-numbers">  app.get('/',function(req,res){
        res.render('main.html')
   });
  app.post('/writeJson', function(req, res){

        var json = req.body;
        console.log(json);
        json = JSON.stringify(json);
        fs.writeFile('WriteASync.json', json ,'utf8', function(error, data){
        if (error) {throw error};
           console.log("ASync Write Complete");
        });

        return res.send('200 ok');
  });
</code></pre>

실질적으로는 <code>html</code>을 전달해주고 해당 내부에 js를 심어서 동작하게 하는 간단한 웹입니다. 그 외에 <code>API</code>들은 router에 붙여서 호출이 가능하도록 했고, 기능 단위는 다음과 같습니다.

<ul>
<li>file DB update -> 엑셀로 관리하던 내용을 file DB 형식으로 변경 (추가로 light한 DB를 연동할 예정입니다.)</li>
<li>AWS ELB 조</li>
</ul>

대시보드를 통해서 아마존 ELB 현황까지 체크를 할 수 있도록 하였습니다.

<h2>2-2. 프론트</h2>

앞서 이야기했듯이 Front-end 같은 경우는 <code>html</code> 구조로 되어있고, 이를 rendering해주는 내용입니다.

<a href="https://github.com/t-edson/bootstable" target="_blank" rel="noopener">대시 보드 UI</a>

대시보드 UI를 입혀서 테이블 구조로 나타냈고, bootstable.js 를 내장하고있기때문에 그 안에서 모든 로직을 구현했습니다.

프론트 엔드에서 기능은 다음과 같습니다.

<ul>
<li>테이블 생성 및 삭제 / 태그 입력</li>
<li>각 타입별 타겟 서버 버튼 자동생성</li>
<li>버튼 클릭시 rundeck api 호출</li>
<li>AWS ELB attach/detach</li>
</ul>

화면에 노출이 되는것은 아니나, javascript를 활용하여 다음의 기능도 가능하도록 했습니다.

<ul>
<li>각 타겟 단위 serial 클릭(배포) -> qa 배포/ live 배포</li>
<li>태그 생성 및 자동 입력</li>
</ul>

<img data-recalc-dims="1" height="291" width="1024" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/10/DEPLOY_TOBE_NEW.png?resize=1024%2C291&#038;ssl=1" alt="DEPLOY_TOBE_NEW" />

기존의 엑셀에서 관리하다가 태그만 입력이 되면, 배포하고 난 뒤, 색깔을 자동으로 색칠해주고, file DB를 업데이트 해주다보니, 손쉽게 배포가 가능하도록 했습니다.

<h2>2-3. 챗옵스 연결</h2>

필자가 있는 프로젝트에서는 챗옵스를 활용한 배포를 하고 있습니다. 챗옵스 플랫폼으로 <code>Slack</code>을 활용하고 있고 내부적으로 custom하게 작성한 bot이 있고, 이 bot으로 일련의 처리들을 진행하고 있었습니다.

상위에서 이야기했던 <code>배포 대시 보드</code>를 활용하기 위해서 ChatOps를 연결하기로 했고, 내부적으로 연결하기 위해서 bot소스 내에 <code>Puppeteer</code>를 활용하여 작업을 했고, 아래의 기능을 이용했습니다.

<ul>
<li>태그 생성 및 자동 입력</li>
</ul>

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/10/DEPLOY_TOBE2_NEW.png?w=1200&#038;ssl=1" alt="DEPLOY_TOBE2_NEW" />

챗옵스 -> puppeteer -> 배포 대시보드 -> Rundeck

위의 순서로 호출을 하고, 배포 결과를 다시 배포 대시 보드에 입력해줌으로써 작업자로 하여금 편리하게 구현을 해두었습니다.

<ul>
<li>각 타겟 단위 serial 클릭(배포) -> qa 배포/ live 배포</li>
</ul>

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/10/DEPLOY_TOBE3_NEW.png?w=1200&#038;ssl=1" alt="DEPLOY_TOBE3_NEW" />

배포 묶음단위를 지정하게 되면 <code>배포 대시보드</code>에서 해당 묶음으로 있는 버튼들에 대한 액션을 순서대로 진행합니다.

(여기서 중요한것은 Rudneck api호출후에 해당 job이 성공이 된것을 받아야 다음으로 진행하게 됩니다.)

챗옵스에게 배포 명령만 해두면, 해당 JOB이 Serial 하게 진행이 되기때문에 작업자는 그안에 다른 유익한 일을 해도 됩니다.

또한 배포가 완료되면, 유관 업무를 하는 곳에 사내 메신저로 <code>배포 완료</code>에 대한 공지를 하기때문에 모든 작업들이 코드화 되어 진행되게 됩니다.

<h1>3. 효과</h1>

기존의 수작업으로 관리되던 배포에서 자동화 된 시스템을 통하여 배포를 진행하다 보니 우선 가시적으로는 시간적인 여유가 많이 생겼습니다. 또한 작업자의 실수를 줄일 수 있다보니, 장애 예방에 대한 효과도 극명하게 드러납니다. 부가적으로 챗옵스를 통하여 작업을 진행하다보니 기존의 이력이 history로 남고, 유관자에게 인수인계하기도 좋습니다.

<img data-recalc-dims="1" height="468" width="1024" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/10/DEPLOY_TOBE5_NEW.png?resize=1024%2C468&#038;ssl=1" alt="DEPLOY_TOBE5_NEW" />

기존 작업대비 80% 이상의 시간감소를 보이고, 정확성도 높아졌습니다. 수치적으로는 정확하게 짚을수는 없지만, 개선의 효과는 극명하게 나타납니다.
<h2 class="wp-block-heading">함께 보면 좋은 글</h2>
<ul class="wp-block-list"><li><a href="https://blog.wonizz.com/2019/09/06/aws-ecs/">[AWS] ECS  서비스란?</a></li><li><a href="https://blog.wonizz.com/2019/10/28/kubernetes-pod-configuration/">[Kubernetes] Pod Configuration &#038; Resource Limit</a></li><li><a href="https://blog.wonizz.com/2019/08/13/docker-compose/">[Docker] Compose 구성과 사용법</a></li><li><a href="https://blog.wonizz.com/2019/10/16/devops-ec2-gazua/">[DevOps] ec2-gazua 사용법 및 커스터마이징</a></li></ul>
<p>The post <a rel="nofollow" href="https://blog.wonizz.com/2019/10/08/rundeck-deploy/">[Rundeck] 배포 개선 내용 공유</a> appeared first on <a rel="nofollow" href="https://blog.wonizz.com">WONIZZ.LOG</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.wonizz.com/2019/10/08/rundeck-deploy/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">839</post-id>	</item>
		<item>
		<title>[Node.JS] 프로세스 관리도구 PM2 사용법</title>
		<link>https://blog.wonizz.com/2019/07/22/nodejs-pm2/</link>
					<comments>https://blog.wonizz.com/2019/07/22/nodejs-pm2/#respond</comments>
		
		<dc:creator><![CDATA[워니즈]]></dc:creator>
		<pubDate>Mon, 22 Jul 2019 04:30:07 +0000</pubDate>
				<category><![CDATA[Node.js]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Tech]]></category>
		<guid isPermaLink="false">http://blog.wonizz.tk/?p=554</guid>

					<description><![CDATA[<p>The standard Lorem Ipsum passage, used since the 1500s<br />
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
<p>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p>
<p>1914 translation by H. Rackham<br />
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"</p>
<p>Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."</p>
<p>1914 translation by H. Rackham<br />
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</p>
<p>필자가 운영하던 Node 프로세스는 forever라는 npm 모듈을 활용하여 운영했었다. 하지만, forever이긴하나 가끔 프로세스가 kill 되는 현상이 있어 좀더 알아보던 차에 PM2라는 것을 알게 되었다. PM2 는 Process Manager 의 약자로 이미 단어에서 모든게 설명 되는데 노드 프로세스를 관리해주는 역할을 한다. 아래에서 간단한 노드 프로그램을 기반으로 PM2 를 차근차근 이해하도록 하자. 보통 서버에 데몬 형태의 application&#8230;&#160;</p>
<p>The post <a rel="nofollow" href="https://blog.wonizz.com/2019/07/22/nodejs-pm2/">[Node.JS] 프로세스 관리도구 PM2 사용법</a> appeared first on <a rel="nofollow" href="https://blog.wonizz.com">WONIZZ.LOG</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The standard Lorem Ipsum passage, used since the 1500s<br />
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."</p>
<p>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?"</p>
<p>1914 translation by H. Rackham<br />
"But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"</p>
<p>Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC<br />
"At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat."</p>
<p>1914 translation by H. Rackham<br />
"On the other hand, we denounce with righteous indignation and dislike men who are so beguiled and demoralized by the charms of pleasure of the moment, so blinded by desire, that they cannot foresee the pain and trouble that are bound to ensue; and equal blame belongs to those who fail in their duty through weakness of will, which is the same as saying through shrinking from toil and pain. These cases are perfectly simple and easy to distinguish. In a free hour, when our power of choice is untrammelled and when nothing prevents our being able to do what we like best, every pleasure is to be welcomed and every pain avoided. But in certain circumstances and owing to the claims of duty or the obligations of business it will frequently occur that pleasures have to be repudiated and annoyances accepted. The wise man therefore always holds in these matters to this principle of selection: he rejects pleasures to secure other greater pleasures, or else he endures pains to avoid worse pains."</p>
필자가 운영하던 Node 프로세스는 forever라는 npm 모듈을 활용하여 운영했었다. 하지만, forever이긴하나 가끔 프로세스가 kill 되는 현상이 있어 좀더 알아보던 차에 PM2라는 것을 알게 되었다.

PM2 는 Process Manager 의 약자로 이미 단어에서 모든게 설명 되는데 노드 프로세스를 관리해주는 역할을 한다. 아래에서 간단한 노드 프로그램을 기반으로 PM2 를 차근차근 이해하도록 하자.

보통 서버에 데몬 형태의 application 을 개발하게 되면 여러가지 것들을 신경써야 했다. 이를테면 application 에서 남기는 로그에 대한 처리( filesystem 을 이용해서 남기는 방법, 날짜 포함, rotate, etc ), 프로세스가 죽었을 때에 대한 처리( restart ), 부하 분산에 따른 동적인 확장 가능성, 부팅시에 자동 실행 등 무수히 많은 것들이 있다.

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/07/PM2_image.JPG?w=1200&#038;ssl=1" alt="Node.JS 프로세스 관리도구 PM2 사용법 설명 이미지 1" />
<a href="http://pm2.keymetrics.io/" title="PM2 링크" target="_blank" rel="noopener">PM2 링크</a>

<h3>1. 설치</h3>

<pre><code class="">$ npm install pm2 -g
</code></pre>

뒤에 -g 옵션을 붙이는 이유는 사용자가 pm2 명령어를 어떤 디렉터리에서건 사용할 수 있게 하기위함이다. 글로벌 세팅이라고 보면 된다. npm 이야기에서 만들어뒀던 API 서버 프로그램을 pm2 로 돌려보자.

<h3>2. 명령어</h3>

<ul>
<li>시작</li>
</ul>

<pre><code class="">$ pm2 start app.js
</code></pre>

실행하고자 하는 Node.js 어플리케이션 실행 파일이 app.js 라면 위와같이 실행을 하면 됩니다.

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/07/PM2_init.jpg?w=1200&#038;ssl=1" alt="PM2 초기설정" />

<ul>
<li>리스트</li>
</ul>

<pre><code class="">$ pm2 list
</code></pre>

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/07/PM2_list.jpg?w=1200&#038;ssl=1" alt="PM2 LIST" />

<ul>
<li>종료</li>
</ul>

<pre><code class="">$ pm2 stop 0
</code></pre>

프로세스를 종료할 때는 pm2 list 에서 확인한 앱의 이름이나 애플리케이션의 ID (list 에서 확인 가능)를 stop 의 인자로 넘겨주면 된다.

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/07/PM2_stop.jpg?w=1200&#038;ssl=1" alt="PM2 STOP" />

<ul>
<li>삭제</li>
</ul>

<pre><code class="">$ pm2 delete 0
</code></pre>

기존에 등록되어 있던 server.js 를 우선 pm2 에서 delete 옵션을 통해 삭제하도록 하자.

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/07/PM2_delete.jpg?w=1200&#038;ssl=1" alt="PM2 DELETE" />

<ul>
<li>아이디 지정</li>
</ul>

<pre><code class="">$ pm2 start server.js --name "API"
</code></pre>

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/07/PM2_id.jpg?w=1200&#038;ssl=1" alt="PM2 ID" />

<ul>
<li>상세보기</li>
</ul>

<pre><code class="">$ pm2 show API
</code></pre>

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/07/PM2_show.jpg?w=1200&#038;ssl=1" alt="PM2 SHOW" />

<ul>
<li>로그 지정</li>
</ul>

기본 로그

<pre><code class="">$ pm2 logs <app Name>
</code></pre>

이 명령어도 지난 15줄의 기록 밖에 확인할 수 없기 때문에, 서버 로그 파일을 확인하면 된다. 파일의 위치는 ~/.pm2/logs 에 있다.

stdout 처리

<pre><code class="">$ pm2 delete API && pm2 start server.js --name "API" -o ./api.log
</code></pre>

out log path (console.log 가 출력되는 위치) 가 기본적으로 .pm2 밑에 저장되고 있는 것을 볼 수 있는데 이 위치를 우리가 원하는 곳으로 옮겨보자. 앞선 설명처럼 API 를 delete 하고 옵션을 추가하도록 한다.

stderr 처리

<pre><code class="">$ pm2 delete API && pm2 start server.js --name "API" -o ./api.log -e ./api.log --merge-logs
</code></pre>

하지만 아직 아쉬운 것이 있다. 위에서 언급한 것 처럼 -o 옵션은 stdout 을 처리하기 때문에 프로세스에서 발생하는 표준에러( stderr ) 에 대해서는 처리하지 못한다. 이를 처리하기 위한 옵션도 있으니 걱정하지마시라. 우선 API 를 삭제하고 -e 옵션으로 stderr 에 대한 처리도 추가해보자.

<ul>
<li>부하 분산</li>
</ul>

<pre><code class="">$ pm2 delete API && pm2 start server.js --name "API" -i 3 -o ./test.log
</code></pre>

트래픽을 받아서 async 하게 처리한다고 해도 내부로직이 복잡해지면 어느순간 치솟는 CPU 를 어찌하지 못하는 상황이 온다. 이때 필요한 것이 클러스터이다. PM2 의 클러스터는 분산컴퓨팅의 그 용어와 비슷한 역할을 하는데 server.js 한 개 노드파일을 지정한 개수만큼 PM2 에 등록하고 Load Balancing (LB) 를 통해 부하를 분산시켜준다. PM2 의 LB 는 round robin (RR) 방식으로 동작하며 모든것은 옵션 하나면 충분하다.

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/07/PM2_LB.jpg?w=1200&#038;ssl=1" alt="PM2 LB" />

<ul>
<li>스케일 조정</li>
</ul>

<pre><code class="">$ pm2 scale API 5
</code></pre>

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/07/PM2_scale.jpg?w=1200&#038;ssl=1" alt="PM2 SCALE" />

<ul>
<li>서비스 중단</li>
</ul>

<pre><code class="">$ pm2 stop all
</code></pre>

혹시 API 를 급하게 중단해야한다? all 을 인자로 넘겨서 아래와 같이 관리되고 있는 전체를 중단하거나 재시작할 수 있다.

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/07/PM2_stopall.jpg?w=1200&#038;ssl=1" alt="PM2 STOP ALL" />

<ul>
<li>모니터링</li>
</ul>

<pre><code class="">$ pm2 monit
</code></pre>

아래와 같이 PM2 로 관리되는 프로세스별 상태를 볼 수 있고 실시간 로그까지 확인 가능하다. 빠져나올때는 키보드의 q 를 눌러주면 되겠다.

원하는 서비스에서 Enter를 눌러주면 됩니다.

<img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/blog.wonizz.com/wp-content/uploads/2019/07/PM2_monit.jpg?w=1200&#038;ssl=1" alt="PM2 MONITORING" />

<a href="http://blog.wonizz.com" title="워니즈 블로그">워니즈 블로그</a>
<a href="http://github.com/wonizz" title="워니즈 깃헙" target="_blank" rel="noopener">워니즈 깃헙</a>
<h2 class="wp-block-heading">함께 보면 좋은 글</h2>
<ul class="wp-block-list"><li><a href="https://blog.wonizz.com/2021/03/11/javascript-promise-1/">[Javascript] Promise 사용법</a></li><li><a href="https://blog.wonizz.com/2020/08/03/linux-command-top/">[Linux] top을 통해 살펴보는 프로세스 정보들</a></li><li><a href="https://blog.wonizz.com/2024/07/18/devops-nginx-lua-module/">[DevOps] Nginx Lua module 사용법</a></li><li><a href="https://blog.wonizz.com/2019/08/13/docker-compose/">[Docker] Compose 구성과 사용법</a></li></ul>
<p>The post <a rel="nofollow" href="https://blog.wonizz.com/2019/07/22/nodejs-pm2/">[Node.JS] 프로세스 관리도구 PM2 사용법</a> appeared first on <a rel="nofollow" href="https://blog.wonizz.com">WONIZZ.LOG</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.wonizz.com/2019/07/22/nodejs-pm2/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">554</post-id>	</item>
	</channel>
</rss>
