반응형

Host OS: Ubuntu 14.04 (amd64)

Linux Container template: ubuntu



우분투 데스크탑과 우분투 서버에서는 문제가 없었지만, 우분투 템플릿으로 Linux Container (LXC)를 새로 생성하고 나서 새로운 패키지를 추가하려고 하면 add-apt-repository 명령이 없다고 에러 메세지가 나온다.


이 때 먼저 software-properties-common 패키지를 설치하고 나면 add-apt-repository를 쓸 수 있다.


$ sudo apt-get -y install software-properties-common




*참고


참고로 add-apt-repository 명령을 치면 무조건 사용자에게 추가할 것인지 한 차례 물어보고 엔터 키를 치면 진행을 하게 되는데, 여기서 사용자의 입력을 생략하고 무조건 실행되도록 하려면 맨 끝에 -y 옵션을 주면 된다. [1]


$ sudo add-apt-repository ppa:openjdk-r/ppa -y


위 예시는 openjdk 패키지를 설치하기 위한 ppa를 추가한 것이다.


일반적인 우분투 터미널에서는 결국 sudo privilege를 얻기 위해서 사용자 패스워드를 입력해야만 하지만, 적어도 기본적으로 root 계정으로 켜지는 Linux Container의 경우에는 저렇게 해 주면 자동으로 진행되므로 편한 점이 있다.


# add-apt-repository ppa:openjdk-r/ppa -y




<참고자료>

[1] http://askubuntu.com/questions/304178/how-do-i-add-a-ppa-in-a-shell-script-without-user-input




반응형
블로그 이미지

Bryan_

,
반응형

Host OS: Ubuntu 16.04 (amd64)

Host Spec (VM): Quad core 2.6GHz (Intel Zeon, Haswell), 4GB RAM

LXC template: ubuntu



지난 여름에는 라즈베리파이 4개를 가지고 무선 메쉬 네트워크를 만들고, 각각의 라즈베리파이가 AP 역할을 함으로써 서로 다른 AP에 물린 클라이언트들 사이에 통신이 되도록 하였고, 이를 중개하는 multi-constrained 라우팅 프로토콜을 Java로 개발해서 테스트를 했었다.


사실 성능을 생각하면 C로 개발해야 하지만 무지막지하게 늘어나는 개발 시간 때문에 그나마 익숙하게 다룰 수 있는 Java로 개발을 했었고, 이제 와서 보니 이게 ns-3에서 시뮬레이션을 돌릴 때 결국 C나 파이썬으로 포팅해야 되는 어려움으로 돌아오고 말았다. ㄷㄷ


하지만 ns-3는 real-world program을 돌릴 수 있는 몇 가지 방법을 제시하고 있었고, 그 중에서 Linux Container (LXC)를 이용한 방법이 있어서 튜토리얼을 따라하며 환경을 구축해 보았다.


실제로 예제를 그대로 따라해서 2개의 노드가 IEEE 802.11g로 서로 애드혹 네트워크로 연결되고 각각의 노드에서 ping, ssh 등을 테스트하는 데에는 아무 문제가 없었다.

여기서 더 나가서 내가 개발한 Java 기반의 라우팅 프로토콜을 실행시키는 과정이 생각보다 오래 걸렸지만, 이것도 각 컨테이너를 인터넷에 먼저 연결시키고 apt-get으로 필요한 패키지를 다 설치하고 나니 어쨌든 내가 라즈베리파이에서 돌리던 모양 그대로 실행시킬 수 있었다.


여기까지는 일단 그대로 실행이 되는지부터 봐야 해서 노드 3개까지만 만들어서 해 본 거였고, 이제 본격적으로 시뮬레이션을 돌리기 위해서 노드 생성과 Java 프로그램 실행을 자동화하는 스크립팅 작업을 했는데 이것 또한 시간이 은근히 많이 걸렸다. ㅜㅜ


우여곡절 끝에 이제 내가 마음대로 원하는 만큼의 노드(컨테이너)를 자동으로 생성/실행할 수 있게 되었고, 네트워크 토폴로지는 ns-3에서 역시나 마음대로 설정해 주면 되었다.


드디어 대망의 첫 실험...

자신있게 10개의 노드를 명령어 한 줄로 간지나게(?) 자동으로 뙇 생성하고, 토폴로지는 4-4-2 그리드 형태로 만든 다음, 실험 시작을 누르고 나서 시범적으로 9번 노드에서 이웃 노드인 10번 노드한테 ping을 날려 봤더니...


root@node9:/# ping 10.0.0.10

PING 10.0.0.10 (10.0.0.10) 56(84) bytes of data.

64 bytes from 10.0.0.10: icmp_seq=1 ttl=64 time=3665 ms

64 bytes from 10.0.0.10: icmp_seq=2 ttl=64 time=4356 ms

64 bytes from 10.0.0.10: icmp_seq=3 ttl=64 time=5375 ms

64 bytes from 10.0.0.10: icmp_seq=4 ttl=64 time=7245 ms

64 bytes from 10.0.0.10: icmp_seq=5 ttl=64 time=8166 ms

64 bytes from 10.0.0.10: icmp_seq=6 ttl=64 time=9149 ms

64 bytes from 10.0.0.10: icmp_seq=7 ttl=64 time=10225 ms

64 bytes from 10.0.0.10: icmp_seq=8 ttl=64 time=11106 ms

64 bytes from 10.0.0.10: icmp_seq=9 ttl=64 time=12252 ms

64 bytes from 10.0.0.10: icmp_seq=10 ttl=64 time=13146 ms

64 bytes from 10.0.0.10: icmp_seq=11 ttl=64 time=14062 ms

64 bytes from 10.0.0.10: icmp_seq=12 ttl=64 time=15261 ms

64 bytes from 10.0.0.10: icmp_seq=13 ttl=64 time=16784 ms

64 bytes from 10.0.0.10: icmp_seq=14 ttl=64 time=18056 ms

64 bytes from 10.0.0.10: icmp_seq=15 ttl=64 time=19286 ms

64 bytes from 10.0.0.10: icmp_seq=16 ttl=64 time=20347 ms

64 bytes from 10.0.0.10: icmp_seq=17 ttl=64 time=21576 ms

64 bytes from 10.0.0.10: icmp_seq=18 ttl=64 time=22208 ms

64 bytes from 10.0.0.10: icmp_seq=19 ttl=64 time=22970 ms

64 bytes from 10.0.0.10: icmp_seq=20 ttl=64 time=23673 ms

64 bytes from 10.0.0.10: icmp_seq=21 ttl=64 time=24549 ms

64 bytes from 10.0.0.10: icmp_seq=22 ttl=64 time=24565 ms

64 bytes from 10.0.0.10: icmp_seq=23 ttl=64 time=24311 ms

64 bytes from 10.0.0.10: icmp_seq=24 ttl=64 time=24205 ms

64 bytes from 10.0.0.10: icmp_seq=25 ttl=64 time=23996 ms

64 bytes from 10.0.0.10: icmp_seq=26 ttl=64 time=23627 ms

64 bytes from 10.0.0.10: icmp_seq=27 ttl=64 time=23452 ms

64 bytes from 10.0.0.10: icmp_seq=28 ttl=64 time=23325 ms

64 bytes from 10.0.0.10: icmp_seq=29 ttl=64 time=23048 ms

64 bytes from 10.0.0.10: icmp_seq=30 ttl=64 time=22669 ms

64 bytes from 10.0.0.10: icmp_seq=31 ttl=64 time=22337 ms

64 bytes from 10.0.0.10: icmp_seq=32 ttl=64 time=21869 ms

64 bytes from 10.0.0.10: icmp_seq=33 ttl=64 time=21127 ms

64 bytes from 10.0.0.10: icmp_seq=34 ttl=64 time=20186 ms

64 bytes from 10.0.0.10: icmp_seq=35 ttl=64 time=19246 ms

64 bytes from 10.0.0.10: icmp_seq=36 ttl=64 time=18327 ms

64 bytes from 10.0.0.10: icmp_seq=37 ttl=64 time=17383 ms

64 bytes from 10.0.0.10: icmp_seq=38 ttl=64 time=16449 ms

64 bytes from 10.0.0.10: icmp_seq=39 ttl=64 time=15512 ms

64 bytes from 10.0.0.10: icmp_seq=40 ttl=64 time=14573 ms

64 bytes from 10.0.0.10: icmp_seq=41 ttl=64 time=13607 ms

64 bytes from 10.0.0.10: icmp_seq=42 ttl=64 time=12676 ms

64 bytes from 10.0.0.10: icmp_seq=43 ttl=64 time=11745 ms

64 bytes from 10.0.0.10: icmp_seq=44 ttl=64 time=10816 ms

64 bytes from 10.0.0.10: icmp_seq=45 ttl=64 time=9876 ms

64 bytes from 10.0.0.10: icmp_seq=46 ttl=64 time=8953 ms

64 bytes from 10.0.0.10: icmp_seq=47 ttl=64 time=8012 ms

64 bytes from 10.0.0.10: icmp_seq=48 ttl=64 time=7037 ms

64 bytes from 10.0.0.10: icmp_seq=49 ttl=64 time=6042 ms

64 bytes from 10.0.0.10: icmp_seq=50 ttl=64 time=5064 ms

64 bytes from 10.0.0.10: icmp_seq=51 ttl=64 time=4069 ms

64 bytes from 10.0.0.10: icmp_seq=52 ttl=64 time=3074 ms

64 bytes from 10.0.0.10: icmp_seq=53 ttl=64 time=2080 ms

64 bytes from 10.0.0.10: icmp_seq=54 ttl=64 time=1087 ms

64 bytes from 10.0.0.10: icmp_seq=55 ttl=64 time=102 ms

64 bytes from 10.0.0.10: icmp_seq=56 ttl=64 time=5.94 ms

64 bytes from 10.0.0.10: icmp_seq=57 ttl=64 time=5.57 ms

64 bytes from 10.0.0.10: icmp_seq=58 ttl=64 time=5.82 ms

64 bytes from 10.0.0.10: icmp_seq=59 ttl=64 time=5.49 ms

64 bytes from 10.0.0.10: icmp_seq=60 ttl=64 time=5.55 ms

^C

--- 10.0.0.10 ping statistics ---

60 packets transmitted, 60 received, 0% packet loss, time 59063ms

rtt min/avg/max/mdev = 5.498/13466.053/24565.805/8177.166 ms, pipe 25

root@node9:/# 



Aㅏ...

저기 중간에 점도 찍히지 않고 당당하게 5자리를 찍어주는 저 결과는 뭥미?

24205는 뭔가요? 저게 진정 와이파이 RTT인가여? 털썩...


각 컨테이너에서 아무 프로그램도 돌고 있지 않을 때는 이웃노드 간에 ping을 날리면 약 5ms가 되어야 정상인데, 보는 것처럼 데이터 패킷도 아닌 ICMP 패킷 하나가 바로 옆으로 가는 데 24초를 넘어섰다. ㄷㄷㄷ 저것도 계속 RTT가 커지기만 하길래 24초쯤 되는 상황에서 돌아가는 모든 Java 프로그램을 죽였더니, 한참이 지나고 나서야 ping이 정상으로 돌아온 것이다.


내가 Java 프로그램을 잘못 만들었구나 자책하려고 했지만, Host 머신에서 CPU 사용량을 확인해 보니 ns-3 프로세스가 혼자 97% ~ 110% 사이를 왔다갔다 하고 있었고, 정작 내가 개발한 Java 프로세스들은 별로 CPU를 차지하고 있지 않았다. (라즈베리파이2에서도 3-9% 수준이긴 했음)


일차적으로 생각해 본 원인은 ns-3 프로세스가 L2 이하를 시뮬레이션 시키고 있는데, 10개의 노드 각각이 라우팅을 위해서 Hello 패킷을 비롯한 컨트롤 패킷을 매 초마다 발생시키니까 싱글 코어만으로는 계산하는 양이 감당이 안돼서 응답이 늦어지는 바람에 ping이 20초를 넘어서는 저런 사단이 난 것 같았다.


아~망했어요 ㅠㅠ

나는 ns-3 코어가 적어도 100노드 정도의 scalability는 책임질 수 있을 거라 생각했는데... 이건 뭐 컨테이너가 제아무리 가벼워도 각자 발생시키는 패킷의 양이 늘어나면 ns-3 코어가 감당을 못하는 상황이라니...


현재까지는 ns-3에 멀티코어 활용하도록 고친다던지, 아예 컨테이너도 없이 real-world 프로그램을 직접 네트워크와 연동하는 방법(DCE라고 하는데... 결국 컨테이너로 해결을 못하면 이것도 공부해야 함...)은 아직 확인하지 못했다.


내가 ns-3에 멀티코어 활용 방법을 아직 몰라서 이런 것이라고 믿고 싶다. ㅜㅜ 

그런데 왠지 보니까 기본적으로 멀티코어를 활용하도록 설계했을 법도 한데 안한 점과 구글 검색(ns-3 multi core)에서 첫 페이지에서 그런 옵션을 켜는 법이라던지 하는 간단한 해결방법이 보이지 않는 것을 보면... 


야~신난다 @_@

대안으로 나온 것이 컨테이너도 없이 DCE라고 직접 프로그램 코드를 바로 실행하는 방법도 있지만 이건 C++만 된다고 한다. DCE에 Java 프로그램을 붙이는 방법이 있는지 찾아보고, 이마저도 없으면 쌩으로 Java를 모두 C++ 또는 파이썬으로 포팅하는 대규모 토건사업이 펼쳐지겠지 ㄹㅇㅁㄴㄹㅇㅁㄹㅁㅈ 일자리 창출 인정? =_=


정신줄 그만 놓고, 해결 방법을 찾아봐야겠다. ㅜㅜ


반응형
블로그 이미지

Bryan_

,
반응형

Host OS: Ubuntu 16.04 (amd64)

lxc version: 2.0.4


Linux Container에 외부(즉 Host)에서 명령어를 주입하는 방법은 Container 시작할 때 명령어 같이 실행하는 방법과 이미 실행중일 때 명령어를 실행하는 방법으로 나뉜다.


일단 시작하지 않은(stop 또는 lxc-create만 해둔 상태) container는 lxc-start 또는 lxc-execute를 통해서 특정 명령어를 같이 실행할 수 있다.


# lxc-execute -n 컨테이너_이름 -- 실행할_명령어


그런데 이미 실행중인 container에 대해서 lxc-execute를 하면 이미 실행중이라는 에러가 나면서 실행되지 않는다. 이 때에는 lxc-attach를 쓰면 된다.


# lxc-attach -n 컨테이너_이름 -- 실행할_명령어


lxc-attach를 추가 명령어 없이 실행하면 해당 노드의 프롬프트로 바뀌어 버리는데, 실행할 명령어를 추가하게 되면 container의 프롬프트로 바뀌지 않은 채 명령어만 실행하고 Host의 쉘을 유지하게 된다. 이렇게 함으로써 host가 여러 개의 container에 대해서 같은 명령어를 일괄 실행할 수 있는 장점이 있다.


예를 들어, node4라는 이름의 container에 default route를 추가하는 명령어를 실행한 결과가 아래 그림과 같다. 원래 실행중인 container에 없던 default 경로가, lxc-attach와 함께 실행하는 route 명령어를 통해서 새로 추가되었음을 확인할 수 있다. 그리고 프롬프트가 바뀌지 않는 것도 확인할 수 있다.



다만 프롬프트만 바뀌지 않을 뿐, 실행 결과에 대한 출력은 host의 쉘에 모두 표시되므로 에러 여부도 판별할 수 있다.



<참고자료>

[1] "9.6 Starting a Command Inside a Running Container",

 https://docs.oracle.com/cd/E37670_01/E37355/html/ol_attach_containers.html



반응형
블로그 이미지

Bryan_

,
반응형

Host OS: Ubuntu 16.04 (amd64)
Container template: ubuntu


ubuntu 템플릿을 가지고 Linux Container를 만들고 난 직후에 환경변수가 하나도 잡혀 있지 않아서 몇 가지 불편한 점이 있었다.

vi는 HOME 환경변수를 참조해야 하는데 없어서 설정파일 저장을 못하고, screen 툴은 TERM 환경변수가 없어서 아예 실행이 안되는 문제가 있었다. 그 외에도 PATH 환경변수가 없으니까 심지어 apt-get install조차 안되었다.


내가 Linux Container 생성 단계에서 뭔가 빠뜨린 것인지 모르겠지만, 일단 기본으로 생성한 Container에서 필요한 몇 가지 환경 변수를 메모하게 되었다.


TERM은 vt100이 무난하다는 의견이 있어서 이것으로 했다. 이렇게 적용했더니 쉘에서 ls를 쳤을 때 파일 종류별로 색상이 달라지는 등 소소한 변화가 있었다. 아니면 xterm을 써도 상관없다.


$ export TERM=vt100



그냥 Container를 만들고 시작하면 root 계정으로 들어가길래 /root/를 HOME으로 설정했다.


$ export HOME=/root/



PATH의 경우 일단 최소한으로 시스템 도구들의 위치를 참조하게 했다.


$ export PATH=$PATH:/usr/local/sbin/

$ export PATH=$PATH:/usr/sbin/                         

$ export PATH=$PATH:/sbin



이 환경변수 값들을 /root/.bashrc 파일에 추가해줄 수도 있지만, Container는 full virtualization처럼 이미지 파일로 독립된 공간을 유지하는 것 같지 않아서 잘 모르겠다. Container를 더 익숙하게 사용하게 되면 이 글을 다시 고칠 예정이다.


반응형
블로그 이미지

Bryan_

,
반응형

Host OS: Ubuntu 16.04 LTS (amd64)


Linux Container를 이용해서 ns-3에서 네트워크 시뮬레이션을 할 필요가 생겼다. 일단 ns-3 공식 사이트에 나와 있는 튜토리얼을 따라해 보니 Linux Container 생성은 되는데, 외부 네트워크에 접속할 수 없다. 개별 네트워크 설정이 가능한 Container가 인터넷이 되게 하는 방법은 VM과 다를 바가 없지만, Container 생성 단계에서 약간의 작업이 들어가기 때문에 기록하게 되었다.



1. Host 머신 설정


Host가 Container들을 브릿지로 관리하는지, NAT로 관리하는지에 따라 설정이 다른데, 여기서는 NAT를 쓰는 경우를 기준으로 설명한다.


우분투에 lxc를 설치하고 나면 자동으로 브릿지가 하나 생성되어 있는데 보통 br과 lxc라는 단어가 동시에 들어가 있다. 필자의 경우 lxcbr0 이름으로 브릿지가 생성되어 있었고, IP주소는 10.0.3.1로 잡혀 있었다.


(Host에서 lxc 설치 후에 lxcbr0 인터페이스가 새로 생긴 것을 확인할 수 있다.)



Host에서 NAT를 통해 인터넷 접속을 허용하기 위해서 몇 가지 작업을 해 줘야 한다. 먼저 iptables에서 NAT 내부에서 인터넷으로 나가는 패킷을 masquerade 시켜 준다.

$ sudo iptables -t nat -A POSTROUTING -s 10.0.3.0/24 ! -d 10.0.3.0/24 -j MASQUERADE


그리고 /etc/sysctl.conf 파일에서,


net.ipv4.ip_forward=1 

위 라인의 주석을 제거한 다음, sysctl을 새로 적용한다.


$ sudo sysctl -p /etc/sysctl.conf



일단 ns-3에서 Linux Container를 생성해서 "시뮬레이션용 네트워크"에 연결하는 튜토리얼 [1] 을 따라해 보면 샘플 lxc 설정 파일이 있는데, 여기에 외부접속 용도의 네트워크 인터페이스를 하나 추가해 준다.


(NOTE)

ns-3 용도가 아니라 일반 VM처럼 쓰고 싶으면 네트워크 인터페이스를 굳이 여러 개 할 필요는 없고, 기본으로 설정하는 한 개의 네트워크 인터페이스 구성을 변경하면 된다.



lxc 설정 파일(여기서는 ns-3에서 샘플로 쓰는 lxc-left.conf 파일에 내용 추가 [1])에 아래 내용을 추가한다.


# Container with network virtualized using a pre-configured bridge named br-left and

# veth pair virtual network devices

lxc.utsname = left

lxc.network.type = veth

lxc.network.flags = up

lxc.network.link = br-left

lxc.network.ipv4 = 10.0.0.1/24


######################################

# 여기 아래부터 새로 추가한 부분

######################################

lxc.network.type = veth

lxc.network.flags = up

lxc.network.link = lxcbr0    <-- Host에 있는 브릿지 인터페이스 이름

lxc.network.ipv4 = 10.0.3.2/24  <-- Host 브릿지의 IP주소 대역에 있는 주소

lxc.network.name = eth1 <-- Container에서 보여지는 인터페이스 이름(임의설정 가능)


이제 위의 설정파일을 가지고 left라는 이름의 Container를 생성하고 시작한다.

$ sudo lxc-create -n left -f lxc-left.conf -t /usr/share/lxc/templates/lxc-ubuntu

$ sudo lxc-start -n left -F /bin/bash



2. Container 내부 설정


만약 Container가 정상적으로 생성되었다면 left라는 이름의 root 계정으로 쉘 프롬프트가 바뀔 것이다. ifconfig를 쳐 보면 아래와 같이 eth1 인터페이스가 인식되는 것을 볼 수 있다. (eth0의 경우는 원래 설정되어 있던 것)


(lxc-left.conf 설정파일에 새로 추가한 eth1 인터페이스가 설정한 IP주소 

10.0.3.2로 표시되는 것을 확인할 수 있다.)


Container를 시작한 직후에는 default route가 설정되어 있지 않기 때문에 인터넷 상의 머신으로 ping이 되지 않는다. 따라서 Container 상의 쉘에서 Host 머신과 연결하는 route를 추가한다. Host 머신의 lxcbr0 인터페이스의 IP주소가 10.0.3.1이기 때문에, default route의 게이트웨이를 10.0.3.1로 설정한다.


root@left:/root# route add default gw 10.0.3.1



여기까지 설정하면 IP주소를 통해 인터넷 상의 아무 컴퓨터에나 접속할 수는 있다. 다만 도메인 네임 서버가 설정되어 있지 않으므로 www.google.com 과 같은 도메인 네임으로는 주소를 찾을 수 없다.


도메인 네임 서버 설정은 여러가지 방법이 있지만, Container 자체가 약간 휘발성에 잠시 쓰는 느낌이 있어서, 일단 임시방편으로 /etc/resolv.conf 파일을 직접 수정했다. (좋은 방법은 아닌 것 같지만... 당장 되긴 되니까.)

네임서버는 일단 구글 도메인 네임 서버(8.8.4.4)로 했는데, 국내 다른 도메인 네임 서버로 설정해도 상관이 없다.


root@left:/root# echo "nameserver 8.8.4.4" > /etc/resolv.conf


여기까지 하고 나면 인터넷에 접속이 된다. 
이제부터 apt-get install 을 써서 원하는 패키지를 설치할 수 있다.




<참고자료>

[1] https://www.nsnam.org/wiki/HOWTO_Use_Linux_Containers_to_set_up_virtual_networks#Running_an_ns-3_Simulated_CSMA_Network



반응형
블로그 이미지

Bryan_

,