ErLang/OTP

Erlang 2014. 3. 10. 13:35

ErLang/OTP 다운로드

http://www.erlang.org/download/otp_src_R16B03-1.tar.gz


관련 패키지 설치

apt-get install build-essential


apt-get install ncurses-dev

apt-get install libssl-dev

apt-get install libxsltproc

apt-get install fop

apt-get install xmllint

apt-get install libwxgtk2.8-dev libwxgtk2.8 libboost-dev

'Erlang' 카테고리의 다른 글

Making erchef  (0) 2014.03.08
Tcp ErLang  (0) 2014.03.07
Posted by sjokim
,

Making erchef

Erlang 2014. 3. 8. 15:53

Making erchef


Opscode publish the new Chef server called erchef. It is build from erlang.

This blog is a log of making erchef on Ubuntu 12.04.1.

1st. erlang install

A default ubuntu erlang apt-package is a little bit old. I compile from the source.

% sudo apt-get install make gcc libncurses5-dev libssl-dev \
  libssl1.0.0 openssl libstdc++6 libstdc++6-4.6-dev
% curl -O http://www.erlang.org/download/otp_src_R15B02.tar.gz
% gzip -dc otp_src_R15B02.tar.gz | tar xvf -
% cd otp_src_R15B02
% ./configure --prefix=/usr/local/ && make
% sudo make install

Next, compile the reber(dependency management tool).

% git clone git://github.com/basho/rebar.git
% cd rebar
% ./bootstrap
% sudo cp -p rebar /usr/local/bin/

2. make

make.

% git clone git://github.com/opscode/erchef.git
% cd erchef
% make rel

That’s it. easy.

I was just tought.

until launching erchef....

3. creating app.config

A configuration file called app.config is required to launching erchef. However, that repository does not contain app.config.

After several googling, I found the omnibus-chef repository.

% sudo apt-get install ruby-bundler rake
% git clone git://github.com/opscode/omnibus-chef.git
% cd omnibus-chef
% bundle install
% mv omnibus.rb.example omnibus.rb
% sudo CHEF_GIT_REV=10.14.4 rake projects:chef-server

But I could not launch this omnibus-chef-server (sorry, I forgot why it could not). So, I use only a attribute and template to build app.config.

Here is the app.config I made after a lot of, a lot of, trial and error.

There are some notes to create app.config.

  • use relative path to choose log directory. not Absolute.
  • I use ‘/’ as rabbitmq directory. A guest can read/write to there. But it should be change.
  • should be change postgres dbname and password.

4. Running erchef

OK. now I got the shiny app.config. Let’s launch erchef!

Install dependency.
(solr does not required?)
% apt-get install postgres rabbitmq-server openjdk-7-jre solr-common solr-jetty

Create log directory.
% mkdir -p log/chef-server/erchef/

Use postgres schema (I cutting corner to use postgres user).
% sudo -u postgres createdb opscode_chef
% sudo -u postgres psql opscode_chef -f deps/chef_db/priv/pgsql_schema.sql

Create chef certificate.
% sudo escript bin/bootstrap-chef-server
client <<"admin">> created. Key written to
<<"/etc/chef-server/admin.pem">>
client <<"chef-validator">> created. Key written to
<<"/etc/chef-server/chef-validator.pem">>
client <<"chef-webui">> created. Key written to
<<"/etc/chef-server/chef-webui.pem">>
environment '_default' created

Place app.config under the erchef/etc.
% mv ~/app.config etc

Launch erchef.
% sudo bin/erchef start

Confirm.
% sudo bin/erchef ping
pong

Yah. erchef started. finally.

next, configure chef-client.

% knife configure -i
Overwrite /home/ubuntu/.chef/knife.rb? (Y/N) Y
Please enter the chef server URL: [http://blah.example:4000]   http://localhost:4000
Please enter a clientname for the new client: [ubuntu] user1  <-- !Another user!
Please enter the existing admin clientname: [chef-webui]
Please enter the location of the existing admin client's private key:
[/etc/chef/webui.pem] /etc/chef-server/chef-webui.pem
Please enter the validation clientname: [chef-validator]
Please enter the location of the validation key:
[/etc/chef/validation.pem] /etc/chef-server/chef-validator.pem
Please enter the path to a chef repository (or leave blank):
Creating initial API user...
Created client[user1]
Configuration file written to /home/ubuntu/.chef/knife.rb

That’s it.

% knife client list
admin
chef-validator
chef-webui
user1

5. However...

I can get list, role, node. However, I still could not upload cookbook or rebuild index. If you have any suggestions, please let me know.


'Erlang' 카테고리의 다른 글

ErLang/OTP  (0) 2014.03.10
Tcp ErLang  (0) 2014.03.07
Posted by sjokim
,

Tcp ErLang

Erlang 2014. 3. 7. 19:41

일단 양해를 구할 것이 있다. 나는 Erlang을 위한 적절한 코드 하이라이터를 아는게 없어서 아래 코드부분에서 검은건 화면이요 하얀건 글씨다. 코드와 주석은 우리 마음속에서 잘 구분해 보도록 하자.


일반적으로 인터넷 상의 함수형 언어에 대한 설명들에서 내가 마음에 들지 않는 부분은 소개되는 코드들 중 실 생활에서 사용 할만한 코드가 거의 없다는 점이다. 아마 함수형 언어들이 현장에서 쓰이는 빈도가 적다보니 대부분 공부용 코드 이외의 것을 보기 어려운 것이 아닌가하는 생각이 든다. 그래서 나는 함수형 언어도 현장에서 써먹을 수 있다는 증거(?)를 블로그에 남기고자 잘 써먹고 있는 TCP 서버 코드를 잘라다가 소개하기로 했다. 이 서버의 디자인은 기본적으로 http://20bits.com/article/erlang-a-generalized-tcp-server 글에 소개된 간단한 OTP 기반 TCP서버 디자인에 기초하고 있다.


이 코드는 OTP gen_server에 기초를 두고 있고, 소켓 단위로 프로세스가 분리되어 비동기적인 작동을 한다. 아래 코드는 작동하는 서버에서 일부분만 잘라낸 것이어서 그 자체로는 아무 작동도 하지 못한다. 무언가 구상한 것이 있다면 이 서버 코드의 파편에 살을 붙여 멋진 애플리케이션으로 살려보기 바란다 :) 참고로 이 코드는 내가 짠 캐시 서버의 일부다. 그 서버에는 지금의 코드보다 더 철저한 애러 핸들러와 잘 작동하는 데이터 파서, gen_server를 통한 ETS 및 데이터 조회, 캐시 삭제를 하는 코드가 포함되어 있다.


-module(tcp_network).
-behaviour(gen_server).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).

-define(TCP_OPTIONS, [binary, {active, once}, {recbuf, 4096},  {reuseaddr, true}]).
%% ====================================================================
%% API functions
%% ====================================================================
-export([open/1]).

open(Port) ->
    gen_server:start_link({local,?MODULE}, ?MODULE, Port, []).

%% ====================================================================
%% Behavioural functions 
%% ====================================================================

%% init/1
init(Port) ->
    case gen_tcp:listen(Port, ?TCP_OPTIONS) of
        {ok, Listen} -> 
            %% server state가 만들어진다
            %% {tcp listen pid, tcp listen}의 튜플이다
            {ok, accept({self(), Listen})};
        {error, Reason} ->
            {stop, Reason}
    end.

%% async cast 다음 소켓에 대한 accept_loop를 준비시킨다
%% handle_cast, accept, accept_loop의 3개 함수는 서로재귀 상태에 있다
%% 서로재귀 함수임에도 accept_loop는 나머지 함수와는 다른 프로세스에 있다
handle_cast({accepted}, State) -> {noreply, accept(State)}.

handle_call(_Request, _From, State) -> {noreply, State}.
handle_info(_Info, State) -> {noreply, State}.
terminate(_Reason, _State) -> ok.
code_change(_OldVsn, State, _Extra) -> {ok, State}.

%% ====================================================================
%% Internal functions
%% ====================================================================

%% 다음 소켓 연결 요청을 처리할 프로세스를 만들어 대기시킨다
accept({Server, Listen}) ->
    proc_lib:spawn_link(fun() -> accept_loop(Server, Listen) end),
    {Server, Listen}.

accept_loop(Server, Listen) ->
    case gen_tcp:accept(Listen) of
        {ok, Socket} ->
            %% 소켓 요청이 받아진 경우
            %% cast에 다음 소켓에 대해 준비할 것을 요청한다
            gen_server:cast(Server, {accepted}),
            
            %% 이 프로세스는 소켓 요청 대기를 끝냈다 
            %% 소켓 데이터 처리를 위한 재귀 루프로 들어간다
            receiver(Socket);
        {error, _Reason} ->
            %% 소켓 요청에 실패한 경우
%% 이 예에서는 일단 다음 소켓에 대한 준비를 요청한다
%% 상황에 따라 이 오류를 처리할 cast를 따로 준비해야 할 수 있다
gen_server:cast(Server, {accepted}),

%% ...... %% 그 밖에 필요한 오류 처리절차 %% ......

%% 처리가 끝났다면 프로세스를 종료 exit(normal) end. %% receiver는 한 소켓을 처리한다 %% receiver와 이를 호출한 accept_loop는 같은 프로세스다 receiver(Socket) -> receive {tcp, Socket, Bin} -> %% Bin은 TCP로 들어온 바이너리 데이터 %% ...... %% 데이터 처리에 필요한 작업들 %% ...... %% 서버는 {active, once} 옵션으로 throttle이 조정되고 있다 %% 작업이 끝났다면 다음번 데이터를 받도록 {active, once} 상태로 돌아간다 inet:setopts(Socket, [{active, once}]), %% 다음 데이터를 받는 재귀 receiver(Socket); {tcp_closed, Socket} -> %% 소켓이 닫힌다면 프로세스 종료 exit(normal) end.


한 소켓으로 들어온 각각의 요청을 비동기적으로 처리하고자 한다면 receiver에서 받은 데이터를 처리하는 프로세스들을 추가로 생성하는 것을 고려해볼 수 있을 것이다. 특히 각 요청들이 서로간에 처리시간이 상이하여 동기적인 처리가 비효율적이고 client가 비동기적인 response를 수용할 수 있는 경우라면 receiver에서 한번 더 worker를 spawn해서 처리를 나누는 것은 필수적이라 할 수 있다. 또한 작은 작업 단위로 프로세스를 나누는 것은 멀티코어 CPU의 자원을 활용하도록 하는 Erlang의 최적화 전략이라는 것도 명심하자. 일반적으로 요청의 처리는 적절한 수준으로 쪼개는 것이 좋다1.


이 코드는 TPKT 같은 헤더가 없으며, 데이터는 recbuf에서 잘린다. TPKT로 길이를 알려주면서 통신하고 싶다면 TCP_OPTIONS에 {packet, tpkt} 튜플을 옵션으로 넣으면 된다. 

  1. 적절하다는 표현이 애매하긴 하다. 근데 이건 정량이 없는 문제라서 그냥 해보고 결정하는 수밖에 없다. [본문으로]

'Erlang' 카테고리의 다른 글

ErLang/OTP  (0) 2014.03.10
Making erchef  (0) 2014.03.08
Posted by sjokim
,