Information content (IC)은 언어학에서 나왔던 개념으로,문맥상에 어떤 개념이 나타내면, 이 개념이 나타내는 것은 정보의 양을 나타냅니다. 주로, 추상적인 개념(상위 개념)일수록 정보량이 많지 않기 때문에, IC값이 낮아지도록 표현이 되고, 구체적인 개념을 일컫을 수록 IC값이 높아지게 됩니다. IC값을 적절하게 설계했으면, 각 개념(또는 단어)가 얼마나 모호한지(=상위개념인지)를 알 수 있습니다. 그리고, 이러한 IC값을 온톨로지들 간의 유사도로 사용할 수 있습니다.

 

IC의 정의는 아래와 같습니다. 온톨로지 상에서 존재하는 모든 개념($C$)내에 특정 개념($c$) 은 $c \in C$이며, 0과 1사이 값을 가진다고 합니다[0, 1]. 그리고, 특정 두 개념이 IS-A 관계라고 하면, $c_{2}$가 상위텀이라면, $p(c_{1}) <= p(c_{2})$여야 합니다. 그리고, 최상위노드가 하나라면, 이 최상위 노드의 확률값은 1이 되게도록 확률을 정의합니다 [1]. 이때 IC값은 다음과 같습니다.

$IC = -log p(c)$

예를 들어, WordNet의 말뭉치내에, 아래와 같은 분류체계가 있다고합시다. 분류체계내에 하위텀으로 갈수록, 구체적이기 때문에, 빈도가 적게나오고 정보도 많을 것입니다, 반대로 상위텀일수록 추상적이 많이 나온 개념이기에, 위로갈수록 확률은 높아집니다. 이러다 극단적으로 최상위개념이면, 모든 개념을 포함하기에 확률을 1로 합니다. IC값은 logP(c)이므로, [0과 1]의 p값이 클수록 (=0.99999)에 가까울수록 0으로 수렴합니다. 반대로 0에 가까울수록 값이 엄청나게 음수가됩니다. 이 음수가된 것을 다시 -을 취하니 값은 커지게 됩니다 (Figure 2).

Figure 1. 자료. https://www.ijcai.org/Proceedings/95-1/Papers/059.pdf
Figure 2. Log fucntion. (https://saylordotorg.github.io/text_intermediate-algebra/s10-03-logarithmic-functions-and-thei.html)

 

Resnik의 semantic similarity (1995)


1995년에 Resnik은 IC을 이용해서 두 개념이 의미론적으로 얼마나 유사한지를 측정할 수 있게 했습니다. 두 개념의 유사도를 측정하기위해서 아래의 공식을 사용합니다 [2].

$sim(c_{1}, c_{2}) = max_{c\inS(c_{1}, c_{2})} [-logP(c)]$

where S(c_{1}, c_{2}) is the set of concepts that subsume both $c_{1}$ and $c_{c2}$

위의 개념에서 subsume은 "포함하다"를 의미합니다. 즉, c1, c2을 포함하는 집합을 의미하므로, 두 개념을 포함하는 상위개념들의 집합을 의미합니다. 두 개념을 포함하는 상위집합중에서 가장 IC가 높은것을 의미하므로, "두 개념을 포함하는 상위 개념중에 가장 아래에 있는 개념(=구체적인 개념)"을 의미합니다.

 

Figure 1에서 S(nickel, dime)은 COIN, CASH, MONEY, MEDIUM OF EXCHANGE...등을 포함하고, 두 개념의 유사도에 쓰이는 c은 이 중에거 가장 하위에 있는 것이기 때문에, COIN이 됩니다. 즉 COIN의 -logP(c)을 구하면됩니다. 이 P(c)은 문제마다 다르므로 구체적인 내용은 스킵합니다. 단, 이를 구하는 예시를 하나 들어보자면, 일반적인 자연어처리문제라면, 전체 corpus가 있을 것이고, 이 corpus에 단어가 전체 K개가 있다고 합시다. 그리고 워드넷이라는 taxonomy에 들어있는 개념이 h개 라면, 전체 N은 각 h가 corpus에 얼마나 있는지를 세어보면 알 것입니다. 그리고 N중에 실제 각 개념 c들이 얼마나 있는지 상대적인 빈도로 제시합니다.

Figure 3. Resnik의 WordNet에서의 IC계산 사례

 

 

[1] Ross, S. M. (2019). A first course in probability. Boston: Pearson.

[2] Resnik, P. (1995). Using information content to evaluate semantic similarity in a taxonomy. arXiv preprint cmp-lg/9511007.

반응형

요약


master node에 쿠버네티스를 세팅하고, 각 노드랑 연결해보려고합니다. 쿠버네티스로 클러스터를 구성하는 것은 1) control-plane을 설치해야합니다(단일 control-plane또는 복수의 control-plane도 가능), 2) 또한, 각 워커노드들을 등로갛여 파드들의 네트웍이 클러스터내에서 잘 통신되게 하는 것입니다.

 

시작전에 앞서


kubeadm을 이용해서 쿠버네티스를 세팅해보려고합니다. kubeadm으로 쿠버네티스를 세팅하는 것이 쿠버네티스 공식홈페이지에서도 "best practice"라고 설명되어있습니다. kubeadm은 쿠버네티스를 간단히 설치해서 사용해보기에 용이합니다. 

 

 

사용 전 확인사항


쿠버네티스를 사용하기전에 장치에 아래의 스펙요구사항을 만족하는지 확인해야합니다.

  • A compatible Linux host. The Kubernetes project provides generic instructions for Linux distributions based on Debian and Red Hat, and those distributions without a package manager.
  • 2 GB or more of RAM per machine (any less will leave little room for your apps).
  • 2 CPUs or more.
  • Full network connectivity between all machines in the cluster (public or private network is fine).
  • Unique hostname, MAC address, and product_uuid for every node. See here for more details.
  • Certain ports are open on your machines. See here for more details.
  • Swap disabled. You MUST disable swap in order for the kubelet to work properly

마지막의 swap을 끄라고 되어있는데 이는 "kubelet"이라는 데몬이 정상적으로 돌게하기위함이라고 합니다. "kubelet"은 파드에서 컨테이너들이 "선언적으로 정의한"(=내가 세팅한 그대로 현 상태를 유지해주는 것)대로 실행되게끔 해주는 데몬입니다. 

 

본 포스팅에서는 카카오클라우드를 이용해서 private network로 구성된 클러스터를 구성해볼 예정입니다. 사설 IP로 구성된 노드들은 아래와 같습니다.

MAC address가 유요한지 product uuid가 각 노드에서 유니크한지 확인합니다. 아래의 명령어를 이용해서, 각 노드에서 MAC adresss, product_uuid가 유일한지 확인해봅니다. 일단은 마스터노드만 확인해봅니다.

ubuntu@k8s-master:~$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback [.........]
2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether [..........]
    
    
ubuntu@k8s-master:~$ sudo cat /sys/class/dmi/id/product_uuid
[...........]

 

K8S을 설치하기전에 필수로 설치해야할 것이 docer가 있습니다. Docker은 다음의 링크로 설치하시길바랍니다 [1]

 

kubeadm, kubelet, kubectl을 설치할 것입니다. 각 기능은 아래와같습니다.

  • kubeadm: 클러스터를 구축하고 실해나는 과정을 의미합니다 (=cluster bootstrap). control-plane, worker nodes을 구성하고 각 노드들끼리 올바른 정보들을 가지고있는지, 통신이 한지를 확인합니다. [2] 
  • kubelet: 선언적으로 정의한 대로 파드를 시작하거나, 컨테이너를 시작해주는 기능을 합니다.
  • kubectl: 쿠버네티스를 운용하는 사용자와 인터페이스하는 기능을 합니다.

 

구글 공개키를 다운로드합니다.

sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg

apt 리포지토리에 쿠버네티스를 등록합니다.

echo "deb [signed-by=/etc/apt/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list

apt 패키지를 업데이트하고, kubelet, kubeadm, kubectl을 설치합니다. 아래의 apt-mark hold은 다른 패키지들이 ㅅ ㅓㄹ치되면서 자동으로 해당패키지들은 업그레이드 되거나, 제거되지 않게 하기 위함입니다.

sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl # 패키지 버전/삭제/업데이트 고정

 

cgroup 드라이버를 systemd로 일치

sudo mkdir /etc/docker
 
cat <<EOF | sudo tee /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
EOF
  
sudo systemctl enable docker
sudo systemctl daemon-reload
sudo systemctl restart docker
 
 
kubeadm reset

 

(option) kubeadm init이 문제가 있는 경우 해결방법

sudo rm /etc/containerd/config.toml
sudo systemctl restart containerd
sudo kubeadm init

 

kubeadm init을 하고나면, 아래와 같이 join하기 위한 토큰도 나오고, 일반사용자도 클러스터를 등록하기위해서 사용하라는 명령어도 나옵니다. 

kubeadm init --apiserver-advertise-address 172.16.2.231  # Master의 Host을 CIDR로 사용합니다.
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:


# 하단의 명령어는 적을 수 있다면 잘 기록하시길 바랍니다.
kubeadm join 172.16.2.231:6443 --token y24p4r.7itfeqy96rkjof8q \
        --discovery-token-ca-cert-hash sha256:5e9e43eadba4eb7858033de6fbb4d99cc811f7d49d96f3637435370463c087e

 

클러스터의 실행을 위해서 위의 나온 메시지대로 $HOME/.kube/config 파일을 설정합니다. (일반사용자로 전환후)

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

 

아래의 명령어로 쿠버네티스(kubelet, kubeadm, kubectl)이 설치된 노드에서 클러스터로 참여할 수 있게됩니다. 그리고, 해당 노드는 워커노드가 됩니다. 이 명령어를 잃버어렸다고해서 참여못하는 것은 아닙니다. 

# kubeadm join <kubernetst cluster API:PORT> --token [token] --discovery-token-ca-cert-hash sha256 <hash>

kubeadm join 172.16.2.231:6443 --token y24p4r.7itfeqy96rkjof8q \
        --discovery-token-ca-cert-hash sha256:5e9e43eadba4eb7858033de6fbb4d99cc811f7d49d96f3637435370463c087e

 

token을 잃어버렸을 경우 및 해시를 잃어버린경우

// 명렁어로 토큰 출력
# kubeadm token list 

// 아래의 명령어로 해시 출력
# openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'

 

 

control-plane에서만 deployment을 실행하면 파드가 생성되지않음을 확인할 수 있습니다. deployment에는 replicas 수를 3으로 지정해놓았는데요. 할당할 worker노드가 없기 때문에 pending으로 나온 것으로 판단됩니다.  실제로 하나의 파드의 상태를 추적해보면 아래와 같습니다.

root@k8s-master:/home/ubuntu# kubectl apply -f controllers-nginx-deployment-yaml
deployment.apps/nginx-deployment created
# watch "kubectl get pods"
Every 2.0s: kubectl get pods                                                                        k8s-master: Sun Jan  8 09:00:15 2023

NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-85996f8dbd-98xlx   0/1     Pending   0          118s
nginx-deployment-85996f8dbd-d9bhg   0/1     Pending   0          118s
nginx-deployment-85996f8dbd-kjk8t   0/1     Pending   0          118s
root@k8s-master:/home/ubuntu# kubectl describe pod nginx-deployment-85996f8dbd-98xlx
Name:             nginx-deployment-85996f8dbd-98xlx
Namespace:        default
Priority:         0
Service Account:  default
Node:             <none>
Labels:           app=nginx
                  pod-template-hash=85996f8dbd
Annotations:      <none>
Status:           Pending
IP:               
IPs:              <none>
Controlled By:    ReplicaSet/nginx-deployment-85996f8dbd
Containers:
  nginx:
    Image:        nginx:1.14.2
    Port:         80/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-h2w8s (ro)
Conditions:
  Type           Status
  PodScheduled   False 
Volumes:
  kube-api-access-h2w8s:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  49s   default-scheduler  0/1 nodes are available: 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }. preemption: 0/1 nodes are available: 1 Preemption is not helpful for scheduling..

 

 

Worker노드를 할당해보겠습니다.

1. 마스터노드에서 join command을 stdout합니다.

root@k8s-master:/home/ubuntu# kubeadm token create --print-join-command
kubeadm join 172.16.2.231:6443 --token 8yxfot.ktr4irill5hqw6h7 --discovery-token-ca-cert-hash sha256:bd91d60981b5774add11106cd42e1f8d6db18b241b5fd529b0d638e71

2. Worker Node에서 해당 명령어를 copy&paste 하여 사용합니다.

root@k8s-test:/home/ubuntu# kubeadm join 172.16.2.231:6443 --token 8yxfot.ktr4irill5hqw6h7 --discovery-token-ca-cert-hash sha256:bd91d60981b5774add11106cd42e1f8d6db18b241b5fd529b0d638e713522494
[preflight] Running pre-flight checks
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

 

control-plane (master node)로 돌아가, 파드가 정상적으로 실행되는지 확인합니다. nginx 서버 3개가 정상적으로 돌아가는 것을 확인할 수 있었습니다.

root@k8s-master:/home/ubuntu# kubectl get pods --all-namespaces
NAMESPACE     NAME                                      READY   STATUS    RESTARTS   AGE
default       nginx-deployment-85996f8dbd-98xlx         1/1     Running   0          30m
default       nginx-deployment-85996f8dbd-d9bhg         1/1     Running   0          30m
default       nginx-deployment-85996f8dbd-kjk8t         1/1     Running   0          30m
kube-system   calico-kube-controllers-7bdbfc669-5qmkf   1/1     Running   0          4h49m
kube-system   calico-node-4ss8x                         0/1     Running   0          86s
kube-system   calico-node-ns4ct                         0/1     Running   0          4h49m
kube-system   coredns-787d4945fb-lgxsp                  1/1     Running   0          5h8m
kube-system   coredns-787d4945fb-xs85r                  1/1     Running   0          5h8m
kube-system   etcd-k8s-master                           1/1     Running   3          5h8m
kube-system   kube-apiserver-k8s-master                 1/1     Running   3          5h8m
kube-system   kube-controller-manager-k8s-master        1/1     Running   3          5h8m
kube-system   kube-proxy-4rkz6                          1/1     Running   0          5h8m
kube-system   kube-proxy-pzbmc                          1/1     Running   0          86s
kube-system   kube-scheduler-k8s-master                 1/1     Running   3          5h8m

 

 

아래와 같이, NodePort와 deployment을 각각 실행합니다. deployment와 nodeport의 manifest(yaml)은 아래와 같습니다.

# nodeport.yaml
apiVersion: v1
kind: Service
metadata:
  name: nodeport-svc
spec:
  type: NodePort
  clusterIP: 10.100.100.200
  selector:
    app: my-nginx  # deployment에 의해서 생성되는 라벨의 이름과 동일해야합니다.
  ports:
  - protocol: TCP
    port: 80         # 쿠버네티스 서비스의 포트
    targetPort: 80   # POD로 전달될 포트
    nodePort: 30052  # 각 노드에 뚫릴 포트입니다. 외부와 통신합니다.

 

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      app: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        app: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports :
        - containerPort: 80

 

// 클러스터에서 실행해봅시다.
# kubectl apply -f nodeport.yaml
# kubectl apply -f deployment.yaml

 

리소스들이 제대로 생성되었는지 확인합니다.

// 리소스들이 잘 실행되는지 확인
root@k8s-master:/home/ubuntu/test# kubectl get pods,deploy,svc,endpoints

NAME                            READY   STATUS    RESTARTS   AGE
pod/my-nginx-7c777db54b-26rcz   1/1     Running   0          34m
pod/my-nginx-7c777db54b-4l2wc   1/1     Running   0          34m
pod/my-nginx-7c777db54b-4wtdn   1/1     Running   0          34m
pod/my-nginx-7c777db54b-8l2vg   1/1     Running   0          34m
pod/my-nginx-7c777db54b-dmtjd   1/1     Running   0          34m
pod/my-nginx-7c777db54b-fphk9   1/1     Running   0          34m
pod/my-nginx-7c777db54b-rcql5   1/1     Running   0          34m
pod/my-nginx-7c777db54b-s658f   1/1     Running   0          34m
pod/my-nginx-7c777db54b-tq5t6   1/1     Running   0          34m
pod/my-nginx-7c777db54b-tqd4q   1/1     Running   0          34m

NAME                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/my-nginx   10/10   10           10          34m

NAME                   TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
service/kubernetes     ClusterIP   10.96.0.1        <none>        443/TCP        34m
service/nodeport-svc   NodePort    10.100.100.200   <none>        80:30052/TCP   34m

NAME                     ENDPOINTS                                                           AGE
endpoints/kubernetes     172.16.2.231:6443                                                   34m
endpoints/nodeport-svc   172.18.137.166:80,172.18.137.167:80,172.18.137.168:80 + 7 more...   34m

 

각 node로 들어가서 listening 중인지 확인합니다. 쿠버네티스 최신버전들은 netstat으로 확인이 불가능하고, iptables로만 확인이 가능합니다.

ubuntu@k8s-master: ssh k8s-test

ubuntu@k8s-master: su

root@k8s-test:/home/ubuntu# iptables -t nat -L KUBE-NODEPORTS | column -t
Chain                      KUBE-NODEPORTS  (1   references)
target                     prot            opt  source       destination
KUBE-EXT-FDIGUWRAAKMFZSYO  tcp             --   anywhere     anywhere     /*  default/nodeport-svc  */  tcp  dpt:30052

 

30052로 제대로 포트로 요청을 보내서 응답이 오는지 확인해봅니다.

root@k8s-test:/home/ubuntu# curl localhost:30052
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

 

localhost말고, 외부에서 해당 노드로도 요청을 보내봅니다.

// 마스터노드에서 노드1의 사설IP:30052포트로 요청
ubuntu@k8s-master:~$ curl 172.16.2.253:30052
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

 

[1] https://confluence.curvc.com/pages/releaseview.action?pageId=98048155#:~:text=kubelet%2C%20kubeadm%2C%20kubectl%20%EC%84%A4%EC%B9%98%20(master%2C%20node),-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4&text=%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4%EB%A5%BC%20%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0%20%EC%9C%84%ED%95%B4%20Kubernetes%20%EC%A0%80%EC%9E%A5%EC%86%8C%20%EC%B6%94%EA%B0%80%ED%95%9C%EB%8B%A4.&text=%EC%A0%80%EC%9E%A5%EC%86%8C%20%EC%97%85%EB%8D%B0%EC%9D%B4%ED%8A%B8%20%ED%9B%84%20kubelet%2C%20kubeadm,%EB%A5%BC%20%EC%88%9C%EC%B0%A8%EC%A0%81%EC%9C%BC%EB%A1%9C%20%EC%A7%84%ED%96%89%ED%95%9C%EB%8B%A4.&text=%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4%EB%A5%BC%20%EC%84%9C%EB%B9%84%EC%8A%A4%20%EB%93%B1%EB%A1%9D%20%EB%B0%8F%20%EC%9E%AC%EC%8B%9C%EC%9E%91%EC%9D%84%20%EC%88%98%ED%96%89%ED%95%9C%EB%8B%A4.

[2] https://www.techtarget.com/searchitoperations/tip/Learn-how-to-bootstrap-Kubernetes-clusters-with-kubeadm

반응형

요약


임상시험은 대부분 무작위 선정(Randomization)으로 시험군(case), 대조군(Control)을 나눈다. 이 시험군과 대조군에 중재를 할 때, 시험군 또는 대조군에 속해있는 대상자들이 모종의 이유로 중재를 못받게 되는 상황이 된다(중도 탈락, 중재 전 사망, 치료 불이행). 이 때, 어쩔수없는 이유로 중재를 못받은 사람을 분석에 포함해서 의학적 성과(outcome)을 측정해야하냐 말아야하나 고민되는 시점이 생긴다. IIT은 모종의 이유가 있다 하더라도, 일단 무작위 배정되었으면, 분석에 포함하는 것을 일컫는다(“once randomized, always analyzed”). 반대의 개념으로는 "Per-Protocol"이라고 하며, 중재를 못받은 샘플을 분석에 포함하지 않는 것을 의미한다.

 

 

Reference

[1] https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5654877/

반응형

딥러닝을 이용한 서비스를 배포할 목적이 있으면, 운영체제 등에서 독립적으로 S/W가 돌아갈 수 있게끔 배포하는 것이 중요하다. 이 때 주로쓰이는 것이 컨테이너 기술인데, 컨테이너 기술을 이용해서, 딥러닝의 GPU가속을 사용해보자.

 

단계는 아래와 같다


  1. NVIDA driver (그레픽 드라이버) 와 docker은 설치
  2. CUDA 이미지 풀하기
  3. GPU 지원 컨테이너 만들기
    1. 방법 1: Native GPU support
    2. 방법 2: Nivida container Runtime을 이용하기
    3. 방법 3: Nivida GPus 을 위한 도커엔진 유틸리티 이용하기
  4. 확인: GPU 지원 컨테이너 내 접속 후 cuda확인

 

0. NVIDIA driver 확인


이미 설치된 경우, 다음의 코드로 CUDA Version을 확인한다.아래와 같이 CUDA Version이 11.7임을 확인할 수 있다. 

$nvidia-smi

 

 

2. 도커허브에서 CUDA 이미지 가져오기


docker hub에 cuda을 검색하면, 아래의 그림과 같이 여러 이미지들이 검색되어 나온다.

그 중에, nvidia/cuda을 설치해본다. (링크: https://hub.docker.com/r/nvidia/cuda)

 

nvidia/cuda 리포지토리에 들어가면 Tags가 나오는데, CUDA 버전에 맞는 tag을 찾아본다.

 

아래와 같이 CUDA 버전에 맞는 이미지를 찾는다.

nvidia-smi 명령어에서 cuda 버전이 11.7이었으므로 11.7을 검색해서 runtime, base, devel, 버전 및 원하는 컨테이너 OS환경에 맞춰 설치한다.

 

필자는 nvidia-11.7.1용 런타임-ubunut22.04을 pull했다.

 

제대로 잘 pulling되었는지 아래와 같이 확인해본다.

 

 

GPU 지원 컨테이너 사용: 방법1: Native GPU 지원


아래와 같이 docker 및 docker환경에서 GPU을 돌리기위한 데몬(nvidia-container-toolkit)을 설치한다

// docker, nvidia-conatiner-toolkit 설치
$ sudo apt-get install -y docker nvidia-container-toolkit

 

모든그레픽카드을 사용할 수 있도록 GPU세팅을 하는 것은 아래와 같다.

docker run --gpus all [이미지명:테그명]

 

필자는 background option으로 (-d), ssh로 접속해서 인터렉션할것이기 떄문에(-it)아래와 같이 옵션을 주어 컨테이너를 실행한다.

컨테이너명이 "2c2e80a61f240a689d1d6d13a94c886fdab9508fc6226e1889ac5cbb623a5528"로 반환되어 컨테이너가 실행중임을 알려준다.

 

컨테이너가 잘 생성되었는지, docker ps명령어로 확인해본다. 33초전에 실행됨을 확인할 수 있다.

이 컨테이너로 직접 들어가보자

 

대화창이 나온다.

 

nvidia-smi명령어로 host graphic card을 사용할수 있는지 확인해본다.

 

반응형

0. PUSH할 원격저장소를 만든다. docker hub (https://hub.docker.com/) 에서 로그인 후, 원격저장소를 생성한다. github저장소처럼 "ID/원격저장소명"으로 주소가 만들어진다.

 

 

1. 도커 로그인

$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: [YourID]
Password: ******

Login Succeeded

 

 

2. Docker hub에 올릴 이미지를 찾는다. 여기서 필자는 REPOSITOY에 simple-nlp-app, TAG은 v1을 올릴 것이다. 그렇지만, 도커허브에 올릴 때는 ID/repository명  = docker image ls에서의 REPOSITORY 명이 동일해야한다. 따라서, 한번 변경이 필요하다. 

$ docker image ls
REPOSITORY                                                TAG                                                                          IMAGE ID       CREATED         SIZE  
simple-nlp-app                                            v1                                                                           7108c8dbe574   6 minutes ago   2.73GB
simple-nlp-app                                            v0                                                                           c82b9d4786fe   9 minutes ago   2.73GB
simple-nlp-app                                            latest                                                                       798c7cf60156   2 days ago      2.72GB
nginx                                                     latest                                                                       ac8efec875ce   6 days ago      142MB 
alpine/git                                                latest                                                                       22d84a66cda4   3 weeks ago     43.6MB
hubproxy.docker.internal:5000/docker/desktop-kubernetes   kubernetes-v1.25.2-cni-v1.1.1-critools-v1.24.2-cri-dockerd-v0.2.5-1-debian   09d7e1dbc2c4   2 months ago    363MB 
k8s.gcr.io/kube-apiserver                                 v1.25.2                                                                      97801f839490   2 months ago    128MB 
k8s.gcr.io/kube-controller-manager                        v1.25.2                                                                      dbfceb93c69b   2 months ago    117MB 
k8s.gcr.io/kube-scheduler                                 v1.25.2                                                                      ca0ea1ee3cfd   2 months ago    50.6MB
k8s.gcr.io/kube-proxy                                     v1.25.2                                                                      1c7d8c51823b   2 months ago    61.7MB
k8s.gcr.io/pause                                          3.8                                                                          4873874c08ef   5 months ago    711kB 
k8s.gcr.io/etcd                                           3.5.4-0                                                                      a8a176a5d5d6   6 months ago    300MB 
k8s.gcr.io/coredns                                        v1.9.3                                                                       5185b96f0bec   6 months ago    48.8MB
docker/desktop-vpnkit-controller                          v2.0                                                                         8c2c38aa676e   19 months ago   21MB  
docker/desktop-storage-provisioner                        v2.0                                                                         99f89471f470   19 months ago   41.9MB
nginx                                                     1.14.2                                                                       295c7be07902   3 years ago     109MB 
dattarajrao/simple-app                                    latest                                                                       3f4a466b587c   4 years ago     132M

 

3. 두 가지 방법이 있는데, 첫 번째는 docker image tag을 이용하는 방법.

  • docker image tag SOURCE_IMAGE[:TAG] TARGET[:TAG]  . 이 명령어는 원본 이미지에서 타겟이이지로 리포지토리 명을 다시 테그를 달 수 있게한다.
  • docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]] : 이 명령어는 실행중인 컨테이너를 다시 이미지화하는 방법이다.

아래의 예시는 docker image tag을 이용한 방법이다. tag을 이용할 때, 미리 생성한 원격저장소의 이름과 동일하게 해준다. 그렇지 않으면 아래와 같이 에러가 뜬다.

$ docker push 4pymgalion/simple-nlp-app:v1
The push refers to repository [docker.io/4pymgalion/simple-nlp-app]
An image does not exist locally with the tag

 

따라서, 아래와 같이 원격저장소의 ID/저장소명과 같이 도커 이미지를 테그를 다시 달아준다. 그러면 추가로 "4pygmalion/simple-nlp-app"라는 리포지토리 이름을 가진 이미지가 생성된다.

$ docker tag simple-nlp-app:v1 4pygmalion/simple-nlp-app:latest
$ docker images
REPOSITORY                                                TAG                                                                          IMAGE ID       CREATED          SIZE
4pygmalion/simple-nlp-app                                 latest                                                                       7108c8dbe574   14 minutes ago   2.73GB
simple-nlp-app                                            v1                                                                           7108c8dbe574   14 minutes ago   2.73GB
nginx                                                     latest                                                                       ac8efec875ce   6 days ago       142MB 
alpine/git                                                latest                                                                       22d84a66cda4   3 weeks ago      43.6MB
hubproxy.docker.internal:5000/docker/desktop-kubernetes   kubernetes-v1.25.2-cni-v1.1.1-critools-v1.24.2-cri-dockerd-v0.2.5-1-debian   09d7e1dbc2c4   2 months ago     363MB 
k8s.gcr.io/kube-apiserver                                 v1.25.2                                                                      97801f839490   2 months ago     128MB 
k8s.gcr.io/kube-scheduler                                 v1.25.2                                                                      ca0ea1ee3cfd   2 months ago     50.6MB

 

4. 푸시: Docker push 도커이미지/리포지토리명

$ docker push 4pygmalion/simple-nlp-app:latest
The push refers to repository [docker.io/4pygmalion/simple-nlp-app]
e56c84262ba7: Pushing [>                                                  ]  35.33kB/2.22MB
cec010fb56f8: Pushing [>                                                  ]  544.8kB/2.262GB
5af9244c08c5: Pushing [==================================================>]  5.632kB
fac360d91a98: Preparing
c43e4ddc5992: Preparing
e5896e4ce6c3: Waiting
7c40600bc52d: Waiting
d326469892d9: Waiting
b5ebffba54d3: Waiting

 

반응형

 

요약


쿠버네티스를 이용하면,파드를 통해 클라이언트들이 어플리케이션을 호출할 수 있다. 그러나, 클라이언트 입장에서는 각각 파드의 주소가 존재하는하고, 클라이언트는 어느 파드로 갈지 명시하지 않았는데도, 쿠버네티스가 알아서 각각의 파드가 처리하게 만들어준다. 즉, 네트워킹이 쿠버네티스에 의해서, 알아서 처리되는데, 이 네트워크 서비스를 제공할 수 있는 자원이 "서비스(Service)"이다. 즉, 파드로 실행중인 앱을 네트워크서비스로 노출하게 해주는 자원이다.

 

 

서비스를 이용하기위해 각 파드, 노드가 만족해야할 사항[1]


  • 각 파드는 노드상의 모든 파드와 통신할 수 있어야함
  • 노드상의 에이전트(데몬, kubelet)은 해당 노드의 모든 파드와 통신할 수 있어야함.

 

 

어플리케이션을 네트워크 서비스로 외부에 노출하기


아래와 같이, 디플로이먼트(deployment)와 서비스(Service)를 명시한 yaml파일을 각각 만든다. 

// nginx-svc.yaml

apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    run: my-nginx
# run-my-nginx.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80

 

그리고, 아래와 같이 클러스터 내부에서는  서비스가 가능하고, 각 클러스터의 IP을 확인할 수 있다.

$ kubectl get services
NAME              TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes        ClusterIP   10.96.0.1        <none>        443/TCP        28h
my-nginx          ClusterIP   10.108.171.235   <none>        80/TCP         26h

해당 클러스터의 내부

 

 

Trouble shooting: Cluster IP에 접속이 안될 때 -> Node Port로 외부 클라이언트가 접속할 수 있도록 변경 [2]


서비스하는 클러스터의 IP는 가상의 IP이기 때문에, 클러스터 내부에서 내부로만 서비스할 수 있다. 즉 위의 예시에서처럼 클러스터 IP가 10.108.171.235면, 이 클러스터로 들어가야만 "10.108.171.235:80"의 서비스를 요청하고 받을 수 있는 것이다. 이것을 해결하기, "Cluster IP"을 "Node Port"로 변경해주어야 한다.

Node Port은 외부 클라이언트가 노드로 접속하기 위한 포트를 의미한다. 이 노드 포트을 변경하려면 아래와 같이 kubectl expose을 이용한다.

$ kubectl expose deployment hello-world --type=LoadBalancer --name=example-service

 

expose을 하면 TYPE이 NodePort인 서비스가 하나 생성이된다.  example-serivce라는 이름을 가진 서비스의 TYPE이 NodePort인 것을 잘보자. 이 클러스터의 가상 IP은 10.101.151.252이다. 이것은 여전히 가상IP이기 때문에 서비스를 요청할 수 없다. 다만, 이 노드의 원래주소(localhost, 또는 privateIP, publicIP)로 들어갈때, 30384포트로 요청을하면 알아서 80번으로 바꿔준다. 즉 포트포워딩으로 30384을 80으로 바꿔서 10.101.151.252로 요청해볼 수 있다.

$ kubectl get services
NAME              TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
example-service   NodePort    10.101.151.252   <none>        80:30384/TCP   26h
kubernetes        ClusterIP   10.96.0.1        <none>        443/TCP        28h

$ curl localhost:30384
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

 

 

[1] https://kubernetes.io/ko/docs/concepts/services-networking/

 

서비스, 로드밸런싱, 네트워킹

쿠버네티스의 네트워킹에 대한 개념과 리소스에 대해 설명한다.

kubernetes.io

[2] https://stackoverflow.com/questions/49297226/kubernetes-cluster-ip-service-not-working-as-expected

반응형

+ Recent posts