Your wish is my command

It’s a long journey

Quantum: Metadata Overlapping Patch 적용기

quantum의 문제중에 하나인 overlapping_ip을 사용할 때 metadata service가 작동하지 않는 문제에 대해서 이전에 언급했었고, 이에 대한 패치가 저번주에 올라왔습니다.

오늘 이를 테스트 해봤는데 대략 잘 동작합니다.

간단한 구조는 다음과 같습니다.

  1. metadata request는 http://169.254.169.254/latest/metadata 형태로 router namespace로 들어온다.
  2. router namespace의 NAT rule에 의해서 localhost의 port 9697로 redirect 된다.
  3. 9696에서 listen하는 process(quantum-ns-metadata-proxy)는 l3_agent에서 network 생성에 맞춰 관리되며, namespace당 하나씩 생성된다.
  4. quantum-ns-metadata-proxy는 파라미터로 router_id를 가지므로 자신이 담당하는 network을 알 수 있다.
  5. quantum-ns-metadata-proxy는 nova-metadata-agent가 필요한 정보를 모아서(instance-id, router-id, network-id) http header에 포함하여 quantum-metadata-agent로 proxy request를 보낸다.
  6. quantum-metadata-agent는 ns-metadata-proxy에서 넘어온 전보를 바탕으로 instance-id를 확인하고 이를 http header에 포함하여 nova-metadata-api에 보낸다.
  7. nova-metadata-api는 X-Instace-ID가 있으면 이 아이디를 기준으로 메타데이터를 넘긴다.

대략 순서를 정리하면 이렇습니다. 마지막으로 quantum-metadata-agent를 upstart service로 등록하여 작업하는 것 까지하면 대략 쓸만할 것 같습니다.

지금은 우선 테스트라 quantum-metadata-agent가 같은 서버로 들어갔지만, metadata_ip를 줄 수 있으므로 별도의 서버에 운영할 수 있겠습니다.

삽질기

위 패치는 nova/ quantum 2개로 구성이 되어있으며, 당연히도 master 소스를 기준으로 작성이 되어있습니다. 그런데 저는 테스트 환경을 ubuntu folsom cloud archive를 사용하기 때문에 folsom 용으로 만들어야 했지요.. git에서 작업하기 위해 몇 가지 삽질을..

  1. master에 patch 적용하고 patch
  2. stable/folsom 기준으로 branch를 하나 만들고…
  3. master의 commit를 cherry picking…
  4. 다시 folsom에 맞게 소스 수정하고 commit…
  5. folsom과 변경된 부분으로 patch 생성…

물론 nova/ quantum도 같이요…

  • upstart-job service 등록

Side effect?

이전에 metadata 접속 방식은 l3 router namespace에서 metadata api로 요청하는 것이었습니다. 이 경우 l3 router namespace 부터는 public ip address이므로 결국 metadata api server의 주소도 public ip address를 가지게 됩니다.

그런데 이 metadata api server는 굳이 외부에서 접속할 필요가 없으므로 public ip를 가질 필요가 없습니다. 따라서 뭔가 꺼림직 했었는데, 이번 패치를 적용하면, quantum-metadata-agent를 내부망에서 운영할 수 있으므로 metadata api server가 내부망에서 운영이 가능합니다.

OpenStack: 가상머신의 네트워크가 안될 때 Quantum의 체크 사항들

openstack에서 가상머신을 생성하기는 했는데, nova에서는 생성이 되었다고 리포트되지만 Quantum 네트워크 문제로 가상머신이 연결되지 않은 경우가 있다. 이러한 경우 몇가지 체크할 포인트를 정리해본다. 물론 여기는 모두 folsom에서 OpenVSwitch + GRE Tunneling을 사용할 경우를 가정한다.

증상들

quantum의 설정 문제라면 보통 아래의 증상이 나타난다.

  • nova list를 보면 가상머신에 ip는 할당이 되어 있지만, ping이 가지 않는다.
  • ping은 가는데 ssh 접속이 안된다.
  • vnc로 접속하면 접속은 된다.

nova list에서 가상머신의 ip address가 할당이 되지 않고 생성되는 문제가 있는데, 이는 대부분 quantum의 문제가 아니고 다른 문제였다. 이 경우는 nova-compute의 로그를 확인하면 된다.

physical network 확인

integration bridge가 설정 되어 있는지 확인

모든 l3-agent, dhcp-agent, ovs-plugin-agent가 동작하는 곳에 br-int bridge가 있는지 확인한다. quantum ovs plugin이 동작하기 위해서는 반드시 br-int bridge가 필요하다. agent가 자동으로 만들어 줄 만 한데 안만들어 주고 있다.(반면에 gre tunnel이 사용하는 br-tun은 알아서 만든다.)

이 경우는 quantum 로그 파일에 br-int bridge가 없다는 에러를 내기 때문에 찾아내기 아주 쉽다.

external bridge 확인

l3-agent가 동작하고 있는 곳에 br-ex bridge가 있는지 확인한다. 그리고 br-ex bridge에는 외부와 연결된 interface가 추가되어 있는지 확인한다.

테스트 환경에서의 bridge를 확인하면 아래와 같다. (qg-*는 tenant network의 gateway port다.)

Bridge br-ex
  Port "qg-5376a58a-a7"
    Interface "qg-5376a58a-a7"
      type: internal
  Port "qg-8be78718-4b"
    Interface "qg-8be78718-4b"
      type: internal
  Port "eth2"
    Interface "eth2"
  Port br-ex
    Interface br-ex
      type: internal

그리고 여기에 연결된 eth2(external nic)에는 ip address가 설정하지 않는다.(물리적 연결을 확인하기 위해서 ip를 추가하고 테스트하기는 한다.)

datapath-dkms

openvswitch는 dynamic kernel module support를 사용한다. openvswitch-switch user space daemon과 커널 모듈이 동시에 사용되는 것이다. 의존성에 의해서 자동으로 설치되기는 하지만, 어떠한 경우에는 커널 모듈을 설치하지 않는 경우도 있기 때문에 한 번 쯤은 확인하는 것이 좋다.

root@net-l3:~# dpkg -l | grep datapath-dkms
ii openvswitch-datapath-dkms 1.4.0-1ubuntu1.3 Open vSwitch datapath module source - DKMS version
root@net-l3:~# dkms status
openvswitch, 1.4.0, 3.2.0-33-generic, x86_64: installed

quantum-plugin-openvswitch-agent 동작 확인

nova-compute, quantum-l3-agent, quantum-dhcp-agent가 동작하는 노드에서는 quantum-plugin-openvswitch-agent가 동작하면서 지속적으로 quantum 서비스를 polling하면서 openvswitch의 설정들을 잡는다. database/ rabbitmq connection이나 keystone 설정들의 문제는 로그파일을 보면 바로 나오니 문제를 파악하기 쉽다. 하지만 gre tunneling을 맺는 것을 명시적으로 오류가 나지 않으므로 이 부분을 확인해야한다.

아래는 테스트 환경에서 gre tunneling 확인한 모습이다. remote_ip=“10.130.1.101” 처럼 보이는 부분이 있어야하며, 기타 여러 다른 문제로 인해서 여기에 상대방의 ip가 정상적으로 나오지 않는 경우를 많이 경험했다.

root@net-dhcp:~# ovs-vsctl show
40a579fe-a5ae-4f63-b6ca-6967280a9893
    Bridge br-tun
        Port "gre-1"
            Interface "gre-1"
                type: gre
                options: {in_key=flow, out_key=flow, remote_ip="10.130.1.101"}
        Port patch-int
            Interface patch-int
                type: patch
                options: {peer=patch-tun}
        Port br-tun
            Interface br-tun
                type: internal
        Port "gre-4"
            Interface "gre-4"
                type: gre
                options: {in_key=flow, out_key=flow, remote_ip="10.130.1.11"}
        Port "gre-3"
            Interface "gre-3"
                type: gre
                options: {in_key=flow, out_key=flow, remote_ip="10.130.1.10"}
    Bridge br-int
        Port patch-tun
            Interface patch-tun
                type: patch
                options: {peer=patch-int}
        Port br-int
            Interface br-int
                type: internal
        Port "tap9dd6bf73-9a"
            tag: 2
            Interface "tap9dd6bf73-9a"
                type: internal
        Port "tap063f59a8-7b"
            tag: 1
            Interface "tap063f59a8-7b"
                type: internal
    ovs_version: "1.4.0+build0"

이런 문제가 있는 경우는 remote_ip가 나오지 않는 호스트의 ovs_quantum_plugin.ini의 local_ip 설정이 있는지 확인하고, 정확하게 gre tunneling으로 사용할 ip가 명시되어 있다면 단순히 quantum-plugin-openvswitch-agent 서비스를 재시작하면 대부분 해결 된다.

dhcp namespace에서 ping이 되는지

dhcp agent가 동작하는 곳에는 dhcp namespace가 생기고 여기에는 해당 네트워크에 동작하는 dhcp 서버가 동작하게 된다. 일만적으로 172.16.1.2처럼 2번의 ip를 가지게 되고 가상머신은 3번 아이피부터 시작한다. 여기는 외부 네트워크 연결과는 상관없이 내부 네트워크만 동작하면 되므로 우선 여기부터 확인한다.

root@net-dhcp:~# ip netns
qdhcp-9cbd5dd0-928a-4808-ae34-4cc2563fa619
qdhcp-55db86bf-7eee-4fac-a928-844218e88a11
root@net-dhcp:~# ip netns exec qdhcp-9cbd5dd0-928a-4808-ae34-4cc2563fa619 ip addr
8: tap9dd6bf73-9a: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN
    link/ether fa:16:3e:eb:c1:b3 brd ff:ff:ff:ff:ff:ff
    inet 172.16.2.2/24 brd 172.16.2.255 scope global tap9dd6bf73-9a
    inet6 fe80::f816:3eff:feeb:c1b3/64 scope link
       valid_lft forever preferred_lft forever
9: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
root@net-dhcp:~# ip netns exec qdhcp-9cbd5dd0-928a-4808-ae34-4cc2563fa619 ping -c 3 172.16.2.5
PING 172.16.2.5 (172.16.2.5) 56(84) bytes of data.
64 bytes from 172.16.2.5: icmp_req=1 ttl=64 time=8.82 ms
64 bytes from 172.16.2.5: icmp_req=2 ttl=64 time=3.98 ms
64 bytes from 172.16.2.5: icmp_req=3 ttl=64 time=2.17 ms

--- 172.16.2.5 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 2.179/4.996/8.823/2.804 ms

가상 머신의 ip로 ping이 간다면 우선 내부 네트워크는 정상적으로 작동한다는 말이다. 더불어 gre tunnel도 정상적으로 잘 된다는 이야기이다.

l3 namespace에서 네트워크 확인

l3 namespace는 해당 네트워크의 gateway가 위치(172.16.1.1)하는 곳이다. 당연히 여기서 네트워크가 문제없이 잘 되어야 외부로 나가는 길이 열리는 것이다.

l3 namespace에서 다음 사항을 확인해본다.

  • instance로의 ping
  • default gateway

..

root@net-l3:~# ip netns
qrouter-2c901c4d-eeb3-43b0-a84a-30da10fa74d7
qrouter-5fce397a-4e9d-4a42-8139-f7748a0f69b6
root@net-l3:~# ip netns exec qrouter-5fce397a-4e9d-4a42-8139-f7748a0f69b6 ip addr
8: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
9: qr-7b757ca9-3f: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN
    link/ether fa:16:3e:23:36:5b brd ff:ff:ff:ff:ff:ff
    inet 172.16.1.1/24 brd 172.16.1.255 scope global qr-7b757ca9-3f
    inet6 fe80::f816:3eff:fe23:365b/64 scope link
       valid_lft forever preferred_lft forever
10: qg-8be78718-4b: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN
    link/ether fa:16:3e:b7:bc:06 brd ff:ff:ff:ff:ff:ff
    inet 10.100.1.130/25 brd 10.100.1.255 scope global qg-8be78718-4b
    inet 10.100.1.131/32 brd 10.100.1.131 scope global qg-8be78718-4b
    inet6 fe80::f816:3eff:feb7:bc06/64 scope link
       valid_lft forever preferred_lft forever
root@net-l3:~# ip netns exec qrouter-5fce397a-4e9d-4a42-8139-f7748a0f69b6 ping -c 3 172.16.1.3
PING 172.16.1.3 (172.16.1.3) 56(84) bytes of data.
64 bytes from 172.16.1.3: icmp_req=1 ttl=64 time=10.4 ms
64 bytes from 172.16.1.3: icmp_req=2 ttl=64 time=0.563 ms
64 bytes from 172.16.1.3: icmp_req=3 ttl=64 time=0.541 ms

--- 172.16.1.3 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.541/3.851/10.450/4.666 ms
root@net-l3:~# ip netns exec qrouter-5fce397a-4e9d-4a42-8139-f7748a0f69b6 route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         10.100.1.129    0.0.0.0         UG    0      0        0 qg-8be78718-4b
10.100.1.128    *               255.255.255.128 U     0      0        0 qg-8be78718-4b
172.16.1.0      *               255.255.255.0   U     0      0        0 qr-7b757ca9-3f
root@net-l3:~# ip netns exec qrouter-5fce397a-4e9d-4a42-8139-f7748a0f69b6 ping -c 3 10.100.1.129
PING 10.100.1.129 (10.100.1.129) 56(84) bytes of data.
64 bytes from 10.100.1.129: icmp_req=1 ttl=64 time=22.1 ms
64 bytes from 10.100.1.129: icmp_req=2 ttl=64 time=0.423 ms
64 bytes from 10.100.1.129: icmp_req=3 ttl=64 time=0.339 ms

--- 10.100.1.129 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.339/7.622/22.105/10.241 ms

여기서 namespace의 gateway는 quantum을 이용해서 네트워크를 생성할때 만들어준 네트워크에서 알아서 잡는 것이다. 따라서 해당 주소는 미리 있어야한다. 위에서는 external network의 subnet을 10.100.1.128/25로 주었기 때문에 해당 네트워크의 첫번째 아이피인 10.100.1.129로 gateway가 자동으로 잡혔다.

또한 10.100.1.130은 해당 네트워크의 nat로 외부 접속할 대표 아이피이고 10.100.1.131은 floatingip로 설정된 것이다.

metadata

어쨌든 가상 머신으로 ping까지 잘 가지만 ssh로 로그인할 수 없는 경우가 있다. 이런 경우는 대부분 가상머신이 metadata를 가져오지 못해서 생기는 문제로 가상머신의 로그나 vnc로 접근해서 확인하면 확인할 수 있다.

ubuntu 가상 머신의 경우는 아래와 같은 메시지가 남는다.

root@c-01-01:~# tail /var/lib/nova/instances/instance-00000003/console.log
cloud-init start-local running: Thu, 22 Nov 2012 15:07:50 +0000. up 3.37 seconds
no instance data found in start-local
ci-info: lo    : 1 127.0.0.1       255.0.0.0       .
ci-info: eth0  : 1 172.16.2.4      255.255.255.0   fa:16:3e:78:fa:03^M
ci-info: route-0: 0.0.0.0         172.16.2.1      0.0.0.0         eth0   UG
ci-info: route-1: 172.16.2.0      0.0.0.0         255.255.255.0   eth0   U
cloud-init start running: Thu, 22 Nov 2012 15:07:54 +0000. up 7.01 seconds
2012-11-22 15:08:48,306 - util.py[WARNING]: 'http://169.254.169.254/2009-04-04/meta-data/instance-id' failed [51/120s]: url error [timed out]
2012-11-22 15:09:39,360 - util.py[WARNING]: 'http://169.254.169.254/2009-04-04/meta-data/instance-id' failed [102/120s]: url error [timed out]
2012-11-22 15:09:56,379 - util.py[WARNING]: 'http://169.254.169.254/2009-04-04/meta-data/instance-id' failed [119/120s]: url error [timed out]

로그를 보면 dhcp를 통해서 ip를 받아왔지만 cloud-init에서 metadata server롤 접속하지 못해서 ssh key를 받아오지 못해 ssh 인증키를 가상머신에 설치하지 못해서 이다. 이 문제에 관해서는 이전에 적었으니 참고하시면 되고, 간단하게 말한다면 l3 agent namespace에서도 metadata server에 접속할 수 있어야되고, 반대로 metadata server에서도 가상 머신에 접속할 수 있어야 합니다. management / data / external / tenant network을 모두 같은 네트워크에서 구성했다면 문제가 안생기겠지만, 별도의 분리된 네트워크나 private network을 사용했다면 직접 연결되는 경로가 없기 때문에 만들어 줘야 합니다.

간단하게 한다면 metadata api server에서 아래처럼 하면 됩니다.

root@api $ route add -net <tenant subnet> gw <tenant default public ip>;
root@api $ route add -net 172.16.1.0/24 gw 10.100.1.130

참고로 metadata_ip는 external network에서 접근 가능한 ip여야 합니다. metadata server를 접근하는 곳이 l3 namespace인데 여기는 이미 external network 영역이기 때문입니다. 여기서 management나 기타 다른 영역으로 들어가는 것은 구성상 바람직 하지 않습니다.

기타 다른 이유들…

  • keystone
    • 설정 오류
    • quantum user의 권한 문제: quantum user는 admin role이 있어야 한다.
  • glance 이미지 설정 오류
    • glance의 설정이 잘못되어 있으면 가상 머신의 상태가 build에서 멈춰있습니다. nova-compute 쪽 로그를 보면 이미지를 찾을 수 없다고 나옵니다.
    • glace 이미지 오류: glance에서 이미지를 추가할 때 뭔가 잘못하여 active가 아닌 queued 상태인 이미지가 만들어 질 수 있는데, 이 이미지로 가상머신을 만들면 역시 build 상태에서 멈춰 있습니다.
  • quantum-service startup error
  • 가끔 nova-network을 설치해놓고선 quantum service가 왜 안뜨냐고 투덜인 분이 있습니다. 녜…. quantum은 nova-network을 완전해 대체할 목적으로 만들어 졌기에 같이 공존할 수 없습니다. nova-volume과 cinder와의 관계와 같습니다.  /etc/nova/nova.conf에 enabled_apis=ec2,osapi_compute,metadata 처럼 몇몇 서비스를 내리세욧

…..

quantum은 openstack의 마지막에 있습니다. 무슨 말이냐 keystone, glance, nova-* 등 여러 openstack 요소들이 동작을 제대로 한 이후에 quantum의 동작을 확인할 수 있습니다. 네트워크가 안된다는 것은 단순 네트워크 문제로 보이지만 다른 여러 요인들이 겹쳐서 생기는 문제가 더 많습니다. 경험상 정작 quantum 자체의 문제보다는 다른쪽의 문제가 더 많았습니다.

감이 오시나요? quantum을 하려면 다른 것도 어느 정도 대충 알아야한다는 이야기입니다. 그러지 않고서는 quantum은 문제 없어!! 라고 끝내버리는 경우가 생길 수 있는데, 이건 팀워크에서는 하면 안되는 것이죠.. 음.. 이상한..

어쨌든 끝~

Bash: Simple Job Control

bash에서 child process를 돌릴 필요가 생겨서 잠깐 테스트 삼아 작성해본 background로 프로세스 돌리고, 죽이기 스크립트

#!/bin/bash
set -m

function sig_int(){
        echo "sig_int"

        kill `jobs -p`
}

function child_process() {
        echo "enter child pid:$$, $1"
        sleep 5
        echo "exit someting $1"
}

# run several jobs
for x in {1..3}; do
        #(something $x &) # parallel executation
        child_process $x & # background executation
done

trap sig_int SIGINT

wait
  • $$는 shell의 pid로 child process에서 같은 값이 나온다.
  • parallel executation은 child process가 아닌 현재 스크립트와 동일한 레벨로 생성된다.

Metadata_overlapping_networks에 대한 패치가 올라와 벼렸군

일전에 지금의 Quantum 구현에 overlapping networks에서 metadata를 가져오는 문제가 있고, 이에 대한 해결책에 대해서 이야기한 적이 있었죠. 시간내서 이 것을 제대로 정리해서 패치를 보낼 생각이었는데… 허걱 오늘 Dream Host에서 이 문제에 대한 패치를 보냈군요.

기본 구현을 보면 기본적인 아이디어는 제 아이디어와 비슷합니다. 역시나 namespace에서 agent를 router_id, network_id를 가지고 있는 agent를 띄우고, 다시 agent가 proxy 역할을 해서 실제 metadata로 proxy 형태로 request를 보내는 겁니다.

소스를 보니 깔끔하군요. 지금 적용해도 큰 무리는 없겠습니다. 다음주에 시도해봐야 겠습니다.

역시.. 빨리 했어야 하는건데. ㅡㅡ;

Fork(?) in Bash

shell script에서 fork와 비슷한 같은 작업을 하는 것은 간단하다. 함수를 호출뒤에 &를 넣어주면 되니깐… 이게 정확하게 fork와 같은 역할을 하는 지는 잘 모르겠지만, 비슷한 역할을 한다.

#!/bin/bash
function foo() {
    echo "function foo $1"
    sleep 5
    echo "exiting foo $1"
}

for x in {1..5}; do
    foo $x &
done

echo 'waiting...'
wait

foo 함수를 5개 호출하면서 child process로 호출하고, parent에서는 child process가 종료할 때 까지 기다린다. 다음은 실행 결과

$ bash fork.sh
function foo 1
function foo 2
waiting...
function foo 3
function foo 5
function foo 4
exiting foo 1
exiting foo 4
exiting foo 3
exiting foo 5
exiting foo 2

이걸 어디에 사용하냐구요? 그래요 snapshot를 뜨는데, 하나하나 하기가 너무 느려서 백그라운드로 돌릴려구요.. 잘 될려나..

Ubuntu Repository Mirror

간단하게 apt-mirror를 이용해서 apt repository mirror를 구축하는 것에 대해 정리해본다. OpenStack을 설치하는데, 원격으로 패키지를 가져오는 것이 영 맘에 안들어 간단히 구축해본 것이다.

물론 현재는 squid를 이용한 proxy를 apt-get에서 이용하도록 하고 있지만, 그래도 외부로 나가는 traffic이 있으니.. 그것을 완전히 없애려고 하는 것이다.

rsync를 이용하는 방법도 있으나, 이것은 전체를 통체로 가져오는 것이라 크기가 너무 크다. 물론 필요한 것만 가져온다고 하지만, 그게 실상 쉽지 않다. ubuntu의 경우는 .pool에 실제 파일이 들어가 있는데, 여기서 구분하기가 만만치 않아서…

$ apt-get install apt-mirror

/etc/apt/mirror.list 파일은 적당히 편집하여 미러링 원하는 레포지트리를 선택한다.

deb-amd64 http://apt.opscode.com quantal-0.10 main testing
deb-i386 http://apt.opscode.com precise-0.10 main testing
deb-i386 http://apt.opscode.com quantal-0.10 main testing
clean http://apt.opscode.com

deb-amd64 http://ubuntu-cloud.archive.canonical.com/ubuntu/ precise-updates/folsom main
deb-amd64 http://ubuntu-cloud.archive.canonical.com/ubuntu/ precise-proposed/folsom main
deb-i386 http://ubuntu-cloud.archive.canonical.com/ubuntu/ precise-updates/folsom main
deb-i386 http://ubuntu-cloud.archive.canonical.com/ubuntu/ precise-proposed/folsom main
clean http://ubuntu-cloud.archive.canonical.com/ubuntu
  • apt-mirror는 기본으로 구동되는 OS의 arch에 맞춰서 해당 패키지만 가져오도록 되어있다. 따라서 deb-[amd64|i386]처럼 직접 아키텍쳐를 지정한다.

OpenStack을 chef로 자동하하기 때문에 chef repository를… OpenStack은 cloud-archive를 가져오기로 했다.

choe@choe-pc:~/public_html$ du -sh /var/spool/apt-mirror/mirror/*
22M /var/spool/apt-mirror/mirror/apt.opscode.com
357M /var/spool/apt-mirror/mirror/ubuntu-cloud.archive.canonical.com

설정이 되었으면 미러링이 잘 되는지 테스트 해본다.

$ sudo apt-mirror

별 문제 없다면 주기적으로 미러링을 하기 위해서 crontab 파일을 수정한다. apt-mirror 패키지에서 기본적인 crontab 파일을 만들어 놨지만, 주석처리되어서 실제로 미러링되지 않는다.

$ sudo vi /etc/cron.d/apt-mirror

참고로 ubuntu 공식 패키지 미러링은 하루에 4번 하는 것을 권장하고 있다. 따라서 crontab도 6시간 간격으로 지정해 놓으면 되겠다. 이제 미러링 된 파일을 웹 서버에 링크하면 된다.

$ ln -s /var/spool/apt-mirror/mirror ~/public_html/apt-mirror

ps. precise의 전체 패키지(precise, precise-updates, precise-security, precise-proposed, precise-backports/ main, multiverse, universe, restricted)는 약 80G 정도 소요된다.

Twisted Powered Http Proxy Server

역시 간단한 서버 작업 하는 데는 twisted 만한 것이 없습니다.

from twisted.web import proxy, http
from twisted.internet import reactor
from twisted.python import log
import sys

log.startLogging(sys.stdout)

class ProxyFactory(http.HTTPFactory):
protocol = proxy.Proxy

reactor.listenTCP(8080, ProxyFactory())
reactor.run()

OpenStack: Allow_overlapping_ip의 해결 아이디어 간단 구현

quantum 제한사항에서 allow_overlapping_ip 기능이 안된다고 이전에 포스트 했었고, 이에 대해서 잠깐 생각을 하다가 아이디어가 떠올라서 몇 가지 작업했더니 대충은 동작합니다.

안되는 근본 원인은 instance의 ip를 가지고 어떤 instance인지 특정할 수 없다는 것이었는데, 여기다 tenant-id를 같이 조합하면 된다는 것이죠. 문제는 어떻게 tenant-id를 넘기느냐 였는데, http를 사용하니 header에 집어넣고, 이 header를 집어 넣는 역할을 하는 proxy를 l3 router namespace에서 동작하면 되는 것입니다.

이제 아래처럼 metadata 요청 흐름이 바뀌는 것이죠.

  • instance -> DNAT -> metadata server
  • instance -> proxy in router namespace -> metadata server

prox 서버는 간단히 twisted를 이용해서 만들었습니다.

적용 순서는…

  1. metadata patch 적용: https://github.com/whitekid/nova/commit/de9b371a4667dd66f510093a1e207bc7f9e02c6d
  2. metadata api restart

router name space에서

  1. lo device에 metadata ip 추가 $ ip netns exec qrouter-XXXX ip addr add 169.254.169.254/32 device lo
  2. DNAT하는 iptables rule 삭제 $ ip netns exec qrouter-XXXX $ iptables -t nat -L quantum-l3-agent-PREROUTING | grep 169.254.169.254 > /dev/null && iptables -t nat -D quantum-l3-agent-PREROUTING 1 $ exit

  3. metadata proxy 실행 $ ip netns exec qrouter-XXX python metadata-proxy [real-metadata-api-server-ip] [tenant-id]

그냥 단순히 아이디어 검증 차원이라, 실제로 쓰고자 한다면 많은 추가 작업이 필요할 것 같습니다.

https://github.com/whitekid/metadata_proxy

ps. 아.. 영어 어렵다.. ㅡㅡ

OpenStack: Quantum과 사용할 때 Metadata Request Back Routing 문제

Quantum으로 tenant network를 디자인 할 때, 딱 드는 생각은 tenant subnet을 private network을 구성하자 입니다. 물론 그렇겠죠. aws처럼 모든 생성되는 가상머신이 모두 public ip를 가질 필요는 없으니깐요. 필요한 인스턴스에 floating ip를 연결해서 외부에서 접속이 가능하게 하면 됩니다.

Quantum 가이드에 나온 Per-tenant Routers with Private Networks처럼 말이지요. 아래 그림처럼 된다면 참으로 멋진 구성이 될 텐데 말입니다. 사용자가 알아서 DMZ도 구성할 수 있고, 개발환경, production 환경의 네트웍을 똑같이 구성하여 테스트할 수 있고… 그런데 이렇게 하면서 quantum에서 예상치 못하는 결과가 발생합니다.

그중에 하나가(overlapping_ip 문제는 별도의 문제!) instance가 처음 부팅할 때 보내는 meta data request의 패킷이 metadata api 서버로는 잘 가지만, 다시 돌아올 경로가 없습니다.

Network Node -> Controller 노드까지 경로를 보면, metadata api가 public_ip이기 때문에 instance에서는 잘 접속이 됩니다. 하지만 패킷이 다시 돌아갈 instance의 주소는 private 네트워크이고 api-host에서 다시 돌아간 패킷은 external-router에서 내부 routing 경로가 아니라고 세상 밖으로 던져져 버립니다.

그래서 metadata connection이 맺여지지 않습니다.

metadata를 가져오지 못하면, 다른 것 다 제쳐두고라도 instance에 ssh keypair를 설정할 수 없기 때문에 가상 머신에 ssh 할 수 없는… 즉 만들었지만 접근하지 못하는 오직 ping만 할 수 있는 상황이 발생합니다. ㅎㅎ

그래서 external-router에서 내부 network으로 routing 틀어줘야 합니다.

어쨌든 그래서 아래처럼 quantum l3_agent를 소스를 기반으로 간단하게 routing 경로를 잡는 agent를 만들었고, 그 일을 하는 소스는 아래와 같습니다. 하나도 정리안된.. 막무가내 소스입니다. ㅎㅎ

tenant의 external router로 연결된 router에 대해서 해당 tenant의 subnet으로 가는 경로를 그 tenant에 기본으로 할당된 public ip로 잡아주는 것이죠. 그러면 해당 l3 name space에서는 적당히 알아서 그 instance로 보내줍니다.

def do_single_loop(self):
    routers = self.qclient.list_routers()['routers'];
    ports = self.qclient.list_ports()

    route_info = []
    for r in routers:
        # get tenant's subnet
        subnet = self.qclient.list_ports(device_id=r['id'],
                device_owner='network:router_interface')['ports'][0]['fixed_ips'][0]['subnet_id']
        cidr = self.qclient.show_subnet(subnet=subnet)['subnet']['cidr']

        # get the tenant's gw
        fixed_ip = self.qclient.list_ports(device_id=r['id'],
                device_owner='network:router_gateway')['ports'][0]['fixed_ips'][0]['ip_address']
        route_info.append((cidr, fixed_ip))

    # get current route info
    old_routes = [x.split() for x in subprocess.check_output(['ip', 'route']).splitlines()[2:] if ('via' in x and 'default' not in x) ]
    old_routes = [(x[0], x[2]) for x in old_routes]

    # add new routing info
    for cidr, fixed_ip in set(route_info) - set(old_routes):
        subprocess.check_call(['route', 'add', '-net', cidr, 'gw', fixed_ip])

    # remove routing info
    for cidr, fixed_ip in set(old_routes) - set(route_info):
            subprocess.check_call(['route', 'del', '-net', cidr, 'gw', fixed_ip])

그리고 더 해야하는 게, openstack에서 외부 명령을 실행하는 것은 rootwarp을 이용해서 사용하도록 되어있습니다. 아무래도 보안상 이유겠지요. 근데 지금은 우선 잘 되는지 테스트 하기 위해서 그거 신경 안썻습니다. 나중에 시간나면 정리 합니다~ ㅎㅎ

마지막으로 소스 위치~

https://github.com/whitekid/metadata_route_agent

Github에서 패치 가져와 적용하기 + Chef

오늘 작업하다 보니 OpenStack에 몇가지 버그가 있었습니다. 버그 있는 것을 확인하고 퇴근했는데, 마침 메일링 리스트에 관련 이야기가 나오더니 커밋 링크(https://github.com/openstack/quantum/commit/84d60f5fd477237bd856b97b9970dd796b10647e)를 알려줍니다.

이걸 지금 chef로 작업하고 있는 것에 적용 시키기로 했지요.

package quantum-l3-agent

# apply l3 agent bug fix patch
execute "apply fetch" do
    action :nothing

    command "wget -O /dev/stdout -q https://github.com/openstack/quantum/commit/84d60f5fd477237bd856b97b9970dd796b10647e.patch | \
        patch -p1"
    cwd "/usr/lib/python2.7/dist-packages"

    subscribes :run, "package[quantum-l3-agent]", :immediately
end
  1. github에서 커밋 아이디를 가져오는 것은 커밋 링크에 .patch를 붙여준다.
  2. patch는 관련 패키지를 설치할 경우만 필요하기 때문에 action :nothing을 주고 subscribe로 해당 패키지가 설치되었을 때 패치를 진행한다.
  3. 소스로 작업했으면 git apply로 할텐데.. 패키지로 작업하기 때문에 patch -p1으로..