Tag: OpenStack

veth가 어떤 디바이스에 연결되어있는지 찾아보기..

Quantum으로 네트워크를 구성하다보면(또는 XLC...) veth를 통해서 다른 network namespace에 interface가 peer로 역이는 것을 볼 수 있습니다.

Network Namespace는 Introducing Linux Network Namespaces 글을 참조하시면 좋습니다. 간단히 말에서 device, routing, iptables, socket 등을 포함하여 linux network stack이 완전히 격리되는 시스템입니다. namespace를 만들어 network stack을 격리시키면 외부랑 완전히 차단이 되기 때문에 root namespace의 interface와 veth로 pair를 맺어 이 interface로 통신합니다.

veth는 참고할 만한 문서를 딱히 못찾았는데요.. interface link의 클론이라고 생각하시면 됩니다. 한쪽에 들어간 패킷은 다른 한쪽으로 흐릅니다. 그리고 당연히 각각이 interface이기 때문에 mac, ipaddress가 다를 수 있습니다. 어떻게보면 bridge와도 비슷합니다.

근데 문제는 veth로 만드는 것은 쉽게 알 수 있는데, 해당 인터페이스가 어떤 인터페이스랑 peer인지 알아내는 방법이 쉽지 않습니다. iproute로는 말이지요.

아래는 quantum으로 구성한 dhcp namespace의 interface 입니다.

# ip netns exec qdhcp-fabc7ead-6132-4920-af57-2ad5e199e1c1 ip a
59: 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
68: ns-39d60faa-aa: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether fa:16:3e:98:e6:f3 brd ff:ff:ff:ff:ff:ff
    inet 10.10.100.2/24 brd 10.10.100.255 scope global ns-39d60faa-aa
    inet 169.254.169.254/16 brd 169.254.255.255 scope global ns-39d60faa-aa
    inet6 fe80::f816:3eff:fe98:e6f3/64 scope link
       valid_lft forever preferred_lft forever
# ip netns exec qdhcp-fabc7ead-6132-4920-af57-2ad5e199e1c1 route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.10.100.1     0.0.0.0         UG    0      0        0 ns-39d60faa-aa
10.10.100.0     0.0.0.0         255.255.255.0   U     0      0        0 ns-39d60faa-aa
169.254.0.0     0.0.0.0         255.255.0.0     U     0      0        0 ns-39d60faa-aa

여기서 routing table을 보면 ns-39d60faa-aa 인터페이스를 통해서 외부로 나가는 것으로 보이는데, namespace 이므로 외부와 직접 연결할 수 없습니다. 당연히 ns-39d60faa-aa는 root namespace의 interface와 veth peer를 이루고 있으며, peer interface를 통해서 외부와 통신합니다.(그 peer는 bridge를 통해서 eth#으로 나가겠지요..)

그럼 여기서 본론인 어떤 interface와 peer를 이루고 있는지 알아보려고 열심히 ifconfig 또는 ip link 명령을 뒤져봐야 안나됩니다. mac도 다르고, peer 정보도 안나오고...

찾는 방법은 조금 복잡하기도 한데... ethtool을 통해서 찾을 수 있습니다.

# ip netns exec qdhcp-fabc7ead-6132-4920-af57-2ad5e199e1c1 \
  ethtool -S ns-39d60faa-aa
NIC statistics:
     peer_ifindex: 69

결과에서 예상하다시피 interface index가 69번인 interface와 peer를 이루고 있습니다. 그럼 아래처럼 찾을 수 있겠습니다.

# ip link ls | grep ^69
69: tap39d60faa-aa: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
# ip link show tap39d60faa-aa
69: tap39d60faa-aa: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 62:41:1f:e2:b2:9d brd ff:ff:ff:ff:ff:ff
# ethtool -S tap39d60faa-aa
NIC statistics:
peer_ifindex: 68

마찬가지로 tap39d60faa-aa interface는 namespace에 있는 68번 interface와 veth peer로 연결되어 있습니다.

지금은 필요없을 지 몰라도 OpenStack 하다보면 언젠가는 마주칠지 모르는 녀석이니 참고하세용..

ps. iproute 사용법은 너무 불친절합니다.


security group: 인스턴스 그룹에 접근 허용하기

SecurityGroup은 인스턴스에 연결된 포트에 허용되는 트래픽을 제어하는 기능입니다.

처음 오픈스택 인스턴스 프로젝트를 할당받고 가장 먼저 하는 것이 22번 포트에 대한 접근을 허용하는 것이니.. 대부분 잘 알고 있을 겁니다.

그런데 기본으로 제공되는 default security group만 운영하다 보면(아마 대부분 그럴지도) 하나의 의문점이 생깁니다.

아래처럼 인스턴스가 있다고 가정했을 때

  • web
  • mysql

web 인스턴스는 80번 포트, mysql 포트는 3306 포트가 필요합니다. 그래서 별 생각없이 default security group에 80, 3306 포트를 열어줍니다. 하지만 여기서 생각해볼 것이..

  • web에서는 3306 포트를 열 필요가 없습니다.
  • mysql에서는 80번 포트를 열 필요가 없습니다. 그리고 db 접근은 web에서만 하니 web에서 접근하는 트래픽만 허용합니다.

첫번째 경우는 큰 문제가 없습니다.  단순히 80번 포트만 여는 security group을 만들고 web 인스턴스에 적용하면 되니깐요.

$ nova secgroup-create web 'allow web access'
+--------------------------------------+------+------------------+
| Id                                   | Name | Description      |
+--------------------------------------+------+------------------+
| d60f5be1-8a60-4523-ba4e-3230edf5b444 | web  | allow web access |
+--------------------------------------+------+------------------+
$ nova secgroup-add-rule web tcp 80 80 0.0.0/0
+-------------+-----------+---------+----------+--------------+
| IP Protocol | From Port | To Port | IP Range | Source Group |
+-------------+-----------+---------+----------+--------------+
| tcp         | 80        | 80      | 0.0.0/0  |              |
+-------------+-----------+---------+----------+--------------+
$ nova add-secgroup web web
$ nova show web
$ nova show charlie-web | grep security
| security_groups             | [{u'name': u'default'}, {u'name': u'web'}]                     |

자.. 이제 MySQL 인스턴스에 Security Group을 적용해야하는데... web에만 적용하면 되니깐.. security group을 만들려고 보는데..

$ nova secgroup-create mysql 'allow mysql access'
+--------------------------------------+-------+--------------------+
| Id                                   | Name  | Description        |
+--------------------------------------+-------+--------------------+
| 7d197716-501f-46fa-a6fb-bd4e0c9dd5bb | mysql | allow mysql access |
+--------------------------------------+-------+--------------------+

이제 rule을 추가하려는데.. web에서만 접근을 하용하는 것이니깐.. web 인스턴스 ip만 cidr로 허용합니다.

$ nova secgroup-add-rule mysql tcp 3306 3306 172.16.202.214/32
+-------------+-----------+---------+-------------------+--------------+
| IP Protocol | From Port | To Port | IP Range          | Source Group |
+-------------+-----------+---------+-------------------+--------------+
| tcp         | 3306      | 3306    | 172.16.202.214/32 |              |
+-------------+-----------+---------+-------------------+--------------+

문제없나요? 근데.. 뭔가 이상하지 않나요? 만일 web 인스턴스가 늘어난다면? 새로운 인스턴스에 대한 rule을 계속 추가해야될까요?.. 만일 그래야된다면... 이거 Security Group이 참 써 먹을 것이 못되는 것이 됩니다.

역시나 예상하다시피 tenant 인스턴스 group에 대해서 traffic을 제어하는 기능이 있습니다. rule을 추가된 후에 나오는 source group이라는 것이 키워드입니다. nova에도 해당 명령이 있고.. 이에 대한 설명은 아래처럼 굉장히 불친절하게 되어있습니다.

secgroup-add-group-rule Add a source group rule to a security group.

설명을 봐도 무슨 말인지 쉽게 알 수 없습니다. 하지만 내용은 간단한 것으로 특정 cidr의 rule을 주는 것이 아니라 주어진 security group이 적용된 인스턴스에 대해서 secutiry group을 적용한다는 이이기 입니다.

즉 mysql 접근을 web에서만 접근하려고 하고, web 인스턴스는 모두 web security group이 적용되어 있다고 한다면

$ nova secgroup-add-group-rule mysql web tcp 3306 3306
+-------------+-----------+---------+----------+--------------+
| IP Protocol | From Port | To Port | IP Range | Source Group |
+-------------+-----------+---------+----------+--------------+
| tcp         | 3306      | 3306    |          | web          |
+-------------+-----------+---------+----------+--------------+

source group을 web으로 지정하여 web 인스턴스에 대해서 mysql port에 대한 접근을 허용할 수 있습니다. 여기서 다른 인스턴스에 web security group을 적용하면 그 인스턴스도 바로 mysql에 접근이 가능합니다(물리 노드에서 보면 해당 인스턴스의 ip address가 iptables에 바로 추가됩니다). 물론 다른 녀석들은 mysql 포트에 접근이 제한되구요.

그러므로 만일 source group을 default로 한다면 해당 tenant의 모든 인스턴스가 mysql에 접근할 수 있습니다


어떤 vm을 누가 만들었는지 찾기 귀찮아서…

$ cat get_user_from_ip.sh
#!/bin/bash
ip=$1

port_id=$(quantum port-list | grep $ip | awk '{print $2}')
device_id=$(quantum port-show $port_id | awk '/device_id/{print $4}')
user_id=$(nova show $device_id | awk '/user_id/{print $4}')
keystone user-get $user_id

$ ./get_user_from_ip.sh x.x.x.x

nova resize

nova resize는 메뉴얼에 나와있는 것 같이, 인스턴스에 적용된 flavor를 바꾸고, 이에 따라서 서버의 설정을 변경하는 명령입니다. 이의 사용 방법은 간단합니다.

$ nova resize --poll <instance id> <flavor id>
$ nova resize-confirm <instance id>

아주 간단하게 보이죠... 근데 이렇다면 제가 이 글을 쓸 이유가 없습니다. 메뉴얼에 나와있지 않은 숨은 복병이 있습니다.

아무 생각없이 단순 무식하게 이 명령을 수행하면 아마 대부분 에러가 발생한 것입니다.

$ nova resize --poll my-instance 3

Instance resizing... 0% complete
Error resizing instance

음.. 이 상태에서는 인스턴스는 종료되어 접근할 수 없고, nova list 명령으로 보면 아래처럼 에러가 났다고 그러고, 재부팅 하기 위해서 nova reboot를 하면 에러 상태에서는 해당 명령을 수행할 수 없다고 합니다.

$ nova list
+--------------------------------------+--------------+--------+------------------------------+
| ID                                   | Name         | Status | Networks                     |
+--------------------------------------+--------------+--------+------------------------------+
| cb0802f6-0946-41d7-a7e6-6280974686e0 | my-instance  | ERROR  | admin=10.10.10.2, 10.250.0.4 |
+--------------------------------------+--------------+--------+------------------------------+

$ nova reboot --hard my-instance
ERROR: Cannot 'reboot' while instance is in vm_state error (HTTP 409) (Request-ID: req-b745b011-961d-4b11-9366-a85cbe027fc8)

recover error state

우선 resize를 제대로 동작하게 하는 것 보다, 이 에러 상태를 해결하는 것이 더 중요해졌습니다. 최악의 경우 DB를 수정하는 방법을 생각할지도 모르나.. 생각보다 간단합니다. 우선 쉼호흡을 하고..

$ nova reset-state --active my-instance
$ nova list
+--------------------------------------+--------------+--------+------------------------------+
| ID                                   | Name         | Status | Networks                     |
+--------------------------------------+--------------+--------+------------------------------+
| cb0802f6-0946-41d7-a7e6-6280974686e0 | my-instance  | ACTIVE | admin=10.10.10.2, 10.250.0.4 |
+--------------------------------------+--------------+--------+------------------------------+

ACTIVE 상태이니... 인스턴스 접근을 해보려 하겠지만 안됩니다. 데이터베이스 상에서 status만 reset된 상태입니다. 아직은 인스턴스는 그대로 죽어있습니다. 이제 인스턴스를 상리기 위해서 reboot 합니다.

$ nova reboot --hard my-instance

이제 잠시 기다리면 인스턴스가 올라옵니다.

resize는 어떻게 동작하는가?

그럼 resize는 어떻게 동작하는지에 대해서 보면, 위에서 에러가 발생했을 때 상황에서 확인할 수 있습니다.

$ nova show my-instance
+----------------------+-----------------------------------------------------------------------------------------------------------------+
| Property             | Value                                                                                                          |
+----------------------+-----------------------------------------------------------------------------------------------------------------+
| status               | ERROR                                                                                                           |
| OS-EXT-STS:vm_state  | error                                                                                                           |
| fault                | {u'message': u'ProcessExecutionError', u'code': 500, u'details': u'Unexpected error while running command.      |
|                      | Command: ssh 10.100.0.32 mkdir -p /var/lib/nova/instances/cb0802f6-0946-41d7-a7e6-6280974686e0                  |
|                      | Exit code: 255                                                                                                  |
|                      | Stdout: \'\'                                                                                                    |
|                      | Stderr: \'Host key verification failed.\\r\                                                                     |
|                      | \'                                                                                                              |
|                      |   File "/usr/lib/python2.7/dist-packages/nova/compute/manager.py", line 224, in decorated_function              |
|                      |     return function(self, context, *args, **kwargs)                                                             |
|                      |   File "/usr/lib/python2.7/dist-packages/nova/compute/manager.py", line 2373, in resize_instance                |
|                      |     block_device_info)                                                                                          |
|                      |   File "/usr/lib/python2.7/dist-packages/nova/virt/libvirt/driver.py", line 3480, in migrate_disk_and_power_off |
|                      |     inst_base_resize)                                                                                           |
|                      |   File "/usr/lib/python2.7/contextlib.py", line 24, in __exit__                                                 |
|                      |     self.gen.next()                                                                                             |
|                      |   File "/usr/lib/python2.7/dist-packages/nova/virt/libvirt/driver.py", line 3457, in migrate_disk_and_power_off |
|                      |     utils.execute(\'ssh\', dest, \'mkdir\', \'-p\', inst_base)                                                  |
|                      |   File "/usr/lib/python2.7/dist-packages/nova/utils.py", line 239, in execute                                   |
|                      |     cmd=\' \'.join(cmd))                                                                                        |
|                      | ', u'created': u'2013-08-14T09:30:00Z'}                                                                         |
+----------------------+-----------------------------------------------------------------------------------------------------------------+

보면, 에러가 발생했을 때 traceback이 보이고, 여기서 관심을 둘 부분은 아래입니다.

Command: ssh 10.100.0.32 mkdir -p /var/lib/nova/instances/cb0802f6-0946-41d7-a7e6-6280974686e0

다른 호스트로 ssh로 디렉토리를 만들면서 명령을 실행하다가 발생합니다. 어디선가 본 적이 있을 겁니다. 녜.. 이 내용은 이전에 migration에 대한 포스트에서 migration에서 실행하는 명령과 같습니다. 즉.. resize는 ssh를 통해서 다른 compute에 디스크를 복사하고, 이는 migration의 필요 요구사항과 같습니다.

정리하면 migration의 요구사항은 다음과 같습니다. 이게 resize의 요구사항과 같습니다.

  • nova user로 다른 compute node에 ssh로 인증없이 로그인 가능(public key authentication)
  • 사용가능한 shell(/bin/bash) 지정: ubuntu 패키지는 /bin/false로 설정하고 있음.
  • known_hosts에 대상 compute 호스트 등록

resize가 완료 되었군요

resize한 이후에 보면, 메모리, vcpu등의 리소스는 큰 문제가 없습니다. 다만 root partition의 경우는 디스크가 더 커질 경우, root partition 다음에 빈 영역으로 남아있습니다.

cloud-init에 의해서 root partition이 자동으로 될 것입니다. 물론 ubuntu의 경우 입니다. CentOS는 안됩니다. CentOS가 안되는 건 좀 복잡한 문제인데.. 그건 나중에...

정리

  • resize는 migrate와 유사합니다. shutdown --> ssh + rsync 복사 --> reboot
  • root partition은 Ubuntu의 경우 사이즈 조절이 자동으로 됩니다.

Quantum Provider network

Provider Network은 문서상에 나와있는 내용을 그대로 빌리자면, OpenStack 네트워킹 네트워크를 데이터 센터의 physical network와 직접적으로  mapping하는 네트워크 입니다. 즉, 데이터 센터에서 제공하는 네트워크를 바로 tenant network에 사용하는 것입니다.

일반적으로 데이터센터에서 제공하는 네트워크는 vlan으로 구분하여 제공하게 됩니다. 이런 상황에서 하나의 vlan을 하나의 tenant에 전용으로 할당하는 것은 효율적이지 않습니다. 이는 vlan이라는 성격상 4096개의 제한도 있겠지만, 데이터 센터의 네트워크 계획에 따라서 vlan을 할당하므로 사용자가 직접 네트워크를 만드는 모델은 적합지 안습니다. provider network 생성 자체를 admin 권한으로 생성하는 것이 아마 이것과 관련있을지 모르겠습니다.

물론 보안 요구사항등의상황에 따라서 특정 provider network을 특정 tenant에 할당하여 사용할 수 있지만, 이 경우는 ip address 낭비를 위하여 subnet mask를 적절히 조절해야 되겠습니다.

provider network으로 네트워크를 디자인한다면...

  • vlan 4개를 24비트로 데이터 센터에서 할당 받음
    • vlan 100: 10.10.100.0/24
    • vlan 101: 10.10.101.0/24
    • vlan 200: 10.10.200.0/24
    • vlan 201: 10.10.201.0/24
  • 각 vlan의 gateway는 각 주소의 1번(e.g. 10.10.100.1)으로 설정됨
  • admin 계정으로 각 vlan에 해당되는 네트워크를 provider network으로 생성
  • tenant들이 해당 네트워크에 인스턴스를 만들 수 있다록 shared network으로 생성

이를 하기 위한 physical node의 네트워크 연결은 network, compute 노드 모두

  • eth0: management
  • eth1: vlan tagging 100, 101, 200, 201, 물론 해당 gateway까지 연결 가능해야함.

그리고 shard network을 사용하고, private network을 사용하지 않기 때문에 l3-agent는 사용하지 않습니다. 그렇기 때문에 private network을 사용했을 때와 같이 external network용 NIC가 필요없습니다.

OpenStack Settings

/etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini

tenant_network_type = vlan
network_vlan_ranges = default:100:101,default:200:201
bridge_mappings=default:br-eth1

tenant_network_type = vlan

provider network으 vlan으로 제공되기 때문에 vlan으로 설정합니다.

network_vlan_ranges = default:100:101,default:200:201

데이터 센터의 상황에 따라서는 연속적인 vlan을 사용할 수 없을 수 있습니다. 그런 경우를 테스트하기 위해서 위처럼 따로 떨어진 범위의 vlan을 설정해봤으며, 이 두 개를 설정하는 것은 위의 예제처럼 컴마(,)로 분리하면 됩니다.

bridge_mappings=default:br-eth1

network_vlan_range에서 설정한 네트워크가 어떤 ovs bridge와 mapping이 될 지 설정합니다. 이 bridge는 openvswitch-agent에서 자동으로 만들어지므로, 별도의 작업은 필요 없습니다.

Create Network

provider network은 admin 권한으로만 생성이 가능합니다. 따라서 admin user에서 생성합니다. 그리고 provider network은 horizon에서 만드는 기능이 없습니다. quantum cli로 아래처럼 만듭니다.

vlan tag 번호와, --shared 옵션을 확인하기 바랍니다.

$ quantum net-create pub100 --provider:network_type vlan \
    --provider:segmentation_id=100 --shared
$ quantum net-create pub101 --provider:network_type vlan \
    --provider:segmentation_id=101 --shared
$ quantum net-create pub200 --provider:network_type vlan \
    --provider:segmentation_id=200 --shared
$ quantum net-create pub201 --provider:network_type vlan \
    --provider:segmentation_id=201 --shared

그리고 만들어진 네트워크에 아래처럼 subnet을 할당합니다.

$ quantum subnet-create pub100 10.10.100.0/24
$ quantum subnet-create pub101 10.10.101.0/24
$ quantum subnet-create pub200 10.10.200.0/24
$ quantum subnet-create pub201 10.10.201.0/24

subnet을 생성할 때는, 반드시 데이터 센터에서 할당핟은 network cidr을 잘 맞춰서 생성해야 합니다.

일반 사용자에서 quantum net-list 명령으로 보면 shared network이기 때문에 방금 생성한 네트워크의 정보를 확인할 수 있습니다.

$ quantum net-list
+--------------------------------------+--------+-----------------------------------------------------+
| id                                   | name   | subnets                                             |
+--------------------------------------+--------+-----------------------------------------------------+
| 546f14c5-b837-41ef-964a-0eba46aa23f9 | pub101 | 34b28d6f-5398-46ed-ba9e-f848ef6269b0 10.10.101.0/24 |
| 7b455fae-a2a5-4204-b04a-4859f335580d | pub100 | 238340a8-7d9c-4a5b-ac34-d8047e1c3f5a 10.10.100.0/24 |
| ce24e1ec-f256-4d81-b99d-668847d7a472 | pub200 | 48df6481-b952-4c92-a8f3-6293ecb4186c 10.10.200.0/24 |
| fc427218-8244-4284-b68c-d3429c8cccec | pub201 | 82274a91-95fb-42cf-895e-e70efff4b062 10.10.201.0/24 |
+--------------------------------------+--------+-----------------------------------------------------+

물론 shared network이므로 network의 subnet 정보도 확인 할 수 있습니다.

Create Instance

Instance를 생성하는 것은 동일합니다.

다만, 여기서는 생성할 수 있는 네트워크가 4가지가 되는데, 사용가자 생성할 때 4가지 중에 하나의 네트워크를 선택해야합니다. 개인적인 의견으로는 아무 네트워크나 자동으로 골라서 만들어주는 옵션이 있으면 좋겠는데, 아직 그런 기능이 없군요.

뭐, 간단한 스크립팅으로 가능은 하겠지만요..

Metadata problem...

인스턴스는 잘 생성이 됩니다. dhcp에서도 ip를 잘 받아옵니다. 그런데 ssh로 연결이 안됩니다. 인스턴스 로그에서 보면 바로 확인할 수 있는데, metadata를 받아오지 못하기 때문입니다.

private network을 사용했던 경우에는 l3-agent가 동작하는 tenant의 default gateway에서 169.254.169.254/32로 가는 요청을 잡아서 quantum-metadata-agent로 보내고, 여기서 다시 nova-api에서 서비스되는 메타데이터 서버로 proxy를 하는 작업을 거칩니다.

그런데 여기서 생성했던 provider network은 l3-agent가 없습니다. 즉, 169.254.169.254로 가는 트래픽은, 데이터 센터에서 제공해주는 physical 라우터로 향하게 됩니다. OpenStack이 관할하는 곳을 벗어나서, metadata를 얻어오지 못하는 것이죠.

그런데, 이 경우에도 대비해서 quantum을 잘 살펴보면 dhcp-agent에서 metadata-ns-metadata-proxy를 띄울 수 있는 옵션이 있습니다.

dhcp_agent에서 quantum-ns-metadata-proxy 띄우기

설정은 간단합니다. 아래처럼 설정해주고,

/etc/qantum/dhcp_agent.ini:

enable_isolated_metadata = True

설정하고, dhcp-agent를 재시작한 후, dhcp-agent가 동작하는 namespace를 보면 아래처럼 169.254.169.254/16 이라는 ip address가 설정된 것을 확인할 수 있습니다.

$ ip netns exec qdhcp-7b455fae-a2a5-4204-b04a-4859f335580d ip a
50: 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
51: ns-61eaed6f-d0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether fa:16:3e:ad:73:bb brd ff:ff:ff:ff:ff:ff
    inet 10.10.100.3/24 brd 10.10.100.255 scope global ns-61eaed6f-d0
    inet 169.254.169.254/16 brd 169.254.255.255 scope global ns-61eaed6f-d0
    inet6 fe80::f816:3eff:fead:73bb/64 scope link
       valid_lft forever preferred_lft forever

이제 instance에서 아래처럼 확인하면 meta-data를 가져오는 것을 확인할 수 있습니다.

$ curl http://10.10.100.3/latest/meta-data/

근데... 헐.. 169.254.169.25로 호출하지 않고, 10.10.100.3으로 요청을 했네요. 혹시나 하고 169.254.169.25로 요청하면 여전히 안됩니다. 여전히 metadata 요청 패킷은 저 멀리 안드로메다로 가고 있습니다.

host routing...

안드로메다로 가는 메타데이터 트래픽을 10.10.100.3으로 보내기 위해서는, l3-agent에서 하는 방법으로는 gateway에서 다른 호스트로 redirect하는 방법이 있습니다. 근데 provider router는 phisycal router를 사용하므로, 거기의 routing table을 OpenStack이 수정할 수 없습니다. 만일 수정할 수 있다고 해도, provider network이 만들어 질 때마다, routing table 추가 작업을 요청해야하기 때문에 그리 좋은 방법은 아닙니다. 물론 OpenStack Agent가 하는 기능을 뚝딱 만들면 되겠지만요.

OpenStack way로 해결하는 방법은 subnet을 생성할 때 host-route 옵션을 주는 것입니다.

$ quantum subnet-create --host-route \
    destination=169.254.0.0/16,nexthop=10.10.100.3 pub100 10.10.100/24

또는 기존의 subnet을 업데이트 하려면... 쬐끔 복잡하게..

$ quantum subnet-update  \
    --host-routes type=dict list=true destination=169.254.0.0/16,nexthop=10.10.100.3

이렇게하면, 인스턴스가 dhcp에서 정보를 가져올 때 routing table까지 가져오므로 instance의 routing table에 의해서 meta-data에 접근이 가능합니다.

cirros bug

그런데 cirros에서 routing table을 dhcp에서 요청하지 않기 때문에 동작하지 않습니다.

cirros의 경우는 부팅 후 routing table을 직접 수정하여 확인하세요.

$ route add -net 169.254.0.0 netmask 255.255.0.0 gw 10.10.100.3 dev eth0

ubuntu cloud 이미지는 아주 잘 동작합니다. 다만 꺼림직하게 인스턴스 routing table이 하나 추가된다는 것 빼구요. 이거 없애려면, 위에서 언급했던, physical router에서 routing table을 추가하면 됩니다.

CentOS 5.x의 문제

CentOS 5.8에서도 dhclient가 static routing을 요청하지 않아서 문제가 발생합니다. 이 경우는 http://jcape.name/2009/07/17/distributing-static-routes-with-dhcp/ 를 참고하세요.

dhcp-agent의 ip address고정...

이렇게 해서 pub100 네트워크는 잘 되었고, pub101에서 하다보면 뭔가 다른 것을 발견하게 됩니다.

pub100에서의 dhcp-agent가 동작하는 port의 ip address는 10.10.100.3인 반면에 pub101에서는 10.10.101.2으로 할당됩니다. 당연히 인스턴스의 ip address도 10.10.100.2, 10.10.101.3으로 서로 다릅니다. 아마도 인스턴스를 생성하고, dhcp-agent의 포트를 생성하는 순서의 문제인 것 같은데, subnet 생성 후에 dhcp-agent의 포트를 강제로 만들어 주면 되겠습니다.

$ quantum dhcp-agent-network-add <agent_id> <network_id>

결론

  • provider network은 SPoF인 l3-agent을 사용하기 않습니다.
  • 모든 네트워크가 physical network으로 구현되어, 기존의 네트워크 인프라에서 운영될 수 있습니다.
  • private network을 사용하기 않기 때문에, 기존 데이터 센터의 인프라와 자연스럽게 통합됩니다.

이를 종합하면, 기존 데이터센터와 통합해야할 필요가 있는 환경에서는 Provider Network이 가장 맞는 선택인 것 같습니다.


OpenStack: block migration

잘 알고 있다시피.. live migration을 하려면 shared storage(NFS, DFS...)가 필요합니다. 근데 share storage는 필연적으로 local storage에 비해서 느릴 수 밖에 없습니다. 그렇지요.

그리고 live migration은 OpenStack 시스템 유지/ 보수를 위해서도 필요합니다. 호스트 머신의 업그레이드가 필요할 때, 호스트 머신에 뭔가 작업을 할 때, 해당 호스트에서 서비스되는 인스턴스를 다른 곳으로 옮기고 작업해야하니깐요...

위에 언급했다시피, live migration은 shared storage가 필요하고, 이를 위해서는 IO를 일정부분 포기해야하는 경우가 생겨서, 이를 어떻게 만회할까하고 여기저기 뒤져보다가... block migration 기능이 있다는 것을 알았습니다.

live migration은 다른 호스트로 메모리만 복사하는 반면에 block migration은 메모리와 블럭 디바이스(인스턴스 스토리지, 볼륨 스토리지)도 같이 대상 호스트로 복사합니다. 결국 live migration이 조금 느린 반면에 shared storage가 필요 없어서, 유지보수를 위한 migration에는 사용할 수 있을 것 같습니다. 물론 갑작스런 호스트 머신의 오류일 경우에는 해당 사항이 없겠습니다.

사용방법은 간단합니다. 기존의 live migration 명령에 --block_migration 옵션만 붙이면 됩니다. 즉, 아래와 같죠.

$ nova live-migration --block_migrate

이를 위한 OpenStack 설정은 live migration 문서처럼 설정하고, 추가로 /etc/nova/nova.conf에 아래처럼 block_migration_flag를 설정합니다.

block_migration_flag= \
        VIR_MIGRATE_UNDEFINE_SOURCE, \
        VIR_MIGRATE_PEER2PEER, \
        VIR_MIGRATE_NON_SHARED_INC, \
        VIR_MIGRATE_LIVE

별 문제 없으면 잘 될겁니다. live migration이 필요했지만, shared storage가 준비되지 않으신 분들.. 한번 써 보세요~

그리고 추가로 OpenStack에서 migration에 대해서 간단히 정리합니다.

(True) live migration

shared storage를 사용하는 경우, instance의 memory만 대상 호스트로 복사하여 live migration을 수행합니다. 당연히 shared storage(NFS, GlusterFS, CephFS...)가 필요합니다.

메모리만 복사하므로 수초내에 migration이 완료됩니다.

$ nova live-migration <instance> <dest host>

참고) shared storage를 사용할 경우, live migration을 사용하기 위해서 disk cache를 disable 해야합니다. file 또는 ceph를 사용할 경우는 이 설정이 자동으로 들어가지만,  GlusterFS를 instance directory에 mount해서 사용할 경우 disk cache를 disable하는 것이 동작하지 않습니다. 따라서 glusterfs를 사용할 경우는 live_migration_flag를 아래처럼 VIR_MIGRATE_UNSAFE를 추가합니다.

live_migration_flag = \
        VIR_MIGRATE_UNDEFINE_SOURCE, \
        VIR_MIGRATE_PEER2PEER, \
        VIR_MIGRATE_LIVE, \
        VIR_MIGRATE_UNSAFE

block migration

live migration에 추가로 스토리지도 복사합니다. 약간 느리지만 live migration의 장점과 local storage의 IO의 장점을 동시에 취할 수 있습니다. 그리고 qemu에서 제공되는 기능을 사용하기 때문에 별도의 설정은 필요 없습니다.

$ nova live-migration --block_migrate <instance> <dest host>

migration

이건 live migration이 아니고, instance shutdown --> disk image copy --> instance boot 과정을 거침니다. 당연히 해당 호스트는 리부팅 됩니다. 그리고 migration이 되는 호스트는 scheduler에 의해서 자동으로 선택됩니다

$ nova migrate <instance>

block migration은 다른 호스트로 복사하는 기능을 qemu의 기능을 사용하므로 별도의 설정이 필요없었지만, migrate는 qemu나 libvirt의 기능을 사용하지 않고 수동(^^)으로 ssh를 이용하여 복사하기 때문에, 이동하려는 nova compute 노드에 nova 유저로 ssh login이 아무런 장애없이 되야됩니다. 또한 ubuntu로 설치했다면 nova 계정의 login shell이 /bin/false로 되어있는데 /bin/bash로 수정합니다. 결과적으로 compute에서 다른 compute로 아래 명령을 수행했을 때 오류가 없어야 합니다(아직까지 문서에 없음^^).

root@compute01:~# sudo -u nova ssh compute02 hostname
compute02
  • ssh public key authentication
  • ssh host key 등록

ps. 예상대로라면 volume을 붙인 인스턴스에서는 볼륨은 굳이 복사할 필요가 없으므로 volume이 없는 인스턴스와 block migration 성능 차이가 없어야 하는데도, 이상하게 volume이 붙어있는 인스턴스는 느리군요.. 이거 왜 이럴까요?

ps. 약간 알콜이 들어간 상태에서 쓴 글이라... 오타 작렬.. 논지도 왔다갔다... ㅎㅎ


keystone token이 너무 많아요..

지난 일주일간 회사 워크삽으로 자리를 비웠다. 그 동안 단 한번도 노트북을 켜지 않았으니, 이거 참 대대한 일인 듯 하다. 작년 휴가에도 중간에 콜 받아서 노트북 켠 경험이 있는데 말이다...

각설하고.. 어쨌든 오늘 출근해서, 그래 내가 뭘 하고 있었던 거지? 하면서 설치된 오픈스택 구성을 둘러보려고, 딸랑 nova list 명령을 치는데, 이녀석이 먹통이다... 아무런 에러로 안뱉어내고 그냥 조용이 가만히 있는다.

이전에도 비슷하나 경험이 있었지만, 그때는 대충 넘어갔었지만, 들은 것도 있어서 뒤져봤는데 역시나... keystone의 token table에 데이터가 많이 쌓었나 보다.

mysql> select count(*) from token;
+----------+
| count(*) |
+----------+
|    20916 |
+----------+
1 row in set (25.17 sec)

뭐.. 개인 테스트 환경이고 해서, 무식하게 다 지우고 하니 nova list 명령이 잘 된다. 대략  들은 적이 있다. 각 호스트들의 agent들이 api를 수행할 때, 모두 keystone 인증 토큰을 발급 받는데, 이 토큰들이 계속 누적되어서 문제를 발생하는 것이다. 우선 간단하게 expire된 token을 날려버리는 것도 좋겠다.

mysql> delete from token where expires < current_timestamp 

근데 저 정도의 숫자로  MySQL의 성능 이슈에  걸리는 것도 이상한 것이다. MySQL 튜닝 문제인 것 같다. token을 보면 primary key를 지외하고는 인덱스를 잡지 않았으며, 쿼리에 맞게 인덱스를 추가하면 되겠다.

 # Query_time: 77.709733  Lock_time: 0.000087 Rows_sent: 0  Rows_examined: 20919 use keystone; SET timestamp=1371436405; SELECT token.id AS token_id, token.expires AS token_expires, token.extra AS token_extra, token.valid AS token_valid, token.user_id AS token_user_id, token.trust_id AS token_trust_id FROM token WHERE token.expires > '2013-06-17 02:32:08' AND token.valid = 0;

그냥 무식하게 DELETE 하기 전의 token 테이블에 걸린 slow query를 보면 위와 같은데... expires, valid에 index를 걸어주면 좀 더 빠른 실행이 가능하지 않을까?

mysql> explain select id from token where expires > '2013-06-17 02:32:08' AND token.valid = 0;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | token | ALL  | NULL          | NULL | NULL    | NULL |  492 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

mysql> create index idx_token_expires_valid on token(expires, valid);
Query OK, 0 rows affected (0.09 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> explain select id from token where expires > '2013-06-17 02:32:08' AND token.valid = 0;
+----+-------------+-------+-------+-------------------------+-------------------------+---------+------+------+--------------------------+
| id | select_type | table | type  | possible_keys           | key                     | key_len | ref  | rows | Extra                    |
+----+-------------+-------+-------+-------------------------+-------------------------+---------+------+------+--------------------------+
|  1 | SIMPLE      | token | index | idx_token_expires_valid | idx_token_expires_valid | 10      | NULL |  492 | Using where; Using index |
+----+-------------+-------+-------+-------------------------+-------------------------+---------+------+------+--------------------------+
1 row in set (0.00 sec)

explain에 보듯이, 해당 slow query는 index를 타고 있다. 이제 일주일 후에도 같은 증상이 발생하는지 확인해보자..

추가) 그리고 어떤 녀석이 이런 token을 무지막지하게 만들어 내는지 확인해볼 필요가 있다.

mysql> select user_id, count(*) from token group by user_id;
+----------------------------------+----------+
| user_id                          | count(*) |
+----------------------------------+----------+
| 36068019a00e427c8c8e97e8a3cee8a2 |        1 |
| 5700bfc6b03b476f97021e5eede7989e |        4 |
| 8232fea985ff44c0be44b0473cac5fac |      557 |
+----------------------------------+----------+
3 rows in set (0.02 sec)

위 처럼 특정 user_id에 의해서 집주적으로 토큰이 발생하는 것을 확인할 수 있으며

mysql> select id, name from user;
+----------------------------------+---------+
| id                               | name    |
+----------------------------------+---------+
| 5700bfc6b03b476f97021e5eede7989e | admin   |
| f09f583150f24c72a3a3ef1e1b12ae7d | cinder  |
| 8152fd3ea78a477eb096e829aa2e0bce | demo    |
| dcabff792209441794a4256f6611f43e | glance  |
| 36068019a00e427c8c8e97e8a3cee8a2 | nova    |
| 8232fea985ff44c0be44b0473cac5fac | quantum |
+----------------------------------+---------+
6 rows in set (0.00 sec)

처럼 quantum 서비스에 의해서 발생됩니다. quantum의 plugin 들이지요.

update 1) 저 무지막지한 토큰은 quantum에 의해 발생하는 것이 아니라, nova 서비스에서 quantum을 사용하면서 keystone token을 재사용하지 않아서 발생하는 문제입니다. 소스는 잊어버렸...

update 2) Launchpad에 버그가 등록되어 있습니다.

update 3) 이 문제를 해결하는 가장 간단한 방법은 token driver를 memcache로 변경하는 것이다.

[token]
driver = keystone.token.backends.memcache.Token

ceph as OpenStack instance storage backend

이 전 포스트에서 GlusterFS를 instance storage backend로 사용했었습니다. Ceph는 GlusterFS에 비해서 콤포넌트도 많고, 설치 과정도  복잡해서 "보여서" 우선 GlusterFS로 했었지요. 이번에는 Ceph로 live migration을 할 수 있게 instance storage backend로 설정해 봤습니다.

GlusterFS와 다르게 Ceph는 swift, {nova,cinder}-volume과 통합도 준비되어 있지만, 현재 목적에 맞지 않기에 여기서는 다루지 않습니다.

Overview

설치 전에 우선 Ceph의 구성을 알아보면, mon, mds, osd 세가지 프로세스로 구성되어 있으며, 각각의 기능은 대략 아래와 같습니다.

  • mon: cluster의 상태등의 데이터를 관리
  • mds: CephFS에 제공하는 메타정보 데이터 관리
  • osd: 데이터 저장, replication, recovery 등을 제공하고, mon 프로세스에 모니터링 정보를 제공

Ceph를 instance storage backend로 사용하기 위해서는 glusterfs와 마찬가지로 /var/lib/nova/instance 디렉토리를 cephfs로 마운트하여 사용합니다. qemu에서 librbd를 이용하여 직접 Ceph를 접근할 것으로 예상했지만 {nova,cinder}-volume은 문서상에 librbd를 이용하도록 나와있는 반면에, instance storage의 경우는 별도의 안내가 없습니다(제가 못찾은건지 모르겠지만....).

또한 ceph cluster를 별도로 구성하는 것을 권장하지만, 실험 환경이기 때문에 compute 노드에 osd를 glance 노드에 mon, msd를 구성하기로 합니다.

참고로 권장하는 최소 구성은 아래와 같습니다.

  • (mon + mds) x 3
  • osd x 3

권장은 저렇고, 제 테스트 환경에서는 충분한 노드가 없기 때문에 glusterfs 경우처럼 compute node에 osd를 glance 노드에 mon + mds, 그리고  control 노드에 ceph-deploy를 준비합니다.

설치 준비

Ceph의 설치는 ceph-deploy를 이용합니다. 이전 버전에서는 mkcephfs 등의 툴을 이용했었지만, 이제는 ceph-deploy를 이용해서 셋업합니다. ceph-deploy는 ssh로 설치하려는 노드에 접속하여 sudo를 통해 패키지 설치, 설정 등을 자동으로 진행합니다. chef, puppet, juju등 자동화 툴로 설치할 필요가 없다고 설명하고 있습니다.

ceph-deploy를 실행할 노드를 ceph admin 노드라고하고, 여기에서는 아래 준비가 필요합니다.

  • ceph 계정 만들기
  • ceph 계정의 private / public key 만들기
  • ceph 패키지 설치

ceph가 설치될 mon, mds, osd 가 실행될 노드에는 아래의 준비가 필요합니다.

  • ceph 계정 만들기
  • ceph 계정의 sudo 허용
  • admin 노드에서 생성된 public key로 접속 허용
  • ceph 패키지 설치: ceph-deploy가 패키지 설치를 하지만, 미러를 사용한다면 직접 설치를..

ceph 패키지 설치: 모든 노드

$ wget -q -O- 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/release.asc' | sudo apt-key add - 
$ echo deb http://ceph.com/debian-cuttlefish/ $(lsb_release -sc) main | sudo tee /etc/apt/sources.list.d/ceph.list
$ apt-get install ceph

ceph 유저 생성: 모든 노드

$ useradd -m ceph

sudoer에 등록: 모든 노드

ceph-deploy는 ssh로 ceph@node로 들어가서 sudo를 이용하여 설정을 하기 때문에 sudoer에 등록한다.

$echo "ceph ALL = (root) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/ceph

ceph keypair 생성: admin 노드

$ su - ceph
$ ssh-keygen -t rsa -q -f /home/ceph/.ssh/id_rsa -P ""

ceph-deploy가 실행할 환경 설정

여기서 생성된 /home/ceph/.ssh/id_rsa.pub 파일을 모든 노드에 /home/ceph/.ssh/authorized_keys로 복사한다. 그리고 admin 노드의 ssh 설정을 아래처럼 하여 ssh hostname으로 ceph 유저로 로그인할 수 있도록 한다. 몰론 ceph-deploy가 접속한 모든 노드 (mon, mds, osd)를 모두 등록한다.

$ more ~/.ssh/config
Host compute01
Hostname compute01.stack
User ceph

....

그리고 처음으로 ssh로 연결하면 ssh key 확인 메시지가 뜨는데, 이를 없애기 위해서 미리 아래처럼 ssh server public key를 등록한다.

$ ssh-keyscan compute01.stack >> .ssh/known_hosts

모든게 정상적으로 설정 되었다면 아래 명령을 내렸을 때 아무런 입력 없이 바로 실행이 되어야 한다.

$ ssh compute01 sudo ls /

cluster 생성

클러스터 생성은 monitor 노드의 호스트를 지정하여 시작합니다. 여기서는 glance 노드를 monitor, mds로 사용하기로 했으므로 아래처럼 합니다.

$ ceph-deploy -v new glance
$ ls
ceph.conf ceph.log ceph.mon.keyring

실행하면 지정한 모니터로 ceph.conf 파일과 ceph.mon.keyring 파일을 생성합니다. 아직까지는 설정 파일만 만든 상태입니다.

만든 설정 파일을 monitor 호스트로 복사하고, 서비스를 시작하는 명령은 아래와 같습니다.

$ ceph-deploy -v mon create glance
Deploying mon, cluster ceph hosts glance
Deploying mon to glance
Distro Ubuntu codename precise, will use upstart

monitor 호스트인 glance에서 프로세스를 보면 ceph-mon 프로세스가 돌아가는 것을 확인할 수 있다. 그리고 glance 호스트에 보면 설정파일이 /etc/ceph/ceph.conf로 복사된 것을 확인할 수 있으며 /etc/ceph/ceph.client.admin.keyring 으로 어드민 키링이 생성된 것을 확인할 수 있다.

gatherkey 명령으로 monitor에 생성된 키를 가져온다.

$ ceph-deploy -v gatherkeys glance
Checking glance for /etc/ceph/ceph.client.admin.keyring
Got ceph.client.admin.keyring key from glance.
Have ceph.mon.keyring
Checking glance for /var/lib/ceph/bootstrap-osd/ceph.keyring
Got ceph.bootstrap-osd.keyring key from glance.
Checking glance for /var/lib/ceph/bootstrap-mds/ceph.keyring
Got ceph.bootstrap-mds.keyring key from glance.

ceph.client.admin.keyring, ceph.bootstrap-osd.keyring, ceph.bootstrap-mds.kerying 파일을 가져왔다. 이 키들은 osd, mds에서 사용된다. 여기서 가저온 ceph.client.admin.keyring은 아래처럼 사용할 수 있다.

$ ceph -c ceph.conf -k ceph.client.admin.keyring mon stat
e1: 1 mons at {glance=10.100.0.8:6789/0}, election epoch 2, quorum 0 glance

mds 설치: admin 노드

mds는 cephfs를 사용(cephfs로 마운트)한다면 필요한 것으로, rbd를 사용한다면 설치할 필요는 없다. 우리는 /var/lib/nova/instance를 cephfs로 마운트해서 사용할 것이므로 mds를 설치한다.

마찬가지로 glance host에 설치한다.

$ ceph-deploy -v mds create glance
Deploying mds, cluster ceph hosts glance:glance
Distro Ubuntu codename precise, will use upstart
Deploying mds bootstrap to glance
Host glance is now ready for MDS use.
Deploying mds.glance to glance

역시 glance 호스트에 보면 ceph-mds 프로세스가 떠있는 것을 확인할 수 있다.

osd 설치

osd는 ceph에 저장되는 데이터가 실제로 저장되는 곳입니다. disk와 journal로 구성이 됩니다.

Disk는 block device 또는 directory이고, 별도의 디스크를 권장하지만, 여기서는 /ceph/disk 디렉토리를 사용하겠습니다. 그리고 디렉토리를 사용할 경우 btrfs 또는 xfs를 권장하고 있지만, 여기서는 그냥 기존 파일 시스템에 쓰겠습니다.

Journal은 SSD를 권장하지만, 그냥 파일로 /ceph/journal 을 사용하겠습니다.

따라서 osd 노드에서는 아래처럼 미리 디렉토리를 생성합니다.

$ mkdir -p /ceph/disk

이제 osd를 설치합니다.

$ ceph-deploy -v osd create compute01:/ceph/disk:/ceph/journal
Preparing cluster ceph disks compute01:/ceph/disk:/ceph/journal
Deploying osd to compute01
Host compute01 is now ready for osd use.
Preparing host compute01 disk /ceph/disk journal /ceph/journal activate True

패키지가 설정되고, /etc/ceph/ceph.conf 파일이 복사됩니다. 하지만 아직은 osd가 활성화되지는 않았고, 아래처럼 활성화합니다.

$ ceph-deploy -v osd activate compute01:/ceph/disk:/ceph/journal
Activating cluster ceph disks compute01:/ceph/disk:/ceph/journal
Activating host compute01 disk /ceph/disk
Distro Ubuntu codename precise, will use upstart

이제 ceph-osd 프로세스가 시작되었으며, 아래처럼 osd가 하나 등록된 것을 확인할 수 있습니다.

$ ceph -c ceph.conf -k ceph.client.admin.keyring osd stat
e5: 1 osds: 1 up, 1 in

그리고 osd 노드에서도 ceph 관련 명령을 수행할 수 있게 admin 키를 보냅니다.

$ ceph-deploy -v admin compute01
Pushing admin keys and conf to compute01

이 키가 있어야 아래처럼 osd 노드에서도 ceph 명령을 수행할 수 있습니다.

ceph@compute01:~$ ceph osd stat
e5: 1 osds: 1 up, 1 in

마찬가지로 compute02, compute03도 설치합니다.

instance 디렉토리 마운트

아래처럼 인스턴스 디렉토리를 마운트 합니다.

$ mount -t ceph 10.100.0.8:6789:/ /var/lib/nova/instances -o name=admin,secretkey=AQA+QrVRYNAnFhAAcN68f1a7xFqBzsSEqXQHmg==

10.100.0.8은 monitor 노드이고 secretkey는 /etc/ceph/ceph.admin.client.keyring에 있는 키를 사용합니다.

live migration

live migration 설정 및 방법은 glusterfs의 경우와 같습니다. 단 glustefs의 경우에는 VIR_MIGRATE_UNSAFE 옵션이 있어야 했지만, ceph의 경우는 해당 옵션이 없이 기본 값으로도 live migration이 됩니다.

$ nova show cirros1
+-------------------------------------+------------------------------------------------------------+
| Property                            | Value                                                      |
+-------------------------------------+------------------------------------------------------------+
| status                              | ACTIVE                                                     |
| updated                             | 2013-06-10T03:59:04Z                                       |
| OS-EXT-STS:task_state               | None                                                       |
| OS-EXT-SRV-ATTR:host                | compute02                                                  |
| key_name                            | admin                                                      |
| image                               | cirros-0.3.1-x86_64 (4f494d0b-ebdc-4ebd-8afc-8df804eaaf4e) |
| hostId                              | 4cf03b72c10726d78424eb6b1a62ddc4762cbbd1b148b8d684020c5b   |
| OS-EXT-STS:vm_state                 | active                                                     |
| OS-EXT-SRV-ATTR:instance_name       | instance-00000003                                          |
| OS-EXT-SRV-ATTR:hypervisor_hostname | compute01.stack                                            |
| flavor                              | m1.tiny (1)                                                |
| id                                  | a01a3bd7-6e49-485a-afc3-88c5b7c401d5                       |
| security_groups                     | [{u'name': u'default'}]                                    |
| user_id                             | 5700bfc6b03b476f97021e5eede7989e                           |
| name                                | cirros1                                                    |
| created                             | 2013-06-10T03:57:17Z                                       |
| tenant_id                           | 6f524cc90eb54f4b99ac70f3a3c070a7                           |
| OS-DCF:diskConfig                   | MANUAL                                                     |
| metadata                            | {}                                                         |
| admin network                       | 10.250.0.4                                                 |
| accessIPv4                          |                                                            |
| accessIPv6                          |                                                            |
| progress                            | 0                                                          |
| OS-EXT-STS:power_state              | 1                                                          |
| OS-EXT-AZ:availability_zone         | nova                                                       |
| config_drive                        |                                                            |
+-------------------------------------+------------------------------------------------------------+
$ nova live-migration cirros1 compute01
$ nova show cirros1
+-------------------------------------+------------------------------------------------------------+
| Property                            | Value                                                      |
+-------------------------------------+------------------------------------------------------------+
| status                              | ACTIVE                                                     |
| updated                             | 2013-06-10T04:03:03Z                                       |
| OS-EXT-STS:task_state               | None                                                       |
| OS-EXT-SRV-ATTR:host                | compute01                                                  |
| key_name                            | admin                                                      |
| image                               | cirros-0.3.1-x86_64 (4f494d0b-ebdc-4ebd-8afc-8df804eaaf4e) |
| hostId                              | beeddd176ef0ed6fdd0c7a04b376ee05dcda276e0596760ea021d649   |
| OS-EXT-STS:vm_state                 | active                                                     |
| OS-EXT-SRV-ATTR:instance_name       | instance-00000003                                          |
| OS-EXT-SRV-ATTR:hypervisor_hostname | compute01.stack                                            |
| flavor                              | m1.tiny (1)                                                |
| id                                  | a01a3bd7-6e49-485a-afc3-88c5b7c401d5                       |
| security_groups                     | [{u'name': u'default'}]                                    |
| user_id                             | 5700bfc6b03b476f97021e5eede7989e                           |
| name                                | cirros1                                                    |
| created                             | 2013-06-10T03:57:17Z                                       |
| tenant_id                           | 6f524cc90eb54f4b99ac70f3a3c070a7                           |
| OS-DCF:diskConfig                   | MANUAL                                                     |
| metadata                            | {}                                                         |
| admin network                       | 10.250.0.4                                                 |
| accessIPv4                          |                                                            |
| accessIPv6                          |                                                            |
| progress                            | 0                                                          |
| OS-EXT-STS:power_state              | 1                                                          |
| OS-EXT-AZ:availability_zone         | nova                                                       |
| config_drive                        |                                                            |
+-------------------------------------+------------------------------------------------------------+

아마도 이 영향인 것인지 live migration이 glusterfs에 비해서 약간 느리다는 인상을 받았습니다.

update) OpenStack 관련 문서에는 없지만, libvirtd 항목에 보면 rbd를 사용할 수 있습니다. 이건 나중에... ^^;


glusterfs as OpenStack instance storage backend

OpenStack에서 Live migration을 지원하려면 기본적으로 shared storage가 있어야 한다. 지금 요구사항 중의 하나가 장애에 대비한 live migration이라 shared storage를 설정해야했다.

요즘 대세는 Ceph이라고, 저번 오픈스택 모임에서 그랬는데, 잠깐 Ceph를 시도해본 결과, 설치과정이 그리 맘에 들지 않습니다. 그래요 완전히 개인적인 생각입니다.

그래서 상대적으로 쉬운 GlusterFS를 먼저 해보고려 합니다.

GlusterFS를 한다면 GlusterFS is Ready for OpenStack이라고 발표를 했는데, 문제는 아직 Beta 단계인 3.4 이야기이고, 자신들의 OpenStack Distribution인 RDO에 테스트 해 봤다는 이야기입니다.

내용을 보면 Instance Storage도 libgfapi를 이용해서 glusterfs에 직접 IO를 통해서 합니다. 그래서 중간의 파일 시스템에서 생기는 성능/ 캐쉬 등등의 문제를  없앴죠. Ceph도 그렇구요. 이거 제대로 된다면 바로 적용해 보려고 했지만... Ubuntu Package가 아직 없어요.. 그래서 정식 버전이 나오기 전에는 3.2에서 테스트 하기로 했습니다. 아고 서론이 길었어요.

Overview

테스트 환경에서는 별도의 glusterfs cluster를 구성하지 않고 glusterfs server는 compute node에 설치하기로 했습니다(아마도 별 문제 없으면 실제로도 그렇게 갈 생각이구요). 그리고 각 compute node는 /var/lib/nova/instance를 glusterfs localhost로 마운트 합니다.

Gluster FS 설치

간단히 각 compute node에서 설치합니다.

$ apt-get install glusterfs-server

Peer probe

$ gluster peer probe compute02.stack
$ gluster peer probe compute03.stack

Volume create

$ gluster volume create vm-instances replica 3 \
      compute01.stack:/gluster/instances \
      compute02.stack:/gluster/instances \
      compute03.stack:/gluster/instances

물론 각 compute node에는 만드려는 brick의 디렉토리인 /gluster/instance를 미리 만들어야합니다.

Volume start

$ gluster volume start vm-instances

마운트

마운트 하기 전에 아무런 인스턴스들이 생성되지 않은 상태로 합니다.

$ mount -t glusterfs localhost:vm-instances /var/lib/nova/instances

마운트하면 인스턴스 디렉토리의 소유권이 root.root가 되는데, nova.nova로 수정합니다. 신기하게도 이거 바꾸면 다른 노드도 같이 수정이 되는군요.

$ chown nova.nova /var/lib/nova/instances

한쪽 compute 노드에서 파일을 생성하면, 다른 컴퓨터 노드에도 같이 보이는 것을 확인할 수 있습니다.

nova.conf 설정

live migration을 하지 않는다면, 별도로 수정할 내용은 없습니다. 파일 권한이 제대로 되어있다면 바로 인스턴스를 생성 가능하고, 생셩된 인스턴스 파일은 다른 컴퓨트 노드에서 잘 보입니다.

live migration

Live Migration을 하려면 우선 OpenStack에 있는데로 설정합니다. 그런데 이 상태로 live migration을 하면 바로 아래처럼 오류가 발생합니다.

2013-06-03 11:52:20.743 11492 ERROR nova.virt.libvirt.driver [-] [instance: 4717b4d4-61a7-4f4d-b5fc-5ff526822e89] Live Migration failure: Unsafe migration: Migration may lead to data corruption if disks use cache != none

이것은 libvirt가 live migration을 할 때 안정성을 이유로 디스크 캐쉬가 된 상태에서는 live migration을 수행하지 않습니다. nova.conf에서 disk_modes=file=none,block=none 형태로 캐쉬를 안해주면 되겠지만, 이렇게 하고 하면 인스턴스를 생성할 때 부터 문제가 생깁니다. ㅎㅎ

그래서 불안정하게라도 live migration 하겠다고 하면 디스크가 캐쉬가 된 상태도 라이브 마이그레이션을 지원합니다. 이를 설정하면 nova.conf에 아래처럼 설정합니다.

live_migration_flag=VIR_MIGRATE_UNDEFINE_SOURCE, \
        VIR_MIGRATE_PEER2PEER, \
        VIR_MIGRATE_LIVE, \
        VIR_MIGRATE_UNSAFE

마지막의 VIR_MIGRATE_UNSAFE가 그것이죠.

어렇게 하고 live migration을 하면 잘 되는 것이죠.

root@control:~# nova show cirros1
+-------------------------------------+------------------------------------------------------------+
| Property                            | Value                                                      |
+-------------------------------------+------------------------------------------------------------+
| status                              | ACTIVE                                                     |
| updated                             | 2013-06-03T07:17:53Z                                       |
| OS-EXT-STS:task_state               | None                                                       |
| OS-EXT-SRV-ATTR:host                | compute01                                                  |
| key_name                            | admin_key                                                  |
| image                               | cirros-0.3.1-x86_64 (f81518a9-9dc2-4a2a-aeaf-331cc074d063) |
| hostId                              | a2b92d1a2237ab4772f395b2fde3e462bfad9420e0ffc33ad3d1a19d   |
| OS-EXT-STS:vm_state                 | active                                                     |
| OS-EXT-SRV-ATTR:instance_name       | instance-00000011                                          |
| OS-EXT-SRV-ATTR:hypervisor_hostname | compute01.stack                                            |
| flavor                              | m1.tiny (1)                                                |
| id                                  | 2991ad7d-b33e-4d3c-828b-da07338119f1                       |
| security_groups                     | [{u'name': u'default'}]                                    |
| user_id                             | 8f5b56a6a51c45338b0c1ba7cd7d9ebb                           |
| name                                | cirros1                                                    |
| created                             | 2013-06-03T06:21:27Z                                       |
| tenant_id                           | b5db61c3fa3845848b0f15c010dd500c                           |
| OS-DCF:diskConfig                   | MANUAL                                                     |
| metadata                            | {}                                                         |
| admin network                       | 10.250.0.2                                                 |
| accessIPv4                          |                                                            |
| accessIPv6                          |                                                            |
| progress                            | 0                                                          |
| OS-EXT-STS:power_state              | 1                                                          |
| OS-EXT-AZ:availability_zone         | nova                                                       |
| config_drive                        |                                                            |
+-------------------------------------+------------------------------------------------------------+

cirros1은 compute01에 있습니다. 이를 compute02로 옮긴다면..

root@control:~# nova live-migration cirros1 compute02

이제 compute02로 이사갔어요...

root@control:~# nova show cirros1
+-------------------------------------+------------------------------------------------------------+
| Property                            | Value                                                      |
+-------------------------------------+------------------------------------------------------------+
| status                              | MIGRATING                                                  |
| updated                             | 2013-06-03T07:18:59Z                                       |
| OS-EXT-STS:task_state               | migrating                                                  |
| OS-EXT-SRV-ATTR:host                | compute01                                                  |
| key_name                            | admin_key                                                  |
| image                               | cirros-0.3.1-x86_64 (f81518a9-9dc2-4a2a-aeaf-331cc074d063) |
| hostId                              | a2b92d1a2237ab4772f395b2fde3e462bfad9420e0ffc33ad3d1a19d   |
| OS-EXT-STS:vm_state                 | active                                                     |
| OS-EXT-SRV-ATTR:instance_name       | instance-00000011                                          |
| OS-EXT-SRV-ATTR:hypervisor_hostname | compute01.stack                                            |
| flavor                              | m1.tiny (1)                                                |
| id                                  | 2991ad7d-b33e-4d3c-828b-da07338119f1                       |
| security_groups                     | [{u'name': u'default'}]                                    |
| user_id                             | 8f5b56a6a51c45338b0c1ba7cd7d9ebb                           |
| name                                | cirros1                                                    |
| created                             | 2013-06-03T06:21:27Z                                       |
| tenant_id                           | b5db61c3fa3845848b0f15c010dd500c                           |
| OS-DCF:diskConfig                   | MANUAL                                                     |
| metadata                            | {}                                                         |
| accessIPv4                          |                                                            |
| accessIPv6                          |                                                            |
| admin network                       | 10.250.0.2                                                 |
| OS-EXT-STS:power_state              | 1                                                          |
| OS-EXT-AZ:availability_zone         | nova                                                       |
| config_drive                        |                                                            |
+-------------------------------------+------------------------------------------------------------+

Update: Andrew님의 제보에 의하면 3.2 버전에서는 파일 싱크할 때 파일이 read only로 걸려서 instance도 read lock이 걸리는 현상이 있다는군요. 3.3 부터는 OK


OpenStack havana에 기대하는 몇가지…

요즘 grizzly 버전가지고 열심히 놀구 있습니다. 써보니깐.. private cloud까지는 훌륭히 만들 수 있을 것 같아요..

그러다 havana 릴리스에 어떤 blue print가 있는가 대충 훑어봤는데, 그중에 몇 개 이야기 해봅니다.

Support for Quantum L3 plugin in Devstack

l3 agent는 linux box에서 돌아가도록 되어있습니다. plugin 형태로 구축하면 hardware 장비를 조절하여 l3의 기능을 처리할 수 있겠죠. 이렇게 하면 l3 agent host에 부하가 줄어들어 보다 안정적인 서비스를 할 수 있습니다.

게다가 인프라 쪽은 s/w 보다는 h/w를 믿는 경향(?)이 있어서, 이게 더 심리적인 안정감을 줄 것 같습니다.

Enable loadbalancing vendors to implement their drivers - step0

이것도 위와 마찬가지로, haproxy로 되어있는 구성을 l4 장비를 이용해서 처리하는 기능이죠.

Dynamic DNS support for instances

aws ec2처럼 dns로 연결하고 싶습니다.

IPSec VPNaaS Python APIs / CRUD Operations

VPN은 public cloud를 한다면 필요한 기능입니다. havana까지는 api가 정리가 될 것 같고, 다음 릴리스에서는 뭔가 사용할 만한 결과물이 나오겠지요. OpenVPN을 이용한 client vpn, site-to-site vpn이면 훌륭합니다.

nova-network에서는 CloudPipe에서 지원했었지만, 아직 Quantum에는 없네요.

QoS API implementation: OpenVSwitch w/ DSCP

네트워크 서비스에 QoS는 기본이겠죠? 옆에 누군가가 엄청나게 네트워크를 써 버린다면.. ㅎㅎ

Ceilometer

metering입니다. 즉 어느 사용자가 얼마나 사용했는지를 나타냅니다. 효율을 측정하기 위해서는 반드시 필요하겠죠?

grizzly에 들어가긴 했지만, havana에 제대로 들어갈 예정입니다.

Heat

Heat는 CloudFormation 처럼 web site stack을 정의하고, 그에 따라서 API를 이용하여 OpenStack을 설정하는 콤포넌트 입니다. 이 기능보다 제가 주목하고 있는 것은 여기에 AutoScaling 기능이 들어간다는 점이죠.

역시 주 관심사가 Quantum이라 네트워크가 대부분이군요. ^^


  • Copyright © 1996-2010 Your wish is my command. All rights reserved.
    iDream theme by Templates Next | Powered by WordPress