dev - web/javascript2014. 11. 21. 22:28
라즈베리 파이에 리눅스 계열인 RASPBIAN을 설치한 경우 이를 위한 Node JS가 준비되어 있으므로 다음 몇 가지 단계를 거치면 손쉽게 Node JS 를 사용할 수 있다.

1. RASPBIAN Package 정보 업데이트


RASPBIAN은 Debian 계열의 패키지 관리 정보를 사용한다. 다음과 같이 apt-get 명령을 이용하여 해당 정보를 업데이트를 한다.

이미지

그림 <sudo apt-get upgrade>


이미지

그림 <sudo apt-get update>


2. 라즈베리파이용 NodeJS 설치


Package 정보를 업데이트 했다면 node-arm 프로젝트 홈페이지 (http://node-arm.herokuapp.com)로부터 NodeJS deb 패키지를 받아 설치한다. 현재 (2014-8-27) NodeJS 최신 공식 버전인 v0.10.31, 30, 29를 제공하므로 필요에 따라 선택한다.


다음 명령어를 이용하면 최신 버젼의 NodeJS 설치 파일을 받을 수 있다.


sudo wget http://node-arm.herokuapp.com/node_latest_armhf.deb


그리고 dpkg를 이용하여 nodejs를 설치한다.


$ sudo dpkg -i node_lasted_armhf.deb 



참고로 NodeJS 홈페이지에서도 라즈베리 파이용 패키지를 제공하고 있으나 v0.10.29 부터 v0.10.31까지는 배포되지 않고 있다.


v0.10.28 을 다음 명령어로 다운로드한다.


$ sudo wget http://nodejs.org/dist/v0.10.28/node-v0.10.28-linux-arm-pi.tar.gz


그리고 파일의 압축을 해제한다.

tar -xzvf node-v0.10.28-linux-arm-pi.tar.gz


다운로드 받은 node를 실행해 보면 현재 버젼을 확인해 볼 수 있다.

node-v0.10.28-linux-arm-pi/bin/node -v


데비안 패키지와 달리 실행 파일만 설치된 것이므로 환경 설정을 해 주어야 한다.


home 디렉토리 (/home/pi) 의 .bash_profile에 다음과 같이 NODE_JS_HOME을 설정한다.


NODE_JS_HOME=/home/pi/node-v0.10.28-linux-arm-pi

PATH=$PATH:$NODE_JS_HOME/bin


Posted by cz
dev - web/javascript2014. 11. 21. 22:24

node.js는 그 바탕이 Javascript이기 때문에 그나마 괜찮다고 하더라도 이런 부분에서 예외는 아니라고 생각합니다. 얼마전에 Socket.IO로 간단한 예제를 만들고 호스팅받고 있는 서버에 올려야겠다고 생각하고 로컬에서 수없이 돌려봤기 때문에 금방 서버에 적용할꺼라고 생각했지만 다 개발된 것을 서버에 서비스로 적용하는 것만도 많은 시간을 소비하게 되었습니다. 이 내용은 Kevin van Zonneveld가 작성한 Run Node.js as a Service on Ubuntu Karmic라는 글과 이 포스트를 보고 Tim Smart가 How To Node에 Deploying Node.js With Upstart and Monit를 보고 우분투 서버에 적용하면서 정리한 내용입니다.

처음에 node.js로 만든 것을 서버에 올려야겠다고 생각했을 때는 로컬에서 개발할 때처럼 node myapp.js로 실행하면 SSH등으로 터미널 원격접속한 상태에서는 터미널을 종료하는 순간 프로세스도 같이 죽어버리기 때문에 node myapp.js & 으로 백그라운드로 실행하였습니다. 이것은 잘 돌아가는 것처럼 보였지만 별로 적절한 방법은 아니었고 실제로 제가 올렸던 것은 딱 한번만 접속하면 무조건 프로세스가 죽어버리는 문제가 있었습니다.

제가 실제 서비스에 적용을 해보면서 느낀 문제점은 아래와 같습니다.

  • node.js개발을 하면 console.log()나 sys.puts()으로 콘솔에 로그 메시지를 출력하는데 SSH등으로 서버에 원격접속하였을때 node.js app를 실행하더라도 터미널을 종료하면 STDOUT이 없기 때문에 콘솔에 로그메시지를 출력하는 부분이 있으면 프로세스가 죽어버립니다. 
  • 이러한 로깅은 소스에서 지워버려도 되겠지만 기본적으로 로그를 남기기 위해서 작성하는 것이므로 이런한 로그를 나중에 참조할 수 있도록 파일로 출력할 필요가 있었습니다.
  • 위 문제가 아니더라도 예상치 못한 문제로 프로세스가 죽어버렸을 때 다시 복구해 주어야 합니다.(저같은 경우 개인서비스이므로 약간의 장애는 큰 문제 안되긴 하지만 그렇다고 마냥 죽어있을수는 없는 노릇이니까요.)


위 문제들을 해결하기 위해서는 node로 돌린 프로세스가 진짜 데몬( Demon)처럼 동작하게 해야 하고 이벤트기반의 init데몬을 위한 툴인 upstart와 프로세스와 파일등을 모니터링하고 관리하는 Monit으로 해결합니다.





Upstart
node앱을 Demon처럼 실행하기 위해서 Kevin은 Upstart를 제시했습니다. Upstart는 /etc/init.d 스크립트를 대체하고 속도, 간결함 등의 추가적인 특징을 가지고 있습니다. 최신 우분투 배포판에는 Upstart가 포함되어 있으며 설치되어 있지 않다면 sudo apt-get install upstart 로 설치할 수 있습니다.

upstart 스크립트는 아래와 같이 작성합니다.

1
2
3
4
5
6
7
8
9
10
description "socket.io-slide server"
author      "Outsider"
 
start on startup
stop on shutdown
 
script
    chdir /path/to/socketio-slide/socket.io
    exec sudo -u USERNAME sh -c "/usr/local/bin/node socketio-slide.js >> /var/log/node/socketio-slide.log 2>&1"
end script


9번 라인의 USERNAME부분은 명령어를 실행할 유저명을 적어주면 됩니다. 일반적으론 PATHS에 node.js가 잡혀있어서 그냥 node 명령어를 사용할 수 있지만 스크립트 내에서는 위처럼 절대경로를 사용해야했습니다.  이 파일을 /etc/init/myapp.conf로 저장을 하고 chomd u+x를 주어 실행가능하게 되도록 합니다. 이렇게 하면 node 앱을 데몬처럼 실행할 수 있고 node 앱의 시작과 중지를 위한 간단한 명령어를 통해서 사용할 수 있게 됩니다.

start myapp
stop myapp


을 이용해서 node 앱을 실행하고 중지할 수 있으며 부팅시에 앱을 실행하고 로그는 /var/log/node/socketio-slide.log 파일에 남게 됩니다.





Monit
아직 문제점이 남아 있는데 Upstart를 이용해서 Demon으로 실행했다고 하더라도 node 앱은 죽어버릴 가능성이 있기 때문에 이에 대한 대처가 필요한데 일정한 인터벌을 두고 테스트를 수행하고 그 결과에 따라 액션을 취하는 모니터링 툴인 Monit으로 이 문제를 해결할 수 있습니다. 우분투에서는 sudo apt-get install monit 를 통해서 설치할 수 있습니다.

1
2
3
4
5
6
7
8
9
set logfile /var/log/monit.log
 
check host socketio-slide with address 127.0.0.1
    start program = "/sbin/start myapp"
    stop program = "/sbin/stop myapp"
    if failed port 8001 protocol HTTP
        request /
        with timeout 10 seconds
        then restart


위 파일이 Monit의 설정파일이고 이것을 /etc/monit/monitrc의 하단에 추가하면 됩니다. 
1번 라인은 Monit의 로그파일을 지정한 부분이며 3번라인이 노드 인스턴스의 이름(로그에 이 이름이 사용됩니다.)과 위치를 지정해 주고 테스트 요청을 날릴 ip지정합니다.(여기서는 같은 서버에서 사용되므로 127.0.0.1을 사용합니다.) 4,5번 라인에서 node앱을 어떻게 시작하고 중지하는지 적어주는데 위에서 만든 upstart로 만든 명령어를 사용하며 이때는 절대주소로 적어주어야 합니다. 6번라인이 핵심적인 부분인 테스트부분인데 HTTP 8001포트로 루트(/)에 요청을 보내서 10초동안 결과가 오지 않는다면 node 앱을 재시작하도록 지정하였습니다.

이제 아래 명령어를 통해서 node앱을 실행하고 모니터링을 위해서 monit을 시작하면 됩니다.

sudo start myapp
sudo monit -d 60 -c /etc/monit/monitrc


 -d 60 플래그는 monit이 60초마다 테스트를 수행하도록 하는 것이고 이렇게 실행해 놓으면 노드앱이 죽어도 자동으로 60초 이내에 재시작되게 됩니다.

여기서 myapp이 죽게 되면 재시작이 되며 monit의 로그에는 아래와 같이 로깅이 됩니다.

[KST Oct 29 22:59:40] error    : 'socketio-slide' failed, cannot open a connection to INET[127.0.0.1:8001] via TCP
[KST Oct 29 22:59:40] info     : 'socketio-slide' trying to restart
[KST Oct 29 22:59:40] info     : 'socketio-slide' stop: /sbin/stop
[KST Oct 29 22:59:40] info     : 'socketio-slide' start: /sbin/start
[KST Oct 29 23:00:40] info     : 'socketio-slide' connection succeeded to INET[127.0.0.1:8001] via TCP


Posted by cz
dev - web/javascript2014. 10. 23. 16:29



아래같은 코드는 항상 사용하는 것이 아니라..생각이 별로 하기 싫어서 이렇게 만들어 놓고 필요할때 가져다 쓰려고 만들어 놓는다.


오브젝트가 윈도우 안에 들어 왔는지를 알아내는 코드이다.


마우스를 스크롤 할때,

현재 윈도우의 크기 ( $(window).height() ) 

이미 스크롤 했던 스크롤의 크기 ( $(window).scrollTop() ) 를 더해서 


찾고자 하는 오브젝트의 바닥면의 위치 ( $("#item").position().top ) + ($("#item).outerHeight())

가 안에 들어 오면 발견 했다라고 치는 코드 이다..


에니메이션은 animate.css를 사용 했고 여기 서 가져왔다


        <div></div>

<div></div>

<div></div>

<div></div>

<div></div>

<div></div>

<div></div>

<div></div>

<div></div>

<div></div>

<div></div>

<div></div>

<div></div>

<div></div>

<div></div>

<div></div>

<div></div>

<div></div>

<div></div>

<div id="item">


$(this).position().top : <span id="obj1_top"></span> <br>

$(this).outerHeight() : <span id="obj1_height"></span> <br>

object : <span id="obj1"></span> <br>


$(window).scrollTop() : <span id="obj2_top"></span> <br>

$(window).height() : <span id="obj2_height"></span> <br>

win : <span id="win1"></span> <br>


</div>

<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>

<script src="//code.jquery.com/jquery-migrate-1.2.1.min.js"></script>

<script>


$(function(){


$(window).scroll(function(){


$('#item').each(function(i){


var bottom_of_object = $(this).position().top + $(this).outerHeight(); //outerHeight() : border를 포함한 높이

var bottom_of_window = $(window).scrollTop() + $(window).height();

//scrollTop : 스크롤되어 올라가있는 만큼의 높이 , $(window).height() : 브라우저 창높이


$('#obj1_top').text($(this).position().top);

$('#obj1_height').text($(this).outerHeight());

$('#obj1').text(bottom_of_object);


$('#obj2_top').text($(window).scrollTop());

$('#obj2_height').text($(window).height());

$('#win1').text(bottom_of_window);


//오브젝트가 윈도우에 완전히 보이면

if( bottom_of_window > bottom_of_object){


$('#item').addClass('animated rubberBand');

}



});

});





});

</script>

 

        

Posted by cz