Systems/Unix2015.08.06 10:42

ToastCloud는 NHN ENTERTAINMENT에서 제공하는 IaaS 서비스이다. 이 서비스를 이용하면 VM들을 할당받아 Kubernetes 클러스터를 만들 수 있다. 


사전 준비 


ToastCloud는 http://cloud.toast.com에서 서비스하고 있다. 우선 아이디를 만들고, 프로젝트를 만들고, Infrastructure 상품을 enable 한 다음 (좌측 메뉴의 Infrastructure > Compute) Ubuntu 14.04 VM을 네 개 만든다. (상세한 과정은 http://cloud.toast.com/documents/1/?content_id=18 참고) 


이 때 Zone은 kr-a나 kr-b 가운데 하나를 선택하며 Flavor는 원하는 VM의 크기에 따라 알맞은 것을 선택하면 되며, 이름은 kubernetes-cluster 같은 것으로 주면 된다. instance의 수는 4 정도로 잡으면 테스트 해 보기에는 적당한데, 더 큰 클러스터를 원하면 더 크게 잡으면 된다. 


Kubernetes 클러스터는 하나의 Kubernetes master와 여러 개의 minion들로 이루어진다. instance를 4로 잡았다는 것은, 마스터 하나에 minion 네 개를 쓰겠다는 뜻이다. 구성하기에 따라서는 마스터 노드에 minion도 같이 구성할 수 있긴 한데, 정신 사나우므로 별로 추천하고 싶진 않다. 


위와 같이 VM을 만들 때 주의할 것은, 아래의 그림과 같은 사항이다. 



외부에서 VM에 ssh에 접속할 때 필요한 private keypair를 만들고, 다운받아 두는 것이다. 이 keypair를 다운받아 두지 않으면 나중에 외부에서 접속할 방법이 없으므로 반드시 다운받아두도록 하자. 


아무튼, 이렇게 해서 VM을 만들면 화면에 VM이 네 개 보이게 될 것이다. 이제 해야 할 것은, 생성된 VM들 가운데 master node로 이용할 VM에 floating IP, 그러니까 public IP를 할당해 두는 것이다. public IP를 할당하지 않으면 외부에서 접속이 불가능하다. 방법은 역시 http://cloud.toast.com/documents/1/?content_id=18를 참고하자. 


이제 SSH 접속을 위해 마지막으로 해야 할 일은 Infrastructure > Network & Security 메뉴에서 'default' security group에 SSH 접속을 위한 규칙 하나를 추가하는 것이다. 방법은 간단하니까 들어가서 해 보면 금방 알 수 있다. 


장비 접속과 추가 설정


이제 아까 다운받았던 pem 파일(private key file)과 ssh 클라이언트, 그리고 public IP 주소로 kubernetes 마스터 노드에 접속을 시도해 보자. 


$> ssh -i my-kuber-keypair.pem ubuntu@<public IP 주소>


모든 VM에는 이미 ubuntu라는 기본 계정이 있다. 이 계정으로 모든 작업을 진행하면 된다. 


접속이 되는 것을 확인하였다면, 아래 명령으로 .pem 파일을 master 노드에 복사해 두자. minion 노드에 접속하려면 마스터 노드를 거치지 않으면 불가능하므로, 이 조치가 필요하다. 


$> scp my-kuber-keypair.pem ubuntu@<public IP 주소>:


이렇게 하면 master 노드의 ubuntu 계정에서 다른 minion 노드로 접속하기 위한 private key file이 master node의 /home/ubuntu 아래에 복사된다. 


복사를 마쳤다면, 이제 다시 master 노드에 ssh 접속해서, .bashrc 파일의 맨 아래쪽에 아래의 코드를 추가하자. 


SSH_AGENT_PID=$(pgrep -f ssh-agent)


if [ ! $SSH_AGENT_PID ]; then

ssh-agent > ~/.ssh-agent.sh

fi


. ~/.ssh-agent.sh 


ssh-add my-kuber-keypair.pem


이 코드를 추가하면 ssh-agent가 실행되고, 거기 private key가 등록된다. 그러면 ssh로 minion에 접속할 때 -i 옵션을 생략할 수 있다. 이 절차가 중요한 이유는, Kubernetes가 클러스터 구성 과정에서 필요한 파일을 각 노드에 복사할 때, -i 옵션을 쓰지 않기 때문이다. 따라서 이 절차가 없으면 클러스터의 각 노드에 접속을 하지 못한다. 


여기까지 했다면 웬만한 건 다 끝났다. 


Docker 설치


이제 클러스터의 각 노드에 docker를 설치하자. VM 이미지로 우분투를 사용하고 있으므로, 아래의 명령으로 각 미니언 노드에 docker 구성을 마칠 수 있다. (docker를 설치하면 안 된다. 반드시 docker.io를 설치하자.) 


$> sudo apt-get install docker.io


삽질 끝에 이렇게 docker를 설치하면 버전이 안맞아서 문제가 꽃핀다는 사실을 발견. 아래 링크를 참조해서 최신 docker-engine을 설치하자. 이미 docker.io를 설치한 사용자는 sudo apt-get purge docker.io 한 다음에 아래의 링크에 나와 있는 대로 시행하면 된다.


http://blog.docker.com/2015/07/new-apt-and-yum-repos/


Kubernetes 클러스터 설치


클러스터 설치는 굉장히 단순하다. 아래 문서를 참고해서 그대로 따라하면 된다.


https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/getting-started-guides/ubuntu.md


몇 줄로 요약하자면, 


1. git clone https://github.com/GoogleCloudPlatform/kubernetes.git

2. cd kubernetes/cluster/ubuntu 

3. ./build.sh 실행

4. config-default.sh 수정

5. cd ..

6. KUBERNETES_PROVIDER=ubuntu ./kube-up.sh


이상의 과정을 실행하면 설치는 끝난다. 주의할 것은, config-default.sh 파일을 조심해서 수정해야 한다는 것. 나는 아래와 같이 수정했다. 


...

# Define all your cluster nodes, MASTER node comes first"

# And separated with blank space like <user_1@ip_1> <user_2@ip_2> <user_3@ip_3> 

export nodes=${nodes:-"ubuntu@192.168.0.14 ubuntu@192.168.0.12 ubuntu@192.168.0.15 ubuntu@192.168.0.13"}


# Define all your nodes role: a(master) or i(minion) or ai(both master and minion), must be the order same 

role=${role:-"a i i i"}

# If it practically impossible to set an array as an environment variable

# from a script, so assume variable is a string then convert it to an array

export roles=($role)


# Define minion numbers

export NUM_MINIONS=${NUM_MINIONS:-3}

# define the IP range used for service cluster IPs.

# according to rfc 1918 ref: https://tools.ietf.org/html/rfc1918 choose a private ip range here.

export SERVICE_CLUSTER_IP_RANGE=${SERVICE_CLUSTER_IP_RANGE:-10.0.0.0/24}  # formerly PORTAL_NET

# define the IP range used for flannel overlay network, should not conflict with above SERVICE_CLUSTER_IP_RANGE

export FLANNEL_NET=${FLANNEL_NET:-172.16.0.0/16}


# Admission Controllers to invoke prior to persisting objects in cluster

export ADMISSION_CONTROL=NamespaceLifecycle,NamespaceExists,LimitRanger,ServiceAccount,ResourceQuota,SecurityContextDeny


SERVICE_NODE_PORT_RANGE=${SERVICE_NODE_PORT_RANGE:-"30000-32767"}


# Optional: Enable node logging.

ENABLE_NODE_LOGGING=false

LOGGING_DESTINATION=${LOGGING_DESTINATION:-elasticsearch}


# Optional: When set to true, Elasticsearch and Kibana will be setup as part of the cluster bring up.

ENABLE_CLUSTER_LOGGING=false

ELASTICSEARCH_LOGGING_REPLICAS=${ELASTICSEARCH_LOGGING_REPLICAS:-1}


# Optional: When set to true, heapster, Influxdb and Grafana will be setup as part of the cluster bring up.

ENABLE_CLUSTER_MONITORING="${KUBE_ENABLE_CLUSTER_MONITORING:-true}"


# Extra options to set on the Docker command line.  This is useful for setting

# --insecure-registry for local registries.

DOCKER_OPTS=${DOCKER_OPTS:-""}


# Optional: Install cluster DNS.

ENABLE_CLUSTER_DNS="${KUBE_ENABLE_CLUSTER_DNS:-true}"

# DNS_SERVER_IP must be a IP in SERVICE_CLUSTER_IP_RANGE

DNS_SERVER_IP=${DNS_SERVER_IP:-"10.0.0.10"}

DNS_DOMAIN=${DNS_DOMAIN:-"cluster.local"}

DNS_REPLICAS=${DNS_REPLICAS:-1}


# Optional: Install Kubernetes UI

ENABLE_CLUSTER_UI="${KUBE_ENABLE_CLUSTER_UI:-true}"

...


주의해서 봐야 할 것은, 변수 nodes와 role의 역할이다. 이 두 변수가 하는 일과 그 값의 의미는 위에 링크 건 문서에 자세히 나와 있으나, 간단히 요약하자면 nodes는 마스터와 미니언 노드의 목록이고 (마스터가 맨 앞에 나와야 한다) role은 그 각 노드가 a(마스터), i(미니언), i(미니언), i(미니언) 순으로 운영된다는 뜻이다. 

이렇게 하면 설치 과정에 별 문제는 없을 것인데, 가끔 cluster validation이 굉장히 오래 걸리는 문제가 생길 수 있다. 대부분의 경우 docker daemon이 정상적으로 실행되지 않아서 생기는 문제며, /var/log/upstart/docker.log를 통해 확인할 수 있다. 대체로 minion으로 사용하는 노드를 재부팅하면 해결된다. 또한, 아래와 같은 문제가 생길 수 있다. 

1. groupadd 관련 오류가 난다
2. 설치 validation이 '.' 표시만 잔뜩 뱉어놓고 끝나지 않는다

1번 문제는 kubernetes/cluster/ubuntu/util.sh 스크립트에 있는 오류 때문인데, 이 문제에 대한 패치는 Kubernetes master 브랜치에 pull request를 했고, 바로 merge되어 고쳐졌으니 아마 kubernetes 소스를 git clone한 지 오래된 분들에게만 해당 증상이 나타날 것이다. 만일 그런 증상이 나타난다면 그냥 kubernetes 디렉터리에 가서 git pull을 다시 하면 된다.

2번 문제는 docker 설치가 각 미니언 노드에 제대로 되어 있지 않아서 생기는 문제인데, 위에 적은 대로 설치를 했다면 아마 같은 증상을 겪을 일은 없을 것이다. 

모든 설치가 정상으로 끝났다면 아마 아래와 같은 메시지를 보게 될 것이다. 

Kubernetes cluster is running.  The master is running at:

  http://192.168.0.2:8080

Using master 192.168.0.2
Wrote config for ubuntu to /home/ubuntu/.kube/config
... calling validate-cluster
Found 3 nodes.
        NAME          LABELS                               STATUS
     1 192.168.0.4   kubernetes.io/hostname=192.168.0.4   Ready
     2 192.168.0.5   kubernetes.io/hostname=192.168.0.5   Ready
     3 192.168.0.6   kubernetes.io/hostname=192.168.0.6   Ready
Validate output:
NAME                 STATUS    MESSAGE              ERROR
controller-manager   Healthy   ok                   nil
scheduler            Healthy   ok                   nil
etcd-0               Healthy   {"health": "true"}   nil
Cluster validation succeeded
Done, listing cluster services:

Kubernetes master is running at http://192.168.0.2:8080

마스터 노드에 웹 서버도 설치되어 접속해 볼 수 있는 상황이다.  http://<public IP 주소>:8080/으로 접속을 시도해 보자. 접속이 안된다면 security group을 고쳐서 8080번 포트를 개방해 주어야 한다. 아래와 같은 화면이 표시될 것이다. 

{
  • paths
    [
    • "/api",
    • "/api/v1",
    • "/healthz",
    • "/healthz/ping",
    • "/logs/",
    • "/metrics",
    • "/resetMetrics",
    • "/swagger-ui/",
    • "/swaggerapi/",
    • "/ui/",
    • "/version"
    ]
}

path에 나와 있는대로 접속을 시도해 보면 된다. http://<public IP 주소>:8080/ui/ 에 접속해보자. 아마 UI가 제대로 표시되지 않을 텐데, 그럴 때는 kubernetes/cluster/ubuntu 디렉터리로 가서 아래를 시행하면 된다. 

$> KUBERNETES_PROVIDER=ubuntu ./deployAddons.sh

이렇게 하면 UI가 addon 형태로 설치된다. 설치가 잘 되었는지는 아래의 명령으로 확인할 수 있다. 

$> kubectl get pods --namespace=kube-system

UI pod가 Running 상태로 나오면 제대로 된 것이다. Pending 상태로 너무 오래 지속되고 있다면, 역시 docker daemon이 문제일 가능성이 제일 크므로, 미니언 노드를 재부팅시켜주는 것이 좋다. 

여기까지 되는 것을 확인하려다 Kubernetes 설치 스크립트의 버그를 몇 개 잡았는데, 전부 Kubernetes 마스터 브랜치에 merge 된 상태이므로, 이 글을 읽는 여러분이 설치를 할 때 쯤에는, 같은 문제를 겪을 일은 아마 없을 것이다. 


저작자 표시 비영리 변경 금지
신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

  1. 임태형

    위 구성을 그대로 적용했는데요. UI를 보기 위해 http://<Master IP>:8080/ui 하면 아래와 같은 에러가 나타납니다.
    Error: 'dial tcp 172.17.0.2:8080: no route to host'
    Trying to reach: 'http://172.17.0.2:8080/'

    172.17.x.x는 docker 안에서의 eth0에 속하는 ip라하는데.. 이쪽으로 redirect를 못해주네요. 혹시 이부분에 대해서 아시는게 있으신가요? 도움 요청 드립니다.

    2015.08.28 14:26 신고 [ ADDR : EDIT/ DEL : REPLY ]
    • 혹시 kubectl get pods --namespace=kube-system의 출력 결과를 보여주실 수 있을까요?

      2015.08.31 20:08 신고 [ ADDR : EDIT/ DEL ]
  2. 최용환

    일단 ifconfig 하셔서 flanneld 네트워크가 떠 있는지 보시고,
    etcdctl ls / 해보시면
    /registry 만 있는지 /coreos 도 있는지 알수 있습니다.
    없으면 설정해주셔야 합니다.

    etcdctl mk <etcd 키 경로> <값> , 경로는 / 로 시작한다.

    2015.11.10 11:11 신고 [ ADDR : EDIT/ DEL : REPLY ]

Systems/Unix2014.12.17 14:32

이더넷 포트에 실제 케이블이 꽂혔는지 빠졌는지 알아내려면?


/sys/class/net 아래에 보면 디바이스 명 별로 디렉터리들이 있다.


eth0

eth1

...


이런 식이다. 


이 디렉터리 아래를 보면 carrier라는 파일이 보인다. 이 파일 안에는 케이블이 빠졌는지 꽂혔는지를 나타내는 0 또는 1 값이 들어 있다. 0이면 빠진 것이고, 1이면 꽂힌 것이다. 


#> cat /sys/class/net/eth0/carrier

1

#>


위의 실행 결과는 eth0이 나타내는 이더넷 포트에 케이블이 꽂혀 있음을 보여준다. 그러나 정확한 값을 얻으려면 해당 인터페이스가 UP 된 상태이어야 함에 주의하자.


ifconfig에 케이블 이탈 여부를 알리는 텍스트가 포함되기도 하는데, 그 값이 정확한지 확신할 수 없다면 이 방법을 이용해 보자. 


ethtool을 이용하는 방법도 있다.


참고: http://stackoverflow.com/questions/808560/how-to-detect-the-physical-connected-state-of-a-network-cable-connector


저작자 표시 비영리 변경 금지
신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

Systems/Unix2014.08.01 09:01

If you are using Ubuntu 14.04, and fed up with the slow speed of compiz (Ubuntu xwindow manager) especially in the virtualized environment, there's a solution. Just boot into the text mode. 


First step is to edit /etc/default/grub as follows: (sudo vi /etc/default/grub)


...

GRUB_CMDLINE_LINUX_DEFAULT="text"

GRUB_CMDLINE_LINUX="quiet splash"

...


After that, do sudo update-grub. Once finished, just reboot. That's it. Now you can boot directly into the simple 'text' mode. 


If you want to start XWindow manager after boot, all you need to do is:


$ sudo service lightdm start


If you want to turn that GUI down, you just need to stop the service. 


$ sudo service lightdm stop


Then, you might see some cursor flickering with no respose: don't panic, just press Ctrl-Alt-F1. Then you will be returned to the original screen that you started the lightdm service. 

저작자 표시 비영리 변경 금지
신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

Systems/Unix2014.07.01 08:58

특정한 포트를 점유하고 있는 프로세스를 찾아서 종료시키고 싶을 때가 있다. 프로그램을 실행시키려고 하는데 특정 포트를 점유하는 다른 프로세스가 있어서 실행 시킬 수 없을 때가 그 예다. 


그럴 때는 fuser라는 명령어를 이용해서 간단하게 처리할 수 있다. 가령 TCP 6633 포트를 점유하는 프로세스를 찾아서 종료시키고 싶다면, UNIX 기반 시스템에서는 다음과 같이 하면 된다. 


fuser -k 6633/tcp


수퍼유저 권한이 필요하다면 다음과 같이 하면 된다. -k는 kill과 같은 의미이다. 


sudo fuser -k 6633/tcp


fuser 프로그램은 원래 특정한 파일을 사용하는 프로세스의 PID를 출력해주는 프로그램이다. man fuser를 실행해 보면 그 자세한 사용법을 확인할 수 있다. 


참고 링크:

http://en.wikipedia.org/wiki/Fuser_(Unix)


저작자 표시 비영리 변경 금지
신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

  1. 곰탱이

    네이버와 다음에 블로그를 가지고 있으나 표현에 제약이 따라 티스토리를 사용 해보고자 합니다.
    처음이라 미숙한데 초대장을 가지신 블로그에게 초대장을 받는 방법이 있다더군요
    미력하나마 새로운 블로그 형식에 도전코자 하오니 귀하의 초대장을 보내주시면 감사히 쓰겠습니다.
    1best@korea.com

    2014.07.04 08:47 신고 [ ADDR : EDIT/ DEL : REPLY ]

Systems/Unix2013.10.30 14:33

OS X 메버릭으로 업그레이드하신 분들께 다양한 무료 업그레이드 혜택이 있었는데요. (iLife, Aperture, iWork 등등) 안타깝게도 모든 맥(Mac) 사용자에게 이런 혜택이 돌아가는 건 아닙니다. 





http://support.apple.com/kb/HT5975 에 따르면, 앱 스토어(App Store)에서 자동으로 업그레이드 되는 소프트웨어는, Aperture 3.x, iMovie '11, iPhoto '11, Keynote '09, Pages '09, Numbers '09 (즉, iWork '09) 버전으로 제한됩니다. 이 소프트웨어들은 시스템에 설치되어 있을 경우 자동으로 업그레이드 됩니다. 


따라서 8.1.2 버전의 iPhoto를 사용하고 있던 사용자는 자동 업그레이드 혜택을 누릴 수 없습니다. 해당 버전의 사용자는 iPhoto를 구매해야 합니다. iPhoto 버전은 iPhoto 실행 후 'About iPhoto'를 클릭하면 확인할 수 있습니다. (iWork '09는 업그레이드해주면서 iLife '09는 업그레이드 안해주다니, 좀 이상하긴 하죠? ㅋㅋ) 



저작자 표시 비영리 변경 금지
신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

  1. 최준호

    아이맥2012년버전을 쓰고 있고 얼마전에 매버릭스로 업뎃 했습니다. 그리고 나서 아이포토는 이 버젼의 맥에서 사용할 수 없다고 나오더니 급기야 앱스토어의 어이포토 업데이트가 되질 않네요...
    애플 아이디가 다를다고 하는데, 애플 아이디는 하나밖에 없거든요...이거 혹시 원인을 알 수 있을까요?

    2013.11.08 14:51 신고 [ ADDR : EDIT/ DEL : REPLY ]
    • 글쎄요. 저로서도 겪어본 문제가 아니면 말씀드리기가 좀 어렵네요.
      죄송합니다.

      2013.11.08 16:34 신고 [ ADDR : EDIT/ DEL ]

Systems/Unix2013.09.24 13:36

SteamOS가 발표되었습니다. 리눅스 답게, 무료입니다. inven 뉴스에 따르면, SteamOS는 거실을 겨냥한 첫 번째 리눅스 배포판입니다. (거실의 대화면 TV를 겨냥한 것이죠.) 



SteamOS 웹 사이트를 (http://store.steampowered.com/livingroom/SteamOS/?l=koreana) 방문해 보면, 이 OS가 크게 게이밍과 스트리밍이라는 두 가지 기술 시장에 주목하고 있음을 알 수 있습니다. 





스트리밍, 음악, TV, 영화, 가족 공유 등이 주된 기능이 될 거라고 이야기하고 있는 이 OS는, 앞서도 밝혔지만 '영원히' 무료로 배포될 예정입니다. 현재 수백개가 넘는 게임이 지원되고 있으며 (리눅스 상에서 실행 가능한 모든 게임이 포함될 듯) SNS 등을 통한 사용자 간 상호작용이 지원될 것으로 보입니다. 클라오드와 연동하는 자동 업데이트와 설정 유지 기능이 지원될 전망이고, 현재 25개의 언어를 지원한다고 하는군요. 



SteamOS는 원래 Steam이라는 이름의 게이밍 플랫폼이었는데 (http://store.steampowered.com/about/)이번에 운영체제화 된 것이라고 하는군요. 종전에는 Steam Play라는 소프트웨어를 통해 게임을 실행했는데, 운영체제에 구애받지 않고 Steam Play가 설치되어 있으면 게임을 실행할 수 있었습니다. 따라서 SteamOS도 Steam Play에서 실행가능했던 게임들은 기본적으로 지원한 것 같군요. (Steam Play는 Ubuntu 등의 Linux이외에 Mac등에서 이용할 수 있었습니다.)


거실의 대화면 TV를 겨냥한 듯한 이 OS의 향후 움직임이 기대됩니다.



저작자 표시 비영리 변경 금지
신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

  1. 마법사

    중간 중간 steam를 stream로 잘못 적은 오타가 있습니다.

    2013.10.10 19:48 신고 [ ADDR : EDIT/ DEL : REPLY ]

Systems/Unix2012.12.14 16:10

어떤 소스를 열심히 다운받아서 tar zxvf로 압축을 해제한 다음에 ./configure ; make ; make install 하고 나서 프로그램 컴파일 시에 라이브러리를 열심히 링크해서 딱 실행하려고 하면!!!


Error while loading shared libraries: ....


라는 오류 메시지와 마주하게 될 떄가 있다. 



캐난감


이런 캐난감한 상황을 타개하기 위해서는 먼저, /etc/ld.so.conf.d/라는 디렉터리가 있는 지 본다. 


있으면 문제를 해결하기 간단하다. 해당 디렉터리 아래에, 방금 설치한 라이브러리의 *.so 파일 위치를 가리키는 xxx.conf 파일을 하나 만들어 넣어주면 되기 때문.


필자가 설치했던 glog (Google Logging) 라이브러리는 기본적으로 make install하면 *.so 파일을 /usr/local/lib 아래에 깔아두기 때문에, vi /etc/ld.so.conf.d/local.conf 를 실행하여 해당 파일에 다음을 적어주었다. 


/usr/local/lib


이렇게 하는 것으로 끝이면 좋겠지만 아니다!!!


이렇게 한 다음에 반드시 


/sbin/ldconfig 


위의 명령을 실행해 주어야 한다. (실행에 좀 오래 걸릴 수도 있다.)


그리고 나서 아까 실행했던 프로그램을 다시 실행해 보면, 거짓말 같이 오류 메시지는 사라질 것이다. 


물론 이 방법만 먹히는 것은 아니고, 임시 땜빵으로 쓸 수 있는 방법으로는 


export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:<설치한 라이브러리의 *.so 파일이 있는 경로>


와 같이 하여 환경 변수를 설정해 준 다음에 다시 프로그램을 실행하는 방법도 있다. 



저작자 표시 비영리 변경 금지
신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

  1. DD

    감사합니다.

    2014.01.09 00:24 신고 [ ADDR : EDIT/ DEL : REPLY ]
  2. dd

    저도 감사합니다.

    2014.10.03 17:51 신고 [ ADDR : EDIT/ DEL : REPLY ]
  3. asdf

    꼬박 하루 삽질하고 여기서 해답을 찾네요 감사합니다.

    2015.07.09 15:29 신고 [ ADDR : EDIT/ DEL : REPLY ]

Systems/Unix2012.07.03 13:04

Makefile을 작성할 때에도 if, else 등의 조건식을 사용할 수 있긴 합니다. GNU make 메뉴얼에 실린 예제를 보시면... 


libs_for_gcc = -lgnu
normal_libs =

foo: $(objects)
ifeq ($(CC),gcc)
        $(CC) -o foo $(objects) $(libs_for_gcc)
else
        $(CC) -o foo $(objects) $(normal_libs)
endif

이렇게 하면 $(CC)의 값이 gcc냐 아니냐에 따라서 선택적으로 컴파일 옵션을 바꿀 수 있는데요. 문제는 Stackoverflow에 실린 글타래에도 나와 있듯이, 아래와 같은 작업을 하려고 하면 잘 안됩니다. 


.c.o .cpp.o .cc.o:

ifeq ($(*D),mySpecialDirectory)  
   @echo "I'm in mySpecialDirectory! \o/"
   $(CC) $(DEBUG_FLAGS) $(MYSPECIALFLAGS) -c $< -o $@
else  
   @echo "Failed! I'm in $(*D)"
   $(CC) $(DEBUG_FLAGS) $(NOTTHATSPECIALFLAGS) -c $< -o $@
endif


http://9gag.com/gag/744366. Makefile이 개그 소재가 될 수도 있다.



위의 코드가 하려는 일을 간단히 요약하면 현재 컴파일하려는 대상이 위치한 디렉터리가 mySpecialDirectory와 일치하면 이렇게 컴파일하고, 아니라면 저렇게 컴파일되도록 하겠다는 것이죠. 위의 코드가 정상 동작하지 않는 이유는...

Conditional Statements

All instances of conditional syntax are parsed immediately, in their entirety; this includes the ifdef, ifeq, ifndef, and ifneq forms. Of course this means that automatic variables cannot be used in conditional statements, as automatic variables are not set until the command script for that rule is invoked. If you need to use automatic variables in a conditional you must use shell conditional syntax, in your command script proper, for these tests, not make conditionals.


그러니까 '실행되는 순간에 그 값이 설정되는 자동 변수' (위의 예제에서는 $(*D))에 대해서는 ifeq 같은 조건절이 정상적으로 동작하지 않는다는 것이죠.


따라서 위의 예제가 정상적으로 동작하도록 만들려면, 다음과 같이 바꿔야 해요.


.c.o .cpp.o .cc.o:
   $(CC) $(DEBUG_FLAGS) $(if $(subst mySpecialDirectory,,$(*D)),$(NOTTHATSPECIALFLAGS),$(MYSPECIALFLAGS)) -c $< -o $@

$(subst mySpecialDirectory,,$(*D))는 mySpecialDirectory와 $(*D)가 일치하는 경우 빈 문자열을 반환합니다. 그리고 그 결과는 $(if condition, then-part [,else-part])에 의해 false condition으로 해석되죠.
저도 이것 때문에 좀 애먹었는데... 결국 다음과 같은 Makefile을 작성해서 문제를 해결했습니다.

$(TARGET): $(OBJS) $(LIBS) $(TARGET): %: %.cc $(CC) $(if $(subst icnfs,,$@), $(CFLAGS), $(FUSE_CFLAGS)) \ $(INCLUDE) $(LIBDIR) -o $@ $< $(OBJS) \ $(if $(subst icnfs,,$@), \ -lbjlee-process -lpthread, \ -lbjlee-process -lpthread -lfuse \ )


$(TARGET)에 명시된 컴파일 대상에 대해 $(CC)를 실행할 때, $@, 즉 컴파일 대상의 이름이 icnfs와 일치할 경우 -lfuse의 플래그가 포함되도록 하는 문장입니다.


저작자 표시 비영리 변경 금지
신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

Systems/Unix2012.06.07 10:34

RAW 소켓을 사용한 패킷 전송 및 수신시 기본적으로 알아야 할 사항은 다음과 같다.


1. IP 헤더를 직접 조작할 것이냐

2. 어떤 프로토콜 번호를 사용할 것이냐

3. 어떤 API를 사용하여 패킷을 전송하고 수신할 것이냐


이상의 사항만 숙지하면 RAW 소켓을 사용하여 패킷을 주고 받는 것도 생각보다는 간단하다. 


먼저 전송하는 소스 코드를 보자



구글에서 RAW 소켓을 이미지 검색하면 뜨는 사진. 소켓 공부하다가 이런 사진을 볼 수도 있다니.. 좋은 세상이다... ㅋㅋ



#include <sys/socket.h>

#include <unistd.h>

#include <stdio.h>

#include <stdlib.h>

#include <arpa/inet.h>

#include <netinet/ip.h>


u_int16_t get_checksum(u_int16_t* buf, int nwords)

{

    u_int32_t sum;

    for(sum=0; nwords>0; nwords--) sum += *buf++;

    sum = (sum >> 16) + (sum & 0xffff);

    sum += (sum >> 16);

    return (u_int16_t)(~sum);

}


int main(int argc, const char** argv)

{

    /*

     * create a raw socket

     */

    int sd = socket(PF_INET, SOCK_RAW, 145 /* not used */);

    if ( sd < 0 ) {

        perror("socket() error");

        return -1;

    }


    int turn_on = 1;

    int turn_off = 0;


    /*

     * I will manipulate IP header myself

     */

    if ( setsockopt(sd,IPPROTO_IP,IP_HDRINCL,&turn_on,sizeof(turn_on)) < 0 ) {

        perror("setsockopt() error");

        return -1;

    }


    struct iphdr iphdr;

    struct sockaddr_in din;


    din.sin_family = AF_INET;

    din.sin_port = 0;

    din.sin_addr.s_addr = inet_addr("129.254.198.212");


    iphdr.ihl = 5;

    iphdr.version = 4;

    iphdr.tos = 0;

    iphdr.tot_len = htons( sizeof(struct iphdr) );

    iphdr.id = htons(rand() % 65535);

    iphdr.frag_off = 0;         

    iphdr.ttl = 64;

    iphdr.protocol = 145;

    iphdr.saddr = inet_addr("129.254.173.145");

    iphdr.daddr = inet_addr("129.254.198.212");

    // iphdr.check = get_checksum((u_int16_t*)&iphdr, sizeof(struct iphdr));

    // IP_HDRINCL인 경우에는 checksum 계산 필요 없음. 하위 layer에서 시행됨.


    if ( sendto(sd, &iphdr, sizeof(iphdr), 0,

            (struct sockaddr*)&din, sizeof(din)) < 0 ) {

        perror("sendto() error");

        return -1;

    }


    return 0;

}


이 코드에서 주의하여 볼 부분은 적색의 굵은 폰트로 표시하였다. 우선 (1) 소켓을 열 때 SOCK_RAW를 사용하여 열어야 하고, 프로토콜 번호로는 현재 시스템에서 사용하고 있지 않은 프로토콜 번호를 준다. 이 번호는 /etc/protocols 파일을 살펴보면 알 수 있는데, 현재 145는 사용되고 있지 않은 번호이므로 테스트를 위해 그 번호를 사용했다. 그리고 (2) setsockopt 함수를 사용해서 IP 헤더를 직접 조작하겠다는 설정을 하고 있다. 이렇게 설정한 경우, 전송할 패킷의 IP 헤더는 직접 구성해 주어야 한다.


나머지 코드는 아주 간단하기 짝이 없는데, 한 가지 유의할 부분은 sendto 대신 send를 사용해서 보내면 패킷이 전송되지 않는다는 것. "Destination address required"와 같은 오류 메시지가 출력될 것이다. IP 헤더에 목적지 주소를 적어주었음에도 굳이 sockaddr_in 구조체를 인자로 전달해 주어야 한다는 것은 분명 비효율적이고 이해되지 않는 부분이지만, 리눅스 시스템 콜이 그렇게 생겨 먹었으니 어쩔 수 없는 부분이다. 


받는 쪽 소스 코드는 이보다 더 간단한데 (IP 헤더 말고 다른 데이터를 전송하지 않도록 했기 때문에 더더욱 그러하다) 소켓 bind를 할 필요도 없고, listen 할 필요도 없고, accept 할 필요도 없기 때문이다. 그냥 recv를 하면 된다. 


#include <sys/socket.h>

#include <unistd.h>

#include <stdio.h>

#include <arpa/inet.h>

#include <netinet/ip.h>

#include <strings.h>


int main(int argc, const char** argv)

{

    /*

     * create a raw socket

     */

    int sd = socket(PF_INET, SOCK_RAW, 145);

    if ( sd < 0 ) {

        perror("socket() error");

        return -1;

    }


    char recvPacket[1024] = {0, };

    int pkt_size = 0;

    if ( (pkt_size = recv(sd, recvPacket, 1024, 0)) < 0 ) {

        perror("recvfrom() failed");

        return -1;

    }


    printf("read succeeded");


    printf("pkt_size = %d\n", pkt_size);

    struct iphdr* iphdr = (struct iphdr*)&recvPacket[0];

    printf("iphdr.ihl = %d\n", iphdr->ihl);

    printf("iphdr.version = %d\n", iphdr->version);

    printf("iphdr.tos = %d\n", iphdr->tos);

    printf("iphdr.tot_len = %d\n", htons(iphdr->tot_len));

    printf("iphdr.frag_off = %d\n", iphdr->frag_off);

    printf("iphdr.ttl = %d\n", iphdr->ttl);

    printf("iphdr.protocol = %d\n", iphdr->protocol);


    return 0;

}


패킷을 보낼 때 굳이 sendto를 통해서 보내도록 하고 있음에도, recvfrom을 하면 뭔가 알 수 없는 오류가 생긴다는 것은 이상한 일이다. "Invalid argument"와 같은 오류가 발생한다는 것. recvfrom 대신 recv를 하면 정상적으로 동작한다. 




저작자 표시 비영리 변경 금지
신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

  1. 정보보안

    저 코드를 컴파일해서 사용하면되는건가요? 공부중인데 저 코드를 어떻게 쓰는건가요? 그냥 컴파일 후 바이너리 파일로 만들고 대상 PC에서 실행하면 되는건가요?

    2013.10.11 20:47 신고 [ ADDR : EDIT/ DEL : REPLY ]

Systems/Unix2012.06.05 16:47

시스템에 iptables가 설치되어 있다면, 이 패키지가 방화벽 기능을 시스템에 제공합니다. iptables가 깔려 있는 경우, 네트워킹 소프트웨어 테스팅 시에 iptables가 패킷을 가로막아 테스트가 온전히 실행되지 못하는 경우가 종종 생깁니다. 


이럴 경우 우선 iptables에 무슨 규칙이 반영되어 있는지 알아야 하는데, 기본적으로 다음과 같이 하면 알 수 있습니다. 





[root@ns2-3 ns2]# iptables -L --line-numbers

Chain INPUT (policy ACCEPT)

num  target     prot opt source               destination

1    ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTABLISHED

2    ACCEPT     icmp --  anywhere             anywhere

3    ACCEPT     all  --  anywhere             anywhere

4    ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:ftp

5    ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:ssh

6    REJECT     all  --  anywhere             anywhere            reject-with icmp-host-prohibited


Chain FORWARD (policy ACCEPT)

num  target     prot opt source               destination

1    REJECT     all  --  anywhere             anywhere            reject-with icmp-host-prohibited


Chain OUTPUT (policy ACCEPT)

num  target     prot opt source               destination


행 번호가 출력되도록 했는데, 이렇게 하면 규칙들이 어떤 순서로 배열되어 있는지를 보기가 좀 더 편해집니다. 위의 규칙을 해석하자면, 이미 허용된 플로우에 속한 패킷들, icmp 패킷, 그리고 ftp, ssh에 해당하는 TCP 패킷은 허용되어 있는 상태고, 나머지는 전부 거부됩니다. 


같은 subnet에 있는 기계들의 경우, 기본적으로 통신이 가능하도록 하고 싶다고 하면 INPUT 체인의 6번 규칙, 그러니까 REJECT all 에 해당하는 규칙 앞에 두어야 합니다. iptables는 규칙을 위에서 아래로 순서대로 검사하기 때문에, REJECT all 규칙 뒤에 둔 규칙은 쓸모가 없습니다. 


[root@ns2-3 ns2]# iptables --insert INPUT 6 -s x.y.0.0/16 -j ACCEPT


위와 같이 하면, INPUT chain의 6번 규칙 앞에 x.y.0.0/16 서브넷에 있는 호스트에서 오는 패킷은 ACCEPT 하라는 규칙이 삽입됩니다. 삽입되고 나면 iptables 규칙은 다음과 같이 바뀝니다. 

[root@ns2-3 ns2]# iptables -L --line-numbers

Chain INPUT (policy ACCEPT)

num  target     prot opt source               destination

1    ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTABLISHED

2    ACCEPT     icmp --  anywhere             anywhere

3    ACCEPT     all  --  anywhere             anywhere

4    ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:ftp

5    ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:ssh

6    ACCEPT     all  --  x.y.0.0/16           anywhere

7    REJECT     all  --  anywhere             anywhere            reject-with icmp-host-prohibited


Chain FORWARD (policy ACCEPT)

num  target     prot opt source               destination

1    REJECT     all  --  anywhere             anywhere            reject-with icmp-host-prohibited


Chain OUTPUT (policy ACCEPT)

num  target     prot opt source               destination


시스템이 재부팅되면 이렇게 설정한 규칙은 사라지기 때문에, 다음과 같이 해 줄 필요가 있습니다. 


[root@ns2-3 ns2]# /sbin/service iptables save

iptables: Saving firewall rules to /etc/sysconfig/iptables:[  OK  ]

[root@ns2-3 ns2]# /sbin/service iptables restart

iptables: Flushing firewall rules:                         [  OK  ]

iptables: Setting chains to policy ACCEPT: filter          [  OK  ]

iptables: Unloading modules:                               [  OK  ]

iptables: Applying firewall rules:                         [  OK  ]

iptables: Loading additional modules: nf_conntrack_ftp     [  OK  ]

[root@ns2-3 ns2]#




저작자 표시 비영리 변경 금지
신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

Systems/Unix2012.05.24 17:23

SSL handshake failed: SSL error: Key usage violation in certificate has been detected


프로젝트 관리를 위한 서버에 VisualSVN 최신버전을 설치하고 Centos에서 svn co (checkout)을 돌렸더니 이런 오류가 발생한다. 자격증명서(certificate)에서 Key 사용에 관한 오류가 발생하여서 SSL 핸드셰이크(handshake)를 할 수 없다는 것. 


인터넷을 뒤져 이 문제가 libneon과 GnuTLS 등등에 있다는 것 까지는 알아냈는데, Centos에는 관련된 라이브러리가 설치되어 있지 않은 것처럼 보이는데도 문제가 생겨서 해결이 난감.


그래서 또다른 우회책을 찾았으니...


일단 VisualSVN 서버가 깔린 기계에서 regedit을 돌린다. 그리고 다음의 필드 추가.




즉, CreateGnuTLSCompatibleCertificate를 DWORD 타입으로 추가해서, 그 값을 1로 설정하는 것.


이렇게 한 다음에 이제 VisualSVN 서버에서 개인 자격 증명을 추가하면 되는데... 절차는 이렇다. 우선 VisualSVN 서버 관리자 화면의 왼쪽 Pane에서 최상위 노드를 클릭한 다음, 마우스 오른쪽 버튼을 누르고 Properties를 선택한다. 




그런 다음에 뜨는 창에서 Certificate를 선택하고, Change certificate를 누른다. 그리고 개인 자격 증명을 생성한다. 




이렇게 하고 Centos 쪽에서 Checkout을 실행해 보면, 다음과 같은 화면이 뜬다. 



지운 부분은 보시면 안되는 부분이니까 궁금해하지 마시고.. (수줍) 


아무튼 P를 선택하고 영구 승인을 한 다음에, 그냥 쓰면 된다. 개인 인증서라는게 껄쩍지근한 분들은 다른 해결책을 인터넷에서 찾아보시기 바라고.. ㅋㅋ


64비트 윈도우즈에서는 Registry 편집을 좀 달리해 주어야 할 수 있는데, 거기에 관해서는 아래의 링크를 참고하시기 바란다. 


http://www.visualsvn.com/support/topic/00056/



저작자 표시 비영리 변경 금지
신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

  1. 잘보고갑니다^^ 몰랐던 정보네요~

    2012.05.25 21:56 신고 [ ADDR : EDIT/ DEL : REPLY ]

Systems/Unix2012.05.08 12:23

제가 쓰고 있는 Linux 배포판은 Centos입니다. 이 배포판에는 FUSE, 그러니까 Filesystem In Userspace 모듈이 함께 깔려 있습니다. 이 모듈은 사용자가 커널이 아닌 사용자 주소 공간에서 파일 시스템을 만들 수 있도록 해 줍니다. 


FUSE 프로젝트의 웹사이트는 http://fuse.sourceforge.net/ 입니다.


이 웹사이트에 가보시면 예제 파일이 하나 있습니다. hello world 파일 시스템이 그것인데요. 이 예제 파일 시스템을 컴파일하려면 약간의 준비작업이 필요합니다. 


먼저, 수퍼유저 계정으로 가셔서 다음과 같이 합니다.


#> yum install fuse-devel 


이렇게 하시면 fuse 라이브러리를 사용해서 파일 시스템을 구현하는 데 필요한 헤더 파일이 설치됩니다. 헤더 파일이 설치되는 위치는 대략 다음과 같습니다.


/usr/include/fuse.h

/usr/include/fuse/*.h


헤더 파일의 설치가 끝나면 이제 웹 사이트에 올려져 있는 예제 파일 시스템을 컴파일해 볼 수 있습니다. 


#> gcc hello.c


그런데 이렇게 하시면 아마 컴파일이 잘 안되실 겁니다. 



-D 플래그를 사용하라니까 그렇게 해 줘야 겠죠. 그런데 그렇게 해 봐도 잘 안됩니다. 



이 문제를 해결하기 위해서는 fuse.h의 documentation에 적혀 있는 다음과 같은 문구를 참조해야 합니다.



그러니까, 결국 다음과 같이 컴파일 해 줘야 하는 셈입니다. 



그런데 보시면 아시겠지만 그렇게 해도 뭔가 잘 안된다는 걸 알 수 있죠. 예제에 사용된 소스코드의 버전이 낮아서 그런 것인데요 (오픈소스 프로젝트에서 종종 발견되곤 하는 문제입니다), 따라서 소스 코드를 다음과 같이 수정해줘야 합니다. 즉, fuse_main을 호출하는 부분에 맨 마지막 인자로 0을 (아무것도 넘기지 않는 다는 뜻) 넘겨주어야 합니다. 




이렇게 하고 컴파일하면 잘 되는 것을 확인할 수 있습니다. (오호)



물론 이렇게만 하면 되는 것은 아니고, 실행이 가능하려면 fuse 라이브러리와 링크도 해 줘야 합니다. 그러니 다시 정리하자면, 


#> gcc -D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=26 -lfuse -o hello -c hello.c


와 같이 해 주셔야 된다는 것이 결론. 물론 소스 코드를 조금 고쳐주셔야 한다는 것은 잊지 마실 것.


저작자 표시 비영리 변경 금지
신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

  1. 저에게도 환청이 들려오는 것 만 같습니다 ㅠ
    얘기들 들어보면 정말 대단한 분들이 많지요

    2012.05.10 12:55 신고 [ ADDR : EDIT/ DEL : REPLY ]

Systems/Unix2011.08.12 14:50
가상화 Solution중에 OpenVZ라는 것이 있습니다. Linux 기반 커널 위에 '컨테이너(container)'라고 불리는 경량의 독립 공간을 만드는 기술인데요. 보통 가상화라고 하면 별도의 운영체제가 완전히 추상화된 하드웨어 계층 위에 독립적으로 설치되어 돌아가는 것을 상상하는 경우가 많은데 OpenVZ는 좀 다릅니다. 커널은 Host OS의 커널을 공유하고, 그 위에 개별적인 OS quota를 주는 형식에 더 가깝죠.

그래서 '커널이 다른 OS를 OpenVZ로 가상화 하는 것은 곤란' 합니다.

자세한 사항은 www.openvz.org 에 가셔서 알아보시기 바라구요. 지금부터는 OpenVZ를 이용해 CentOS 5.6을 여러 개의 CentOS 5 머신으로 가상화하는 방법을 살펴보겠습니다. (이 문서는 작성일 이후 1년쯤 뒤에는 더 이상 참고자료로서 활용되지 못할 수 있으므로 주의하세요. 작성일은 2011년 8월 12일입니다.)

1. Centos 5.6 설치

OpenVZ는 아직 CentOS 6.0을 지원하지 않고 있습니다. (이 문서 작성일을 기준으로) 그래서 CentOS 5.6을 설치합니다. http://ftp.daum.net/centos/5.6/isos/i386/CentOS-5.6-i386-bin-DVD.torrent 링크를 클릭하셔서 torrent 프로그램을 통해 운영체제 이미지를 다운받고, 이미지를 DVD로 구워서 설치하시면 됩니다. torrent 프로그램으로는 uTorrent를 쓰시면 되겠군요.

운영체제 설치하실 때는 가급적 /vz/ 파티션을 따로 잡아주시고, 해당 파티션은 반드시 ext3 파일 시스템을 사용하도록 해 주세요. 이 아래에 가상 머신 이미지들이 들어간다고 보시면 됩니다.

2. OpenVZ 설치

설치가 끝나고 재부팅이 되면, 다음을 실행합니다.

# cd /etc/yum.repos.d
# wget http://download.openvz.org/openvz.repo
# rpm --import  http://download.openvz.org/RPM-GPG-Key-OpenVZ
# yum install ovzkernel
이제 OpenVZ 커널이 설치되었으니 부트로더를 수정할 순서입니다. /boot/grup/grub.conf 파일을 열어보면 아마 다음과 같은 항목이 추가되었을 겁니다.

title OpenVZ (2.6.8-022stab029.1)
        root (hd0,0)
        kernel /vmlinuz-2.6.8-022stab029.1 ro root=/dev/sda5
        initrd /initrd-2.6.8-022stab029.1.img
이제 재부팅할때 OpenVZ를 선택하면 되는데, 그 때 마다 OpenVZ를 수동으로 선택하는 것은 귀찮으니까 이 파일 안에 있는 default= 뒤에 있는 숫자를 OpenVZ에 할당되어 있는 숫자로 (아마 십중팔구 0일 겁니다) 바꾸어 주세요.

그런 다음에는 이제 sysctl 파일을 ( /etc/sysctl.conf ) 변경해야 합니다.

# On Hardware Node we generally need
# packet forwarding enabled and proxy arp disabled
net.ipv4.ip_forward = 1
net.ipv6.conf.default.forwarding = 1
net.ipv6.conf.all.forwarding = 1
net.ipv4.conf.default.proxy_arp = 0

# Enables source route verification
net.ipv4.conf.all.rp_filter = 1

# Enables the magic-sysrq key
kernel.sysrq = 1

# We do not want all our interfaces to send redirects
net.ipv4.conf.default.send_redirects = 1
net.ipv4.conf.all.send_redirects = 0
없는 항목은 추가하고, 있는 항목의 값은 적절히 바꾸어 주세요.

그런 다음에는 /etc/sysconfig/selinux 파일을 고쳐서 다음과 같이 해야 합니다.

SELINUX=disabled
그런 다음 재부팅 하시고,

이제 OpenVZ 사용에 필요한 파일을 다음과 같이 해서 깔아줍니다.

# yum install vzctl vzquota
x86_64 플랫폼이면 다음과 같이 해야 한다고 하는군요. 저는 안해봤습니다.

# yum install vzctl.x86_64 vzquota.x86_64
자. 그럼 이제 OpenVZ 설치는 끝난 겁니다. 다음과 같이 해서, 실행합시다.

# /sbin/service vz start
여기까지 하면 이제 OpenVZ 커널 모듈이 올라가 있을 것입니다. 시스템이 재부팅되었을 때 이 마지막 절차를 또 해야 하는지는 잘 모르겠군요.





3. 가상머신 생성

자. 그럼 이제 가상머신을 생성해 보죠. 가상머신을 생성할 때에는 소위 가상머신 템플릿이라는 것이 /vz/template/cache/ 디렉터리 아래에 있어야 합니다. wget http://download.openvz.org/template/precreated/centos-5-x86.tar.gz 같이 입력해서 다운받습니다. 그리고 해당 디렉터리 아래에 갖다놓습니다. 그리고 다음과 같이 합니다.

# ln -s /vz/template/cache/centos-5-x86.tar.gz /vz/template/cache/centos-5.tar.gz
가상머신 생성은 굉장히 간단합니다.

# vzctl create 1011
이렇게 하면 1011번 가상머신이 만들어집니다. 그럼 해당 가상머신을 설정해보죠.

# vzctl set 1011 --hostname 1011.xxxx.re.kr --save
# vzctl set 1011 --ipadd 10.0.0.11 --save
# vzctl set 1011 --nameserver 1.2.3.4 --save
# vzctl set 1011 --userpasswd root:rootpasswd
호스트 이름, 가상머신의 IP 주소, 네임서버, 패스워드 등은 적절히 입력해 주세요. ^^ 그런 다음 가상머신을 다음과 같이 실행합니다.

# vzctl start 1011
그런 다음 ssh 10.0.0.11해 보시면, 해당 가상머신으로 SSH 접속이 가능함을 확인하실 수 있을겁니다. :-)

SSH 접속 후에 외부로 PING을 해보면 가상 머신을 설치한 기계의 IP주소 외에는 PING이 안될수도 있습니다. 주로 가상머신에 사설 IP 주소를 할당한 경우에 그러한데요.

그런 경우에는 가상 머신을 설치한 HOST 운영체제에 IP_TABLE을 조작해서 NAT처럼 동작하도록 만들어줘야 합니다. 여러분이 설치한 기계의 IP 주소가 192.168.5.4라고 해 볼까요? 그럼 다음과 같이 하시면 됩니다.

# iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 -j SNAT --to 192.168.5.4

그리고 나서는 firewall 설정을 변경해줘야 합니다.

# /sbin/iptables -A RH-Firewall-1-INPUT -s 10.0.0.0/24 -j ACCEPT
# /sbin/iptables-save > /etc/sysconfig/iptables
# /sbin/service iptables restart

간혹 VE 안에서 DNS가 안되는 경우가 있는데, 그런 경우가 발생하면 강제로 DNS 포트를 개방해야합니다.

# /sbin/iptables -A RH-Firewall-1-INPUT -p udp --dport 53 -j ACCEPT
이렇게 하면 VE 안에서 네트워킹도 웬만하면 다 되실겁니다. 뭔가 안되는 프로그램이 있다면 (yum 같은 것이 안될 수도 있습니다) 관련된 포트를 찾아서 열어주면 됩니다 (yum의 경우에는 80 포트를 개방해야 합니다.) 이거 저거 다 귀찮으실 때는 모든 ip 프로토콜을 다 개방하는 방법도 있습니다. 좀 껄쩍지근하긴 하지만 -A RH-Firewall-1-INPUT -p ip -j ACCEPT 처럼 하시면 되겠습니다.

각각의 컨테이너에 프로그램을 깔때는 vzctl exec를 사용하면 편합니다.

# vzctl exec 1011 yum -y install gcc autoconf automake

4. Troubleshooting

4.1. Java

Java를 설치하고 실행하면  Error occurred during initialization of VM : java.lang.OutOfMemoryError: unable to create new native thread 같은 오류가 뜨면서 java가 실행이 안될때가 있습니다. 그럴때는 java -Xmx64m 처럼 해 보실 것. 안되면 64보다 더 낮은 값으로 낮추는 것도 괜찮습니다. 그래도 해결이 안되실 때는 http://forum.openvz.org/index.php?t=msg&goto=7057 이 쓰레드를 참고하실 것.

4.2 메모리 등의 자원 부족

OpenVZ 컨테이너 안에서 메모리 등의 자원 부족 현상이 발생할 경우, 쓰레드가 안뜬다거나 자바 가상 머신이 안돈다거나 하는 문제가 생길 수 있습니다. 그럴 때는 해당 자원을 늘려주어야 하는데요. http://wiki.openvz.org/Resource_shortage 여기 언급된 대로 실제 물리적 기계 상에서 cat /proc/user_beancounters 를 해 보면 각각의 컨테이너 ID 별로 어떤 자원이 부족해서 문제가 생겼는지를 파악할 수 있습니다. failcnt에 0 아닌 숫자가 찍히거든요.

그런 문제가 생기면 문제가 생긴 자원을 두배로 늘려줘 보세요. 하는 방법은 다음과 같이 하시면 됩니다. 물리적 메모리의 양을 화면에 표시된 barrier, limit의 값의 두 배 값으로 setting하는 예제입니다.

# vzctl set 1011 --kmemsize $((2752512*2)):$((2936012*2)) --save



신고
Posted by 이병준
TAG centos, OpenVZ

소중한 의견, 감사합니다. ^^

Systems/Unix2011.08.11 17:18

가장 단순하게 맥북을 백업하고 하드 디스크를 교체하기 위한 절차를 살펴보면 (OS X Lion 기준) 다음과 같습니다.

1. 백업

가장 먼저 해야 할 일은 백업을 하는 것입니다. 백업을 하는 가장 단순한 방법은 (1) 외장 하드디스크를 연결하고 (2) 해당 하드디스크를 타임머신(Time Machine) 디스크로 만든 다음(아래 그림에서 '디스크 선택...'을 클릭하시면 됩니다) (3) 백업하는 것입니다.

이렇게 하면 나중에 하드 디스크를 교체하고 해당 하드 디스크에 Lion을 다시 설치하는 절차가 굉장히 단순해 집니다. 절차는 http://support.apple.com/kb/ht1427?viewlocale=ko_KR&locale=ko_KR 이 링크를 참고하시면 됩니다.

이 그림 파일의 저작권은 Apple Korea에 있습니다.



2. Mac OS X Lion 설치 디스크 만들기

설치 디스크를 만드는 절차는 http://www.buggymind.com/349 이 글에 소개한 바 있습니다. 이 절차를 따라 설치 디스크를 생성합니다.



3. 하드 디스크 교체

이제 하드 디스크를 물리적으로 교체해야 하는데요. 맥북 프로의 경우에는 http://blog.naver.com/PostView.nhn?blogId=luke1011&logNo=70089111055 이 글을 참고하시면 됩니다. 아주 깔끔하게 정리가 잘 되어 있습니다.

4. 만들어 둔 설치 디스크로 재부팅

설치 디스크를 DVD 트레이에 넣고, 재부팅합니다. 재부팅하면 아마 다음과 같은 화면을 보게 될 것입니다.


이 화면에서 Restore Frome TIme Machine Backup을 하면 되는데, 하드 디스크가 새것이므로 먼저 파티션을 만들어 줘야 합니다. Disk Utility를 선택하고 들어가서 아무 것도 없는 여러분의 새 디스크에 통짜 파티션을 하나 만들어 줍시다.

그런 다음에 위의 화면으로 다시 돌아와서 Restore From Time Machine Backup, 즉 타임머신 백업으로부터 복구를 선택합시다. 복구할 백업을 선택하라는 말이 나오면 최신 백업을 선택합시다. 백업 선택 후에는 이제 대상 하드 디스크를 선택해 줘야 하는데, 아까 파티션을 잡는 절차를 안했으면 아무 디스크도 나오지 않을 것입니다. 파티션을 잡았다면, 나올 터이니 그 하드 디스크를 선택합시다.

나머지 절차는 전부 맥이 알아서 해 줄 터이고, 시스템 복구가 끝나고 나면 여러분의 OS 상태는 하드 디스크를 교체하기 직전 상태로, 깔끔하게 정리되어 있을 겁니다.

Olleh! (Windows를 쓸때는 이렇게 깔끔하게 하드를 교체한 적이 없었는데.. ㅎㅎㅎ)


신고
Posted by 이병준

소중한 의견, 감사합니다. ^^

  1. 이번에 맥북에 SSD을 설치하려는 데 참고할께요. 타이머신을 해서 SSD로 복원하는 데 복원 마지막에 오류가 나서 애먹고 있어요

    2011.09.21 00:43 신고 [ ADDR : EDIT/ DEL : REPLY ]

Systems/Unix2011.07.26 15:56
라이언 설치 과정은 앞선 글에서 살펴본 대로 두 단계로 나뉜다. (1) 설치 App 다운로드 (2) 설치. 근데 성질이 급해서 (2)를 완료하신 분들은 아쉽지만 설치 디스크를 만들기가 거의 불가능하다. 설치 App이 이미 디스크에서 사라져버렸기 때문이다.

복구 파티션에서 설치 디스크 이미지를 추출할 방법은 없나?

http://www.hyemi.org/26504 에 나오는 대로 복구 파티션을 마운트해서 보면 BaseSystem.dmg 파일이 있어야 하는데, 실제로 해 보면 없다. 아니, 터미널에서는 보이는데 이 파일을 마운트하거나 공 DVD에 기록할 방법이 없다. diskutil도 이 파일을 읽지 못한다. Lion 정식 버전에서는 BaseSystem.dmg를 볼 수 없도록 꽁수를 쓴 듯. 카피 도중에는 보이는데 카피가 끝나면 다시 볼 수 없는 상태가 된다.

저 파일이 보이지 않는다



그렇다면 설치 App을 다시 받을 수 있는 방법은 없나?

있다. App Store로 다시 가자. OS X 라이언으로 가는 링크가 대문짝만하게 보일 것이다. 이 상태에서 "Option" 키를 누르고 링크를 클릭한다. 그러면 묘하게도 "설치됨"으로 나와 있어야 할 콤보박스가 "29.99$"로 바뀐다. 다시 다운 받을 수 있다는 뜻.

하지만 그냥은 안된다. 역시 "Option" 키를 누르고 해당 버튼을 클릭해야 한다. 그래야 Apple Id 비번을 물어보면서 다시 다운로드 한다.

이제 설치 디스크를 만들 수 있다 

이제 https://iglassbox.wordpress.com/2011/07/20/mac-os-x-lion-%EB%B6%80%ED%8C%85-dvd-%EB%A7%8C%EB%93%A4%EA%B8%B0/ 에 기술된 방법을 써서 설치 디스크를 만들 수 있다. 

내부가 이렇게 생겨먹었다


 
설치 디스크를 만들어 두면 언제 써먹나? 하드를 일반 하드에서 SSD 등으로 교체하였을 경우 유용하다. 하드를 교체한 경우에는 설치 CD가 없으면 곤란하다. 갖고 있는게 Snow Leopard CD밖에 없다면? Lion 설치하자고 이전 운영체제를 통째로 다 설치한 다음에... 귀찮은 과정일 거라는 감이 팍팍 오실 듯.



실제로 재설치를 시도해 보면?

뭐 굳이 강조할 필요 없는 이야기지만... 타임머신에 백업을 받아놓든 뭘 하든 일단은 백업을 잘 받아 두자. 그리고 나서 재설치를 시도해 보면...

위의 방법으로 만든 디스크는 엄밀한 의미에서의 "설치용 배포판"은 아니라는 사실이 감이 딱 온다. 오히려, Lion으로 업그레이드 하면 생기는 "Recovery HD" 파티션 안에 들어있는 이미지에 가깝다. 구동되고 나면, 타임머신 백업으로부터 복원할 건지, 파티션부터 나눌 건지, 친절하게 물어보는 걸로 봐서 그렇다. 

요런 화면이 뜬다. Recovery HD로 부팅한 화면과 똑같다. http://www.cultofmac.com/mac-os-x-lion-adds-recovery-partition-support-gallery/83737

 

어쨌든, Recovery HD에 있는 내용과 똑같은 부팅 디스크를 얻었으니, 이제 맥이든 맥북이든 하드디스크 교체와 같은 빡센 작업을 할 때 활용해먹을 수 있다.

 
신고
Posted by 이병준

소중한 의견, 감사합니다. ^^