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 ]