요즘 관심 있는 분야가 웹, 빅데이터, 인프라, AI인데, 이 포스팅은 인프라 관련된 내용! 

보통 개발자가 개인 피시에서 개발을 하고, 개발한 소프트웨어를 운영서버에 올리게 된다.

개발서버와 운영서버는 환경이 다르기에, 개발서버에서 설치한 소프트웨어들을 운영서버에도 설치해줘야 하고, 코드에 문제가 있을 시 다시 배포해줘야 한다. 
위 작업들이 실제 개발을 할 때, 생각보다 많은 비용(시간)이 소요될 수가 있다. 

또한, 이러한 작업을 사람이 직접 여러 서버에 하다 보면, 실수가 발생하여 서버 간 환경이 조금씩 달라질 수 있다. 이를 snowflake 서버라고 한다.  눈송이를 보면 다 똑같은 모양처럼 느껴지지만 실제론 다들 조금씩 다르다. 
( 모든 서버에 똑같이 설치된 거 같지만, 실제론 약간씩 다르다 ) 



운영하는 입장에서  가장 껄끄러운 게 오래된 서버라고 한다. 조금씩 다른 서버에 ( snowflake서버 ) 무슨 문제가 일어날지 모르기 때문에 .. 


이래서 나온 게 phoenix서버 !  
피닉스 서버는 말 그대로 불사조! 다시 살아나는 서버 ( 말 그대로 서버를 아예 비우고, 다시 설치함 [Immutable Server] )

기업들은 이러한 작업들을 자동화(생산성 향상) 하는 방안들에 대해 고민을 하게 되었다. 
그래서 나온 게  Infrastructure as Code 수작업으로 해오던 인프라 구축이나 변경 작업을 코드로 자동화하는것. 이러한 작업으로 인프라에 반복성과 확장성을 부여한다. 
이러한 Tools로 나온 게 Ansible, Chief, puppet, Terraform, AWS Cloudformation

위와 같은 자동화 기술이 발전하면서 Immutable Infrastructure( 서버가 배포된 후에 수정되지 않는 인프라 )란 말도 같이 이슈도 떠올랐다. 

Immutable Infrastructure : 아예 인프라 구축이나 변경 작업을 모두 자동화하자! 

이런 것을 가능하게 해주는 도구가 여러 가지가 있다. 
먼저 개발 환경과 동일한 환경을 이미지로서 제공해주는 Docker와 이를 관리하기 위한 Kubernetes, Docker Swarm, Apache Mesos 등의 도구가 있다. 
( bare metal서버 환경은 안 변하고 이미지만 교체하여 컨테이너로 띄우기 때문에 snowflake서버 같은 문제를 피할 수 있음 )

또한, 개발자가 코드를 commit 하면 빌드, 테스트, 배포 과정을 UI로서 제공하고, 특정 step에서 문제 발생 시 committer에게 알려주는  CI/CD Pipeline 툴인 Jenkins와 Spinnaker도 있다. 
( 코드를 빌드 하면 테스트와 배포하는 과정을 자동화함으로써 비용을 절감 )

예) jenkins 화면



이러한 기술의 발전으로 Dev + Ops( 개발팀과 운영팀 사이의 소통, 협업을 강조하는 S/W 개발 방법론 ) 가 가능해졌고, 많은 기업들이 도입하고 있다. 
DevOps를 잘하고 있는 기업으로는 Netflix, Facebook 가 대표적으로 떠오르고 있다. 
빠른 배포 주기를 통해 더욱 효율적으로 작업하고 더 빠르게 혁신하며 기업과 고객을 대상으로 더 큰 가치를 제공할 수 있도록 돕는다.



'apps > docker' 카테고리의 다른 글

쿠버네티스란 무엇인가?  (0) 2018.08.18
도커란 무엇인가?  (0) 2018.08.04
flannel을 통한 pod간 통신  (2) 2018.07.03
도커에서 nodejs+mongodb 테스트  (0) 2018.07.01
kubernetes에서 gpu pod생성( nvidia-docker2 )  (2) 2018.05.30
참조 :

도커란 무엇인가? 포스팅에 이어 쿠버네티스에 정리하고자한다. 

 위키백과에서 쿠버네티스를 찾아보면 "쿠버네티스(Kubernetes, 쿠베르네테스, "K8s"[3])는 디플로이 자동화, 스케일링, 컨테이너화된 애플리케이션의 관리를 위한 오픈 소스 시스템으로서[4] 원래 구글에 의해 설계되었고 현재 리눅스 재단에 의해 관리되고 있다. 목적은 여러 클러스터의 호스트 간에 애플리케이션 컨테이너의 배치, 스케일링, 운영을 자동화하기 위한 플랫폼을 제공하기 위함이다.[3] 도커를 포함하여 일련의 컨테이너 도구들과 함께 동작한다.” 라고 나온다.

 처음 저 글을 봤을 땐 전혀 와 닿지 않지만, 쿠버네티스를 이용해 서비스를 짧은 기간인 3개월 정도 운영해본 후, 저 글을 다시 읽으니 저 3문장에 쿠버네티스를 아주 잘 설명 한 거같다. 요즘 오픈소스의 이름들을 보면 명칭에 아주 신경을 많이 쓴 것을 알 수 있는데, 쿠버네티스는 그리스어로 키잡이를 뜻한다고 한다. 




kubernetes는 플랫폼 이름이 길어서 줄여 k8s라고도 한다. 앞으로는 k8s라고 적겠다. ( 8은 kubernetes의 중간의 글자라고 생각하면 된다 )
 왼쪽 그림은 k8s의 마크다. k8s가 앞서 키잡이(배의 키를 조정하는 사람)를 뜻한다고 했는데, 옆에 도커마크랑 같이 봄 이해가 간다.

도커란 배들의 키잡이 역할을 해주는 플랫폼이구나 하고 넘어가면 된다.

그럼 k8s가 왜 필요한지 생각해보자 우리한테는 앞서 여러 application을 올릴 수 있는 컨테이너 플랫폼인 도커를 공부 하였다. 

도커만으로 충분하지 않을까? 
물론 경우에 따라선 도커만으로 충분하다. 앞으로는 관리자 역할에서 생각해보자.
하나의 노드에서 여러 컨테이너를 띄우다 보니 자원( disk, memory, cpu )이 부족하기 시작했다. 

관리자 : 서버를 하나 추가해서 컨테이너를 나눠서 노드에 담자


위 그림처럼 노드를 하나 늘려서 도커를 설치하였다. 하지만 관리하는 노드가 많아질수록 점점 복잡해진다.
또한 이러한 요구사항이 올 수도있다.

클라이언트 :  웹 서버를 배포할 건데 죽으면 안되니까 이중화로 구성해주고 로드밸런서를 둬서 트래픽을 분산시켜줘. !
관리자 :#@($

예가 이상할 수도 있지만, 간단하게 k8s의 필요성에 관해 설명하고자 했다. 
k8s은 위에서 필요한 기능들을 다 제공하고 있다. ! 

대충 이런 그림 !




그럼 좀 더 자세히 k8s의 아키텍처를 보자 
( 처음에 모르는 오픈소스를 볼 때, 이러한 그림부터 보면 좀 더 시간을 아낄 수 있다 )




일단 각각의 역할을 그림을 보면서 이해해보자. 
큰 그림으로 보면 kubectl을 통해 받은 명령어를 api server를 통해 kubelet으로 전달하면 Pod( container 묶음 )를 생성하며 서비스를 제공한다. 물론 메타데이터를 저장하는 etcd, 다양한 제어기능을 위한 controller-manager, 자원분배를 도와주는 scheduler, 네트워크 트래픽을 담당하는 kube-proxy도 있다. 

자세히 적으면 처음 k8s을 접하는 사용자의 이해에 어려움이 있을 수 있어, 여기서는 간략하게만 소개하고 나중에 좀 더 자세히 소개하도록 하겠다.

kubectl : kubectl은 간단하게 명령어를 보내는 역할만 한다. 
예) kubectl get pods  ( pod들을 확인하는 명령어  )
API server : 간단하게 명령어를 전달해주는 역할만 진행한다. 또한 etcd클러스터랑 통신한다. 이 정도만 알고 가자 !
( 기본적으로 REST방식으로 통신한다 ) 
etcd : kubernetes 클러스터 데이터(포드 수,상태,네임 스페이스 등), API 객체 및 서비스 검색 세부정보를 저장하는 데 사용되는 분산 키 값 저장소다. 
( 메타 데이터가 저장되는 역할을 한다 생각하면 된다 ) 
controller-manager :  컨트롤러 매니저는 복제, 서비스계정, 네임스페이스 등을 생성하고 이를 각 노드에 배포하며 관리하는 역할을 한다.
( 여기선 사용자가 다양한 설정을 정할 수 있는데 이러한 것을 제어하기 위해 도와주는 역할이라고 간단하게 넘어가자 ) 
scheduler : 스케줄러는 Pod,서비스 등 각 자원을 적절한 노드에 할당하는 역할을 한다.
kubelet :  노드는 기본적으로 정기적으로 새로운 pod 또는 수정된 pod의 사양으로 포드 및 컨테이너가 원하는 상태로 실행되고 있는지 확인한다.
kube-proxy :  노드로 들어오는 네트워크 트래픽을 적절한 컨테이너로 라우팅하고, 로드밸런싱 등 노드로 나가는 네트워크 트랙픽을 프록시하고 노드와 마스터간 통신을 관리한다.

이 포스팅은 k8s가 무엇인지 이해하는 것이 목적이기 때문에, 이해를 쉽게 하기 위해 어려운 내용은 다 제거했다. 좀 더 자세한 내용은 시간이 생긴다면, k8s 내부 컴포넌트들이 어떤 식으로 통신하는지 그림과 같이 정리할 생각이다.


 


'apps > docker' 카테고리의 다른 글

DevOps가 떠오른 이유  (0) 2018.11.25
도커란 무엇인가?  (0) 2018.08.04
flannel을 통한 pod간 통신  (2) 2018.07.03
도커에서 nodejs+mongodb 테스트  (0) 2018.07.01
kubernetes에서 gpu pod생성( nvidia-docker2 )  (2) 2018.05.30
docker에 대해 공부하면서 느낀 점을 공유하면 좋을 것 같아 포스팅합니다.


먼저 도커란 무엇인가 ? 
 공식 홈페이지에서 도커의 개요를 보면 도커란 "Docker는 컨테이너 이동을 주도하는 회사이며 하이브리드 클라우드의 모든 애플리케이션을 처리할 수 있는 유일한 컨테이너 플랫폼 제공 업체입니다“ 라고 쓰여있다. 

여기서 '컨테이너'란 말에 주목할 필요가 있다. 
컨테이너란 무엇일까? 
아래 그림을 보면 대충 감이 온다. 아래에 도커 이미지를 보면 귀여운 배 위에 컨테이너를 올린 모습을 볼 수 있다. 
대충 아! 컨테이너란 "다양한 OS에 여러 application이 올려져 있는 것"을 의미하는 거고 그런 컨테이너를 도커 위에 올리는구나 





그럼 이미 존재하는 Virtual Machines랑 뭐가 달라 ..? 
물론 다르다 위에 그림을 보면 각 컨테이너가 같은 Kernel을 공유하고 있는 모습을 볼 수 있다.


 위 그림을 보면 좀 더 명확하다. 
virtual machine의 경우 Hypervisor을 통해 가상화 기능을 제공한다. 각 독립 된 커널 공간을 가진 OS를 생성하는 식의 환경 구성을 해준다.
containers의 경우 커널 공간을 공유하며 같은 가상화 기능을 제공해준다.

* 같은 커 널공간을 공유하기 때문에 virtual machines보다 좀 더 가볍다. 


이런 구성도 가능하다.!! ( Virtual Machine에 OS를 설치 후 Docker를 설치 )
* 물론 이런 구성으로 실제 서비스를 제공하는 기업은 없을 거로 생각한다.  


어떻게 이런 게 가능할까 ? 
namespaces 와 cgroup에 대해서 알아야 한다. 

namespace 
먼저 리눅스 커널의 주요 이름 공간에 대해서 알아보자.
이름공간
기능
Mount namespace
파일 시스템 분리
UTS namespace
호스트 네임 분리
IPC namespace
프로세스간 통신 분리
User namespace
유저(UID/GID) 분리
PID namespace
프로세스 테이블 분리
Network namespace
네트워크 설정 분리
이름 공간은 모두 리눅스 상에서 동작하는 프로세스에 할당하는 자원을 분리하는 기능을 한다.

cgroups (Control Groups)
cgroups(Control Groups)는 자원(resources)에 대한 제어를 가능하게 해주는 리눅스 커널의 기능입니다.
cgroups는 다음 자원을 제어할 수 있다.
* 메모리, CPU, I/O, 네트워크, device노드

사실 이러한 기술이 처음 나온 건 아니다. LXC 등 유사한 기술이 많았으나 도커가 히트친 이유는 사용자 편의성 ( 이미지 repository 등 )에 있다고 생각한다

그럼 마지막으로 도커 이미지에 대해 알아보자.

도커 이미지
도커 이미지는 특정 프로세스를 실행하기 위한 환경이다. 
이 이미지는 필자가 가진 이미지들이다. 
Default registry ( hub.docker.com )에 등록된 centos:7같은 이미지를 가져올 수도 있고, 개인적으로 172.30.1.19:5000같은 registry을 등록해서 이미지를 주고 받을 수도 있다.
또한 nodejs-mongodb-test처럼 자신이 만든 서비스( api서버로 데이터를 받아 mongodb에 저장하는 간단한 서비스)를 이미지로써 제공할 수도 있다. 
yjhui-MacBook-Pro:elk yjh$ docker images
REPOSITORY                TAG                     IMAGE ID            CREATED             SIZE
nodejs-mongodb-test       yang                    ffe8520fe8cd        4 weeks ago         664MB
172.30.1.19:5000/centos   7                       e934aafc2206        3 months ago        199MB
centos                    7                       e934aafc2206        3 months ago        199M
mongo                     latest                  9a63ed32fc2b        5 weeks ago         378MB

도커를 사용하며 가장 편리한 점은 서비스를 만들어 상용 서버에 배포를 하려고 하면 환경이 달라 예상치 못한 일들이 발생해서 반나절을 보낸 경우가 많았다....
도커를 사용한다면 이런 불필요한 삽질을 줄일 수 있을 거로 생각한다. 
이미지를 구워서 실행하면 배포 완료..?  또한 서비스가 죽어도 다시 살리는 기능도 제공한다. 

물론 실제 서비스에서 도커를 통해 서비스를 안정적으로 제공하기 위해서는 도커에 대해 좀 더 공부가 필요하다.
앞으로의 포스팅은 도커의 다양한 기능에 대해 공부해 포스팅할 예정이다. 



'apps > docker' 카테고리의 다른 글

DevOps가 떠오른 이유  (0) 2018.11.25
쿠버네티스란 무엇인가?  (0) 2018.08.18
flannel을 통한 pod간 통신  (2) 2018.07.03
도커에서 nodejs+mongodb 테스트  (0) 2018.07.01
kubernetes에서 gpu pod생성( nvidia-docker2 )  (2) 2018.05.30
간단한 내용이지만 이 간단한 정보를 확인하는데 불필요한 삽질을 하였기에 도움이 될까 포스팅합니다.

서로 다른 노드에 있는 pod간 통신을 완성하기 위해서는 관련 기능을 제공하는 network plugin이 필요하다.
필자의 경우는 flannel plugin을 설치했다.

구글링하다 좋은 케이스를 찾았기에 공유

* 만약 잘못된 정보가 있으면 지적해주세요




그림을 보면 노드1에서 노드2로 다른 ip끼리 패킷을 보낼 때, 보내는 컨테이너의 출발지와 목적지를 가지고 있는 모습을 확인 할 수 있다.
그리고 flannel에서 패킷을 주고받는 node의 출발지와 목적지 정보를 UDP로 캡슐화해서 보내는 역할을 수행한다. 
이런 식으로 flannel plugin을 설치하여 컨테이너 간 통신을 할 수 있다.

테스트한 yaml파일은 아래와 같다.
$ cat cent.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: test
  labels:
    app: test
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: test
    spec:
      containers:
      - image: centos:7.2.1511
        name: test
        command: ["/bin/bash","-c","while true; do sleep 1000; done"]
        imagePullPolicy: IfNotPresent



$ cat mysql.yaml
apiVersion: v1
kind: Pod
metadata:
  name: mysql-pod
  labels:
    name: mysql-pod
    context: docker-k8s-lab
spec:
  containers:
    -
      name: mysql
      image: mysql:5.7
      env:
        -
          name: "MYSQL_USER"
          value: "mysql"
        -
          name: "MYSQL_PASSWORD"
          value: "mysql"
        -
          name: "MYSQL_DATABASE"
          value: "sample"
        -
          name: "MYSQL_ROOT_PASSWORD"
          value: "supersecret"
      ports:
        -
          containerPort: 3306

yaml을 통해 centos, mysql을 실행하여 centos pod에서 mysql에 접속되는 지 테스트

pods 확인
$ kubectl get pods
mysql-pod                       1/1       Running   0          6m
test-6b5c774944-fqcdl           1/1       Running   0          17m


mysql을 설치해준다.
$ yum install mysql 

master서버에서 mysql pod의 ip주소 체크
$  kubectl describe pod test-6b5c774944-fqcdl
Name:               mysql-pod
Namespace:          default
Priority:           0
PriorityClassName:  <none>
Node:               jf-api/192.168.0.89
Start Time:         Tue, 03 Jul 2018 17:32:13 +0900
Labels:             context=docker-k8s-lab
                    name=mysql-pod
Annotations:        kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"labels":{"context":"docker-k8s-lab","name":"mysql-pod"},"name":"mysql-pod","namespace":"d...
Status:             Running
IP:                 10.244.1.53
Containers:
  mysql:
    Container ID:   docker://ee63968f90c86a3062627a68c3830d425b1b385ebc61cc1c960e824411799f7e
    Image:          mysql:5.7
    Image ID:       docker-pullable://mysql@sha256:f030e84582d939d313fe2ef469b5c65ffd0f7dff3b4b98e6ec9ae2dccd83dcdf
    Port:           3306/TCP
    State:          Running
      Started:      Tue, 03 Jul 2018 17:32:16 +0900
    Ready:          True
    Restart Count:  0
    Environment:
      MYSQL_USER:           mysql
      MYSQL_PASSWORD:       mysql
      MYSQL_DATABASE:       sample
      MYSQL_ROOT_PASSWORD:  supersecret
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-dn4mq (ro)
Conditions:
  Type           Status
  Initialized    True
  Ready          True
  PodScheduled   True
Volumes:
  default-token-dn4mq:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-dn4mq
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason                 Age   From               Message
  ----    ------                 ----  ----               -------
  Normal  Scheduled              9m    default-scheduler  Successfully assigned mysql-pod to jf-api
  Normal  SuccessfulMountVolume  9m    kubelet, jf-api    MountVolume.SetUp succeeded for volume "default-token-dn4mq"
  Normal  Pulled                 9m    kubelet, jf-api    Container image "mysql:5.7" already present on machine
  Normal  Created                9m    kubelet, jf-api    Created container
  Normal  Started                9m    kubelet, jf-api    Started container


centos접속 후 mysql 접속확인
$ kubectl exec -it test-6b5c774944-fqcdl /bin/sh

sh-4.2# mysql -h10.244.1.22 -umysql -pmysql -Dsample
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.22 MySQL Community Server (GPL)

Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [sample]

이와 같이 pod간 커뮤니케이션을 flannel을 통해 할 수 있다는 것을 확인했다.!




 



'apps > docker' 카테고리의 다른 글

쿠버네티스란 무엇인가?  (0) 2018.08.18
도커란 무엇인가?  (0) 2018.08.04
도커에서 nodejs+mongodb 테스트  (0) 2018.07.01
kubernetes에서 gpu pod생성( nvidia-docker2 )  (2) 2018.05.30
centos7에서 nvidia driver설치하기  (0) 2018.05.28

최근 도커를 공부하다가 다른 컨테이너에 있는 프로세스끼리 어떤 식으로 통신하는지 궁금해져서 테스트를 해봤다. 

 
도커를 통해 두 개의 컨테이너를 만들 건데 하나는 nodejs 하나는 mongodb을 띄울 거다.


움 완성하고 보니 대충 이런 그림?


코드는 아래와 같이 진행하면 된다.


완성하고 보니 link로 연결하면 컨테이너의 /etc/hosts  에 다른 컨테이너 아이디가 등록된 것을 확인할 수 있었다.


도커프록시를 통해 내부에서 할당받은 아이피대역대끼리는 통신이 되기 때문에 이런 식으로 가능한 듯 ..


문득 궁금한게 k8s에서는 pod간 통신이 궁금해진.. ( 다음 포스팅에 올려볼예정 )


** 이 포스팅에 잘못 된 내용이 있으면 지적해주세요 


nodejs-mongo-test

First : mongodb을 시작한다. ( 여기선 docker를 이용하여 시작 ).


몽고디비 컨테이너에 생성

$ docker run --name mongo -p 27017:27017 -d mongo

도커 프로세스 확인

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                      NAMES
b2482f6a58be        mongo               "docker-entrypoint.s…"   5 minutes ago       Up 5 minutes        0.0.0.0:27017->27017/tcp   mongo

컨테이너에 접속

$ docker exec -it mongo /bin/bash

mongo를 입력하여 제대로 동작하는지 확인

root@b2482f6a58be:/# mongo

MongoDB shell version v4.0.0
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 4.0.0
Server has startup warnings:
2018-06-30T04:51:49.681+0000 I STORAGE  [initandlisten]
2018-06-30T04:51:49.681+0000 I STORAGE  [initandlisten] ** WARNING: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine
2018-06-30T04:51:49.681+0000 I STORAGE  [initandlisten] **          See http://dochub.mongodb.org/core/prodnotes-filesystem
2018-06-30T04:51:50.154+0000 I CONTROL  [initandlisten]
2018-06-30T04:51:50.154+0000 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2018-06-30T04:51:50.154+0000 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
2018-06-30T04:51:50.154+0000 I CONTROL  [initandlisten]
---
Enable MongoDB's free cloud-based monitoring service to collect and display
metrics about your deployment (disk utilization, CPU, operation statistics,
etc).

The monitoring data will be available on a MongoDB website with a unique
URL created for you. Anyone you share the URL with will also be able to
view this page. MongoDB may use this information to make product
improvements and to suggest MongoDB products and deployment options to you.

To enable free monitoring, run the following command:
db.enableFreeMonitoring()
>

>  db
test

Second : nodejs 실행


우선 해당 git에 프로젝트 다운

$ git clone https://github.com/yangjeehan/nodejs-mongo-test.git 

해당 도커파일을 통해 이미지를 만든다.

$ docker build -t nodejs-mongodb-test:yang

*만든 이미지를 실행한다. ( 전에 만든 mongo container을 link을 통해 연결 ) *

$ docker run -i --link mongo --name test -t nodejs-mongodb-test:yang /bin/bash 

만든 컨테이너에 접속하여 아래명령어 수행

$ docker exec -it test /bin/bash 
root@ee137a79dd4e:/usr/src/app# node demo_mongo_insert.js 

몽고디비에 접속해서 데이터 입력 체크

root@b2482f6a58be:/# mongo

> show databases;
admin   0.000GB
config  0.000GB
local   0.000GB
mydb    0.000GB

> use mydb
switched to db mydb
>
> show collections;
customers

> db.customers.find()
{ "_id" : ObjectId("5b371eb7d8daba00078e2fdf"), "name" : "Company Inc", "address" : "Highway 37" }

End


'apps > docker' 카테고리의 다른 글

도커란 무엇인가?  (0) 2018.08.04
flannel을 통한 pod간 통신  (2) 2018.07.03
kubernetes에서 gpu pod생성( nvidia-docker2 )  (2) 2018.05.30
centos7에서 nvidia driver설치하기  (0) 2018.05.28
kubenetes설치 실패 시 초기화방법  (0) 2018.05.28
Centos 7에서 설치를 진행하였습니다.

공식홈페이지에서 요구사항입니다.

Prerequisites

The list of prerequisites for running the NVIDIA device plugin is described below:

  • NVIDIA drivers ~= 361.93
  • nvidia-docker version > 2.0 (see how to install and it's prerequisites)
  • docker configured with nvidia as the default runtime.
  • Kubernetes version = 1.10
  • The DevicePlugins feature gate enabled


참고사이트 : 

먼저 nvidia-docker2 을 설치한다
이전에 버전1을 깔았다면 아래 명령어로 제거해준다.
$ yum install nvidia-docker2
docker volume ls -q -f driver=nvidia-docker | xargs -r -I{} -n1 docker ps -q -a -f volume={} | xargs -r docker rm -f
yum remove nvidia-docker


버전 2설치
$ yum install nvidia-docker2
$ pkill -SIGHUP dockerd


도커 실행

$ docker run --runtime=nvidia --rm nvidia/cuda nvidia-smi



도커에서 제대로 실행이 된다면 이젠 k8s에서 pod으로 띄워본다.


k8s에서 띄우기 위해선 몇가지 작업을 더 해줘야한다.


아래 과정들은 모든 노드에서 진행한다.

데몬 설정에 아래와 같이 해준다 path엔 실제 돌아가는 nvidia-container-runtime을 추가해준다.


$ vi /etc/docker/daemon.json
{
   "default-runtime": "nvidia",
    "runtimes": {
        "nvidia": {
            "path": "/usr/bin/nvidia-container-runtime-hook",
            "runtimeArgs": []
        }
    }
}

DevicePlugins에 아래와같이 하여 enable시켜준다
$ vi /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
[Service]
Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf"
Environment="KUBELET_SYSTEM_PODS_ARGS=--pod-manifest-path=/etc/kubernetes/manifests --allow-privileged=true"
Environment="KUBELET_NETWORK_ARGS=--network-plugin=cni --cni-conf-dir=/etc/cni/net.d --cni-bin-dir=/opt/cni/bin"
Environment="KUBELET_DNS_ARGS=--cluster-dns=10.96.0.10 --cluster-domain=cluster.local"
Environment="KUBELET_AUTHZ_ARGS=--authorization-mode=Webhook --client-ca-file=/etc/kubernetes/pki/ca.crt"
Environment="KUBELET_CADVISOR_ARGS=--cadvisor-port=0"
Environment="KUBELET_CGROUP_ARGS=--cgroup-driver=systemd"
Environment="KUBELET_CERTIFICATE_ARGS=--rotate-certificates=true --cert-dir=/var/lib/kubelet/pki"
Environment="KUBELET_EXTRA_ARGS=--feature-gates=DevicePlugins=true"

ExecStart=
ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_SYSTEM_PODS_ARGS $KUBELET_NETWORK_ARGS $KUBELET_DNS_ARGS $KUBELET_AUTHZ_ARGS $KUBELET_CADVISOR_ARGS $KUBELET_CGROUP_ARGS $KUBELET_CERTIFICATE_ARGS $KUBELET_EXTRA_ARGS


데몬에 적용
$ systemctl daemon-reload
$ systemctl restart kubelet

쿠버네티스에 gpu support을 enable시켜준다. ( 버전 정보는 자신의 k8s 버전에 맞게 ^^ )

$ kubectl create -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v1.10/nvidia-device-plugin.yml


pod이 제대로 떠있는지 확인 ( nvidia-device-plugin-daemonset 이 올라왔다면 완료 !) 

$ kubectl get pods --all-namespaces
NAMESPACE     NAME                                    READY     STATUS             RESTARTS   AGE
default       test-p-5f44f8586f-g98pd                 0/1       ImagePullBackOff   0          16m
kube-system   etcd-jframe-master                      1/1       Running            2          2d
kube-system   kube-apiserver-jframe-master            1/1       Running            2          2d
kube-system   kube-controller-manager-jframe-master   1/1       Running            2          2d
kube-system   kube-dns-86f4d74b45-nxqfr               3/3       Running            6          2d
kube-system   kube-flannel-ds-7dmtt                   1/1       Running            3          2d
kube-system   kube-flannel-ds-f9vbs                   1/1       Running            0          2d
kube-system   kube-proxy-9xgll                        1/1       Running            0          2d
kube-system   kube-proxy-w6hm8                        1/1       Running            3          2d
kube-system   kube-scheduler-jframe-master            1/1       Running            2          2d
kube-system   nvidia-device-plugin-daemonset-7vdwp    1/1       Running            6          2d

gpu의 개수를 출력해보았다 ( 실제론 master에도 gpu가 2개 장착되어있지만, 실제 pod가 실행되는 곳이 slave라 마스터엔 nvidia-device-plugin이 설치안된듯 )
만약 여기서 실제 노드에 gpu가 장착되어있음에도 0으로 잡힌다면 각 노드에서 docker ps을 통해 nvidia-device-plugin이 제대로 떠 있는지 확인해본다.
$ kubectl get nodes "-o=custom-columns=NAME:.metadata.name,GPU:.status.allocatable.nvidia\.com/gpu"
NAME             GPU
master    0
slave   2


만들어둔 yaml을 통해 실행시켜봤다.

$ cat test.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: gpu-demo
spec:
  replicas: 1
  template:
    metadata:
      labels:
        run: gpu-demo
      annotations:
        scheduler.alpha.kubernetes.io/nvidiaGPU: "{ \n  \"AllocationPriority\": \"Dense\"\n}\n"
    spec:
      containers:
      - name: gpu-demo
        image: nvidia/cuda:7.5-runtime
        command:
        - "/bin/sh"
        - "-c"
        args:
        - nvidia-smi && tail -f /dev/null
        resources:
          limits:
            alpha.kubernetes.io/gpu: 2

만들어둔 yaml을 통해 실행시켜봤다.

$ kubectl apply -f test.yaml

실행한 pod의 로그를 확인 ( 제대로 설치 된것을 확인할 수 있다 )
$ kubectl logs gpu-demo-85bdc64dd7-5grcg
Mon May 28 17:25:27 2018
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 390.59                 Driver Version: 390.59                    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 108...  Off  | 00000000:01:00.0 Off |                  N/A |
|  0%   48C    P8    18W / 250W |      0MiB / 11176MiB |      1%      Default |
+-------------------------------+----------------------+----------------------+
|   1  GeForce GTX 108...  Off  | 00000000:04:00.0 Off |                  N/A |
|  0%   41C    P8     9W / 250W |      0MiB / 11178MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+


k8s에서 gpu을 사용하는 pod을 만들일이 있어 관련 내용을 정리하였다. 


gpu을 사용하기 위해서는 nvidia driver가 있어야한다.

  

이번 포스팅엔 먼저 nvidia 드라이버 설치 관련 내용을 정리하였다.


nvdia driver설치하기 

$ yum update
$ yum install kernel-devel kernel-headers gcc make
 

nouveau 을 활성화시키면 충돌가능성이 있기에 blacklist해준다. 
$ echo 'blacklist nouveau' >> /etc/modprobe.d/blacklist.conf
$ dracut /boot/initramfs-$(uname -r).img $(uname -r) --force
$ reboot

파일다운

이것저것 뜨는데 다 ok, yes해줌 된다.
$ bash NVIDIA-Linux-x86_64-390.59.run

1. WARNING: nvidia-installer was forced to guess the X library path '/usr/lib64' and X
           module path '/usr/lib64/xorg/modules'; these paths were not queryable from the
           system.  If X fails to find the NVIDIA X driver module, please install the
           `pkg-config` utility and the X.Org SDK/development package for your distribution
           and reinstall the driver
OK
2. Install NVIDIA's 32-bit compatibility libraries?
YES

3. Would you like to run the nvidia-xconfig utility to automatically update your X
  configuration file so that the NVIDIA X driver will be used when you restart X?  Any
  pre-existing X configuration file will be backed up.
YES

4.  Your X configuration file has been successfully updated.  Installation of the NVIDIA
  Accelerated Graphics Driver for Linux-x86_64 (version: 390.59) is now complete.
OK



$ nvidia-smi


Thu May 24 21:39:10 2018
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 390.59                 Driver Version: 390.59                    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 108...  Off  | 00000000:01:00.0 Off |                  N/A |
|  0%   34C    P5    15W / 250W |      0MiB / 11178MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   1  GeForce GTX 108...  Off  | 00000000:04:00.0 Off |                  N/A |
|  0%   33C    P5    13W / 250W |      0MiB / 11178MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|  No running processes found                                                 | 


위 화면이 뜬다면 완료 

k8s을 설치하고 재 설치 시 전에 있던 데이터가 남아 있어서 문제가 생긴다.


$ kubeadm init 


필자의 경우 위 명령어가 time out으로 계속 실패하여 원인을 찾는데 많은 시간을 소비했다. 

아래 명령어를 통해 docker, k8s을 초기화하고 다시 설치하자 문제 없이 설치가 되었다. 


# docker 초기화

$ docker rm -f `docker ps -aq`

$ docker volume rm `docker volume ls -q`
$ umount /var/lib/docker/volumes
$ rm -rf /var/lib/docker/

$ systemctl restart docker 


# k8s 초기화

$ kubeadm reset

$ systemctl restart kublet


# iptables에 있는 데이터를 청소하기 위해

$ reboot 


 







참고사이트 : 

https://www.howtoforge.com/tutorial/centos-kubernetes-docker-cluster/



설치버전 :

CentOS버전 :
$ cat /etc/redhat-release
CentOS Linux release 7.4.1708 (Core)

리눅스 커널버전 : 

$ uname -sr
Linux 3.10.0-693.el7.x86_64 


호스트 : 
# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

192.168.0.2 master
192.168.0.3 slave01



모든 노드에서 진행해준다.

Disable selinux 
$ setenforce 0
$ sed -i --follow-symlinks 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/sysconfig/selinux



Enable br_netfilter Kernel Module
$ modprobe br_netfilter
$ echo '1' > /proc/sys/net/bridge/bridge-nf-call-iptables
$ modprobe br_netfilter


위에 modprobe을 하면 bridge관련 모듈이 추가된다.

  
$ ll /proc/sys/net/
total 0
dr-xr-xr-x. 1 root root 0 May 24 22:23 core
dr-xr-xr-x. 1 root root 0 May 24 02:30 ipv4
dr-xr-xr-x. 1 root root 0 May 24 02:30 ipv6
dr-xr-xr-x. 1 root root 0 May 24 02:30 netfilter
-rw-r--r--. 1 root root 0 May 24 22:23 nf_conntrack_max
dr-xr-xr-x. 1 root root 0 May 24 02:30 unix

$ ll /proc/sys/net/
total 0
dr-xr-xr-x. 1 root root 0 May 24 01:19 bridge
dr-xr-xr-x. 1 root root 0 May 24 01:06 core
dr-xr-xr-x. 1 root root 0 May 23 21:09 ipv4
dr-xr-xr-x. 1 root root 0 May 23 21:09 ipv6
dr-xr-xr-x. 1 root root 0 May 23 21:09 netfilter
-rw-r--r--. 1 root root 0 May 24 01:06 nf_conntrack_max
dr-xr-xr-x. 1 root root 0 May 23 21:09 unix 


Disable SWAP

$ swapoff -a
# swap 파티션이나 swap 파일의 구동을 중단시키는 명령어

swap이란 하드디스크를 메모리처럼 사용하는 기법
-> 물리적인 메모리가 모자라면 하드디스크를 메모리처럼 데이터를 기록하여 메모리를 확보
프로그램들을 많이 실행해서 메모리가 부족해지면, 메모리 상에 적재된 프로그램 중 당장 필요하지 않은 프로그램 데이터를 하드디스크에 옮겨서 메모리 공간을 확보

출처: http://nextcube.tistory.com/137 [중성자 별의 충돌 에너지]



$ vi /etc/fstab

/dev/mapper/centos-root /                       xfs     defaults        0 0
UUID=e68efdc4-b1c1-4f94-ab67-72d611499e13 /boot                   xfs     defaults        0 0
UUID=E849-B774          /boot/efi               vfat    umask=0077,shortname=winnt 0 0
#/dev/mapper/centos-swap swap                    swap    defaults        0 0



Install Docker 

$ yum install -y yum-utils device-mapper-persistent-data lvm2
$ yum install -y docker-ce




Install Kubernetes

$ cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF

# /etc/yum.repos.d/kubernetes.repo


$ yum install -y kubeadm


$ systemctl start docker && systemctl enable docker
$ systemctl start kubelet && systemctl enable kubelet 



Change the cgroup-driver

$ docker info | grep -i cgroup
Cgroup Driver: cgroupfs

$ sed -i 's/cgroup-driver=systemd/cgroup-driver=cgroupfs/g' /etc/systemd/system/kubelet.service.d/10-kubeadm.conf

$ systemctl daemon-reload
$ systemctl restart kubelet 



k8S Cluster Initialization


Master서버에서 ( apiserver-advertise-address 에 master서버 아이피 입력 ) 
$  kubeadm init --apiserver-advertise-address=192.168.0.2 --pod-network-cidr=10.244.0.0/16


Your Kubernetes master 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

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/

You can now join any number of machines by running the following on each node
as root:

 kubeadm join 192.168.0.2:6443 --token bi09ej.5z5q8osipp4r9w5u --discovery-token-ca-cert-hash sha256:0aa7b7489d097ae88ad17c7dad7a591d2da711fca6ed533b4063979c917747a5

# 따로 메모 해둔다. 슬레이브서버에서 조인할때 필요



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



# 여기선 flannel네트웍으로 사용



$ kubectl get nodes
$ kubectl get pods --all-namespaces
NAMESPACE     NAME                                    READY     STATUS    RESTARTS   AGE
kube-system   etcd-jframe-master                      1/1       Running   0          22s
kube-system   kube-apiserver-jframe-master            1/1       Running   0          28s
kube-system   kube-controller-manager-jframe-master   1/1       Running   0          42s
kube-system   kube-dns-86f4d74b45-nxqfr               3/3       Running   0          1m
kube-system   kube-flannel-ds-7dmtt                   1/1       Running   0          1m
kube-system   kube-proxy-w6hm8                        1/1       Running   0          1m
kube-system   kube-scheduler-jframe-master            1/1       Running   0          19s



슬레이브노드에서 진행 : 

$ kubeadm join 192.168.0.2:6443 --token bi09ej.5z5q8osipp4r9w5u --discovery-token-ca-cert-hash sha256:0aa7b7489d097ae88ad17c7dad7a591d2da711fca6ed533b4063979c917747a5


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

Run 'kubectl get nodes' on the master to see this node join the cluster.


마스터노드에서 확인 : ( slave01이 제대로 안 올라오면 위에 과정을 제대로 입력했는지 확인해본다 ) 
$ kubectl get nodes
NAME             STATUS    ROLES     AGE       VERSION
master    Ready     master    21m       v1.10.3
slave01   Ready     <none>    57s       v1.10.3

$  kubectl get pods --all-namespaces
NAMESPACE     NAME                                    READY     STATUS    RESTARTS   AGE
kube-system   etcd-jframe-master                      1/1       Running   0          46m
kube-system   kube-apiserver-jframe-master            1/1       Running   0          46m
kube-system   kube-controller-manager-jframe-master   1/1       Running   0          46m
kube-system   kube-dns-86f4d74b45-nxqfr               3/3       Running   0          47m
kube-system   kube-flannel-ds-7dmtt                   1/1       Running   0          47m
kube-system   kube-flannel-ds-f9vbs                   1/1       Running   0          56s
kube-system   kube-proxy-9xgll                        1/1       Running   0          56s
kube-system   kube-proxy-w6hm8                        1/1       Running   0          47m
kube-system   kube-scheduler-jframe-master            1/1       Running   0          46m



마지막으로 팟을 만들어서 확인해본다.
Testing Create First Pod

$ kubectl create deployment nginx --image=nginx
$ kubectl describe deployment nginx
$ kubectl create service nodeport nginx --tcp=80:80
$ kubectl get svc
( 이 명령어를 통해 PORT에 포워딩한 포트를 기억한다 ) 

$  curl master:31280
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    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>


$ curl slave01:31280
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    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>





+ Recent posts