Jeen - Yet anothere techlog

STFUAWSC

Using Rex - Environment

주위 사람들은 Chef나 Fabric 을 많이 쓴다고 하지만 ( 그보다 손으로 여전히 하는 사람들이 더 많은 것 같기도 ), Rex 에 그냥 적응하면서 여전히 Rex 를 사용하고 있습니다. 회사를 옮기고 새로운 작업환경을 둘러보다가 이전의 패턴이 그대로 먹히지 않기에 기존에 사용하던 Rexfile 의 구조도 살며시 바꿔나가야 했습니다.

Rex 초기 설정

Rex 가 설치되어 있다면, rexify 커맨드를 사용할 수 있습니다. 이 커맨드를 이용해서 초기 뼈대를 만들어 봅니다.

1
$ rexify M

그러면 아래와 같은 구성으로 Rex 를 사용하기 위한 기본 구성이 마련됩니다.

1
2
3
4
5
$ tree
.
├── Rexfile
└── lib
    └── M.pm

Rexfile 에는 온갖 설정 정보를 넣고, M.pm 에는 각 Task 를 정의해둡니다.

서버 그룹 위의 또 다른 그룹을 정의한다?

 지금까지는 서버의 목적, 그러니까 DB 서버 면 DB 그룹에 , Web 서버면 Web 그룹에 묶으면 되었는데요. 하지만 현재의 회사에서는 서비스그룹이 나뉘어져 있기도 하고, 계정정보도 좀 다르기도 하고 그런 게 있습니다. –_–;

그래서 environment 로 각 그룹을 묶어서 별도로 관리하기로 했습니다.

그런 것을 고려해서 써놓은 Rexfile 은 아래와 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
use Rex -feature => 0.40;

environment sdt => sub {
    set user => "xxxx";
    set password => "xxxxxx";
    set -passauth;

    set group => "all" => qw/1.2.3.51 1.2.3.52 1.2.3.53 1.2.3.54 1.2.3.55 1.2.3.56/;
    set group => "db"  => qw/1.2.3.53 1.2.3.54/;
    set group => "web" => qw/1.2.3.51 1.2.3.52 1.2.3.55 1.2.3.56/;
};

environment pshd => sub {
    set user => "xxxx";
    set password => "xxxxxxxx";
    set -passauth;
    set group => "all" => qw/1.2.4.31 1.2.4.32 1.2.4.33 1.2.4.34 1.2.4.35 1.2.4.36/;
    set group => "db"  => qw/1.2.4.35 1.2.4.36/;
    set group => "web" => qw/1.2.4.31 1.2.4.32 1.2.4.33 1.2.4.34/;
};

require M;

이렇게 sdtpshd 라는 environment 를 따로 빼놓고 그 안에 각각 전체와 Web, DB 각각을 정의해둡니다.

M.pm 에는 restart-opsview-agent, restart-munin-node, restart-apache, deploy-apps 같은 뭐 이런저런 Task 들이 정의되어 있다고 치고…

그런 것들을 각 environment 의 그룹단위로 실행시키도록 합니다.

1
$ rex -E sdt -G all M:restart-opsview-agent

위처럼 -E 의 인자값으로 environment 를 지정하고 -G 의 인자값으로 all 그룹을 지정해줌으로써, sdt 의 전체 서버에 대해서 opsview-agent 를 재시작하게끔 합니다.

결론

사실은 뭐 각 서버에 SSH Key 를 박아넣고 사용해야 좀 더 안심이 되기도 하지만, 여기에는 뜻모를 어른들의 사정이 숨어져 있는지라 쉽게 그럴수는 없기도 하답니다. –_–; 좀 더 시간을 두고 뭐 여러가지 불안요소와 편의성을 도모하기로 하고…

터미널 사용에 익숙하지 않은 팀원들을 위해서 Rex::WebUI 도 살며시 검토해봤는데, 아직까지는 Task 에 기재된 정보를 기준으로 읽어들이는 것 밖에 되지 않는지라… 위처럼 그룹을 지정하거나 environment 를 지정하거나 하는 것은 불가능하군요. 뭐 어차피 서버 데몬을 아무나 만지게 하고 그러는 것도 조심스러운 지라… –_–;; 꼭 모두가 써야하는 것인가 하는 의문이 있어서, 이건 뭐 전제자체가 붕괴되는 군요.

아무튼 Rex 괜찮습니다.

Cpanm 1.6 Is Here for You

엊그제 cpanm 1.6 이 릴리즈되었습니다. 그동안 개발버젼으로 1.6에 포함될 기능들이 일부 소개되어 왔지만, 아무튼 뭐 @miyagawa 씨가 친히 Screencast 까지 준비해서 소개할 정도로 많은 기능들이 추가되었습니다.

버젼지정 설치

1
$ cpanm MIYAGAWA/Plack-1.0015.tar.gz

위처럼 번거로운 버젼지정 설치방식이

1
$ cpanm Plack@1.0015

이렇게 간단해졌습니다.

예전에 Mail::Sender 의 마이너버젼에 따라서 인코딩지정이 좀 엉망이 되어서 우회코드를 쓸 까 하다가

그냥 증상이 나타나기 이전버젼으로 땜빵으로 버티던 기억이 있습니다. (물론 해당 버젼의 동작이 이상해서 뭐 금방 업데이트 되었었지만…)

개발버젼 설치

1
$ cpanm --dev Plack

--dev 옵션을 이용하여 개발버젼의 모듈을 설치할 수 있습니다.

저같은 경우는 요즘 거의 개발버젼을 보고 사용하는 경우가 없어서 쓸 일은 없을 것 같습니다.

  • 버젼범위 지정

1.0000 이상 2.0000 미만의 Plack 모듈 설치

1
$ cpanm Plack~">= 1.0000, < 2.0000"

1.0000 버젼의 Plack 설치 (cpanm Plack@1.0000 과 동일합니다.)

1
$ cpanm Plack~"== 1.0000"

1.0000 이상이지만 1.0016 버젼은 제외한 가장 최신의 Plack 모듈 설치

1
$ cpanm Plack~">= 1.0000, != 1.0016"

사실 Makefile.PL 에 의존모듈들을 넣었을 때 위와 같은 표기가 필요할 경우가 발생할 수 있겠습니다만, 대개의 경우는 특정 버젼만 지정해서 사용하는 경우가 많았기 때문에 어떨런지 잘 모르겠습니다.

Git Repository 에서 받아서 설치

몇몇 CPAN Author 들을 보면, CPAN 에 올릴 만큼 정비되지 않았다는 이유로 Github 에만 공개해놓는 경우를 많이 볼 수 있습니다. 몇번 그런 경우가 있었고, 일부러 다른 툴을 사용해서 Github 에서 CPAN Module 을 설치했던 기억도 있습니다. 이제부터 cpanm 이 이런 케이스를 지원해주니 다행이군요.

기본 브랜치를 설치

1
$ cpanm git://github.com/JEEN/p5-WebService-Aladdin.git

devel 브랜치를 설치

1
$ cpanm git://github.com/JEEN/p5-WebService-Aladdin.git@devel

특정 커밋내용이 적용된 부분을 설치

1
$ cpanm git://github.com/JEEN/p5-WebService-Aladdin.git@730fbd0a80

결론

perlbrew 에서 perlbrew install-cpanm 으로 설치된 cpanm 을 사용하고 있었는데,

1
$ cpanm --self-upgrade

로는 perlbrew 를 통해서 설치된 cpanm 의 버젼이 바뀌지 않는군요. 그럴 경우는,

1
$ perlbrew install-cpanm

을 통해서 기존의 cpanm 을 덮어써서 설치할 수 있습니다.

A Usecase of App::Fatpacker - Nagios Plugin

최근 업무때문에 Nagios Plugin 을 만져야 하는 일들이 빈번하게 있었고, 앞으로도 발생할 소지가 상당히 높습니다. 이런 Nagios Plugin 을 만들거나 기존에 만들어 진 것들을 간편하게 다른 복수의 서버에 배포하는 일도 필요합니다.

Nagios Plugin 이야 굳이 언어를 가리지 않는다고 치더라도, 언어의 특정 라이브러리에 의존을 가지는 경우가 많습니다. MongoDB 용 Nagios Plugin 에는 Python 의 pymongo 라이브러리를 설치해야하는 경우가 있지요.

일례로 Redis 용 Nagios Plugin 을 설치할 시에는 Redis CPAN 모듈을 필요로 합니다. 그런데 Redis 서버가 여러대이고, 이 여러대의 서버에 매번 Redis 모듈을 깔고, Redis 모니터링용 Nagios Plugin 도 설치를 해야하는 경우가 있습니다. 그냥 뭐 시간을 좀 허비해서라도 그렇게 번거로운 일을 하면 일이야 끝나겠지만, 현인(@aer0 님)의 조언을 빌어서 App::FatPacker 를 사용해서 단일 스크립트에 우겨넣는 방향으로 돌리도록 합니다.

우선은 App::FatPacker 를 설치하면 fatpack 이라는 커맨드를 사용할 수 있습니다.

Nagios Exchange 에서 찾아낸 check_redis 중에 check_redis.pl 파일이 위에 말한대로 Redis 모듈에 의존이 걸린 상황입니다.

그럼 우선 fatpack 커맨드로 다음과 같이 입력을 합니다.

bash $ fatpack trace check_redis.pl check_redis.pl syntax OK

결과 syntax OK 가 뜨고 해당 디렉토리에 fatpacker.trace 라는 파일이 생성됩니다.

bash $ cat fatpacker.trace IO/Handle.pm List/Util.pm Getopt/Long.pm SelectSaver.pm IO/Socket.pm Fcntl.pm Text/ParseWords.pm Symbol.pm Scalar/Util.pm IO/Socket/INET.pm Errno.pm fields.pm warnings/register.pm Encode/Alias.pm Time/HiRes.pm Encode/Config.pm Encode/Encoding.pm Redis.pm Encode.pm base.pm Config.pm IO.pm IO/Socket/UNIX.pm Carp.pm bytes.pm Exporter/Heavy.pm vars.pm constant.pm Socket.pm Try/Tiny.pm IO/Select.pm overload.pm lib.pm DynaLoader.pm Data/Dumper.pm

내용을 보면 말 그대로 해당 모듈이 가지고 있는 의존 모듈이 좌르르륵 표시됩니다. 물론 걔중에는 Core 모듈도 있기도 합니다.

일단 App::FatPacker SYNOPSIS 대로 진행을 해보면…

bash $ fatpack packlists-for cat fatpacker.trace > packlists

위 결과로 생긴 packlists 는 파일은 다음과 같은 내용을 가집니다.

bash $ cat packlists /home/jeen/perl5/perlbrew/perls/perl-5.14.0/lib/5.14.0/x86_64-linux-thread-multi/auto/Time/HiRes/.packlist /home/jeen/perl5/perlbrew/perls/perl-5.14.0/lib/site_perl/5.14.0/x86_64-linux-thread-multi/auto/Redis/.packlist /home/jeen/perl5/perlbrew/perls/perl-5.14.0/lib/site_perl/5.14.0/x86_64-linux-thread-multi/auto/Try/Tiny/.packlist

각 의존 모듈 위치에 맞춰서 .packlist 파일이 생성되고, 그 내용은…

bash $ cat /home/jeen/perl5/perlbrew/perls/perl-5.14.0/lib/site_perl/5.14.0/x86_64-linux-thread-multi/auto/Redis/.packlist /home/jeen/perl5/perlbrew/perls/perl-5.14.0/lib/site_perl/5.14.0/Redis.pm /home/jeen/perl5/perlbrew/perls/perl-5.14.0/lib/site_perl/5.14.0/Redis/Hash.pm /home/jeen/perl5/perlbrew/perls/perl-5.14.0/lib/site_perl/5.14.0/Redis/List.pm /home/jeen/perl5/perlbrew/perls/perl-5.14.0/man/man3/Redis.3 /home/jeen/perl5/perlbrew/perls/perl-5.14.0/man/man3/Redis::Hash.3 /home/jeen/perl5/perlbrew/perls/perl-5.14.0/man/man3/Redis::List.3

위와 같습니다.

그리고 다음 커맨드를 입력해봅니다.

bash $ fatpack tree cat packlists

그 결과 현재 디렉토리에서 fatlib 이라는 디렉토리가 생성되고 그 안에 관련 의존모듈들이 복사됩니다.

bash $ tree … ├── fatlib │   ├── Redis │   │   ├── Hash.pm │   │   └── List.pm │   ├── Redis.pm │   ├── Try │   │   └── Tiny.pm │   └── x86_64-linux-thread-multi │   ├── Time │   │   └── HiRes.pm │   └── auto │   └── Time │   └── HiRes │   ├── HiRes.bs │   └── HiRes.so …

그럼 다음 커맨드를 입력해보면…

bash $ (fatpack file; cat check_redis.pl ) > check_redis.packed.pl Can’t stat /home/jeen/fp/tt/lib: 그런 파일이나 디렉터리가 없습니다 at /home/jeen/perl5/perlbrew/perls/perl-5.14.0/lib/site_perl/5.14.0/App/FatPacker.pm line 200 BEGIN failed—compilation aborted at /home/jeen/perl5/perlbrew/perls/perl-5.14.0/bin/fatpack line 3.

제대로 동작하지 않습니다. 에러가 발생하네요. 정답은 에러메시지에 있습니다. App::FatPacker 자체는 Perl Library 규칙에 정형화된 디렉토리 구조를 가정하고 있습니다. 즉 lib 디렉토리가 존재하지 않기 때문에 발생하는 것이죠. 뭐 물론 다운받은 check_redis.pl 파일 하나만 있는 데 lib 디렉토리를 가지고 뭐 더 넣고 자시고 할 것도 아닌데…, 그래도 뭐 일단 사태해결을 위해서 아무것도 없어도 그냥 lib 디렉토리 하나는 만들어 줍니다.

그리고 다시 실행해보면 check_redis.packed.pl 이라는 파일이 생성됩니다.

~~~ perl # This chunk of stuff was generated by App::FatPacker. To find the original # file’s code, look for the end of this BEGIN block or the string ‘FATPACK’ BEGIN { my %fatpacked;

$fatpacked{“Redis.pm”} = <<‘REDIS’; package Redis;

# ABSTRACT: Perl binding for Redis database our $VERSION = ‘1.955’; # VERSION our $AUTHORITY = ‘cpan:MELO’; # AUTHORITY … ~~~

일단 Nagios Plugin 은 기본 실행권한을 가지는 파일로 해두는 것이 여러모로 편합니다. 한가지 주의할 점은 일단 위처럼 생성된 파일에서 shebang line 이 존재하지 않기때문에 shebang line 을 추가해주면 됩니다. :–)

perl #!/usr/bin/env perl

위의 내용을 check_redis.packed.pl 파일의 첫째줄에 추가해줍니다.

그리고 완성된 파일들을 Redis 서버에 붙여서 check_nrpe 등으로 동작을 확인하고 설정에 추가하는 것으로 관련된 작업은 끝이 났습니다.

파일 중앙배포와 관련해서도 다양한 이슈가 있지만 이에 관련해서는 추후 Rex 를 다루면서 이야기를 계속할 까 합니다.

다 쓰고 나서 검색을 해보니 예전에 @aer0 님께서 작성하신 블로그 기사가 있군요.

덩달아서 같이 참고하시면 좋을 것 같습니다.