Chef 서버 설치하고 테스트해보기

Chef 서버 설치하고 테스트해보기

vagrant + virtualbox로 5대의 멀티 인스턴스 올리기

Chef 서버의 환경을 이해해 보려면 3개이상 가상머신을 설치해서 해보는게 좋다.
Vagrant로 5대의 가상머신을 올려보자.
Vagrant를 설치하고 VagrantFile에 아래와 같이 설정한 후

vagrant up을 실행하면 된다.

vagrant 사용법은 아래의 링크를 참고 하자.

Chef의 테스트 환경을 만드는데 매우 적합한 툴 – Vagrant (http://gyus.me/?p=326)

 

VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.define :chef_server do |cfg|
cfg.vm.box = "base"
cfg.vm.network :private_network, ip: "192.168.30.10"
cfg.vm.host_name = "chef-server"
end
config.vm.define :workstation do |cfg|
cfg.vm.box = "base"
cfg.vm.network :private_network, ip: "192.168.30.20"
cfg.vm.host_name = "workstation"
end
config.vm.define :node01 do |cfg|
cfg.vm.box = "base"
cfg.vm.network :private_network, ip: "192.168.30.21"
cfg.vm.host_name = "node01"
end
config.vm.define :node02 do |cfg|
cfg.vm.box = "base"
cfg.vm.network :private_network, ip: "192.168.30.22"
cfg.vm.host_name = "node02"
end
config.vm.define :node03 do |cfg|
cfg.vm.box = "base"
cfg.vm.network :private_network, ip: "192.168.30.23"
cfg.vm.host_name = "node03"
end
end

 

chef server 설치

아래 사이트에서 패키지를 다운 받아서 설치

http://www.getchef.com/chef/install/

[code lang=text]
wget https://opscode-omnitruck-release.s3.amazonaws.com/ubuntu/12.04/x86_64/chef-server_11.0.6-1.ubuntu.12.04_amd64.deb
[/code]

[code lang=text]
sudo dpkg -i chef-server.deb
[/code]

설치 완료후 chef-server-ctl로 Chef Server를 설정함

[code lang=text]
sudo chef-server-ctl reconfigure
[/code]

위 커맨드를 실행하면 서버를 기동시키고, nginx가 HTTPS 443포트를 바인드한다.

Chef의 각종 파일은 /opt 디렉토리에 인스톨된다.

knife 설정

[code lang=text]
knife configure
[/code]

실행하면 아래와 같은 설정 항목들이 나옴 걍 엔터.

[code lang=text]
Where should I put the config file? [/home/vagrant/.chef/knife.rb]
Please enter the chef server URL: [https://chef-server:443]
Please enter an existing username or clientname for the API: [vagrant]
Please enter the validation clientname: [chef-validator]
Please enter the location of the validation key: [/etc/chef-server/chef-validator.pem]
Please enter the path to a chef repository (or leave blank):
[/code]

임의의 클라이언트가 처음 Chef Server와 통신을 할경우, 디지털서명이 없기 때문에,
최초 한번, chef-validator라는 Client등록작업만을 전문으로 하는 클라이언트 에서 인증서를 빌려서 Chef Client의 등록작업을 하게됨. 이 작업이 완료되면 이후는 클라이언트 쪽에서 작성한 디지털서명에 의해 통신이 이루어지도록 된다.

dep패키지로 Chef Server를 설치하면 /etc/chef-server 디렉토리에 아래와 같은 파일이 있음. knife configure로 knife에게 이러한 인증서의 패스를 정확히 설정할 필요가 있다.
우선은 서버와 같은 호스트의 knife가 잘동작하도록 하고, 후에 workstation에 인증서를 전송하는 순서로 설치를 하겠음.
일단은 /etc/chef-server이하의 pem파일을 홈디렉토리로 카피함.

  • chef-validator.pem : chef-validator용의 디지털 인증서 파일
  • admin.pem : 관리자용의 클라이언트 인증서 파일(이 것을 사용하는 클라이언트 만 chef-validator를 통하지 않고 미리 작성되어 있음)

[code lang=text]
vagrant@chef-server:/$ sudo knife configure
Please enter the chef server URL: [https://chef-server:443] https://192.168.30.10
Please enter an existing username or clientname for the API: [vagrant] admin
Please enter the validation clientname: [chef-validator]
Please enter the location of the validation key: [/etc/chef-server/chef-validator.pem] ~/.chef/validation.pem
Please enter the path to a chef repository (or leave blank):
[/code]

위의 설정에서
* server URL : https://192.168.30.10
* clientname : admin
* validation key : /etc/chef-server/chef-validation.pem
을 설정함. 이것으로 해당 서버의 knife는 클라이언트의 인증서가 있는 ~/.chef/admin.pem을 이용해서 통신을 하게끔 된다. 한번 시험해봅시다.

[code lang=text]
$ knife client list
[/code]

Work Station의 셋업

새로운 Chef Client를 셋업 할 경우, 인증서의 생성과 클라이언트를 서버에 등록하는 것이 필요하다. 이것도 knife로 하게됨. 서버에 설치한 knfie를 사용해 보도록 하자.

knife client create를 실행하면 에디터에서 메타데이터의 편집을 요구하기때문에, EDITOR의 환경변수를 미리 설정해둠. knife client create 옵션의 -a 는 관리권한을 가진 클라이언트의 작성, -f는 인증파일의 저장소 지정. Vagrant를 사용하는 경우는 가상머신의 /vagrant는 공유 디렉토리로 마운트되어 있어서 다른 가상서버로의 파일전송이 편리하다. 거기에 저장을 하도록 해보자.

[code lang=text]
$ export EDITOR=vi
$ knife client create workstation -a -f /vagrant/workstation.pem
[/code]

Work Station의 knife에도 validation.pem을 저장해두면 나중에 편하니 거기에도 카피해두자.

그리고 여기서 부터는 Work Station에서 작업해야한다. 우선은 Work Station에 Chef Solo를 설치할때 사용한 Opscode Omnibug Packaging의 인스톨스크립트를 실행해서 Chef를 설치한다.

[code lang=text]
$ vagrant ssh workstation
$ curl -L https://www.opscode.com/chef/install.sh | sudo bash
$ chef-client -v
Chef: 11.8.2
[/code]

이 다음으로는 서버에서 한것과 동일하게 knife를 설정해야한다.

[code lang=text]
$ cp /vagrant/workstation.pem ~/.chef/
$ cp /vagrant/validation.pem ~/.chef/
$ knife configure
WARNING: No knife configuration file found
Where should I put the config file? [/home/vagrant/.chef/knife.rb]
Please enter the chef server URL: [https://workstation:443] https://192.168.30.10
Please enter an existing username or clientname for the API: [vagrant] workstation
Please enter the validation clientname: [chef-validator]
Please enter the location of the validation key: [/etc/chef-server/chef-validator.pem] ~/.chef/validation.pem
Please enter the path to a chef repository (or leave blank):
[/code]

서버의 URL과 방금 설정한 인승키의 패스를 설정.
제대로 설정을 했다면 knife client list로 출력이 되고 새로운 Client로 workstation이 등록된다.

[code lang=text]
### Chef Server에서 작업
$ knife client list
chef-validator
chef-webui
workstation
[/code]

<h3>Chef Client의 설치</h3>
Chef Server와 Work Station이 완료된 후에는 Client를 작업하자.
관리 대상이 되는 노드를 Chef Client로 셋업하자.

클라이언트측의 Chef인스톨도 Opscode Omnibus Packaging의 인스톨 스크립트를 실행하면 된다.

우분투를 클린상태로 설치했다면, 몇가지 패키지를 설치해야하니 다음 순서로 설치해보자.

[code lang=text]
### Chef Client에서 실행함.
$ sudo apt-get update
$ sudo apt-get install curl vim -y
$ curl -L https://www.opscode.com/chef/install.sh | sudo bash
$ chef-client -v
$ sudo mkdir -p /etc/chef
$ sudo cp /vagrant/validation.pem /etc/chef/validation.pem
[/code]

위의 스크립트를 한줄 한줄 실행해도 되고 귀찮은 사람은 파일로 만들어서 한방에 실행해도 된다.

노드에서 chef-client를 실행해서 해당 노드를 서버에 등록하자. –server로 서버의 URL을 지정하고, -N으로 노드명을 지정할 수 있다.(생략하려면 /etc/chef/client.rb를 설정하면 된다. 자세히 알고 싶으면 매뉴얼을 보도록 하자.)

[code lang=text]
$ sudo chef-client –server https://192.168.30.10 -N node01
[/code]

최초의 Client실행 때에 /etc/chef/client.pem에 클라이언트용 인증서가 생성되고, 이후의 통신은 validation.pem이 아닌 클라이언트용 인증서를 사용하게 된다.

Chef Server에 노드가 등록되었는지 Work Station의 knife에서 확인가능하다.

[code lang=text]
### Work Station에서 실행
$ knife client list
chef-validator
chef-webui
node01
workstation
[/code]

node02, node03에는 추후에 따로 세팅을 할테니 우선 두자.

헉헉헉…길다…
<h3>레시피 실행하기</h3>
잘동작하는지 테스트용 레시피를 작성후 실행해보자.
테스트로는 해당노드에 대한 각종 정보를 가지고 있는 ohai를 확인해 보는 레시피를 작성하도록 하자.
Work Station에서 쿡북을 작성하고 Server에 업로드 한 뒤 클라이언트에 적용해보자.
<h4>쿡북의 작성</h4>

[code lang=text]
$ knife cookbook create sample -o ~/chef-repo/cookbooks
[/code]

<h4>
레시피의 작성</h4>

[code lang=text]
$ vi ~/chef-repo/cookbooks/recipes/default.rb

bash "print ohai info" do
user 'vagrant'
group 'vagrant'
cwd '/home/vagrant'
environment "HOME" => '/home/vagrant'
code < /tmp/ohai.txt
EOC
creates "/tmp/ohai.txt"
end
[/code]

<h4>쿡북의 업로드</h4>

[code lang=text]
$ knife cookbook upload -a -o ~/chef-repo/cookbooks
[/code]

<h4>Node Object의 run_list 레시피 추가</h4>

[code lang=text]
$ knife node run_list add node01 'recipe[sample]'
[/code]

<h4>Node Object를 에디터에서 편집하고 싶은 경우</h4>

[code lang=text]
$ knife node edit node01
[/code]

이제 서버에 필요한 정보의 등록은 완료됐다.
노드 쪽에서 chef-client를 실행하고 생성된 파일을 확인해 보자.

[code lang=text]
$ sudo chef-client –server https://192.168.30.10 -N node01
$ cat /tmp/ohai.txt | head
{
"languages": {
"ruby": {
"platform": "x86_64-linux",
"version": "1.8.7",
"release_date": "2012-02-08",
"target": "x86_64-unknown-linux-gnu",
"target_cpu": "x86_64",
"target_vendor": "unknown",
"target_os": "linux",

[/code]

knife bootstrap 으로 노드 설정하기

가상머신으로 실행중인 경우 Work Station에서 knife bootstrap 명령을 원격으로 실행 가능하도록, 몇가지 선행되어야하는 작업이 있는데 다음과 같다.

  • 가상서버에 ssh로그인 가능하도록 호스트 OS의 ~/.vagrant.d/insecure_private_key를 Work Station의 ~/.ssh/id_rsa에 카피

[code lang=text]
### 호스트 OS에서 작업
$ scp ~/.vagrant.d/insecure_private_key worksstation:~/.ssh/id_rsa
[/code]

  • 가상서버에 설치되어 있는 옛날 버젼의 Chef가 설치시 에러를 일으킬 수 있으므로 제거. /usr/bin 디렉토리의 chef-* 파일을 어딘가로 이동해두면 된다.

[code lang=text]
### Work Station에서 작업
$ mv /usr/bin/chef-* /tmp/
[/code]

  • Work Station의 /etc/hosts에 각 노드의 IP주소를 등록해둔다.

[code lang=text]
# /etc/hosts

192.168.30.21 node01
192.168.30.22 node02
192.168.30.23 node03
[/code]

위의 설정은 knife ssh가 호스트로의 통신을 FQDN(Fully Qualified Domain Name)으로 실행하기 위한 것이다.

정리

설치와 실행이 매우 길고 좀 복잡해 보이는데, 차근차근 따라해보면 그렇지도 않다. 관리하는 서버가 10대를 넘어가면 Chef Server를 고려해 보는 것이 좋은 것 같다.

[ruby기초] Kernel모듈의 출력 메서드들 – p, print, printf, putc, puts –

원래는 shallow copy랑 deep copy라는 것에 대해서 쓸려고 했는데,
그것 관련해서 찾다보니 「p」라는 녀석이 테스트 코드에 보이길래
출력메서드에 대해서 적고자 한다.

찾아보니 문자열을 출력해주는 메서드는 루비의 Kernel모듈에 들어 있는데
거기에 포함되어 있는 출력관련 메서드는 아래와 같다.
p, print, printf, putc, puts

루비의 레퍼런스에 있는 설명들을 보자.
p
– 각 객체에 대해 obj.inspect를 출력하고, 그 다음 현재 출력 레코드 구분자를 프로그램의 표준출력에 쓴다.

테스트 코드

p("Hello, Ruby !\n")

결과

"Hello, Ruby !\n"

음..inspect가 실행된건지 잘 모르겠다. 하나 더 테스트해보자.

User = Struct.new(:name, :id)
u = User['park', 'wapj']
p u

결과

#<struct User name="park", id="wapj">

print – 각 객체를 차례로 STDOUT에 출력한다. 출력필드구분자($,)가 nil이 아니라면 그 내용이 각 필드 사이에 나타날 것이다. 출력레코드 구분자($\)가 nil이 아니라면 결과에 이 값도 추가될 것이다. 아무런 매개변수도 건네지 않으면 $_를 출력한다. 문자열이 아닌 객체들은 그 객체의 to_s메서드를 호출하여 문자열로 변환한다.
테스트 코드

print "apple", [1,2,3], 9876, "\n"
$, = ","
$\ = "\n"
print "apple", [1,2,3], 99

실행결과

apple1239876
apple,1,2,3,99

출력필드 구분자를 지정안하면 문자들이 붙어서나오고
지정한 뒤에는 문자열 사이사이에 출력필드구분자가 붙어서 나온다.

printf – 아래 코드와 동일하다
io.write sprintf(format, obj …)
또는
STDOUT.write sprintf(format, obj …)

형식은 printf(format, arg*)과 같고
format에다 arg로 들어온 파라메터를 적용한 문자열을 반환한다.
기본적으로는 C의 sprintf와 동일하다.

테스트코드

#2진수
printf("%b", 10) # -> 1010
#8진수
printf("%o", 10) # -> 12
#16진수
printf("%x", 10) # -> a
printf("%X", 10) # -> A

#부동소수점 
printf("%.0f", 10.12) # -> 10
printf("%.1f", 10.12) # -> 10.1
printf("%.2f", 10.12) # -> 10.12

#문자열
printf("%s", "abcdefg") # -> abcdefg

# Object#inspect의 결과를 출력
printf("%p", [1, 2, 3]) # -> [1,2,3]

# 10진수 d,i
printf("%d %i", 10, 20) # -> 10 20

플래그, 폭, 정확도등의 표시자가 있는데 이건 다음에 따로 써야 될듯..

putc – STDOUT.putc(int)와 동일.
주어진 문자(String, Fixnum)를 io에 쓴다.

putc "A"
putc 65

결과

AA

puts – STDOUT.puts(arg…)와 동일.
주어진 객체를 IO#print를 이용해서 쓴다. 개행문자로 끝나지 않는 객체는 개행문자를 붙인다.
배열을 넣으면 각요소를 새로운줄에 쓴다.

테스트 코드

puts ("hello", "ruby", "!")

결과

hello
ruby
!

※참고
출력메서드를 사용할 때에는 쌍따옴표 [“]나 홑따옴표[‘]로 보통 감싸주는데,
홑따옴표는 그냥 그대로 표시해준다고 생각하면 되고,
쌍따옴표는 [\n]같은 역슬래시[\]로 시작하는 문자를
특수문자로 치환해 주는 기능이 추가로 더 있다.

루비 습작3 스트링의 개행문자 제거하기(String#chop!)

오늘은 바로 코드로 들어가보자.

def makeCode(var)
  puts "/home/www/conf/#{var}.properties"
  puts "/home/www/db/#{var}.data"
  puts "/home/www/xml/#{var}.xml"
end

x = gets

makeCode(x)

위의 루비코드는 별거 아니다. 그냥 코드 생성기다.
위의 코드를 실행하면 변수를 콘솔에서 받아온다.
그런데 문제가 하나 있는것이 엔터키로 변수를 받아오기에 #{var} 뒤에 꼭 \n이 붙어서 온다.
실행하면 아래와 같이 변수뒤에 개행이 들어가는데, 아주 신경쓰인다.

/home/www/conf/test
.properties
/home/www/db/test
.data
/home/www/xml/test
.xml

어차피 가장뒤에 있는 문자가 ‘\n’으로 달려오니 이걸 삭제해주면 될것 같다.
찾아보니 역시나 있구만..ㅎ

[ruby] var.chop! [/ruby]

String#chop! 이라는 녀셕을 사용해서 해결했다.
문자열의 가장뒤에 있는 문자를 삭제해주는 메서드인데,
아마도 이런용도로 쓰라고 만든거라는 생각이 든다.

자세한 것은 역시나 루비의 레퍼런스를 참고하자.
http://ruby-doc.org/core-1.9.3/String.html#chop-method

변경된 소스는 다음과 같다.

def makeCode(var)
  var.chop!  
  puts "/home/www/conf/#{var}.properties"
  puts "/home/www/db/#{var}.data"
  puts "/home/www/xml/#{var}.xml"
end

x = gets

makeCode(x)

루비 습작2 카멜케이스를 abc_def_ghi형식으로 변환하기

루비로 이것 저것 만들기 시작하니 참 재미있고,
편리하다는 생각이 든다.
오늘은 어제랑 완전 반대인 예제를 만들었다.

testClassMethod 라는 문자열을 주면 test_class_method의 형식으로 변환해 주는
메서드를 만들어 보았다.

기능은 반대인데 코드는 그다지 닮지 않았다.
이번 예제에서 사용된 중요한 메서드는 gsub메서드인데 풀어쓰면
global substitute정도 될라나? 아래 레퍼런스를 참고하는게 확실하긴 하지만,
간단히 설명하면, 정규식을 사용해서 스트링내부의 문자열을 치환하는 기능을 제공한다.
자바로 치면 replaceAll() 정도 되는 메서드이다. 자주 사용될듯.

나는 책보고 했는데, 책이 없으신분들은 아래 사이트를 참고하자.
http://ruby-doc.org/core-1.9.3/String.html#method-i-gsub
책은 프로그래밍 루비 790쪽에 레퍼런스가 있다.

코드는 아래와 같다.

#!/usr/bin/ruby

def makeDowncase(val)

  val  = val.gsub(/[A-Z]/) {|x| '_' + x.downcase}

  puts val

end

print "input CamelCases : "
vars = gets
varList = vars.split(" ")
varList.each { |x| makeDowncase(x)}

실행하면 아래와 같이 나오고

input CamelCase : testClassMethod1 testClassMethod2 testClassMethod3 aaaBbbCcc dddEeeFff

결과는 이렇게 된다.

test_class_method1
test_class_method2
test_class_method3
aaa_bbb_ccc
ddd_eee_fff

루비 습작1 abc_def의 문자열을 카멜표기법으로 변경하기

루비를 공부중인데, 책보고 따라하는거 보다는 실제로 만들어보는게
재밌기도하고 실제로 도움이 되기도 해서
반복적인 작업을 없애기 위해서 아래와 같은 유틸리티성 메서드를 만들어봤다.

제목처럼 abc_def_xyz 처럼 되어있는 문자열을 abcDefXyz로 변경해주는 메서드이다.

여러개를 동시에 받아서 변환가능하다.
(문자열이 ‘ ‘ 공백으로 구분되어있어야된다. 머 더 잘 할수 있겠지만, 이 정도로도 사용하는데 문제 없음.^^;)

소스는 아래와 같다.

[ruby]
#!/usr/bin/ruby

### MAKE Camel Case from abc_def -> abcDef

def makeCapitalize(var1)
array1 = var1.split("_")
array2 = array1[1, array1.length].collect! {|x| x.capitalize}
puts "===================="
array2.insert(0, array1[0]);
puts array2.join
return array2.join
end

print "input text : "
variables = gets

varList = variables.split(" ")

varList.each { |x| makeCapitalize(x)}
[/ruby]

실제로 돌려본거는 아래와 같은 형식으로 했다.

[gyus@gyue:string]$ ./makeCamel.rb

input text : tx_server_target_method tx_server_ntype tx_server_access_method tx_naming_postfix tx_client_class tx_client_super tx_client_access tx_client_prefix tx_client_using_param profile_class tx_server_target_method profile_prefix profile_access_method lwst_txclient_method_using_param

결과

====================
txServerTargetMethod
====================
txServerNtype
====================
txServerAccessMethod
====================
txNamingPostfix
====================
txClientClass
====================
txClientSuper
====================
txClientAccess
====================
txClientPrefix
====================
txClientUsingParam
====================
profileClass
====================
txServerTargetMethod
====================
profilePrefix
====================
profileAccessMethod
====================
lwstTxclientMethodUsingParam

오홋.. 재밌네.ㅋ

참고
– 프로그래밍 루비 책
site : http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-collect

 

프로그래밍 루비 3장 클래스와 객체

프로그래밍루비 pdf를 샀으니 열심히 공부해야지. 그닥 특별한건 없는데. attr_reader랑 attr_writer는 좋네. 속성과 메서드가 거의 동일하게 작동하는게 신기하다. 일단 기록해두고 나중에 다시 참고. -> 스레드 세이프하게 싱글톤만드는거는 필수로 해야됨. $globalParam = “I’ll be always with you” # $param은 전역변수 @instanceParam = “I’ll stand with instance” #@instanceParam은 인스턴스 변수 루비 메서드에서 반환하는 값은 마지막으로 실행된 표현식의 결과값이다. (19페이지) 즉 아래의 메서드를 [ruby] def say(name) sayWhat = "How you doing? #{name} return sayWhat end [/ruby] 이렇게 고칠 수 있다는 말임 [ruby] def say(name) "How you doing? #{name} end [/ruby] 클래스 정의하기 [ruby] class Song #reader 인스턴스 변수는 자동으로 만들어짐 attr_reader :name, :artist, :duration #writer attr_writer :duration def duration_in_minutes @duratino/60.0 #부동소수점으로 설정 end def initialize(name, artist, duration) @name = name @artist = artist @duration = duration end end [/ruby] 상속 [ruby] class KaraokeSong < Song def initialize(name, artist, duration, lyrics) super(name, artist, duration) @lyrics = lyrics end end [/ruby] 클래스 변수 – 그 클래스의 모든 객체가 공유하며 클래스메서드를 통해 접근 할 수 있다. – 클래스 변수는 @@value 처럼 표시 – 클래스 변수는 사용하기전에 반드시 초기화 해야한다. – 클래스 메서드를 선언할 때는 ClassName.methodName 같은 식으로 선언 [ruby] class TestClass def method print "this is instance method" end def TestClass.class_method print "this is class method" end end [/ruby] 싱글톤 클래스 만들기 – 객체를 생성할 수 있는 메서드를 private로 만들고 getInstance메서드로만 생성할 수 있게 한다. -> 그런데 아래와 같이 만드는거는 스레드세이프 하지 않다. -> 스레드 세이프 하게 만들려면 singleton 믹스인을 사용해야됨. – (음..이건 나중에..) [ruby] class TestSingleton private_class_method :new @@classVariable = nil def TestSingleton.getInstance @@classVariable = new unless @@classVariable @@classVariable end end [/ruby] 접근 제어 – public, protected, private – 약간 특이하게 메서드 앞에 붙여주는 방식은 아니고 키워드를 지정하면 그 아래 있는거는 메서드에 다 적용하는 방식과 – 접근제어 키워드 뒤에 메서드를 :{메서드1}, :{메서드2} 이렇게 붙여주는 방식 2가지가 있다. [ruby] class AccessControl //기본값은 public def method1 end protected //여기부터는 protected def method2 end private //여기부터는 private def method3 end [/ruby] [ruby] class AccessControl public :method1, :method2 protected :method3 private :method4 end [/ruby]