System Compleat.

Start Chef from opcode on Ubuntu

Techs

( younjin.jeong@gmail.com , 정윤진 )


세월은 빠르게 흘러, 시스템 관리에도 고전적인 perl / python 과 같은 언어를 제치고 ruby 가 등장하게 되었다.
Chef 라고 하면 이미 나온지 그렇게 오래 된 툴은 아니지만, 그렇다고 얼마 되지 않은 것도 아니다.
이 글을 쓰게 되는 것도 번역이나 샘플 코드 조사를 통한 기본적인 동작의 이해를 위한 것임을 미리 밝히며, 시스템 자동화를 구현 할 수 있는 이런 툴을 개발하고 또 미리 알아내어 접하는 분들에게 새삼 놀랄 따름이다.

우분투에서의 ruby 인스톨은 아주 쉬운 과정으로 이루어 지며, 이거 왜 안되 할 만한 부분이 있어 별도로 소개한다.
( 우분투에서는 gem update --system 을 지원하지 않는다.  패키지 매니저로 처리 하라는 친절한 시스템사마의 설명 )

# sudo apt-get install ruby rubygem
# sudo gem install ohai chef       

하다 보면 여기서 에러를 줄줄이 뱉어 낼 것이다.  에러를 살펴보면, extconf.rb:1:in 'require': no such file to load - mkmf 라는 에러 메세지 인데, 결국 extconf.rb 는 ruby-dev 패키지를 참조하기 때문에 이 패키지를 설치 하지 않으면 정상적으로 동작하지 않는다.  따라서,  정상적으로 진행하기 위해서는

# sudo apt-get install ruby-dev

해 준다.  이후 다음의 링크에서 제공하는 Chef 를 시작하는데 안성맞춤인 내용을 따라하는데 우분투로 충분 할 것이다.

이제부터 설명할 내용은 다음의 링크에서 가져왔다.
http://brainspl.at/articles/2009/01/31/cooking-with-chef-101


Cooking with Chef 101

Chef 의 가장 매력적인 점은 확장 및 축소가 매우 쉽다는 점이다.  처음 시작할 때는 chef-solo 로 쉽게 시작하고, 이후 필요에 따라 chef-client 나 chef-server 를 통해 원하는 대로 구현이 가능해 진다. Chef 로 작성한 동일한 recipe 를 가지고  웹 서버, 데이터베이스, 어플리케이션 , couchdb 서버 및 기타 등등의 거의 모든 서버에 대한 수평적 확장이 가능하다.
구체적 설명은 됬고, 일단 간단한 recipe 를 통해 rubygem 의 일부 패키지를 설치 해 보기로 한다. 그리고, chef 가 베이스 시스템을 구성한 이후에 간단한 디렉토리 설정과 어플리케이션을 배포 해 보도록 하겠다 .

일단 chef-101 의 코드를 GitHub 로 부터 가져온다.

# git clone git://github.com/ezmobius/chef-101.git

Chef 를 설치한다. ( root 계정 또는 sudo )

# gem install chef ohai  --source http://gems.opcode.com  --source http://gems.rubyforge.org

( 일부 패키지 의존성 문제로 인해 rubygem 이 gems.opcode.com 에 의해 서비스 받고 있음에도 불구하고 rubyforge 를 소스로 추가해 주는 것이 좋다.  Rubygem 은 그런식으로 동작한단다. )
여기까지 준비 되었으면 이제 실행시켜 보면 된다.  ( 이 단계는 일부 디렉토리 생성 및 어플리케이션 들을 인스톨 하기 때문에 원치 않으면 넘어가도 관계 없다. )

실행하기전,  config/dna.json 의 user 설정을 변경 할 필요가 있다.  소스에는 'ez'로 되어있을 것이나, 시스템에 나와 같이 'ez' 계정이 없다면 변경 해 주는 것이 좋다.

# cd chef-101
# chef-solo -l debug -c config/solo.rb -j config/dna.json

엄청나게 많은 메세지들이 줄줄이 올라가는 것을 볼 수 있는데, 처음부터 대부분의 메세지는 시스템 output 컬렉터인 ohai 가 수집한 정보들이다.  이는 recipe 에서 수행하는 모든 내역을 알려주며, 정상적으로 종료 된 경우에는 다음과 같은 내용을 보여준다.

INFO: Chef Run complete in 1.09344323 seconds

여기까지 나왔다면 요리를 잘 했다고 볼 수 있다.   이제 이 Chef 가 어떤 식으로 동작하는지 알아 볼 필요가 있다.
먼저,  dns.json 을 보면,

{
  "apps": [
    "beast",
    "mephisto"
  ],
  "user": "ez",
  "gems": [
    {
      "name": "rake",
      "version": "0.8.3"
    },
    {
      "name": "tmm1-amqp",
      "source": "http://gems.github.com",
      "version": "0.6.0"
    }
  ],
  "recipes": ["main"]
}

이는, 내가 JSON DNA 라고 부르는 recipe 세트다.  이는 노드에 설치할 것들에 대한 레시피로, 코드 안에서 어플리케이션 이름, 사용자 명 등을 찾아 볼 수 있다.

시스템으로의 엔트리 포인트인 main 으로 지정된 recipe 를 보면,

include_recipe 'gems'
include_recipe 'applications'

template "/data/someservice.conf" do
  owner node[:user]
  mode 0644
  source "someservice.conf.erb"
  variables({
    :applications => node[:apps]
  })
end

include_recipe 로 필요한 recipe 를 순차적으로 호출하는 것을 볼 수 있는데, 이는  호출 순서에 따라 필요한 레시피가 동작하도록 설정 할 수 있게 하기 위함이다.  만약 다른 레시피를 먼저 구동하고 싶으면, 그 레시피를 다른 것보다 먼저 호출 하도록 한다.

자, 우리는 gem 레시피 이후 application 레시피를 호출하고, 이후 일부 디렉토리 작업을 수행 하는 것을 볼 수 있다. 이 이후작업에서 우리는 쉽게 템플릿을 정의하고, 네이밍 하여 해당 템플릿이 가져야 하는 속성의 정의를 구현하는 것을 볼 수 있다. 
이제, gem 레시피를 보자.

node[:gems].each do |gem|
  gem_package gem[:name] do
    if gem[:version] && !gem[:version].empty?
      version gem[:version]
    end
    if gem[:source]
      source gem[:source]
    end
    action :install
  end
end

여기서 우리는 loop 를 돌려가며 dna.json 에서 정의 되어 설치할 각 gem 의 버전을 가져오는 것을 볼 수 있다. Gem 은 버전과 소스를 가질 수 있으나, 주의할 점은 비어있으면 설정하지 않아야 한다. 버전을 정의하지 않으면 가장 최신의 버전을 가져오게 될 것이며, 소스를 지정하지 않으면 rubyforge.org 에서 가져오게 될 것이다. 
결국 마지막 줄에, 우리는 action :install 으로서 각 gem 에 대한 인스톨을 수행한다. 이는, 시스템에 이미 해당 gem 이 설치 되어 있으면 다시 설치하지 않는다.

자 이제 application recipe 를 보면,

directory "/data" do
  owner node[:user]
  mode 0755
end

node[:apps].each do |app|

  cap_directories = [
    "/data/#{app}/shared",
    "/data/#{app}/shared/config",
    "/data/#{app}/shared/system",
    "/data/#{app}/releases"
  ]

  cap_directories.each do |dir|
    directory dir do
      owner node[:user]
      mode 0755
      recursive true
    end
  end

end

먼저 우리는 /data 디렉토리를 생성하고 원하는 권한을 할당한 이후, json 에 명시한 owner 로 디렉토리를 설정하는것을 볼 수 있다. 이후 루프를 돌면서 필요한 디렉토리 생성 등 모든 액션을 취한다. 

보는 바와 같이 비교적 간단하게 chef-101 코드는 종료된다. 매우 간단하지만 보기 쉽게 로직을 설명하고 있어서, Chef 를 시작하는 엔트리 포인트로는 나쁘지 않을 것이다.


여기까지 날림 번역.


Chef 는, 상상할 수 있는 시스템 설정의 모든 부분에 관여 할 수있다.  각종 daemon 의 동작에 필요한 설정 파일 부터,
필요한 패키지의 설치 또는 웹 서버들의 컨텐츠 배포, Mysql 의 복제 구성까지도 모두 가능하다.

ruby 라는 언어를 먼저 습득할 필요는 있지만, perl 이나 python 중 둘중 하나에 엑스퍼트가 아니어서 하나를 배워야 한다면 루비를 적극 추천하며, 두가지 언어 모두를 알고 있는 사람에게도 Chef 는 좋은 툴이 될 수 있을 것이다.



( younjin.jeong@gmail.com , 정윤진 )