Your wish is my command

It’s a long journey

Chef Data_bag/ Cookbook Upload Script

chef로 작업하다보면 참 불편한 것이 있다.

$ knife cookbook upload -a -o cookbook # ---- [1]
$ knife data bag from file hosts default.json # ---- [2]

#1은 cookbook을 업로드하고 #2는 data bag을 업로드한다. 그런데 여기서 문제는 이 명령을 실행하는 디렉토리가 중요하다는 것이다. cookbook을 업로드 할 때는 -o로 cookbook 디렉토리를 지정해줘야하고, data bag을 업로드할 때는 chef-repository의 root에서 실행해야하는 것이다.

작업하다보면 여기저기 디렉토리를 이동하게 되는데, 그에 따라서 명령이 다르단 말이지.. 이거 귀찮아서 간단히 스크립트 만들었다. 원리는 간단하다. chef-repository의 root 디레토리에는 .chef 디렉토리에서 해당 레포지트리의 chef-server를 관리하는데, 이 디렉토리를 찾아서 해당 명령을 수행하는 것이다. 단순히 아래처럼 하면 된다.

$ kup.sh
$ bag.sh

이러면 자동으로 chef-repository root 디렉토리에서 cookbook, data bag upload를 수행한다.

kup.sh

#!/bin/bash
# upload all cookbooks
set -e

base_dir=`dirname $0`
if [ -f $base_dir/cheflib.sh ]; then
    source $base_dir/cheflib.sh
fi

chef_dir=$(find_chef_repo)

knife cookbook upload -a -o $chef_dir/cookbooks

bag.sh

#!/bin/bash
# upload all data bags

set -e

base_dir=`dirname $0`
if [ -f $base_dir/cheflib.sh ]; then
    source $base_dir/cheflib.sh
fi

chef_dir=$(find_chef_repo)

cd $chef_dir

for x in `(cd data_bags; find . -name '*.json' -type f)`; do
    bag=$(echo $x | cut -d / -f 2)
    item=$(echo $x | cut -d / -f 3)

    knife data bag from file $bag $item
done

cheflib.sh

#!/bin/bash

function fatal() {
    echo $@
    exit
}

function find_chef_repo() {
    pushd `pwd` > /dev/null

    # find .chef directory
    until [ -d .chef ]; do
        [ $(pwd) = '/' ] && break
        cd ..
    done

    [ `pwd` = '/' ] && fatal "Can't find chef repository"

    echo `pwd`
    popd > /dev/null
}

VMWare에서 Hostonly Vmnet간의 Routing

VMWare를 사용하면서 뭔가 복잡한 네트워크 모델을 사용하려면 hostonly vmnet을 여러개 사용하게 됩니다. VMWare를 OpenStack 테스트 용으로 사용하고 있는 저는 현재 테스트 환경에서 hostonly vmnet을 4개 사용하고 있으며 실제 환경을 그대로 묘사하기 위해서 조만간 6~7개로 늘려서 테스트할 예정입니다.

그런데 처음에 잘 모르고 지나갔다가 낭패를 본게 hostonly로 네트웍을 구성하면 host-pc에서 vmnet간에 routing을 지원하지 않습니다. 정리하면 아래와 같습니다.

  • host-pc <-> vmnet: OK
  • vmnet <-> Internet: N/A
  • vnmet <->  vmnet : N/A

당연히 되는지 알았는데, vmnet간에 NATing이 되고 있었던 것과 이로 인한 routering filter의 간섭이었죠. 이 상황을 알아채려면 상대방의 ip까지 확인 해야하는데, 그럴 일이 거의 없다가 문제가 발생해 추척하다 발견한 것이죠.. ㅎㅎ

어쨌든 vmnet간에 routing하는 방법은 VMWare 사이트에 잘 설명이 되어있습니다. 근데 여기서 방법 중에 host-pc에서 routing을 잡는 방법은 ubuntu에서 테스트하니 안됩니다. 그래서 routing을 담당하는 VM을 만들어 합니다.

간단히 정리하면

  1. hostonly network을 가지는 2개의 vm(10.20.1.10, 10.20.2.10)을 만든다. ==> 이하 internal vm
  2. 두 hostonly network을 가지는 router vm을 만든다. ==> 이하 router vm eth0: NAT network for external internet access eth1: 10.20.1.2 eth2: 10.20.2.2
  3. 여기서 .2를 가지는 것은 .1은 host-pc에 연결하고 host-pc에서 management용으로 사용할 것이므로 .2를 사용한다.
  4. router vm에서 routing이 되도록 설정한다. 간단히 $ systctl net.ipv4.ip_foward=1
  5. router vm에 internal vm이 외부 인터넷 접근을 위해 NATing을 설정한다. 외부 인터넷 접근 필요 하다면… $ iptables -t nat -A POSTROUTING -j MASQUERADE -o eth0
  6. internal vm의 default gateway를 .2번으로 설정한다.
  7. internal vm에서 tracepath 를 통해서 각각의 vm을 router vm을 통해서 접근하는지 확인한다.
  8. internal vm에서 tracepath google.com으로 외부 인터넷 연결 확인
  9. 끝..

참고..

  • iptables rule 저장은 여기를 참고

Twisted를 이용한 심플한 Dns Proxy: Dnspost

Mac OSX의 resolver라는 기능이 있습니다. 간단히 말해서 특정 도메인에 해당하는 DNS 쿼리를 특정 DNS 서버에 요청하는 것이지요.. 뭐 일상생활에서는 필요없겠는데, 개발용으로 내부 네임서버를 돌리고 있는 경우에 가끔 유용하게 쓸 수 있습니다.

아래처럼 도메일별로 다른 서버에 DNS 쿼리가 가능하다는 것이죠.

  • *.dev.company.com -> 192.168.1.199
  • *.myteam.company.com -> 192.168.1.200
  • 나머지 -> 168.126.63.1

OSX에서는 resover를 사용해서 하고.. 또한 우리 회사 개발자도 OSX를 좋아해서 이 기능을 쓰라고 그러고, 다른 OS는 별로 관심이 없습니다.(OSX가 기본 개발 OS인양…). Ubuntu를 데스크탑으로 사용하는 제가 이상하게 소외받는 ㅎㅎ

그래서 목마른 사람이 우물을 판다고 python twisted name 라이브러리를 이용해서 간단히 뚝딱뚝딱 만들어 봤습니다. 로컬에서 네임서버 돌리고 이 것을 사용하면 됩니다.

https://github.com/whitekid/dnspost

Installation

$ apt-get install python-twisted-names
$ git clone https://github.com/whitekid/dnspost.git
$ cd dnspost
# edit dnspost.conf listen_port
$ ./dnspost.py

Ubuntu/NetworkManager note

ubuntu desktop에서는 NetworkManager를 사용하고, NetworkManager에서는 dnsmasq를 사용하여 dns를 캐슁하면서 로컬에서 서비스 하고 있습니다. NetworkManager에서 dnsmasq가 상위 dns 쿼리할때 특정 포트로 쿼리할 수 있는 기능이 있다면 로컬에서 별도의 포트로 돌리고있는 dnspost로 설정하여 할 수 있지만, 그런 기능이 없기에 dnsmasq를 사용하지 않고 합니다.

disable dnsmasq

/etc/NetworkManager/NetworkManager.conf에서 dns=dnsmasq라는 라인을 삭제합니다

#dns=dnsmasq

NetworkManager restart

$ service network-manager restart

px ax | grep dnsmasq로 dnsmasq가 없는지 확인합니다.

set nameserver to localhost

네트워크 연결 설정에서 DNS 서버를 127.0.0.1로 변경합니다. 설정을 변경한 후 /etc/resolv.conf에는 설정이 없거나 127.0.0.1로 설정이 됩니다.

만일 반영이 안되면 network-manager를 다시 시작합니다.

$ service network-manager restart

register dnspost upstart service

$ cp dnspost.conf /etc/init/dnspost.conf
$ ln -s /lib/upstart-job /etc/init.d/dnspost
$ service dnspost start

test

$ dig daum.net localhost

잘 동작하는 것을 확인하였다면 이제 설정파일 적당히 바꿔서 도메인별로 DNS Server를 다르게 사용해보시기 바랍니다. - 끝 -

Shell Script: “Set -e”가 뭐하는 것일까?

쉘 스크립트를 보면 시작부분에 아래와 같은 문장이 있는 것을 자주 확인할 수 있다.

set -e

그냥 무심결에 넘겨왔었는데, 오늘 찾아봤다. http://julipedia.meroh.net/2010/01/set-e-and-set-x.html

내용은 간단하다. set -e로 설정되어 있으면 쉘 스크립트가 실행될 때 모든 라인의 실행 결과를 검사해서 실패할 경우는 바로 스크립트 실행을 종료한다.

예를들어 아래의 스크립트를 보면

#!/bin/sh
set -e
echo 'hello'
false # 여기서 스크립트 실행이 끝남..
echo 'world'

그냥 hello만 출력하고 실행을 끝낸다.

그리고 set -x는 trace로 shell이 실행하는 모든 명령을 화면에 출력한다. 디버그용으로 좋겠다.

Quantum의 Limitation…

-fomsom 버전의 quantum에는 몇 가지 제한 사항이 있습니다. 그중에 몇가지 중요하다고 생각 되는 내용만 추려봅니다.

overlapping ip문제

quantum에 들어가면서 새로 생긴 기능입니다. 이 기능이 뭐냐.. 간략하게 CloudStack에서 router vm을 사용하면서 그들만의 private network을 가집니다. 결국은 다른 사용자와 나는 같은 subnet을 가지는 것입니다.

KT uCloud biz에서 가상머신을 만들면 가상 머신은 사설 아이피를 가지게 되고 외부에는 NATing을 통해서 대표 아이피를 가지게 됩니다. quantum을 사용하면 이러한 가상 네트웍을 구성할 수 있는 것이죠.

그런데, 이것을 구현하면서 약간은 문제가 생겼습니다.

nova의 기존 네트워킹 모델은 가상 머신의 ip address가 unique하다는 가정 하에서 만들어 졌습니다. 그런데 이제 그런 가정 자체가 망가졌네요. ㅎㅎ 그래서 overlapping ip 기능을 사용하면 다음의 기능을 사용할 수 없습니다.

  • nova security group
  • metadata service

security group: security group은 computing node에서 iptable로 동작합니다. 그런데 여기서 ip로 ip table을 걸어놓으면? 그렇습니다. 다른 tenant가 같은 ip를 가질 수 있으므로 다른 사용자에게 영향을 미처 버립니다.

metadata service: metadata는 가상 머신 템플릿에 미리 설치된 cloud-init 패키지를 통해서 ec2 api spec을 사용하고 있습니다. ec2.. 네트워킹 모델은 모든 가상 머신의 ip가 unique합니다. 그래서 cloud-init에서 http로 보낼때 특별한 정보를 보내지 않고, 받는 측에서 request_ip 또는 X-Forward-For http header를 통하여 어떤 가상머신에서 요청이 왔는지 확인하고 응답을 합니다. 느낌이 오죠? IP는 알아냈지만 그게 어떤 tenant의 가상 머신인지 알 수 없습니다. 그리고 설사 안다고 하여도 다시 그 가상 머신으로 response를 보낼 routing 경로를 결정할 수 없습니다.

해결 방법에 대한 고민?

security group: 해결할 수 있는 방법은 quantum-network이 사용하고 있는 namespace 기능을 compute 노드까지 사용하고, 그 namespace에 security group에 해당하는 iptables rule을 적용하면 됩니다. quantum-plugin-ovs-agent가 해야겠습니다.

metadata service: 이건 해결 방법이 조금 복잡할 것 같습니다. tenant의 network 밖으로 metadata request packet이 NATing할때 DNAT으로 처리합니다. destination만 metadata_ip로 변경하는 것이죠. 여기서부터 문제인데 DNAT으로 밖으로 보내지 않고 router namespace 안에서 metadata proxy를 거치고 proxy는 request_ip + tenant_id를 조합하여 metadata api server로 날립니다. 그리고 metadat server는 지금처럼 request ip를 기준으로 하지말고 새로 받은 request_ip + tenant_id로 해서 다시 받아서 던지면 되겠습니다.

multi-host 기능 없음

quantum을 쓴다면 제 생각엔 굳이 필요 없을 기능입니다. 근데 혹시나 network host에 부하가 걱정이 되신다면 Quantum HA를 한 번 봐보세요. 아직은 저도 보지 못해서 뭐라하지는 못하지만, 문서상에는 Active-Active HA도 된다고 합니다.

linux namespace 기능이 필요함

quantum-l3-agent, quantum-dhcp-agent가 tenant 간의 네트웍 영역을 분리하기 때문에 필요합니다. 안쓰고 사용할 수 있지만, 그럴 이유가…

Ubuntu는 지원을 하지만, CentOS는 지원하지 않습니다. CentOS도 커널은 지원(커널 2.6.4 부터 들어감)하지만, 이 기능을 사용하는 iproute 패키지가 해당 기능을 지원하지 않는 플래그를 사용하고 빌드되었습니다. 그래서 사용할 수 없죠. epel repository로 사용해보려 시도했지만 다른 패키지랑 의존성이 너무 많이 걸려서 포기했습니다.

현재로써는 Ubuntu가 OpenStack의 유일한 답입니다.

Horizon에 통합되지 않음

quantum이 적용되었다고, 설치 후에 horizon을 보고 뭔가 하려고 하지만, 안될겁니다. 이전 포스트에도 보이지만 quantum으로 만드는 과정도 복잡할 뿐더러 만들 수 있는 네트워크 모델도 다양합니다.

보시면 가장 간단한 amazon 모델부터 아주 목잡한 overlapping_ip를 사용한 모델까지… 이를 horizon에서 지원하려면.. 한참 걸릴거라 생각합니다.

기타

  • IPv6 지원하지 않음
  • L3 Agent의 scale limit
  • ZeroMQ is experimental
  • MetaPlugin is experimental

참고: http://docs.openstack.org/trunk/openstack-network/admin/content/ch_limitations.html

ps. folsom에 야심차게 quantum이 나왔지만, 지금까지 쭈욱 둘러본 결과론 아직 quantum은 beta 상태인 것 같습니다. 그리고 openvswitch을 사용해 quantum network의 기능을 모두 볼 수는 있겠지만, 이걸 사용 수준으로 사용할 수 없을 것 같고, Nicira NVP, MidoNet 같은 OVS 기반의 SDN 플렛폼을 사용하거나, Cisco NVGRE를 사용해야할 듯 합니다. 물론 내부 개발 인프라 정도로는 큰 무리 없을 것으로 생각합니다.

Socks5 Proxy With Ssh

오늘 ssh가 sock5 proxy로도 사용될 수 있다는 사실을 알았다. 예전엔 ss5를 쓴 기억이 있어서 우분투에도 찾아봤는데, 이거 왠걸 여기는 패키지가 없다. 그래서 ubuntu에도 사용할 괜찮을 sock5 프록시 서버가 뭐가 있을가 하고 찾아봤는데 떡하니 ssh를 사용하는 방법이.. 게다가 당연히 별도의 설정도 거의 필요 없었다.

프록시 서버는 sshd만 돌고 있으면 된다. 내 데스크탑이 ubuntu이니 당연히 사용중이니 설정 건드릴 것 없고, 사용하려는 컴퓨터에서 프록시 서버로 사용할 컴퓨터로 ssh 접속을 아래와 같이 한다.

$ ssh -D 9999 <user@192.168.xxx.xxx>

이제 프록시 연결은 끝났다. 프록시를 사용할 컴퓨터에서 아래처럼 설정하고 사용하면 된다.

  • 프록시 타입: SOCKS v5
  • 호스트: 127.0.0.1
  • 포트: 9999

아주 간단~

참 혹시나 sshd 설정에서 AllowTcpForwarding true로 설정이 되어있는지 확인하시기 바랍니다. 기본값은 true이지만 배포판에 따라서 설정이 되어있을 수 있어요.

ps. 왜 이게 필요하냐고? 회사에서는 데스크탑 용 IP와 노트북용 IP를 별도의 영역으로 구분해 할당해 줬습니다. 노트북용 아이피는 또한 외부 방문자도 사용하는 것을 염두해두고 있어서 내부 개발 서버에 접근하는 것을 막아놨죠.

녜.. 데스크탑은 개발 서버에 접속이 되지만, 노트북은 안됩니다. 그래서 데스크탑을 프록시 서버로 사용해 접속하는 꽁수를… ㅎㅎ

참고

Iptables로 NAT을 구성하다 낭패를…

내 PC안에서 VMWare로 가상 환경을 구축하여 테스트하고 있기 때문에 가상머신이 인터넷을 접속하기 위해서 아래처럼 NAT을 구성했다.

$ iptables -A POSTROUTING -t nat -j MASQUERADE

아주 무리없이 잘 돌아가는 것 처럼 보였다.

가낭 VMWare에서 내부적으로 구성하는 vmnet# 간에 네트웍을 하는 것도 잘 되고 있었다. 그런데 뭔가 좀 설명할 수 없는 이상한 현상이 계속 발생 했다.

vmnet 간에 traffic이 soruce ip가 해당 네트웍의 gateway로 잡혀서 들어오는 것이다. 이것 때문에 다른 네트워간의 연결이 잘 안되는 것이었다. 한동안 문제를 찾아 해매다가 결국 찾은 것은 위에서 NAT하는 것이 문제가 있다는 것이다.

위에서 NATing을 설정할 때 input/ ouput interface를 지정하지 않았기 때문에 이녀석은 모든 interface간에 통신을 모두다 NATing 해버리는 것이다… 결국 source ip가 gateway ip(즉 호스트에 있는 해당 네트워크의 ip)로 말이지…

$ iptables -A POSTROUTING -t nat -j MASQUERADE -o eth0

그래서 다시 eth0로 나가는 놈만 하는 것으로 했다. 그랬더니 이제 이해할 수 있는 오류들이 나오기 시작한다.. ㅎㅎ

그래 대충한 것은 나중에 이해할 수 없는 현상을 유발한다니깐..

Dhclient가 Ip 받아올 때 까지 기다리기…

dhcp로 아이피 받아올 때 까지 기다려서 ip 리턴하는 스크립트…

#!/bin/bash
function get_dhcp_ip() {
  IFACE=${1:-eth1}

  until ifconfig ${IFACE} | grep 'inet addr' > /dev/null; do
      dhclient ${IFACE} > /dev/null;
      sleep 1;
  done;

  ifconfig ${IFACE} | grep 'inet addr' | cut -d : -f 2 | awk '{print $1}'
}

echo $(get_dhcp_ip eth1)

왜 이런 삽질이 필요한지.. ㅡㅡ;

주어진 명령이 성공할 때까지 계속 시도하기…

#!/bin/bash
function wait_for() {
    until $1; do
        echo $2
        sleep $3
    done
}

어디에 필요하냐구요?

$ wait_for "ssh $ip echo" "waiting $ip to boot up..." 3

이렇게 하면 서버가 부팅하고 ssh로 명령을 내릴 수 있을 때까지 대기합니다.

그렇죠 삽질이죠.. ㅎㅎ

이러다 영원히 끝나지 않을 것이 두려우신 분은 timeout 명령을 같이 쓰세요…

$ timeout 10 wait_for “ssh $ip echo” “waiting $ip to boot up…” 3

Vmware 사용중에 Vmnet 간에 Routing이 안되는 문제가 발생할 때…

OpenStack folsom + Quantum 구성을 vmware을 이용하여 테스트 하고 있습니다.

  • vmnet0: external network
  • vmnet1: control node network
  • vmnet2: compute node network
  • vmnet3: internal data network
  • vmnet4: network node network
  • vmnet5: storage network(not done)

이렇게 대략 6개 정도 사용하는데, 가상 머신이 만들어 내부 네트워킹을 시도하면 routing이 안되는 문제가 발생합니다. 물론 외부랑 정상적이고, 또한 host 컴퓨터에서도 해당 머신들에 정상적으로 ping 가는데도 말입니다..

결국은 리눅스 네트워크 전문가를 대동하여 약1시간에 걸쳐서 확인한 결과 iptables 쪽에서 막은 건 아니고 vmnet간의 routing이 안된다는 결론을 얻었고, rp_filter 기능을  사용하지 않으면 되는군요.

$ sysctl -a | grep vmnet | grep \\.rp_filter | awk '{print $1}' | \
sudo xargs -L1 -I% sysctl %=0
  • \ 두개입니다. 하나만 하면 arp_filter도 먹어버림…