Android, Cocos2d, Java Web, Linux, reading...

CrashLoopBackOff 에러가 났을 때


이번 포스팅에서는 CrashLoopBackOff 에러에 대해서 다뤄보려고 한다. 이 에러는 Pod를 온전히 생성하는 데 실패했을 경우 나타나는 에러이다. 이런 에러가 났을 시에 어떻게 해결해야 하는지에 대해 알아보자. 환경은 저번 포스팅과 같이 모든 노드들은 VM의 CentOS 7이다.

11번째 줄을 보면 Pod가 관리할 컨테이너의 환경설정을 해주는 부분이라고 저번 포스팅에서 설명했다. nginx의 경우 이러한 설정을 해줄 필요 없지만 거의 대부분의 컨테이너들, 예를 들어, mysql, django, python 등은 이러한 설정을 해줘야 한다고 했다. 만약 해주지 않는다면 어떤 현상이 발생할까?? 궁금해서 직접 해보기로 했다.

밑의 pod.yml은 위의 pod.yml에서 env부분을 삭제한 상태이다.

이 상태에서 Pod 오브젝트를 생성해보자.

kubectl create -f pod.yml

Pod 오브젝트를 만든 다음 잘 생성되었는지 확인하기 위해 kubectl get pods -o wide 명령어를 입력해봤더니 STATUS에 Running이 아니라 CrashLoopBackOff라는 에러가 떴다. 컨테이너를 만드는 데 실패했다는 뜻이다. 잘 생성되었으면 READY도 2/2여야 하는데 READY에 1/2로 표시되어 있다. 즉, pod.yml에 2개의 컨테이너를 정의했는데 이 중 1개의 컨테이너만 생성되었다는 의미이다. 어떤 컨테이너가 잘못됐는지 확인해보기 위해 로그를 보자.

Pod에서 생성한 컨테이너의 로그를 보기 위해서는

kubectl logs [Pod명] -c [Pod에서 지정한 컨테이너명]

우리는 pod.yml에 각 컨테이너의 이름을 pooh-db-container와 pooh-nginx-container라고 지정해주었다. 이들을 [Pod에서 지정한 컨테이너명]에 넣어주면 되고 Pod명은 pooh-db-nginx-pod라고 정의했으므로 [Pod명]에 입력해주면 된다. 그럼 먼저 pooh-db-container부터 확인해보자.

kubectl logs pooh-db-nginx-pod -c pooh-db-container

이렇게 설정을 해주지 않았기 때문에 실패했다는 문구가 뜬다. 에러를 살펴보면 PASSWORD를 지정해주지 않았기 때문에 발생했다고 나온다(password option is not specified). 그래서 맨 처음에 pod.yml의 env에다가 여기에 나온 MYSQL_ROOT_PASSWORD를 설정해 준 것이다. 이런 식으로 Pod의 컨테이너에 대한 로그를 확인할 수 있다. 이번엔 pooh-nginx-container에 대한 로그를 확인해보자.

kubectl logs pooh-db-nginx-pod -c pooh-nginx-container

아무 에러가 없기 때문에 로그가 나오지 않는다. 그러면 여기는 단지 Pod가 잘 생성되는지 아닌지만 기록해주는 로그일까?? 아니다. 해당 컨테이너들을 배포된 worker-node2에서 실행하게 되면 그에 대한 로그들이 여기에 쌓이게 된다. 그래서 배포된 컨테이너에서 이런저런 작업들을 한 후 마스터 노드에서 로그를 확인해보면 해당 로그들이 많이 쌓여있게 될 것이다.

로그를 남겨보기 위해 worker-node2에서 이것저것 시도하다가 pooh-nginx-container를 stop하고 restart했더니 처리가 잘못되어 pooh-nginx-container가 2개 생기는 현상이 발생했다. 그래서 마스터 노드에서 pooh-nginx-container의 로그를 살펴보면 address already in use가 기록되어 있다. 물론 잘 처리되면 이런 fail 기록이 남지 않는다(운이 좋았네요… ^^).

정리하면, Pod를 생성하다가 CrashLoopBackOff 에러가 뜨면 해당 컨테이너의 로그를 확인해서 설정하라는 대로 pod.yml의 env에 설정해주면 잘 생성이 될 것이다.




참고 블로그 :

  • https://www.linuxtechi.com/deploy-pod-replication-controller-service-kubernetes-1-7-on-centos-7/
  • https://stackoverflow.com/questions/47129376/kubernetes-kubectl-a-container-name-must-be-specified-but-seems-like-it-is
  • https://portworx.com/mysql-kubernetes/

阅读全文 »


Pod란?


이번 포스팅에서는 Pod에 대해 알아보고자 한다. 환경은 저번 포스팅과 같이 마스터 노드, 작업자 노드 모두 VM의 CentOS 7이다.

쿠버네티스를 이해하기 위해서는 먼저 클러스터의 구조를 이해해야 한다. 클러스터 전체를 관리하는 컨트롤러로써 마스터 노드가 존재하고, 컨테이너가 배포되는 머신(가상 머신이나 물리적인 서버 머신)인 노드(작업자 노드)가 존재한다. 쿠버네티스를 이해하기 위해서 또한 중요한 게 오브젝트(object)인데, 쿠버네티스는 가장 기본적인 구성단위가 되는 기본 오브젝트와 이러한 기본 오브젝트를 생성하고 관리함과 동시에 이에 추가적인 기능을 가진 컨트롤러(Controller)로 이루어진다. 그리고 이러한 오브젝트의 스펙(설정) 이외에 추가 정보인 메타 정보들로 구성이 되어 있다.

  • 기본 오브젝트(Basic Object)

    여기서 말하는 오브젝트가 모두 기본 오브젝트(Basic Object)이며 쿠버네티스에 의해서 배포 및 관리되는 가장 기본적인 오브젝트는 컨테이너화되어 배포되는 애플리케이션의 워크로드를 기술하는 오브젝트로 Pod, Service, Volume, Namespace 4가지가 있다. 간단하게 설명 하자면 Pod는 컨테이너화된 애플리케이션, Volume은 디스크, Service는 로드밸런서 그리고 Namespace는 패키지명 정도로 생각하면 된다. 이번 포스팅에서는 Pod에 대해서만 살펴볼 것이다.

  • 오브젝트 스펙(Object Spec)

    오브젝트들은 모두 오브젝트의 설정 정보를 기술한 오브젝트 스펙(Object Spec)으로 정의가 되고, 커맨드 라인을 통해서 오브젝트 생성시 인자로 전달하여 정의를 하거나 또는 yaml(또는 yml)이나 json 파일로 스펙을 정의할 수 있다.

    Pod

Pod 는 쿠버네티스에서 가장 기본적인 배포 단위로 컨테이너를 포함하는 단위이기도 하며 하나 이상의 컨테이너를 포함한다. 쿠버네티스는 컨테이너를 개별적으로 하나씩 배포하는 것이 아니라 Pod 단위로 배포한다.

아래는 간단한 Pod를 정의한 오브젝트 스펙이다. 하나하나 살펴보면

(보기 쉽게 :set number를 이용했습니다.)

  • apiVersion

    이 스크립트를 실행하기 위한 쿠버네티스 API 버전으로 보통 v1을 사용한다.

  • kind

    리소스의 종류를 정의하는 곳으로 Pod를 정의하려고 하기 때문에, Pod라고 넣는다. 어떤 오브젝트냐에 따라 정의가 달라진다.

  • metadata

    이 리소스(Pod)의 라벨(Label)이나 리소스의 이름 등 각종 메타 데이타를 넣는다. 여기서는 Pod의 이름을 pooh-db-nginx-pod라고 정의했으며 label을 pooh-db-nginx-app라고 정의하였다. 이 라벨은 추후에 포스팅할 Service에 필요한데 Pod를 서비스할 때 Service 오브젝트에 라벨 셀렉터(label selector)로 해당 라벨을 지정해주면 지정해준 라벨의 Pod만 선택해서 서비스하게 되는 것이다(좀 더 자세히 알고 싶다면 뒤의 Service 포스팅을 참고해주세요!!). 약간 그룹화 비슷하게 생각하면 된다.

  • spec

    이 리소스(Pod)에 대한 상세한 스펙을 정의하는 곳으로 Pod가 하나 이상의 컨테이너를 포함한다고 해서 2개의 컨테이너를 포함시켜 보았다. 그 밑은 spec에 대한 상세 내용들이다.

  • spec.containers

    Pod가 관리할 컨테이너를 정의하는 부분이다.

  • spec.containers.name

    Pod가 관리할 컨테이너의 이름을 정의한다.

  • spec.containers.image

    Pod가 관리할 컨테이너에 해당하는 image이다.

  • spec.containers.env

    Pod가 관리할 컨테이너의 환경설정을 해주는 부분이다. nginx의 경우 이러한 설정을 해줄 필요 없지만 거의 대부분의 컨테이너들이 이러한 설정을 해줘야 한다. mysql, django, python 등 모두 env 설정을 해주지 않고 진행했더니 CrashLoopBackOff 에러가 뜬다. 이에 대한 자세한 내용은 다음 포스팅인 CrashLoopBackOff를 참고하기 바란다.

  • spec.containers.ports

    Pod가 관리할 컨테이너가 사용할 포트를 설정해주는 부분으로 mysql을 사용할 것이기 때문에 3306으로 설정해주었고 nginx의 경우는 웹서버로 80번 포트를 사용하기 때문에 80으로 설정해주었다.

  • spec.nodeSelector

    Pod가 특정 노드에서만 실행되도록 정의하는 부분으로 hostname=worker-node2라고 정의했으므로 hostname(노드 이름)이 worker-node2인 노드에만 실행(배포)되도록 해준다. 이를 지정해주지 않으면 임의의 노드에 Pod가 실행된다. 어느 노드에서 실행되어도 상관없다면 굳이 정의해 줄 필요는 없다.
    단, 이 옵션을 사용하기 위해선 해당 노드에 label을 추가해줘야 한다. 이 nodeSelector가 노드의 label을 보고 해당 노드에 Pod를 서비스하기 때문이다.

    kubectl label nodes [node명] hostname=[label명]

    node명은 kubectl get nodes 명령어를 통해 node들을 볼 수 있는데 이들 중 하나를 택하면 된다. 뒤의 label명은 짓고 싶은대로 지으면 되는데 필자의 경우는 이름과 label을 그냥 똑같이 했다(hostname=[label명]의 hostname은 nodeSeletor에 hostname으로 구별하기 때문에 저렇게 써준 거고 다른 것들을 쓸 수도 있다. 추후에 또 다룰 기회가 있으면 그 때 다시 설명하겠다).

    kubectl label nodes worker-node2 hostname=worker-node2

    노드에 지정한 label을 삭제할 수도 있다. 삭제하는 방법은

    kubectl label nodes worker-node2 hostname-

    이렇게 노드에 라벨을 지정해주지 않고 nodeSeletor 옵션을 주게 되면 계속 이런 대기상태가 된다.

이제 pod.yml에 정의한 Pod를 오브젝트로 생성해 줄 차례이다. Kubernetes에서 오브젝트 생성을 위한 명령어는

kubectl create -f 파일명.yml 또는 kubectl apply -f 파일명.yml

필자는 kubectl create -f pod.yml을 사용했다. 이를 입력하면

이렇게 아까 정의한 Pod의 이름(pooh-db-nginx-pod)대로 오브젝트가 생성됐다.

잘 생성되었는지 확인해보면

kubectl get pods

-o wide를 추가해주면 더 자세한 정보들을 볼 수 있고 아까 Pod에 특정 노드(worker-node2)에 지정되도록 설정해줘서 worker-node2에 배포되었음을 확인할 수 있다. nodeSeletor를 설정해주지 않으면 현재 worker-node1, worker-node2 이렇게 있는 상태인데 worker-node1에 배포될 수도 있다.

하지만, 이렇게 Pod 오브젝트만 생성해주면 외부에서 Pod 내부에서 실행되는 컨테이너의 응용 프로그램(application)에는 접근할 수 없다. 외부에서 접근이 가능하도록 노출을 시켜줘야 한다(해당 서비스를 외부의 사용자가 사용할테니까). 이를 서비스시킨다고 하는데, 현재 Pod 오브젝트에 대해서 다루는 것처럼 나중에 Service 오브젝트에 대해서도 다룰 것이다. 지금은 그냥 Pod를 서비스하기 위해 외부에 노출시켜야 한다는 정도로만 이해하고 넘어가자. 일단 Pod를 외부로 노출시켜주는 명령어는

kubectl expose pods [Pod명] –name=[Service name] –type=Nodeport

해당 Pod를 [Service name]이라는 이름으로 서비스한다는 의미이다. 제일 중요한 게 맨 뒤의 –type=Nodeport이다. 이렇게 type을 Nodeport로 바꿔줌으로 인해서 외부에서 접근이 가능해지기 때문이다.

다음 그림은 클러스터 외부를 가정하기 위해 만든 VM Ubuntu이다.

kubernetes를 설치하지도 않았고 서비스되고 있는 노드의 IP와 포트는 안다는 가정 하에 curl 명령어를 통해 봤더니 서비스가 잘 되고 있음을 확인할 수 있다.

지금은 이렇게 간단하게 했지만 여기도 Service.yml을 만들어 오브젝트로 생성하면 더 많은 설정들을 담아 서비스할 수 있다. 아까도 언급했지만 추후에 다룰 예정이다.

잘 서비스되는지 확인해보려면

kubectl get service

이 역시 -o wide로 좀 더 자세하게 볼 수 있으며 service 대신 svc로 써도 있다(kubectl get svc).

그럼 worker-node2로 잘 배포가 되었는지 worker-node2로 가서 직접 확인해보자.

밑에 아까 pod.yml에서 설정한 이름들이 보인다. 설정해준대로 잘 배포가 된 것이다.

잘 돌아가고 있는지 docker exec 명령어로 컨테이너에 접속해보자.

pooh-db-container라는 이름의 mysql 컨테이너에 접속해봤는데 잘 실행이 된다. nginx 컨테이너도 이런 식으로 접속할 수 있다. 그럼 꼭 배포된 노드에서만 접속 가능한 것일까? 아니다. 마스터 노드에서도 접속이 가능하다.

kubectl exec -ti [Pod명] bash(또는 /bin/bash)

마스터 노드에서도 해당 Pod의 컨테이너에 접속이 잘 된다. 하지만 의문점이 하나 든다. 우리는 분명 하나의 Pod에 컨테이너를 2개 생성했다. 그런데 Pod명을 입력했을 때 어떤 특정 컨테이너에 접속된다. 이는 확인해보면 알겠지만 pod.yml에 먼저 설정해 준 컨테이너이다. pod.yml에 pooh-db-container를 먼저 써줬으므로 지금 마스터 노드에서 들어간 컨테이너는 pooh-db-container이다. 의심이 가면 mysql 명령어로 확인해보길 바란다.

지금까지는 Pod와 expose 명령어를 통한 Service를 생성해봤다면 이제 삭제하는 방법에 대해 보도록 하자. 방법은 2가지다.

kubectl delete -f 파일명.yml 또는 kubectl delete pod [Pod명]

필자는 후자의 명령어를 사용했다. 만약 전자의 명령어를 사용했다면 pod.yml로 Pod를 생성했기 때문에 kubectl delete -f pod.yml을 입력해주면 된다. Pod가 잘 삭제됐는지 확인해보면 No resources found, 즉, 잘 삭제되었다는 것을 알 수 있다. Service의 경우도 마찬가지이다. expose를 통해 Service를 생성했으니 unexpose같은 게 아닐까하고 처음에 생각했지만 어쨌든 Service를 생성한 것이기 때문에 Service를 삭제해주면 된다. Pod 삭제할 때와 똑같다.

kubectl delete -f 파일명.yml 또는 kubectl delete service [Service명]

나중에 포스팅할 Service때는 Service.yml이라는 파일을 만들어 Serivce 오브젝트를 생성해 서비스를 할 건데 이 때 전자의 방법을 사용할 수 있다. kubectl delete -f Service.yml
하지만 지금은 그게 아니므로 후자의 방법을 택하면 된다.

kubectl delete service pooh-pod-service

아까 위에서 봤던 Nodeport 유형의 pooh-pod-service가 없다. 잘 삭제된 것이다.

※ Pod 안에 한 개 이상의 컨테이너를 가질 수 있다고 했는데 왜 개별적으로 하나씩 컨테이너를 배포하지 않고 여러 개의 컨테이너를 Pod 단위로 묶어서 배포하는 것일까? 그 이유는 Pod가 다음과 같은 재미있는 특징을 갖고 있기 때문이다.

  • 1. Pod 내의 컨테이너는 IP와 Port를 공유한다.

    : 예를 들어 2개의 컨테이너가 하나의 Pod를 통해서 배포되었다고 할 때, localhost를 통해서 통신이 가능하다. 만약 컨테이너 A가 80, 컨테이너 B가 6543으로 배포가 되었다고 하면 컨테이너 B에서 컨테이너 A를 호출할때는 localhost:80으로 호출하면 되고, 반대로 A에서 B를 호출할 때는 localhost:6543로 호출하면 된다. 위에서 만든 pod.yml로 실험을 해보자. 아까의 얘기를 다시 말해보면 현재 worker-node2에 pooh-db-container가 3306번 포트로 pooh-nginx-container가 80번 포트로 2개의 컨테이너가 배포된 상태이다. pooh-db-container에서 pooh-nginx-container를 호출할 때 localhost:80으로 호출할 수 있다. nginx는 웹서버이므로 눈으로 확인하기 쉽게 curl 명령어를 이용해보자(단, 컨테이너에 curl 명령어가 없어 apt-get install로 설치했습니다. 이 과정은 생략하고 썼음을 알려드립니다).

    먼저 pooh-db-container에 접속한다.

    docker exec -it 8ec122944cd6 /bin/bash

    그 다음 curl 명령어로 확인해보면

    curl localhost:80

    nginx가 잘 나옴을 확인할 수 있다. 원래는 각 컨테이너마다 IP가 달라 curl 명령어에 해당 컨테이너의 IP를 입력해야 하는데, 그럴 필요 없이 각 컨테이너들이 같은 Pod에 있으면 이렇게 IP를 공유하기 때문에 localhost로 쓸 수 있다(물론 IP를 직접 입력해도 된다). 실제로 각 컨테이너에 접속해서 net-tools를 설치한 후 ifconfig로 IP를 조회해보면 IP가 같다.

    이는 pooh-db-container이고

    이는 pooh-nginx-container이다. 둘 다 10.40.0.1을 사용하고 있음을 확인할 수 있다. 지금까지 잘 따라왔다면 이 IP를 보고 아까 kubectl get pods -o wide에서 봤던 즉, 우리가 배포한 Pod의 IP임을 알 수 있다.

  • 2. Pod 내에 배포된 컨테이너 간에는 디스크 볼륨을 공유할 수 있다.

    여기는 뒤의 Volume 포스팅을 참고해주세요!

이러한 특징들로 인해 컨테이너를 Pod 단위로 배포하는 것이다. 다음 포스팅에서는 CrashLoopBackOff 오류에 대해서 다뤄보겠다.




참고 블로그 :

  • http://bcho.tistory.com/1256?category=731548
  • http://tech.cloudz-labs.io/posts/kubernetes/getting-start/
  • https://www.linuxtechi.com/deploy-pod-replication-controller-service-kubernetes-1-7-on-centos-7/
  • https://developer.ibm.com/kr/cloud/2018/01/25/%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4-%EC%8B%A4%EC%8A%B5/
  • https://kubernetes.io/docs/concepts/storage/volumes/

阅读全文 »


Linux 시간 설정하기(2)


저번 포스팅에서는 UTC로 설정된 시간을 KST로 바꿔 한국의 시간으로 설정해주는 것에 대해서 배워봤는데, KST로 설정되어 있다고 해도 시간이 다른 경우가 있다. 이번에도 Ubuntu일 때와 CentOS일 때 2가지 경우를 모두 다뤄볼 것이며 실습은 모두 VM에서 진행했다. 다음의 경우를 보자.

  • Ubuntu 16.04

포스팅을 위해 오랜만에 VM을 켰더니 시간이 약 한 달 정도나 멈춰있었다. 하지만 저번 포스팅 때 KST로 설정해놔서 지역시간 설정은 건드릴 필요없고 진짜 시간 자체만 바꿔주면 된다. 방법이 여러가지가 있는데 하나하나씩 설명해보겠다.

  1. 타임 서버 이용하기

    타임 서버는 말 그대로 시간이 제대로 설정되어 있는 서버를 말한다. 즉, 이 서버의 시간과 맞춰주면 현재 시간과 맞게 되는 것이다. 사용법은

    rdate -s [타임서버]

    타임서버에는

    time.bora.net
    time.nist.gov 
    time.nuri.net
    time.kriss.re.kr
    time.windows.com
    

    등이 있고 시간 설정부분이므로 root권한에서 진행해야 한다. rdate가 없으면 먼저 apt-get update를 해준 후 rdate를 설치해서 실행하면 된다.

    sudo apt-get install rdate

    사실 엄밀히 말하면 시간이 저렇게 늦어져버리면 클라이언트(Ubuntu)와 update나 패키지를 설치해주는 서버가 시간이 서로 맞지 않는 상태이므로 update가 되지 않고 rdate 또한 설치가 진행되지 않아 결국 타임 서버를 이용할 수 없다. 여기서는 방법론에 대해서 설명하는 것이기 때문에 이렇게 설명을 한 것이지만 실제로 1번부터 진행해보면 안 될 것이다. 밑의 2,3 방법으로 시간을 먼저 맞춰놓고 rdate를 설치한 후 나중에 시간이 다시 맞지 않을 때 사용할 수 있는 것이다. rdate를 설치했다고 가정하고 하나의 예로 time.bora.net을 써보면

    sudo rdate -s time.bora.net

    이렇게 시간이 제대로 맞춰짐을 확인할 수 있다.

  2. 직접 설정하기

    이는 직접 시간을 입력하여 설정해주는 방법이다. 역시 root에서 진행해야 하며 사용법은

    sudo date -s [시간] 또는 sudo timedatectl set-time [시간]

    date -s [시간]은 날짜에 -를 빼고 20180814로 해도 똑같이 된다. 다음엔 timedatectl set-time [시간]을 써보자.

    timedatectl은 날짜에 -를 빼면 오류가 난다.

  3. 서버(하드웨어) 시간을 통한 설정

    1,2는 리눅스 시스템의 시간 설정 방법이고 3은 하드웨어의 자체 시간을 다루는 방법이다. 이는 hwclock 명령어를 이용한다. 이거 역시 root권한에서 진행해야 한다.

    date를 입력했을 때 리눅스 시스템의 시간은 7월 22일인 반면 hwclock을 입력했을 때 나오는 하드웨어 시간은 현재 시간에 맞춰져 있었다(오른쪽이 잘 맞춰져있는 현재 시간). 그래서 하드웨어 시간은 항상 현재에 맞게 설정되어 있는건가 생각했는데 다른 VM들을 보니까 그렇지도 않았다. 다른 경우도 종종 있었다. 따라서, 그냥 시간이 다르면 맞춰주면 될 것 같다.

    일단, 이번의 경우 하드웨어 시간은 현재 시간과 잘 맞춰져 있으므로 리눅스 시스템 시간을 하드웨어 시간에 맞춰보자. 사용법은

    hwclock -s

    리눅스 시스템 시간이 하드웨어 시간에 잘 맞춰졌음을 확인할 수 있다.

    그럼 반대로 리눅스 시스템 시간은 현재 시간과 맞는데 하드웨어 시간이 안 맞으면 어떻게 할까?? 예를 들어 현재 시간이 7월 22일인데 하드웨어 시간이 8월 14일인 경우인 상황이다.

    이런 경우는 hwclock -w를 써주면 된다.

    리눅스 시스템 시간에 맞춰서 하드웨어 시간이 변경되었다.


    • 참고 : 하드웨어 시간을 수동으로 설정할 수도 있다. 이 역시 root에서 진행해야 하며 명령어는

    sudo hwclock –set –date=”2018-08-13 12:24:42”

    잘 설정이 되었다.

  • CentOS 7

    Ubuntu와 그냥 똑같다. 위에 한 것처럼 똑같은 순서대로 해보면

    VM의 CentOS의 경우 시스템 시간이 실제 시간과 약 하루 정도 차이가 나는 상태였다. 이 역시 KST로 설정해놔서 지역시간 설정은 건드릴 필요 없고 진짜 시간 자체만 바꿔주면 된다.

  1. 타임 서버 이용하기

    타임 서버는 말 그대로 시간이 제대로 설정돼있는 서버를 말한다. 즉, 이 서버의 시간과 맞춰주면 현재 시간과 맞게 되는 것이다. 사용법은

    rdate -s [타임서버]

    타임서버에는

    time.bora.net
    time.nist.gov 
    time.nuri.net
    time.kriss.re.kr
    time.windows.com
    

    등이 있고 시간 설정부분이므로 root권한에서 진행해야 한다. 하나의 예로 time.bora.net을 써보면

    rdate -s time.bora.net

    오른쪽 현재 시간과 동일해진 것으로 보아 시간이 제대로 맞춰졌음을 확인할 수 있다. CentOS는 Ubuntu처럼 rdate를 따로 설치하지 않아도 됐다. 해당 명령어가 있어서 바로 타임서버를 이용할 수 있었다.

  2. 직접 설정하기

    이는 직접 시간을 입력하여 설정해주는 방법이다. 이 역시 root에서 진행해야 하며 사용법은

    date -s [시간] 또는 timedatectl set-time [시간]

    CentOS에서도 date -s [시간]을 사용할 때 날짜에 -를 빼고 20180722로 해도 똑같이 된다. 다음엔 timedatectl set-time [시간]을 써보자.

    반면 timedatectl은 Ubuntu에서와 똑같이 날짜에 -를 빼면 오류가 난다.

  3. 서버(하드웨어) 시간을 통한 설정

    1,2는 리눅스 시스템의 시간 설정 방법이고 3은 하드웨어인 서버의 자체 시간을 다루는 방법이다. 이는 hwclock 명령어를 이용한다. 이거 역시 root권한에서 진행해야 한다.

    앞에서 배운 rdate를 이용해 타임서버 시간과 맞춰져서 date를 입력하면 맞춰진 현재 시간이 나온다. 그런데 hwclock으로 하드웨어 시간을 보면 오히려 시간이 빠르다. 아까 Ubuntu 설명할 때 언급했던 부분이 이런 부분이다. 이 과정 역시 Ubuntu와 동일하다. 리눅스 시스템의 시간이 맞게 설정되어 있으니 이번엔 먼저 하드웨어 시간을 리눅스 시스템에 맞춰보자. 사용법은

    hwclock -w

    리눅스 시스템 시간에 맞춰서 하드웨어 시간이 변경되었다.

    반대로 리눅스 시스템의 시간을 하드웨어 시간에 맞추는 경우는

    hwclock -s

    리눅스 시스템 시간이 하드웨어 시간에 잘 맞춰졌음을 확인할 수 있다.

    • 참고 : 하드웨어 시간을 수동으로 설정할 수도 있다. 이 역시 root에서 진행해야 하며 명령어는

    hwclock –set –date=”2018-08-14 11:02:34”

    잘 설정이 되었다.




참고 사이트 :

  • http://frody.tistory.com/106
  • http://blog.cafe24.com/1929

阅读全文 »


IP란?


모든 컴퓨터나 네트워크 장비, 통신기기들은 인터넷을 사용하기 위해 IP주소를 할당받아 이용하게 된다. 이번 포스팅에서는 IP에 대해 알아보고자 한다.

  • IP

    인터넷 프로토콜(Internet Protocol)의 약자로 각 장치를 나타내는 IP 주소를 가리키는 말로 많이 쓰인다.
    컴퓨터의 경우 사용하는 운영체제도 서로 다르고, 프로그램의 경우 아예 구현된 언어가 다르기 때문에 네트워크에서 이들이 서로 통신할 수 있도록 하려면 공통된 통신 규약(프로토콜)이 필요해 만들어졌다.

    네트워크 상에서 컴퓨터는 다른 컴퓨터와 구별 될 수 있도록 고유번호를 가지게 되는데, 이것은 인터넷에 접속 할 때 컴퓨터 각각에 부여 받는 주소 혹은 전화번호 같은 것이라고 생각하면 된다. 만약 동일한 전화번호가 2개 있다면 서로 충돌이 되면서 혼란이 생길 것이다. 웹(인터넷) 상에서도 이런 현상들을 방지하기 위해서 IP주소를 만들어서 상호 충돌을 방지하고 있다.

    이렇게 IP주소를 사용함으로써 각각의 Host들을 구분할 수 있고, 부여받은 IP는 자기 고유의 IP가 되기 때문에 다른 사람이 사용할 수 없다. 그렇다고 하나의 Host에 하나의 IP만 사용되는 건 또 아니다. 한 컴퓨터에 여러 개의 NIC(Network Interface Card / 흔히 랜카드라 불리는 장치)를 장착하여 여러 개의 IP를 사용하는 경우도 있다. 대표적인 예로 라우터가 있다. 지금 언급되는 IP는 모두 공인 IP를 말하는 것이며 이에 대해서는 다시 포스팅을 할 예정이다. 이러한 IP는 각 나라마다 나라의 공인기관에서 할당하고 관리해준다. 우리나라의 경우는 한국인터넷진흥원에서 이를 담당하고 있으며 이것을 다시 SKT, KT, LG U+ 가 부여받고, 우리가 이 3사 중 한 곳에 가입을 함으로써 모뎀을 통해 각 컴퓨터마다 IP를 제공받아 인터넷을 사용하게 되는데 제공받을 때 고정 IP와 유동 IP로 나뉜다.

    • 고정 IP

      : IP가 고정되어 있어서 컴퓨터가 부팅되거나 해도 변경이 되지 않는 것을 말한다. 고정IP는 나만이 사용하는 주소이기 때문에 보안성이 우수해서 유동IP에 비해 가격이 비싸지만 보안이 필요한 업체나 기관에서는 주로 고정IP를 사용한다.

    • 유동 IP

      : 접속 할 때마다 그때 그때 IP의 주소 값이 변환되는 것으로 일반 가정집이나 대부분은 유동 IP를 사용한다. 이는 주로 IP의 부족현상을 방지하기 위해 사용되는데 예를 들어 SKT에서 보유하고 있는 IP의 갯수가 1만개인데, SKT 가입한 사람의 수가 3만명이면 IP가 그만큼 모자르다. 하지만 모든 회원이 계속 24시간 인터넷에 접속하는 것은 아니기 때문에 해당 기기의 전원이 Off됐을 때 IP주소가 필요없으므로 DHCP Server를 이용해 IP를 회수하여 다른 전원이 켜져있는 기기에 할당해주는 방식으로 계속 돌려가면서 IP를 부여해주는 방식이다. 이는 IP 주소를 공유한다고도 볼 수 있다(동시간대에 여러 기기가 같은 IP를 공유한다는 의미가 아님). 이러한 IP주소 부여는 모뎀에서 이루어진다.



  • ISP

    : Internet Service Provider의 약자로 인터넷 서비스 제공자라는 의미이다. 우리나라의 경우 SKT, KT, LG 유플러스 등 대기업 계열의 IT서비스 기업 등이 인터넷 서비스를 제공해준다. 이런 기업들을 ISP라고 부른다.

  • DHCP 서버

    : DHCP는 Dynamic Host Configuration Protocol의 약자로 호스트(서버)에서 보유하고 있는 IP를 유동적으로 관리하는 프로토콜이다. 즉, IP를 자동으로 할당하고 분배해주는 기능을 하므로 유동 IP를 관리하는데 사용되고 있다. IPv4를 디자인 했을 당시에는 현재처럼 많은 장치들이 인터넷에 연결될 것이라는 걸 고려하지 않았고 전 세계에 스마트폰 등의 휴대 장치, 인터넷 사물 장치(IoT) 등이 연결되어 장치마다 IP를 하나씩 할당하게 되면 IP의 관리 문제도 있고 그 중 사용하지 않는 장치가 있는 경우 IP가 낭비되기 때문에 이러한 문제를 해결하기 위해 고안되었다.
    DHCP 서버는 일정한 IP 대역을 가지고 있고 네트워크에 연결된 장치가 IP를 필요로 하는 경우 제한된 대역 안에서 IP를 발급해주며 발급해 준 IP를 일정 시간 동안 사용하지 않는 경우에는 다시 IP를 회수하여 다른 장치에서 요청이 있을 때 발급해준다. 이렇게 DHCP 임대시간(DHCP Lease Time)을 적용해 유동적으로 IP를 관리해서 제한된 자원을 효율적으로 관리하고 분배할 수 있게 하는 역할을 하는 것이다.

    출처 : https://www.netmanias.com/ko/post/blog/5348/dhcp-ip-allocation-network-protocol/understanding-the-basic-operations-of-dhcp

    그림은 PC라고 되어 있지만 공유기에 연결하면 공유기가 되는 것이다. 임대시간(DHCP Lease Time)이 끝나면 다시 IP를 회수해 다른 장치에서 요청이 들어왔을 때 똑같이 임대해주는 방식으로 계속 유동적으로 운영한다.지금은 IP에 대해서 다루는 것이기 때문에 그림에 대한 자세한 설명은 추후에 따로 다시 포스팅하겠다. 일단은 이런 식으로 유동 IP가 할당되는 것에 초점을 맞추자.

    이러한 이유 때문에 가끔 인터넷 업체에서 회선 공사나 점검을 할 때 그 지역을 담당하는 DHCP 서버를 리셋하게 되면 IP가 바뀌게 되는 것이다. 반대로 공유기의 Mac Address(네트워크 장치의 고유 번호)가 변경되면 ISP의 DHCP 서버 입장에서 장치가 바뀌게 되는 것이니 마찬가지로 IP가 변경되게 된다(해당 기기(Mac Address)에 맞춰서 사설IP가 할당되기 때문). 또한 IP를 DHCP 서버에서 관리하기 때문에 클라이언트에서 직접 입력해서 사용하는 고정 IP(DHCP 서버에서 할당해주는 고정 IP와 다른 개념)에 비해 관리가 수월하고 IP 충돌 등의 문제가 없어지는 이점을 갖게 되는 것이다. 이게 무슨 말이냐면 IP를 할당받는 것이 아닌 직접 손으로 입력했을 때(직접 수동으로 IP를 설정하는 경우는 당연히 고정 IP), IP를 잘못 입력한 경우 잘못 입력한 IP를 누군가가 사용하고 있다면 IP는 충돌난다는 말이다.
    사실 DHCP 서버는 우리도 모두 운영하고 있다고 할 수 있는데 그게 바로 공유기이다. 집에서 인터넷을 사용할 때 PC, 노트북, 스마트폰 등 여러 장치를 인터넷에 연결하기 위해서는 공유기가 필요한데 이 공유기는 DHCP 서버와 NAT 기능, 스위치 기능, 방화벽 기능을 포함한 라우터로 우리가 여러 장치를 연결해서 인터넷을 사용할 수 있게 도와준다. 공유기의 관리자 페이지로 로그인을 하면 DHCP 서버에 대한 설정이 있고 여기서 IP 대역을 설정하여 다른 장치들에게 192.168.xxx.xxx 등의 내부 IP를 발급해 주게 되고 Mac Address를 기반으로 해당 장치를 DHCP 서버에서 항상 같은 IP로 사용할 수 있게 고정할 수 있는 기능도 사용할 수 있다. 반대로 인터넷을 못하게 막을 수도 있다. 인터넷 서비스 업체에서 운영하는 DHCP 서버와 공유기의 DHCP 서버 기능은 규모만 다를 뿐 똑같은 역할을 하고 있다고 생각하면 된다.

다음 포스팅에서는 IP 클래스들에 대해 알아보도록 하자.


참고 사이트 :

  • http://korean-daeddo.blogspot.com/2015/12/ip.html
  • https://m.blog.naver.com/PostView.nhn?blogId=minwook74&logNo=120188168899&proxyReferer=https%3A%2F%2Fwww.google.co.kr%2F
  • https://www.netmanias.com/ko/post/blog/5348/dhcp-ip-allocation-network-protocol/understanding-the-basic-operations-of-dhcp
  • https://namu.wiki/w/IP

阅读全文 »


Kubernetes 설치(작업자 노드)


이번 포스팅에서는 마스토 노드가 아닌 작업자 노드에서 kubernetes를 설치해보려고 한다. 마스터 노드일 때와 상당히 비슷하다. 환경은 저번 포스팅과 같이 VM의 CentOS 7이다.

kubernetes를 설치하기 전에 먼저 update를 해준다.

업데이트를 마쳤으면 이번에도 역시 각 VM들을 구분해주기 위하여 hostnamectl 명령어로 이름을 지었는데 작업자 노드가 여러 개 있으면 그것들도 다 구분해야 하므로 ‘worker-node1’라는 이름을 주었고 exec bash로 실행시켜 주면 이름이 localhost에서 worker-node1로 바뀌었음을 확인할 수 있다. 그 다음은 selinux를 해제해준다.

setenforce 0

sed -i –follow-symlinks ‘s/SELINUX=enforcing/SELINUX=disabled/g’ /etc/sysconfig/selinux

그 다음 밑처럼 방화벽 설정을 해준다.

마스터 노드에서 열어준 포트랑 약간 다르고 이를 반영하기 위해서 그리고 서비스를 재구동하기 위해서 마찬가지로 –reload를 해준다. 마스터 노드에서는 reload해주고 나서 modprobe br_netfilter 명령어를 실행시켜야 하기 때문에 reboot을 해줘야 하지만 작업자 노드에서는 그런 과정이 필요없기 때문에 reboot을 해줄 필요도 없다. 하지만 iptable에서 Bridge된 트래픽을 볼 수 있게 하기 위해 /proc/sys/net/bridge/bridge-nf-call-iptables을 echo ‘1’로 해서 활성화해준다.

echo ‘1’ > /proc/sys/net/bridge/bridge-nf-call-iptables

그 다음은 Kubernetes 저장소를 구성하는 과정인데 마스터 노드 때도 언급했지만 Kubernetes 패키지는 기본 CentOS 7 및 RHEL 7 저장소(repository)에서 사용할 수 없기 때문에 아래 명령을 이용하여 저장소(repository) 파일을 만들어 패키지 저장소(repository)를 구성하는 것이다.

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

  • [kubernetes]

    저장소를 식별할 수 있는 id 로 여기에서는 “Kubernetes” 가 된다. yum 의 명령어 중에 저장소 목록을 보거나 특정 저장소를 지정하여 패키지를 설치하는 등의 저장소 관련 작업을 할 경우 필수 옵션으로 저장소의 id 를 넘겨줘야 하며 그 때 이 id를 사용하면 된다.

  • name

    저장소의 이름이다.

  • baseurl

    패키지를 설치하거나 업데이트 시 사용할 기본 저장소의 URL을 지정하며 fastestmirror 를 사용하여 동적으로 저장소를 찾지 않을 수 있지만 고정된 URL 의 저장소를 사용할 경우 baseurl로 설정해 주면 된다.

  • mirrorlist

    RHEL은 RedHat이 제공하는 중앙 저장소의 URL이 고정되어 있지만 CentOS 는 나라별로 미러 사이트들이 다르므로 빠른 속도로 저장소에 접속하려면 CentOS 를 설치한 국가에 따라 저장소 URL이 달라져야 한다. mirrorlist 가 설정되어 있으면 fastestmirror라는 yum 플러그인이 동작하여 가장 빠른 미러 사이트를 찾아서 저장소 URL 을 변환해 준다.

  • enabled
    1로 설정되어 있으면 이 저장소를 사용하겠다는 의미이며 0일 경우 사용하지 않겠다는 의미이다.
    –enablerepo, –disablerepo 옵션으로 실행 시점에 사용 여부를 변경할 수 있다.
  • gpgcheck, repo_gpgcheck

    yum 으로 패키지 설치시 GPG(GNU Privacy Guard) 서명 검증을 할 지 여부이며 yum.conf 처럼 기본 설정은 서명 검증하는 모드인 1이며 0일 경우 서명 검증을 하지 않는다.

  • gpgkey

    gpgcheck 를 할 경우 사용할 서버의 공개키 경로를 설정한다. 일반적으로 저장소를 제공하는 측에서 GPG 키를 같이 배포하므로 저장소 추가시 공개키를 같이 받아서 설정해 주면 된다. 밑에 적힌 두 URL이 공개키 경로이다.

패키지 저장소(repository)를 다 만들었으면 kubeadm 및 docker 패키지를 설치한다.

yum install kubeadm docker -y

다 설치했으면 이제 docker를 서비스 시작 및 사용가능(enable)하도록 해줘야 하는데(마스터 노드에서는 kubectl을 사용해야 하기 때문에 kubelet도 서비스 시작 및 사용가능(enable)하도록 해줘야 했지만 작업자 노드에서는 docker만 해주면 된다.)

오류가 난다. 똑같이 docker 상태를 확인해보니 역시나 docker가 죽어 있다. 원래 restart를 하면 다시 살아나야 하는데 살아나지 않아 reboot를 해준 후 다시 restart해줬더니 잘 동작했다(restart 했는데 잘 살아나면 굳이 reboot 해 줄 필요 X). 그 다음 enable도 해준다.

이제 마스터 노드에 작업자 노드를 join 시켜볼 차례이다.

여기가 저번 포스팅에서 봤던 마스터 노드 화면인데 빨간색 표시된 부분을 통째로 복사해 그대로 작업자 노드에 붙여넣기하면 된다. 하지만 join해보면

certificated has expired or is not yet valid라고 뜬다. 즉, 마스터에 join할 때 인증서 같은 거로 인증을 하는데 이가 파괴되었거나 유효하지 않다는 뜻이다. 검색해보니 이는 서로 시간이 안 맞을 때 발생하는 것이라고 한다. 그래서 마스터 노드와 작업자 노드의 시간을 비교해보니

마스터 노드

작업자 노드

역시나 시간이 서로 맞지 않았다. 마스터 노드의 시간이 잘못된 상태에서 설정이 된 상태라서 작업자 노드 시간은 현재 시간과 잘 맞았음에도 마스터 노드 입장에서는 잘못된 시간으로 인식되어 저런 오류가 났던 것이다. 그럼 마스터 노드의 설정을 다시 해주자. 지금부터는 마스터 노드 화면이다.

먼저 시간을 바로 잡아주자.

혹시 UTC로 되어있지 않나 해서 봤더니 Asia/Seoul로 잘 연결되어 있었다. 즉, 지역은 바꿀 필요 없고 시간만 바꿔주면 된다는 뜻이다. timedatectl 명령어로 시간을 바꿔준다. 시간을 맞춰주었으면 마스터 노드를 다시 설정해줘야 하기 때문에 마스터 노드를 다시 reset해줘야 한다.

kubeadm reset

해당 명령어로 reset을 해준 후 다시 마스터 노드를 초기화시켜준다(설정해준다).

kubeadm init

초기화해 줄 때 원래는 running with swap on is not supported. Please disable swap 이라는 메시지가 떠서 swapoff -a를 해준 후 다시 kubeadm init을 입력해야 하는데 reset해주고 다시 init해주면 이게 안 뜨고 한 번에 초기화되기도 한다. 상황에 따라 유동적으로 하면 된다.

다시 새로운 값으로 초기화가 됐다. 저번 포스팅에서 했던 것처럼 똑같이 해주면 된다.

mkdir -p $HOME/.kube

sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config

sudo chown $(id -u):$(id -g) $HOME/.kube/config

그 다음에 Pod Network를 배포해준다.

export kubever=$(kubectl version base64 tr -d ‘\n’)

kubectl apply -f “https://cloud.weave.works/k8s/net?k8s-version=$kubever”

그 다음 마지막 부분(kubeadm join ~)을 그대로 복사해서 해당 노드에 입력해주면 마스터에 노드가 연결된다. 지금부터는 다시 작업자 노드이다.

그대로 복사해주면 이 노드가 마스터에 잘 join됐다고 나온다. 성공한 것이다. 단, 여기서도 running with swap on is not supported. Please disable swap가 뜨기도 한다. worker-node1은 안 떴으나 worker-node2는 떴다.

이 때는 swapoff -a 해준 후 다시 kubeadm join ~을 해주면 된다.

마스터 노드로 가서 확인해보면

worker-node1이라는 이름의 노드가 생성됐다. 이런 식으로 추가하고 싶은 노드들을 다 추가해주면 된다. 필자는 최종적으로 worker-node2라는 노드도 추가해서 총 마스터 노드 포함 총 3개의 노드를 만들 것이다. worker-node2는 worker-node1처럼 똑같이 해주면 되고 다 해주면 최종적으로는

이런 식으로 계속 마스터에 연결(join)하고 싶은 노드들을 연결해 줄 수 있다.




참고 블로그 :

  • https://www.linuxtechi.com/install-kubernetes-1-7-centos7-rhel7/

阅读全文 »


Kubernetes 설치(마스터 노드)


이번 포스팅에서는 kubernetes를 설치해보려고 한다. 마스터 노드와 작업자 노드들이 있지만 마스터 노드에 대해서만 다루도록 하겠다. 환경은 VM의 CentOS 7이다.

kubernetes를 설치하기 전에 먼저 update를 해준다.

각 노드(VM)들을 구분해주기 위하여 hostnamectl 명령어로 ‘k8s-master’라는 이름을 주었고 exec bash로 실행시켜 주면 이름이 localhost에서 k8s-master로 바뀌었음을 확인할 수 있다. 구분을 할 수 있다면 따로 해주지 않아도 상관은 없다. 그 다음 selinux를 해제해준다.

setenforce 0

sed -i –follow-symlinks ‘s/SELINUX=enforcing/SELINUX=disabled/g’ /etc/sysconfig/selinux

그 다음 밑의 그림처럼 방화벽 설정을 해준다.

RHEL 7 부터는 방화벽을 관리하는 데몬이 firewalld 로 변경되었고 방화벽 설정은 복잡한 iptables 명령어 대신 firewall-cmd(콘솔), firewall-config(X-Windows) 명령어를 사용하는 것을 권장한다고 한다. firewall-cmd는 iptables 를 쓰기 쉽게 하는 wrapper이고 복잡한 규칙을 사용할 경우 –direct 옵션으로 iptables 내부에 접근해야 한다.
–add-port는 포트를 열어준다는 뜻이고 이를 반영하기 위해서 그리고 서비스를 재구동하기 위해서 –reload를 해준다(서비스 재구동시 service iptables restart 대신 firewall-cmd 명령어를 사용함). reload해주고 나서 reboot를 해줘야 modprobe br_netfilter 명령어가 작동한다. 그렇지 않으면 맨 밑에 나온 거처럼 FATAL: Module br_netfilter not found라는 오류가 발생한다.

reboot를 해주고 다음 명령어들을 입력해주면 잘 동작한다. br_netfilter는 bridge-netfilter라고 해서 {ip, ip6, arp} table이 802.1Q VLAN 또는 PPPoE 헤더에 캡슐화 된 경우에도 Bridge된 IPv4 / IPv6 / ARP 패킷을 필터링한다. 이렇게 하면 상태 보존형 투명 방화벽의 기능을 사용할 수 있으며, 모든 필터링, 로깅 및 NAT 기능 역시 Bridge된 프레임에서 사용할 수 있다. 또한 br_netfilter를 설치하면 모든 로컬 호스트가 인터넷에 직접 연결되어 있다고 간주한다. Linux 커널 3.18-rc1 이후로, bridge-netfilter를 활성화하려면 br-netfilter를 modprobe해줘야 하기 때문에 저렇게 명령어를 입력한 것이다.
(modprobe : 적재 가능한 커널 모듈을 리눅스 커널에 추가하거나 커널로부터 제거하는데 사용되는 Linux 프로그램)

밑에 echo ‘1’ > /proc/sys/net/bridge/bridge-nf-call-iptables는

{ip, ip6, arp} table에서 Bridge된 트래픽을 볼 수 있게 하기 위해 /proc/sys/net/bridge/bridge-nf-call-iptables을 echo ‘1’로 해서 활성화해주는 것이다(물론 ip6, arp는 bridge-nf-call-iptables 대신에 bridge-nf-call-ip6tables, bridge-nf-call-arptables를 써줘야 함). 여기서는 iptable에서 Bridge된 트래픽만 설정해주었다.

그 다음은 Kubernetes 저장소를 구성하는 과정인데 Kubernetes 패키지는 기본 CentOS 7 및 RHEL 7 저장소(repository)에서 사용할 수 없기 때문에 아래 명령을 이용하여 저장소(repository) 파일을 만들어 패키지 저장소(repository)를 구성하는 것이다.

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

  • [kubernetes]
    저장소를 식별할 수 있는 id 로 여기에서는 “Kubernetes” 가 된다. yum 의 명령어 중에 저장소 목록을 보거나 특정 저장소를 지정하여 패키지를 설치하는 등의 저장소 관련 작업을 할 경우 필수 옵션으로 저장소의 id 를 넘겨줘야 하며 그 때 이 id를 사용하면 된다.
  • name

    저장소의 이름이다.

  • baseurl
    패키지를 설치하거나 업데이트 시 사용할 기본 저장소의 URL을 지정하며 fastestmirror 를 사용하여 동적으로 저장소를 찾지 않을 수 있지만 고정된 URL의 저장소를 사용할 경우 baseurl로 설정해 주면 된다.
  • mirrorlist

    RHEL은 RedHat이 제공하는 중앙 저장소의 URL이 고정되어 있지만 CentOS 는 나라별로 미러 사이트들이 다르므로 빠른 속도로 저장소에 접속하려면 CentOS 를 설치한 국가에 따라 저장소 URL이 달라져야 한다. mirrorlist 가 설정되어 있으면 fastestmirror라는 yum 플러그인이 동작하여 가장 빠른 미러 사이트를 찾아서 저장소 URL 을 변환해 준다.

  • enabled
    1로 설정되어 있으면 이 저장소를 사용하겠다는 의미이며 0일 경우 사용하지 않겠다는 의미이다.
    –enablerepo, –disablerepo 옵션으로 실행 시점에 사용 여부를 변경할 수 있다.
  • gpgcheck, repo_gpgcheck

    yum 으로 패키지 설치시 GPG(GNU Privacy Guard) 서명 검증을 할 지 여부이며 yum.conf 처럼 기본 설정은 서명 검증하는 모드인 1이며 0일 경우 서명 검증을 하지 않는다.

  • gpgkey

    gpgcheck 를 할 경우 사용할 서버의 공개키 경로를 설정한다. 일반적으로 저장소를 제공하는 측에서 GPG 키를 같이 배포하므로 저장소 추가시 공개키를 같이 받아서 설정해 주면 된다. 밑에 적힌 두 URL이 공개키 경로이다.

패키지 저장소(repository)를 다 만들었으면 kubeadm 및 docker 패키지를 설치한다.

yum install kubeadm docker -y

다 설치했으면 이제 kubectl 및 docker를 서비스 시작 및 사용가능(enable)하도록 해줘야하는데

막상 해보면 이런 오류가 난다. 그래서 docker 상태를 확인해보니

systemctl status docker.service

docker가 죽어 있다. 원래 restart를 하면 다시 살아나야 하는데 계속 살아나지 않아 reboot를 해준 후 다시 restart해줬더니 잘 동작했다(restart 했는데 잘 살아나면 굳이 reboot 해 줄 필요 X).

이게 VM이라서 그런 건지 아니면 실서버에서도 이렇게 적용되는지는 잘 모르겠다. reboot을 해준 후 못해줬던 restart 및 enable을 다시 해주면

이렇게 명령어가 잘 동작한다. 이제 kubeadm init 명령어를 통해 Kubernetes Master를 초기화해줘야 한다.

kubeadm init

하지만 맨 밑을 보면 running with swap on is not supported. Please disable swap 이라는 메시지가 떴다. 이는 swap 파일의 구동을 지원하지 않아 swap을 중단시키라는 의미로 swap 파티션이나 swap 파일의 구동을 중단시키는 명령어인 swapoff -a를 써주면 된다.

swapoff -a

그러고 나서 다시 kubeadm init으로 Kubernetes Master를 초기화해주면

아까와는 다르게 오류는 뜨지않고

Your Kubernetes master has initialized successfully!라는 메시지가 떴다. 성공적으로 초기화했다는 뜻이다.

그런데, 그 밑에 너의 클러스터를 사용하기 위해서는 다음 명령어를 실행해야 한다고 한다.

mkdir -p $HOME/.kube

sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config

sudo chown $(id -u):$(id -g) $HOME/.kube/config

만약 이를 실행하지 않고 kubectl을 사용하려고 하면

The connection to the server localhost:8080 was refused - did you specify the right host or port? 오류가 발생한다.

그 다음 줄에는 클러스터에 Pod Network를 배포해야된다고 나와 있으며 그 밑에는 root로써 각 동작하고 있는 노드들을 join시킬 수 있다고 나온다. 밑의 부분(kubeadm join ~)을 그대로 복사헤서 해당 노드에 입력해주면 마스터노드에 작업자 노드가 연결된다. 이 부분은 작업자 노드를 설치하는 과정에서 다시 보여주겠다.

이 명령어를 입력한 후 클러스터의 상태를 확인해보자.

kubectl get nodes

(참고 : kubectl은 Kubernetes를 운영하기 위한 CLI 도구로 상당히 많은 기능들을 제공한다.)

일단은 node를 따로 연결하지 않았기 때문에 아무것도 연결되어 있지 않고 Master만 있다. Host의 이름이 k8s-master여서 저렇게 나오는 것이고 aaa로 지정했으면 aaa로 나온다. 다음 포스팅에서 node에다가도 알기 쉽게 hostnamectl을 통해 이름을 지을 건데 지은 이름 그대로 클러스터에 나타나게 된다. 그리고 지금은 NotReady 상태이다.

kubectl get pods –all-namespaces

이는 Pod의 모든 리스트들을 조회하는 명령어인데 처음엔 이런 상태이다가 시간이 지나면

이렇게 바뀌는데 위의 coredns들은 pending 즉, 계속 대기중인 상태이다. 클러스터 상태를 준비하고 coredns 상태를 실행하려면 다른 호스트의 컨테이너가 서로 통신하도록 Pod Network를 배포해야 한다. Pod Network는 작업자 노드 간의 Overlay 네트워크이다.
(Overlay Network : 기존 Network를 바탕으로 그 위에 구성된 또 다른 Network로 기존의 Network 위에 별도의 노드들(nodes)과 논리적 링크들(logical links)을 구성하여 이루어진 가상 Network이다. Overlay Network에서 이웃 노드들은 물리적인 이웃 노드가 아니라 논리적인 이웃 노드이다. 기존의 Network를 최대한 활용하여 보다 효율적인 Network 서비스를 제공할 수 있다.)

Pod Network를 배포하는 방법은 아래처럼 해주면 된다.

export kubever=$(kubectl version base64 tr -d ‘\n’)

kubectl apply -f “https://cloud.weave.works/k8s/net?k8s-version=$kubever”

이 다음에 다시 Pod를 조회해보면

이제 coredns 부분도 Running 상태가 되었다. 아까 Master도 NotReady 상태였는데 지금은 Ready상태로 바뀐 것을 확인할 수 있다.

이제 마스터 노드는 설정이 완료되었다. 다음 포스팅에서는 작업자 노드 설정을 해보자.




참고 블로그 :

  • https://www.linuxtechi.com/install-kubernetes-1-7-centos7-rhel7/
  • https://www.lesstif.com/pages/viewpage.action?pageId=22053128
  • https://www.lesstif.com/display/1STB/yum
  • http://ebtables.netfilter.org/documentation/bridge-nf.html

阅读全文 »


Linux 시간 설정하기(1)


서버를 구축하면서 반드시 해야 할 작업 중의 하나가 시간을 제대로 맞추는 것이다. 도커 컨테이너를 띄울 때도 서버 시간과 컨테이너의 시간이 다른 경우가 있는데 상황에 따라 시간을 맞춰줘야 하는 경우가 생긴다. 해당 지역의 로컬 시간을 설정하기 위해서는 /etc/localtime을 원하는 지역의 것으로 바꾸어 주면 된다. 실습환경은 VM의 Ubuntu 16.04와 CentOS 7 두 곳에서 진행할 것이다.

  • Ubuntu 16.04

    오른쪽을 보면 현재시간은 2018년 07월 22일 08:03이다. 하지만 date를 입력해보면 시간이 다르다. 저번 포스팅에서 봤던 UTC(협정 세계시)로 되어있기 때문이다. 해당 시간은 /etc/localtime에 저장되어 있기 때문에 ls -al 명령어로 확인해보면

    ls -al /etc/localtime

    심볼릭 링크로 UTC파일 즉, /usr/share/zoneinfo/UTC에 연결되어 있다. /usr/share/zoneinfo/로 가면 해당 지역들이 나온다. 거기서 지정하고 싶은 나라와 지역을 설정해주면 된다.

    ls -al /usr/share/zoneinfo

    이런 식으로 쭉 나오는데 우리는 대한민국에 살기 때문에 Asia에 해당하므로 Asia를 택해준다. Asia가 directory로 되어 있으므로 해당 디렉토리를 살펴보자.

    ls -al /usr/share/zoneinfo/Asia

    여기에 Seoul이 보인다. Seoul은 파일로 되어있으므로 여기를 /etc/localtime이랑 연결해주면 된다.

    sudo ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime

    이러고 나서 ls -al /etc/localtime으로 확인해보면 Seoul파일에 잘 연결되어 있다. date로도 입력해보면 KST 즉, 한국 시간으로 바뀌어 있음을 확인할 수 있다.

    하지만 여기서 드는 의문점이 하나 있었다. Seoul 파일을 보면 사실 심볼릭링크로 무언가에 연결되어 있는 것을 볼 수 있다. 보면 –> ../ROK라고 되어 있는 것으로 보아 Seoul 파일이 있는 위치의 상위 경로에 있는 ROK파일에 연결되어 있는 것을 알 수 있다. 그 말은 /usr/share/zoneinfo/Asia/Seoul이 아닌 /usr/share/zoneinfo/ROK로 해도 똑같다는 말 같아서 시간을 UTC로 되돌린 후 실험을 해봤다.

    UTC 시간으로 맞춘 다음 /etc/localtime을 /usr/share/zoneinfo/ROK로 연결했더니 똑같이 한국시간 KST로 바뀌었다. 그럼 ROK도 Seoul처럼 어딘가에 심볼링 링크가 걸려있지않나 확인을 해봤더니

    ls -al /usr/share/zoneinfo

    따로 걸려있지 않다. 이 ROK 파일에 한국 시간이 저장되어 있는 것이다. 이걸 확인하다 보니 밑에 있는 UTC도 맨 밑의 Zulu와 심볼릭 링크로 연결되어 있는데 이 역시 /usr/share/zoneinfo/UTC 대신 /usr/share/zoneinfo/Zulu로 해도 똑같이 UTC로 시간이 설정된다.

  • CentOS 7

    여기도 마찬가지로 오른쪽을 보면 현재시간은 2018년 07월 29일 16:53이다. 하지만 date를 입력해보면 시간이 다르다. UTC(협정 세계시)로 되어있기 때문이다. CentOS 7 역시 해당 시간은 /etc/localtime에 저장되어 있기 때문에 ls -al 명령어로 확인해보면

    ls -al /etc/localtime

    심볼릭 링크로 UTC파일 즉, /usr/share/zoneinfo/UTC에 연결되어 있다. CentOS도 /usr/share/zoneinfo/로 가면 해당 지역들이 나온다. 똑같이 지정하고 싶은 나라와 지역을 설정해주면 된다.

    ls -al /usr/share/zoneinfo

    우리는 대한민국에 살기 때문에 Asia에 해당하므로 Asia를 택해준다. 여기도 Asia가 directory로 되어 있으므로 해당 디렉토리를 살펴보자.

    ls -al /usr/share/zoneinfo/Asia

    여기에 Seoul이 보인다. Seoul은 파일로 되어있으므로 여기를 /etc/localtime이랑 연결해주면 된다.

    ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime

    이러고 나서 ls -al /etc/localtime으로 확인해보면 Seoul파일에 잘 연결되어 있다. date로도 입력해보면 KST 즉, 한국 시간으로 바뀌어 있음을 확인할 수 있다.

    하지만 Ubuntu와 약간의 차이가 있다. 아까는 Seoul 파일이 ../ROK 파일과 심볼릭 링크로 연결이 되어 있었는데 CentOS 7은 그렇지가 않다. 근데 Ubuntu처럼 /usr/share/zoneinfo에 ROK파일이 존재하긴 한다. ROK가 Republic Of Korea 같아서 ROK를 /etc/localtime에 연결해도 한국 시간이 될 것 같긴 했지만 혹시나 해서 한 번 진행해봤는데

    역시나 한국시간 KST로 잘 설정됨을 확인할 수 있다.

결론은 Ubuntu와 CentOS의 시간 설정해주는 방법은 아예 똑같다고 보면 된다.



검색해보다가 dpkg-reconfigure라는 툴을 이용해서 시간을 설정하는 방법이 있었다. 이는 약간 번외느낌이므로 귀찮으신 분들은 스킵하면 될 것 같다. 이 방법은 Debian/Ubuntu 계열에만 해당되며 도커 컨테이너 이미지들이 대부분 기본으로 Debian이 깔려있기 때문에 도커 컨테이너에다가 직접 설정을 해볼 예정이다. 도커를 잘 모르시는 분들은 그냥 Ubuntu나 Debian에 설치한다고 생각하면 될 것 같다.

환경은 VM의 CentOS 7이고 여기에 mysql 컨테이너가 있다. mysql 컨테이너의 경우는 Debian으로 되어 있기 때문에 위 내용들을 실행할 수 있다.

  • dpkg-reconfigure 툴을 이용한 설치

도커를 모르시는 분들은 root@localhost pooh는 CentOS 7(현재시간이 맞춰져 있는 상태), root@b319cd6ad559:/ 를 Debian이라고 생각하면 된다. Debian에 mysql이 깔려있는 상태인 것이다. Debian의 시간이 따로 설정이 되어있지 않아 UTC로 되어 있다. 그리고 밑에 보면 Debian임을 확인할 수 있다. Debian에 dpkg-reconfigure 툴을 설치해서 시간을 맞춰보자.

먼저 업데이트를 해준다.

apt-get update -y

업데이트를 마쳤으면 이제 dpkg-reconfigure 툴을 이용한다.

dpkg-reconfigure tzdata

위 명령어를 입력하면 이렇게 화면이 뜨게 된다. 우리는 Asia / Seoul이므로 Asia를 선택한다. 6번에 Asia가 있으므로 6 누르고 Enter키를 누르면

이런 화면이 나온다. 여기서 Seoul을 선택해주면 된다. 68번에 Seoul이 있으므로 68 누르고 Enter키를 누르면

이제 설정이 끝났다. time zone이 Asia/Seoul로 설정되었고 Local time이 KST 즉, 한국시간으로 설정되었다. date로 확인해봐도 KST로 잘 나온다. CentOS 7의 시간과 비교해보면

컨테이너 밖으로 빠져나올 때의 시간으로 인해 3초의 차이가 생긴 것이고 결국 현재 시간과 잘 맞춰졌음을 확인할 수 있다(도커를 모르시는 분들은 Debian의 시간확인을 하고 CentOS 7로 넘어갈 때 3초의 시간이 걸려 3초가 차이 난 것이지 결국 똑같아졌다고 이해하면 된다(위의 시간은 Debian, 밑의 시간은 CentOS 7)).


참고 블로그 :

  • https://m.blog.naver.com/PostView.nhn?blogId=ksmsumu&logNo=220039780937&proxyReferer=https%3A%2F%2Fwww.google.co.kr%2F
  • http://gauryan.tistory.com/128

阅读全文 »


Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?


CentOS 7에서 docker로 작업을 해야해서 docker ps 명령어를 입력했는데, "Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?" 오류가 뜨면서 아무것도 나오지 않았다. 혹시 docker ps만 이런가 해서 다른 docker 명령어(docker images)를 입력해봤는데 역시나 똑같은 오류가 떴다.

이렇게 docker 명령어가 안 먹을때는 역시 docker의 상태를 확인해보면 된다.

systemctl status docker.service

역시나 도커가 죽어있다. 그러면 restart시켜주자.

systemctl restart docker

그러고 나서 다시 docker 명령어를 입력하면(docker ps), 다시 잘 작동됨을 확인할 수 있다.

阅读全文 »